From cdf342536db6ebfe63e08eb38974423d72c309de Mon Sep 17 00:00:00 2001 From: Victor Lazzarini Date: Tue, 18 Mar 2008 22:46:52 +0000 Subject: added Waves activity example --- diff --git a/Waves.activity/MANIFEST b/Waves.activity/MANIFEST new file mode 100644 index 0000000..2671c12 --- /dev/null +++ b/Waves.activity/MANIFEST @@ -0,0 +1,7 @@ +setup.py +waves.csd +activity/activity.info +activity/activity-waves.svg +csndsugui.py +waves.py +MANIFEST \ No newline at end of file diff --git a/Waves.activity/activity/activity-waves.svg b/Waves.activity/activity/activity-waves.svg new file mode 100644 index 0000000..e0e7f4a --- /dev/null +++ b/Waves.activity/activity/activity-waves.svg @@ -0,0 +1,22 @@ + + + +]> + + + + + + + diff --git a/Waves.activity/activity/activity.info b/Waves.activity/activity/activity.info new file mode 100644 index 0000000..cb183a1 --- /dev/null +++ b/Waves.activity/activity/activity.info @@ -0,0 +1,7 @@ +[Activity] +name = Waves +service_name = org.laptop.Waves +class = waves.Waves +icon = activity-waves +activity_version = 1 +show_launcher = yes diff --git a/Waves.activity/csndsugui.py b/Waves.activity/csndsugui.py new file mode 100644 index 0000000..803152e --- /dev/null +++ b/Waves.activity/csndsugui.py @@ -0,0 +1,616 @@ +# sugar-aware GUI classes +# with boxes, sliders, spinbuttons, buttons, etc +# +# (c) Victor Lazzarini, 2006-08 +# +# This library is free software; you can redistribute it +# and/or modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# csndsugui is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with csndsugui; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA +# +# As a special exception, if other files instantiate templates or +# use macros or inline functions from this file, this file does not +# by itself cause the resulting executable or library to be covered +# by the GNU Lesser General Public License. This exception does not +# however invalidate any other reasons why the library or executable +# file might be covered by the GNU Lesser General Public License. +# +# +# version 0.1.2 18/03/08 + +import pygtk +pygtk.require('2.0') +from sugar.activity import activity +import gtk +import sys +import csnd +import math +import locale +import os + +# Basic GUI with boxes, sliders, spins, buttons etc +# using pygtk/sugar, from which GUI classes +# can be derived for Csound use +class BasicGUI: + + # basic bus channel setting method, + # should be overriden for full-functionality + def set_channel(self,name, val): + print "channel:%s, value:%.1f" % (name,val) + + # basic filename channel setting method + # should be overriden for full-functionality + def set_filechannel(self,chan,name): + print "channel:%s, filename:%s" % (chan,name) + + # basic message setting method + # should be overriden for full-functionality + def set_message(self, mess): + print mess + + # returns the slider value + # + # name: slider name (which should also be + # the attached bus channel name) + def get_slider_value(self,name): + for i in self.sliders: + if i[1] == name: + return i[2] + return 0 + + # returns the button value (0 or 1) + # + # name: button name (which should also be + # the attached bus channel name) + def get_button_value(self,name): + for i in self.buttons: + if i[1] == name: + return i[2] + return 0 + + # returns the slider widget instance + # + # name: slider name + def get_slider(self,name): + for i in self.sliders: + if i[1] == name: + return i[0] + return 0 + + # returns the button widget instance + # + # name: button name + def get_button(self,name): + for i in self.sliders: + if i[1] == name: + return i[0] + return 0 + + # internal button callback + def buttcallback(self, widget, data=None): + for i in self.buttons: + if i[0] == widget: + if i[2]: + i[2] = 0 + i[0].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x0FFF,0,0x00FF, 2)) + i[0].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF,0,0xFFFF, 2)) + else: + i[2] = 1 + i[0].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0xFFFF,0,0, 1)) + i[0].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF,0,0, 2)) + self.set_channel(i[1], i[2]) + + # internal button callback + def mbuttcallback(self, widget, data=None): + for i in self.buttons: + if i[0] == widget: + self.set_message(i[2]) + + # internal slider callback + def slidcallback(self,adj,widget): + for i in self.sliders: + if i[0] == widget: + i[2] = adj.value + if i[4]: + self.set_channel(i[1],i[2]) + i[3].set_text("%f" % i[2]) + pass + else: + value = i[5]*pow(i[6]/i[5], i[2]/i[6]) + self.set_channel(i[1], value) + i[3].set_text("%.3f" % value) + pass + + # internal spin callback + def spincallback(self,adj,widget): + for i in self.spins: + if i[0] == widget: + i[2] = adj.value + self.set_channel(i[1],i[2]) + + # internal callback + def filecallback(self,widget): + name = self.curfile[0].get_filename() + self.set_filechannel(self.curfile[1], name) + self.filenames.update({self.curfile[1] : name}) + self.curfile[0].destroy() + + # internal callback + def fbuttcallback(self, widget, data=None): + for i in self.buttons: + if i[0] == widget: + chooser = gtk.FileSelection(i[1]) + self.curfile = (chooser, i[1]) + chooser.set_filename(self.data_path) + chooser.ok_button.connect("clicked", self.filecallback) + chooser.cancel_button.connect("clicked", lambda h: chooser.destroy()) + chooser.show() + + # creates a callbackbutton () + # + # box: parent box + # callback: click callback + # title: if given, the button name + # returns the widget instance + def cbbutton(self,box,callback,title=""): + self.cbbutts = self.cbbutts + 1 + butt = gtk.Button(" %s " % title) + box.pack_start(butt, False, False, 5) + self.cbbuttons.append([butt,title,0]) + butt.connect("clicked", callback) + butt.show() + return butt + + # creates a button (on/off) + # + # box: parent box + # title: if given, the button name, + # which will also be the bus channel + # name. Otherwise a default name is + # given, BN, where N is button number + # in order of creation. + # label: if given, an alternative button name, + # which will be displayed instead of title + # returns the widget instance + def button(self,box, title="",label=""): + self.butts = self.butts + 1 + if title == "": + title = "B%d" % self.butts + if label == "": name = title + else: name = label + butt = gtk.Button(" %s " % name) + butt.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.Color(0xFFFF,0,0, 1)) + butt.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF,0,0xFFFF, 2)) + box.pack_start(butt, False, False, 5) + self.buttons.append([butt,title,0]) + butt.connect("clicked", self.buttcallback) + butt.show() + return butt + + # creates a mbutton (sending a message) + # + # box: parent box + # title: if given, the button name, otherwise a default name is + # given, BN, where N is button number + # in order of creation. + # mess: message to be sent when button is clicked + # returns the widget instance + def mbutton(self,box,mess,title=""): + self.mbutts = self.mbutts + 1 + if title == "": + title = "B%d" % self.mbutts + butt = gtk.Button(title) + butt.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x0FFF,0,0x00FF, 1)) + butt.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF,0xFFFF,0x0000, 2)) + box.pack_start(butt, False, False, 5) + self.buttons.append([butt,title,mess]) + butt.connect("clicked", self.mbuttcallback) + butt.show() + return butt + + # creates a box + # + # vert: True, creates a vertical box; horiz. + # otherwise + # parent: parent box, None if this is a toplevel box + # padding: box padding + # returns the widget instance + def box(self,vert=True, parent=None, padding=5): + if vert: + box = gtk.VBox() + else: + box = gtk.HBox() + if parent: + parent.pack_start(box, False, False, padding) + else: + self.outbox.pack_start(box, False, False, padding) + self.boxes.append(box) + box.show() + return box + + # creates a filechooser button + # title: button name, also file bus channel name + # box: parent box + # label: if given, alternative name, for display purposes only + # otherwise button will display its title + def filechooser(self,box,title,label=""): + if label == "": name = title + else: name = label + butt = gtk.Button(name) + box.pack_start(butt, False, False, 5) + self.buttons.append([butt,title]) + butt.connect("clicked", self.fbuttcallback) + self.set_filechannel(title,"0") + self.filenames.update({title:"0"}) + butt.show() + return butt + + # creates a slider + # + # init: initial value + # start, end: start and end of slider range + # x, y: x and y sizes of slider + # box: parent box + # title: if given, the slider name, + # which will also be the bus channel + # name. Otherwise a default name is + # given, SN, where N is slider number + # in order of creation. + # vert: vertical slider (True), else horiz. + # linear: linear response (True), else exponential (zero or negative + # ranges are not allowed) + # dwid: display width in pixels + # label: if given, the alternative slider name, for display only + # returns the widget instance + def slider(self,init, start, end, x, y, box, title="",vert=True,linear=True,dwid=100,label=""): + self.slids = self.slids + 1 + if title == "": + title = "S%d" % self.slids + a = end - start + if vert: + step = a/y + adj = gtk.Adjustment(init,start,end,step,step,0) + slider = gtk.VScale(adj) + slider.set_inverted(True) + else: + step = a/x + adj = gtk.Adjustment(init,start,end,step,step,0) + slider = gtk.HScale(adj) + + slider.set_draw_value(False) + if step < 1.0: + slider.set_digits(3) + elif step < 10: + slider.set_digits(2) + elif step < 100: + slider.set_digits(1) + else: + slider.set_digits(0) + + entry = gtk.Entry(5) + if vert: entry.set_size_request(dwid,50) + else: entry.set_size_request(dwid,50) + entry.set_editable(False) + + if not linear: + if (init <= 0) or (start <= 0) or (end <= 0): + linear = True + + if not linear: + pos = end*math.log(1,end/start) + slider.set_range(pos, end) + pos = end*math.log(init/start,end/start) + slider.set_value(pos) + + if label == "": name = title + else: name = label + entry.set_text("%f" % init) + label = gtk.Label(name) + slider.set_size_request(x,y) + box.pack_start(slider, False, False, 5) + box.pack_start(entry, False, False, 2) + box.pack_start(label, False, False, 2) + self.sliders.append([slider,title,init,entry,linear,start,end]) + adj.connect("value_changed", self.slidcallback, slider) + slider.show() + entry.show() + label.show() + self.set_channel(title, init) + return slider + + + # creates a spin button + # + # init: initial value + # start, end: start and end of slider range + # step, page: small and large step sizes + # box: parent box + # accel: acceleration or 'climb rate' (0.0-1.0) + # title: if given, the spin button name, + # which will also be the bus channel + # name. Otherwise a default name is + # given, SPN, where N is spin number + # in order of creation. + # label: if given, the alternative name for the widget, for display only. + # returns the widget instance + def spin(self,init, start, end, step, page, box, accel=0,title="",label=""): + self.spinbs = self.spinbs + 1 + if title == "": + title = "SP%d" % self.spinbs + adj = gtk.Adjustment(init,start,end,step,page,0) + spin = gtk.SpinButton(adj,accel) + if step < 1.0: + spin.set_digits(3) + elif step < 10: + spin.set_digits(2) + elif step < 100: + spin.set_digits(1) + else: + spin.set_digits(0) + + if label == "": name = title + else: name = label + label = gtk.Label(name) + box.pack_start(spin, False, False, 5) + box.pack_start(label, False, False, 2) + self.spins.append([spin,title,init]) + adj.connect("value_changed", self.spincallback, spin) + spin.show() + label.show() + self.set_channel(title, init) + return spin + + + # creates a static text label + # + # name: text label + # box: parent box, None if text is to be placed toplevel + # colour: RGB values in a tuple (R,G,B) + # returns the widget instance + def text(self, name, box=None,colour=(0,0,0)): + label = gtk.Label(name) + label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(colour[0],colour[1],colour[2], 0)) + if box: + box.pack_start(label, False, False, 5) + else: + self.outbox.pack_start(label, False, False, 5) + label.show() + return label + + # creates a frame box + # + # name: text label + # vert: vertical (True) box, else horiz. + # parent: parent box, if None, this is a toplevel box + # colour: RGB values in a tuple (R,G,B) + # padding: padding space + # returns the box widget instance + def framebox(self, name, vert=True, parent=None, colour=(0,0,0), padding=5): + frame = gtk.Frame(name) + frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(colour[0],colour[1],colour[2], 0)) + frame.get_label_widget().modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(colour[0],colour[1],colour[2], 0)) + if parent: + parent.pack_start(frame, False, False, padding) + else: + self.outbox.pack_start(frame, False, False, padding) + if vert: + box = gtk.VBox() + else: + box = gtk.HBox() + frame.add(box) + frame.show() + box.show() + return box + + + # creates a vertical slider bank + # + # items: number of sliders + # init: initial value + # start, end: start and end of slider range + # x, y: x and y sizes of slider + # box: parent box + def vsliderbank(self,items,init, start, end, x, y, box): + slid = self.slids + for i in range(slid, slid+items): + cbox = self.box(parent=box) + self.slider(init,start,end,x,y,cbox) + + # creates a horizontal slider bank + # + # items: number of sliders + # init: initial value + # start, end: start and end of slider range + # x, y: x and y sizes of slider + # box: parent box + def hsliderbank(self,items,init, start, end, x, y, box): + slid = self.slids + for i in range(slid, slid+items): + cbox = self.box(False,box) + self.slider(init,start,end,x,y,cbox,"",False) + + + # creates a button bank + # + # items: number of sliders + # box: parent box + def buttonbank(self,items, box): + start = self.butts + for i in range(start, start+items): + self.button(box) + + # internal callback + def delete_event(self, widget, event, data=None): + return False + + # get the toolbox + def get_toolbox(self): + return self.toolbox + + # constructor + # act: activity object + # colour: bg colour RGB tuple (R,G, B) + # vert: True for vertical topmost arrangement, horiz. otherwise + # toolbox: activity toolbox object, if None (default) a + # standard toolbox will be supplied + def __init__(self,act,colour=(-1,-1,-1),vert=True,toolbox=None): + self.sliders = [] + self.slids = 0 + self.spins = [] + self.spinbs = 0 + self.buttons = [] + self.butts = 0 + self.cbbuttons = [] + self.cbbutts = 0 + self.mbuttons = [] + self.mbutts = 0 + self.boxes = [] + self.filenames = dict() + self.window = act + if toolbox == None: + self.toolbox = activity.ActivityToolbox(self.window) + else: self.toolbox = toolbox + self.window.set_toolbox(self.toolbox) + self.toolbox.show() + if colour[0] >= 0: + self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(colour[0],colour[1],colour[2], 0)) + + + if vert: self.outbox = gtk.VBox() + else: self.outbox = gtk.HBox() + + self.window.set_canvas(self.outbox) + self.data_path = os.path.join(act.get_activity_root(),"data/") + self.outbox.show() + +# A class inheriting from BasicGUI +# containing a Csound instance and +# a performance thread instance +class CsoundGUI(BasicGUI): + + # overrides the base method + # sets the bus channel value + # called by the widget callbacks + # channel names 'play', 'pause' and + # 'reset' are reserved for these + # respective uses + def set_channel(self,name,val): + if not self.ready: + if name == "play": + self.play() + elif name == "pause": + self.pause() + elif name == "reset": + self.reset() + self.csound.SetChannel(name,val) + else: + BasicGUI.set_channel(self,name,val) + + # overrides the base method + # sets the file bus channel string + def set_filechannel(self,chan,name): + if not self.ready: + self.csound.SetChannel(chan,name) + else: + BasicGUI.set_filechannel(self,chan,name) + + + # overrides the base method + # sends a score message + def set_message(self, mess): + self.perf.InputMessage(mess) + + # starts a performance + def play(self): + if not self.on: + if self.paused: return + self.on = True + self.perf.Play() + else: + self.on = False + self.perf.Pause() + + # pauses a performance + def pause(self): + if self.on: + self.on = False + self.paused = True + self.perf.Pause() + elif self.paused: + self.on = True + self.paused = False + self.perf.Play() + + # sets the source CSD and compiles it + # + # name: CSD filename + # extra: one extra parameter + # returns zero if successful + def csd(self, name, extra=None): + self.extra = extra + path = activity.get_bundle_path() + if self.ready: + if self.extra != None: + res = self.csound.Compile("%s/%s" % (path,name), extra) + else: + res = self.csound.Compile("%s/%s" % (path,name)) + if not res: self.ready = False + self.path = path + self.name = name + return res + + # recompiles csound with the set CSD + # returns zero if successful + def recompile(self): + if not self.ready and self.name != "0": + self.perf.Stop() + self.perf.Join() + self.on = False + self.paused = False + self.perf = csnd.CsoundPerformanceThread(self.csound) + if self.extra != None: + res = self.csound.Compile("%s/%s" % (self.path,self.name), self.extra) + else: + res = self.csound.Compile("%s/%s" % (self.path,self.name)) + if(res): self.ready = True + return res + + # resets Csound ready for a new CSD + def reset(self): + if not self.ready: + self.perf.Stop() + self.perf.Join() + self.on = False + self.pause = False + self.perf = csnd.CsoundPerformanceThread(self.csound) + self.ready = True + + # internal callback + def close(self, event): + self.reset() + sys.exit(0) + + # constructor + # act: activity object + # colour: bg colour RGB tuple (R,G, B) + # vert: True for vertical topmost arrangement, horiz. otherwise + def __init__(self,act,colour=(-1,-1,-1),vert=True): + locale.setlocale(locale.LC_NUMERIC, 'C') + self.csound = csnd.Csound() + self.perf = csnd.CsoundPerformanceThread(self.csound) + BasicGUI.__init__(self,act,colour,vert) + self.ready = True + self.on = False + self.paused = False + self.name = "0" + diff --git a/Waves.activity/csndsugui.pyc b/Waves.activity/csndsugui.pyc new file mode 100644 index 0000000..3e0ec4b --- /dev/null +++ b/Waves.activity/csndsugui.pyc Binary files differ diff --git a/Waves.activity/setup.py b/Waves.activity/setup.py new file mode 100644 index 0000000..c5a7ac5 --- /dev/null +++ b/Waves.activity/setup.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +from sugar.activity import bundlebuilder +if __name__ == "__main__": + bundlebuilder.start("Waves") + diff --git a/Waves.activity/waves.csd b/Waves.activity/waves.csd new file mode 100644 index 0000000..1594045 --- /dev/null +++ b/Waves.activity/waves.csd @@ -0,0 +1,148 @@ + + +-odac -B2048 -b1024 -d -+rtaudio=alsa + + +sr=44100 +ksmps=100 +nchnls=2 + + +gkb1 chnexport "B1", 1 +gkb2 chnexport "B2", 1 +gkb3 chnexport "B3", 1 +gkb4 chnexport "B4", 1 +gkb5 chnexport "B5", 1 +gkb6 chnexport "B6", 1 +gkb7 chnexport "B7", 1 +gkb8 chnexport "B8", 1 + + +instr 1 + +k1 init 1 +k2 init 1 +k3 init 1 +k4 init 1 +k5 init 1 +k6 init 1 +k7 init 1 +k8 init 1 + + +if gkb1 == 1 then +if k1 == 1 then +event "i", 11.1, 0, -1, 1 +k1=0 +endif +else +if k1 == 0 then +event "i", -11.1, 0, -1,1 +k1=1 +endif +endif + +if gkb2 == 1 then +if k2 == 1 then +event "i", 11.2, 0, -1, 2 +k2=0 +endif +else +if k2 == 0 then +event "i", -11.2, 0, -1, 2 +k2=1 +endif +endif + +if gkb3 == 1 then +if k3 == 1 then +event "i", 11.3, 0, -1, 3 +k3=0 +endif +else +if k3 == 0 then +event "i", -11.3, 0, -1, 3 +k3=1 +endif +endif + +if gkb4 == 1 then +if k4 == 1 then +event "i", 11.4, 0, -1, 4 +k4=0 +endif +else +if k4 == 0 then +event "i", -11.4, 0, -1, 4 +k4=1 +endif +endif + +if gkb5 == 1 then +if k5 == 1 then +event "i", 11.5, 0, -1, 5 +k5=0 +endif +else +if k5 == 0 then +event "i", -11.5, 0, -1, 5 +k5=1 +endif +endif + +if gkb6 == 1 then +if k6 == 1 then +event "i", 11.6, 0, -1, 6 +k6=0 +endif +else +if k6 == 0 then +event "i", -11.6, 0, -1, 6 +k6=1 +endif +endif + +if gkb7 == 1 then +if k7 == 1 then +event "i", 11.7, 0, -1, 7 +k7=0 +endif +else +if k7 == 0 then +event "i", -11.7, 0, -1, 7 +k7=1 +endif +endif + +if gkb8 == 1 then +if k8 == 1 then +event "i", 11.8, 0, -1, 8 +k8=0 +endif +else +if k8 == 0 then +event "i", -11.8, 0, -1, 8 +k8=1 +endif +endif + +endin + + +instr 11 +S1 sprintf "S%d", p4 +k1 chnget S1 +k2 chnget "main_volume" +kv tonek k2/10, 10 +ka linenr 2000*kv,0.1,0.1,0.05 +a1 oscili ka, k1, 1 + outs a1,a1 + endin + + + +f1 0 1024 10 1 0.5 0.3 0.25 0.2 0.18 0.15 0.13 0.11 0.1 0.09 +i1 0 3600 + + + diff --git a/Waves.activity/waves.py b/Waves.activity/waves.py new file mode 100644 index 0000000..15b0307 --- /dev/null +++ b/Waves.activity/waves.py @@ -0,0 +1,28 @@ +import csndsugui +from sugar.activity import activity + + +class Waves(activity.Activity): + + def __init__(self, handle): + + activity.Activity.__init__(self, handle) + + + # colours + red = (0xFFFF,0,0) + bg = (0xF000, 0xFF00, 0xFFFF) + win = csndsugui.CsoundGUI(self,bg) + + win.csd("waves.csd") + txt = win.text("Making Waves") + sfbox = win.box(False) + bfbox = win.box(False) + sbox = win.framebox("frequencies", False, sfbox, red, 40) + bbox = win.framebox("oscillators", False, bfbox, red, 40) + + win.buttonbank(8,bbox) + win.spin(0,0,10,0.5,1,bbox,0, "main_volume") + win.vsliderbank(8,400.0,400.0,500.0,80,200,sbox) + + win.play() diff --git a/Waves.activity/waves.pyc b/Waves.activity/waves.pyc new file mode 100644 index 0000000..f4d17d1 --- /dev/null +++ b/Waves.activity/waves.pyc Binary files differ -- cgit v0.9.1