Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorabhunkin <abhunkin@uncg.edu>2012-03-05 02:42:02 (GMT)
committer abhunkin <abhunkin@uncg.edu>2012-03-05 02:42:02 (GMT)
commit1c7cecc5f46222cabbe3b4f11e099c35efa501eb (patch)
treec612e28c7e23d610c6eacecd0e342599f1eacfd2
Version 1
-rw-r--r--ChimePlay.csd162
-rw-r--r--ChimePlayAuto.csd271
-rw-r--r--ChimePlayReadMe.txt150
-rw-r--r--MANIFEST27
-rw-r--r--activity/activity-chimeplay.svg33
-rw-r--r--activity/activity.info14
-rw-r--r--chimeplay.py214
-rw-r--r--csndsugui.py816
-rw-r--r--setup.py4
-rw-r--r--soundin.0bin0 -> 598360 bytes
-rw-r--r--soundin.1bin0 -> 882020 bytes
-rw-r--r--soundin.10bin0 -> 659344 bytes
-rw-r--r--soundin.11bin0 -> 880664 bytes
-rw-r--r--soundin.12bin0 -> 881476 bytes
-rw-r--r--soundin.13bin0 -> 883060 bytes
-rw-r--r--soundin.14bin0 -> 882700 bytes
-rw-r--r--soundin.15bin0 -> 882152 bytes
-rw-r--r--soundin.16bin0 -> 881384 bytes
-rw-r--r--soundin.17bin0 -> 44 bytes
-rw-r--r--soundin.18bin0 -> 44 bytes
-rw-r--r--soundin.2bin0 -> 881384 bytes
-rw-r--r--soundin.3bin0 -> 882052 bytes
-rw-r--r--soundin.4bin0 -> 879104 bytes
-rw-r--r--soundin.5bin0 -> 881184 bytes
-rw-r--r--soundin.6bin0 -> 881956 bytes
-rw-r--r--soundin.7bin0 -> 44 bytes
-rw-r--r--soundin.8bin0 -> 44 bytes
27 files changed, 1691 insertions, 0 deletions
diff --git a/ChimePlay.csd b/ChimePlay.csd
new file mode 100644
index 0000000..c40fbd4
--- /dev/null
+++ b/ChimePlay.csd
@@ -0,0 +1,162 @@
+; CHIMEPLAY (2012) for realtime Csound5 - by Arthur B. Hunkins
+; Custom version of SAMPLEPLAY for chime and bell samples (up to 8)
+; Requires MIDI device with up to 8 keys, buttons or pads
+; optionally, keys/button/pads velocity sensitive
+; optionally, 1 additional key/button/pad and/or 1-3 MIDI knobs or sliders
+; 0-1 background loop, 1-8 single-shot samples of minimum 3-second duration
+; Files may be mono or stereo, must have same Sample Rate and agree with this SR.
+; They may be a variety of uncompressed types including WAV and AIFF; also
+; Ogg/Vorbis (with Sugar 0.86/Blueberry or later, or Sugar 0.84/Strawberry
+; with updated libsndfile) but not MP3.
+; Choice of two chime sets; both default sets include 6 chimes and an ambient loop.
+; Background loop must be named soundin.0 (set 1) or soundin.10 (set 2),
+; and samples labeled soundin.1 and up (set 1), or soundin.11 and up (set 2).
+; They must be placed in the same folder as this file.
+
+<CsoundSynthesizer>
+<CsOptions>
+
+-odac -+rtaudio=alsa -+rtmidi=alsa -M hw:1,0 -m0d --expression-opt -b128 -B2048 -+raw_controller_mode=1
+
+</CsOptions>
+<CsInstruments>
+
+sr = 44100
+; change sample rate to 48000 (or 32000 if necessary) when 44100 gives no audio.
+; (Necessary for Intel Classmate PC and some other systems.)
+ksmps = 100
+nchnls = 2
+
+ seed 0
+ massign 0, 0
+
+gichan chnexport "Chan", 1
+gibackgnd chnexport "Backgnd", 1
+gibgmax chnexport "Bgmax", 1
+gistctrl chnexport "Stctrl", 1
+gistnote chnexport "Stnote", 1
+gistfade chnexport "Stfade", 1
+gisamps chnexport "Samps", 1
+gisset chnexport "Sset", 1
+gisampamp chnexport "Sampamp", 1
+girndrang chnexport "Rndrange", 1
+gismpctrl chnexport "Smpctrl", 1
+gisampdur chnexport "Sampdur", 1
+gimidi1 chnexport "MIDI1", 1
+gipanpos chnexport "Panpos", 1
+gipanctrl chnexport "Panctrl", 1
+
+ instr 1
+
+gkfreq init 0
+gkpan init .5
+kflag init 0
+ if ((gibackgnd == 0) || (kflag == 1)) goto skip
+kinstr = (gisset == 0? 2: 12)
+ event "i", kinstr, 0, -1
+kflag = 1
+skip:
+gkstat,gkchan,gkd1,gkd2 midiin
+ if ((gkstat == 0) || (gkchan != gichan)) goto end
+ if ((gkstat != 144) || ((gkstat == 144) && (gkd2 == 0))) goto end
+ if ((gkd1 < gimidi1) || (gkd1 > (gimidi1 + (gisamps - 1)))) goto end
+kbase = gkd1 - gimidi1 + 1
+kinstr = (gisset == 0? kbase + 2: kbase + 12)
+ if gisampamp > 0 goto skip2
+kamp = 1
+ goto skip3
+skip2:
+ if gisampamp > 1 goto skip4
+kamp random girndrang * .01, 1
+ goto skip3
+skip4:
+ if gisampamp > 2 goto skip5
+kamp = gkd2 / 127
+ goto skip3
+skip5:
+kamp ctrl7 gichan, gismpctrl, 0, 1
+skip3:
+ if gipanpos = 0 goto skip6
+ if gipanpos > 1 goto skip7
+gkpan linrand 1
+ goto skip6
+skip7:
+ if gipanpos > 2 goto skip8
+gkpan = gkd2 / 127
+ goto skip6
+skip8:
+gkpan ctrl7 gichan, gipanctrl, 0, 1
+skip6:
+ goto skip9
+skip10:
+isamp = i(kinstr) - 2
+ilen filelen isamp
+ rireturn
+skip9:
+ reinit skip10
+ event "i", kinstr, 0, ilen, kamp * .5, gkpan
+
+end: endin
+
+ instr 2, 12
+
+isamp = p1 - 2
+kamp init 0
+ibgmax = gibgmax * .1
+ichans filenchnls isamp
+ if gibackgnd == 2 goto skip
+ if ((gkstat == 144) && (gkd1 == gistnote) && (gkd2 > 0)) goto skip2
+ goto skip3
+skip2:
+kamp = (kamp == 0? ibgmax: 0)
+skip3:
+kamp2 lineto kamp, gistfade
+kamp2 = (kamp2 < .01? 0: kamp2)
+ goto skip4
+skip:
+kamp2 ctrl7 gichan, gistctrl, 0, ibgmax
+skip4:
+ if ichans == 2 goto skip5
+aout diskin2 isamp, 1, 0, 1
+ outs aout * kamp2, aout * kamp2
+ goto end
+skip5:
+a1, a2 diskin2 isamp, 1, 0, 1
+ outs a1 * kamp2, a2 * kamp2
+
+end: endin
+
+ instr 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 18, 19, 20
+
+isamp = p1 - 2
+ichans filenchnls isamp
+ilen = ((gisampdur == 2) || (gisampdur > p3)? p3: gisampdur)
+kamp linsegr 0, .025, p4, ilen - 2.025, p4, 2, 0
+ if ichans == 2 goto skip
+aout diskin2 isamp, 1
+a1,a2,a3,a4 pan aout, p5, 1, 1, 1
+ outs a1 * kamp, a2 * kamp
+ goto skip2
+skip:
+aout,aout2 diskin2 isamp, 1
+a1,a2,a3,a4 pan aout, p5, 1, 1, 1
+a5,a6,a7,a8 pan aout2, p5, 1, 1, 1
+ outs (a1 + a5) * kamp, (a2 + a6) * kamp
+skip2:
+ktime timeinsts
+ if ktime < (ilen - 2) goto end
+ turnoff
+
+end: endin
+
+</CsInstruments>
+
+<CsScore>
+
+f1 0 8193 9 .25 1 0
+i1 0 3600
+
+e
+
+</CsScore>
+</CsoundSynthesizer>
diff --git a/ChimePlayAuto.csd b/ChimePlayAuto.csd
new file mode 100644
index 0000000..2553e08
--- /dev/null
+++ b/ChimePlayAuto.csd
@@ -0,0 +1,271 @@
+; CHIMEPLAYAUTO (2012) for realtime Csound5 - by Arthur B. Hunkins
+; A custom autoplay version of SAMPLEPLAY for chime and bell samples (up to 8)
+; ChimePlayAuto.csd - no MIDI device required
+; 0-1 background loop, 1-8 single-shot samples of minimum 3-second duration
+; Files may be mono or stereo, must have same Sample Rate and agree with this SR.
+; Choice of two chime sets; both default sets include 6 chimes and an ambient loop.
+; Background loop must be named soundin.0 (set 1) or soundin.10 (set 2),
+; and samples labeled soundin.1 and up (set 1), or soundin.11 and up (set 2).
+; They must be placed in the same folder as this file.
+
+<CsoundSynthesizer>
+<CsOptions>
+
+-odac -+rtaudio=alsa -m0d --expression-opt -b128 -B2048
+
+</CsOptions>
+<CsInstruments>
+
+sr = 44100
+; change sample rate to 48000 (or 32000 if necessary) when 44100 gives no audio.
+; (Necessary for Intel Classmate PC and some other systems.)
+ksmps = 100
+nchnls = 2
+
+ seed 0
+gifirst init 1
+gilen init 0
+
+gibackgnd chnexport "Loop", 1
+gibgmax chnexport "Bgmax", 1
+gistfade chnexport "Stfade", 1
+gisamps chnexport "Samps", 1
+gisset chnexport "Sset", 1
+girndsamp chnexport "Rndsamp", 1
+girndrang chnexport "Rndrange", 1
+gisampdur chnexport "Sampdur", 1
+gipanpos chnexport "Panpos", 1
+gitotdur chnexport "Totaldur", 1
+
+gimindur1 chnexport "Min1", 1
+gimaxdur1 chnexport "Max1", 1
+gimindur2 chnexport "Min2", 1
+gimaxdur2 chnexport "Max2", 1
+gimindur3 chnexport "Min3", 1
+gimaxdur3 chnexport "Max3", 1
+gimindur4 chnexport "Min4", 1
+gimaxdur4 chnexport "Max4", 1
+gimindur5 chnexport "Min5", 1
+gimaxdur5 chnexport "Max5", 1
+gimindur6 chnexport "Min6", 1
+gimaxdur6 chnexport "Max6", 1
+gimindur7 chnexport "Min7", 1
+gimaxdur7 chnexport "Max7", 1
+gimindur8 chnexport "Min8", 1
+gimaxdur8 chnexport "Max8", 1
+
+ instr 1
+
+kflag init 0
+kflag1 init 0
+kflag2 init 0
+kflag3 init 0
+kflag4 init 0
+kflag5 init 0
+kflag6 init 0
+kflag7 init 0
+kflag8 init 0
+ktime1 init 0
+ktime2 init 0
+ktime3 init 0
+ktime4 init 0
+ktime5 init 0
+ktime6 init 0
+ktime7 init 0
+ktime8 init 0
+kinst3 init 3
+kinst4 init 4
+kinst5 init 5
+kinst6 init 6
+kinst7 init 7
+kinst8 init 8
+kinst9 init 9
+kinst10 init 10
+gidur = (gitotdur == 0? 30: gitotdur * 60)
+gktime times
+ibase = (gisset == 0? 0: 10)
+ if gisamps == 0 igoto skip
+ilen3 filelen 1 + ibase
+gilen = ilen3
+ if gisamps == 1 igoto skip
+ilen4 filelen 2 + ibase
+gilen = (ilen4 > gilen? ilen4: gilen)
+ if gisamps == 2 igoto skip
+ilen5 filelen 3 + ibase
+gilen = (ilen5 > gilen? ilen5: gilen)
+ if gisamps == 3 igoto skip
+ilen6 filelen 4 + ibase
+gilen = (ilen6 > gilen? ilen6: gilen)
+ if gisamps == 4 igoto skip
+ilen7 filelen 5 + ibase
+gilen = (ilen7 > gilen? ilen7: gilen)
+ if gisamps == 5 igoto skip
+ilen8 filelen 6 + ibase
+gilen = (ilen8 > gilen? ilen8: gilen)
+ if gisamps == 6 igoto skip
+ilen9 filelen 7 + ibase
+gilen = (ilen9 > gilen? ilen9: gilen)
+ if gisamps == 7 igoto skip
+ilen10 filelen 8 + ibase
+gilen = (ilen10 > gilen? ilen10: gilen)
+skip:
+ if ((gibackgnd == 0) || (kflag == 1)) goto skip2
+kinstr = (gisset == 0? 2: 12)
+ event "i", kinstr, 0, gidur
+kflag = 1
+skip2:
+ if gisamps == 0 goto end
+ifade = (gibackgnd == 0? 0: gistfade)
+ if gktime > (gidur - ifade - gilen) goto end
+ if gktime < ifade goto end
+ if kflag1 == 1 goto skip3
+k1 random gimindur1, gimaxdur1
+ktime1 = gktime + k1
+kflag1 = 1
+skip3:
+ if gktime < ktime1 goto skip4
+klen = (gisampdur < 3? ilen3: gisampdur)
+ event "i", kinst3, 0, klen
+kflag1 = 0
+skip4:
+ if gisamps < 2 goto end
+ if kflag2 == 1 goto skip5
+k2 random gimindur2, gimaxdur2
+ktime2 = gktime + k2
+kflag2 = 1
+skip5:
+ if gktime < ktime2 goto skip6
+klen = (gisampdur < 3? ilen4: gisampdur)
+ event "i", kinst4, 0, klen
+kflag2 = 0
+skip6:
+ if gisamps < 3 goto end
+ if kflag3 == 1 goto skip7
+k3 random gimindur3, gimaxdur3
+ktime3 = gktime + k3
+kflag3 = 1
+skip7:
+ if gktime < ktime3 goto skip8
+klen = (gisampdur < 3? ilen5: gisampdur)
+ event "i", kinst5, 0, klen
+kflag3 = 0
+skip8:
+ if gisamps < 4 goto end
+ if kflag4 == 1 goto skip9
+k4 random gimindur4, gimaxdur4
+ktime4 = gktime + k4
+kflag4 = 1
+skip9:
+ if gktime < ktime4 goto skip10
+klen = (gisampdur < 3? ilen6: gisampdur)
+ event "i", kinst6, 0, klen
+kflag4 = 0
+skip10:
+ if gisamps < 5 goto end
+ if kflag5 == 1 goto skip11
+k5 random gimindur5, gimaxdur5
+ktime5 = gktime + k5
+kflag5 = 1
+skip11:
+ if gktime < ktime5 goto skip12
+klen = (gisampdur < 3? ilen7: gisampdur)
+ event "i", kinst7, 0, klen
+kflag5 = 0
+skip12:
+ if gisamps < 6 goto end
+ if kflag6 == 1 goto skip13
+k6 random gimindur6, gimaxdur6
+ktime6 = gktime + k6
+kflag6 = 1
+skip13:
+ if gktime < ktime6 goto skip14
+klen = (gisampdur < 3? ilen8: gisampdur)
+ event "i", kinst8, 0, klen
+kflag6 = 0
+skip14:
+ if gisamps < 7 goto end
+ if kflag7 == 1 goto skip15
+k7 random gimindur7, gimaxdur7
+ktime7 = gktime + k7
+kflag7 = 1
+skip15:
+ if gktime < ktime7 goto skip16
+klen = (gisampdur < 3? ilen9: gisampdur)
+ event "i", kinst9, 0, klen
+kflag7 = 0
+skip16:
+ if gisamps < 8 goto end
+ if kflag8 == 1 goto skip17
+k8 random gimindur8, gimaxdur8
+ktime8 = gktime + k8
+kflag8 = 1
+skip17:
+ if gktime < ktime8 goto end
+klen = (gisampdur < 3? ilen10: gisampdur)
+ event "i", kinst10, 0, klen
+kflag8 = 0
+
+end: endin
+
+ instr 2, 12
+
+isamp = p1 - 2
+ichans filenchnls isamp
+ibgmax = gibgmax * .1
+kamp linseg 0, gistfade, ibgmax, gidur - (gistfade * 2), ibgmax, gistfade, 0
+ if ichans == 2 goto skip
+aout diskin2 isamp, 1, 0, 1
+ outs aout * kamp, aout * kamp
+ goto end
+skip:
+a1, a2 diskin2 isamp, 1, 0, 1
+ outs a1 * kamp, a2 * kamp
+
+end: endin
+
+ instr 3, 4, 5, 6, 7, 8, 9, 10
+
+isamp = (gisset == 0? p1 - 2: p1 + 8)
+ichans filenchnls isamp
+ilen filelen isamp
+ilen = ((gisampdur == 2) || (gisampdur > ilen)? ilen: gisampdur)
+;gilen = (ilen > gilen? ilen: gilen)
+ if girndsamp > 0 goto skip
+iamp = 1
+ goto skip2
+skip:
+iamp random girndrang * .01, 1
+iamp = (gifirst == 1? 1: iamp)
+gifirst = 0
+skip2:
+ if gipanpos = 0 goto skip3
+ipan linrand 1
+ goto skip4
+skip3:
+ipan = .5
+skip4:
+kamp linseg 0, .025, iamp * .5, p3 - 2.025, iamp * .5, 2, 0
+ if ichans == 2 goto skip5
+aout diskin2 isamp, 1
+a1,a2,a3,a4 pan aout, ipan, 1, 1, 1
+ outs a1 * kamp, a2 * kamp
+ goto end
+skip5:
+aout,aout2 diskin2 isamp, 1
+a1,a2,a3,a4 pan aout, ipan, 1, 1, 1
+a5,a6,a7,a8 pan aout2, ipan, 1, 1, 1
+ outs (a1 + a5) * kamp, (a2 + a6) * kamp
+
+end: endin
+
+</CsInstruments>
+
+<CsScore>
+
+f1 0 8193 9 .25 1 0
+i1 0 3600
+
+e
+
+</CsScore>
+</CsoundSynthesizer>
diff --git a/ChimePlayReadMe.txt b/ChimePlayReadMe.txt
new file mode 100644
index 0000000..a42a507
--- /dev/null
+++ b/ChimePlayReadMe.txt
@@ -0,0 +1,150 @@
+CHIMEPLAY and CHIMEPLAYAUTO - Sugar Activity/Linux version - Notes
+Art Hunkins
+abhunkin@uncg.edu
+www.arthunkins.com
+
+
+Working with User Soundfiles
+
+The ChimePlay utility series includes ChimePlay (requiring a MIDI
+controller) and ChimePlayAuto (which is self-performing and needs no
+MIDI device). Both can handle mono or stereo soundfiles, up to 8
+chime or bell samples and a single optional background loop. The
+files can be of any sample rate and a variety of uncompressed formats
+including WAV and AIFF; also Ogg/Vorbis, but not MP3. The Ogg/Vorbis
+format is only possible when the Sugar version is later than 0.84;
+this excludes the original XO-1 and SoaS (Sugar-on-a-Stick)
+Strawberry.
+
+*However*, the ogg vorbis format (which is written by later versions
+of the Record activity) *can* be used by SoaS (Strawberry) 0.84 if
+libsndfile is updated. This can be done while connected to the
+internet by issuing the following commands in the Terminal:
+ su <Enter>
+ yum update libsndfile <Enter>
+Neither the XO-1.5, nor XO-1 upgraded to Sugar 0.84 require this mod.
+
+Students are encouraged to create their own soundfiles, especially to
+make their own windchime or bell collections. (This is the primary
+intent behind these utilities.) The two 6-chime sets included here
+are from the St. Francis Prayer Center in Stoneville, NC (USA). Set
+one consists of recordings of chimes located under an interior cupola
+opposite the Chapel. The second is a set found on the patio of the
+Center's main building. Soundin.1 through soundin.6 and background
+loop soundin.0 comprise set one (the inside set); soundin.11 through
+soundin.16 and ambient loop soundin.10 are set two (the outside
+chimes). Soundin.7, 8, 17 and 18 are dummy samples that complete the
+possible sets of 8. The optional ambient loops can help mask and
+"homogenize" unwanted noise that may be present in the samples.
+
+These samples were created with a high-quality handheld digital
+recorder (at 44100Hz sample rate stereo, uncompressed WAV) using its
+built-in mike. Sounds were then selected, edited and looped in
+Audacity (see below). It was important to record all sounds in the
+same environment and at the same level. An ambient background loop
+of the location helped mask unwanted noise (as did the high pass
+filter effect available in Audacity - cutoff frequency = 661Hz).
+
+The natural vehicle for soundfile creation is the Record activity.
+This activity is fairly simple and straightforward; the only problem
+is that many versions of it do not work with various incarnations of
+Sugar. The following pairings of Record with Sugar seem to work
+reliably: v86 with XO-1.5 and XO-1 upgraded to Sugar 0.84, Sugar-on-
+a-Stick Strawberry (0.84) and Blueberry (0.86). Sugar 0.86 and above
+(as of 3/2012) are compatible with Record v90, including XO's
+updated to at least 0.90. Please note that Record prior to v74
+(except for v61-64) produce ogg *speex* files; these files are
+incompatible with ChimePlay. Though the Record activity produces
+mono files only, at 16000Hz, such samples are nevertheless quite
+useable.
+
+Soundfiles must be moved into the folder where this file resides,
+and be renamed soundin.0 or soundin.10 (for the background loop) and
+soundin.1 or soundin.11 through soundin.8 or .18 (for the samples).
+Rename them in the Journal (where Record deposits its files), then
+click/drag samples to an external USB stick.
+
+Unfortunately, no other Sugar activity (including TimeLapse,
+ShowNTell, and most importantly, Etoys) produces soundfiles useable
+by ChimePlay. Either they write files other than Ogg Vorbis or wav,
+or are restricted to Sugar 0.82.
+
+More advanced users may wish to record their soundfiles on some other
+system, and copy the files to a USB drive with an appropriate
+soundin.x filename. Then recopy the samples (in the Terminal, from
+the ChimePlay.activity folder) to their new location.
+[cp /media/USBname/soundin.x soundin.x]
+
+Otherwise, adventurous users may run the fine Audacity application to
+record and edit. (Happily, none of the limitations of the Record
+activity apply here.) In the Terminal, connected to the web, enter:
+ su <Enter>
+ yum import audacity <Enter>
+ ...
+ audacity <Enter>
+(you are now running Audacity from the Terminal).
+
+When you are finished recording and editing (including auditioning
+the background loop in loop mode), pay particular attention to making
+the loop point as inconspicuous as possible), "Export" the file in
+wav or ogg vorbis format, saving it to a USB drive with appropriate
+filename (soundin.x). It can then be copied to your
+ChimePlay.activity folder. Since your chime/bell sets are on a
+USB drive they can easily be shared with other students.
+
+
+MIDI Controller Hints (ChimePlay only)
+
+Important: The controller must be attached AFTER boot, and BEFORE
+the MIDI version is selected. It is assumed that the controller is a
+USB device.
+
+ChimePlay was specifically designed for minimal (8-9 key) velocity-
+sensitive MIDI keyboards, preferably those with 1 or 2 additional
+sliders or modulation wheels (rotary knobs are OK, but not as easy to
+work with). Suggested inexpensive USB models: Alesis Q25, Akai LPK25
+(no sliders/knobs), Korg nanoKey (no sliders/knobs and rather flimsy
+construction), M-audio O2, and M-audio Oxygen8.
+
+The Korg nanoKontrol is an adequate, if not ideal mini-controller for
+ChimePlay; unfortunately, its numerous buttons, which can issue MIDI
+note data (it has no pads or keys), are not velocity-sensitive. One of
+its four "Scenes" must be significantly reprogrammed by the Korg
+Kontrol Editor to function with ChimePlay. Though it has a multitude
+of programmable sliders and knobs, unfortunately the buttons are not
+laid out well for ChimePlay performance.
+
+
+No Sound - Sample Rate Issues
+
+On a few systems, e.g. the Intel Classmate PC, the specified sr
+(sample rate) of 44100 may not produce audio. Substitute a rate of
+48000 (or, if necessary, 32000) toward the beginning of each .csd
+file, using a text editor. (The sample rate, sr, is specified on
+line 24 of ChimePlay.csd, and line 19 of ChimePlayAuto.csd.)
+
+
+Audio Glitching/Breakup
+
+If you get audio glitching, open Sugar's Control Panel, and turn off
+Extreme power management (under Power) or Wireless radio (under
+Network). A more drastic solution is to reduce textural density
+(fewer chimes, fewer chimes ringing simultaneously). It is also
+possible to lower the sample rate to 32000 or even 24000 (see above).
+
+Stereo headphones (an inexpensive set will work fine) or external
+amplifier/speaker system are highly recommended. Speakers built into
+computers are fairly worthless musically.
+
+
+Resizing the Font
+
+The font display of this activity can be resized in csndsugui.py,
+using any text editor. Further instructions are found toward the
+beginning of csndsugui.py. (Simply change the value of the "resize"
+variable (= 0), plus or minus.)
+
+
+Further relevent items of interest may be found in the document
+ChimePlay.txt on the author's website. (It is the text file
+associated with the *all-platform* non-Sugar version of ChimePlay.)
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..bc6fd59
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,27 @@
+csndsugui.py
+ChimePlay.csd
+ChimePlayAuto.csd
+chimeplay.py
+activity/activity.info
+activity/activity-chimeplay.svg
+setup.py
+soundin.0
+soundin.1
+soundin.2
+soundin.3
+soundin.4
+soundin.5
+soundin.6
+soundin.7
+soundin.8
+soundin.10
+soundin.11
+soundin.12
+soundin.13
+soundin.14
+soundin.15
+soundin.16
+soundin.17
+soundin.18
+ChimePlayReadMe.txt
+
diff --git a/activity/activity-chimeplay.svg b/activity/activity-chimeplay.svg
new file mode 100644
index 0000000..986c636
--- /dev/null
+++ b/activity/activity-chimeplay.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" ?><!-- Created with Inkscape (http://www.inkscape.org/) --><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [
+ <!ENTITY stroke_color "#000000">
+ <!ENTITY fill_color "#ffffff">
+]><svg height="55.008945" id="svg2" version="1.0" width="54.992115" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs id="defs4"/>
+ <g id="layer1" transform="translate(-244.50394,-269.85727)">
+ <image height="55.008945" id="image2449" width="54.992115" x="244.50394" xlink:href="Good.jpg" y="269.85727"/>
+ <path d="M 280.30753,282.18787 C 272.19566,282.06004 261.42749,281.86466 256.37828,281.75368 L 247.19786,281.5519 L 247.20709,278.96394 C 247.21215,277.54058 247.41533,276.22392 247.65858,276.03805 C 248.52397,275.37681 254.11179,273.4324 257.1023,272.75191 C 262.70455,271.47708 267.41943,271.04478 273.68558,271.23136 C 282.63871,271.49795 289.17919,272.92501 295.22306,275.9306 L 297.76533,277.19486 L 297.76533,279.85395 C 297.76533,282.4257 297.72084,282.51152 296.41085,282.46667 C 295.66588,282.44116 288.41939,282.3157 280.30753,282.18787 L 280.30753,282.18787 z" id="path2453" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 270.37463,281.7468 C 260.11063,281.5394 250.8324,281.35752 249.75634,281.34264 L 247.79986,281.31558 L 247.79986,278.82313 C 247.79986,275.98926 247.88785,275.91999 253.88809,274.03101 C 259.74468,272.18726 264.00889,271.60471 271.57862,271.61423 C 281.34065,271.62652 287.0786,272.71104 294.30388,275.90949 L 297.16334,277.1753 L 297.16334,279.69449 L 297.16334,282.21368 L 293.09989,282.16878 C 290.86498,282.1441 280.63861,281.95421 270.37463,281.7468 L 270.37463,281.7468 z" id="path2455" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 247.79986,304.96569 L 247.79986,285.80609 L 252.11214,285.80609 L 256.42442,285.80609 L 256.02615,303.09464 C 255.80711,312.60332 255.62741,321.22513 255.62683,322.25421 L 255.62579,324.12526 L 251.71282,324.12526 L 247.79986,324.12526 L 247.79986,304.96569 z" id="path2457" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 248.40185,304.96569 L 248.40185,286.10547 L 252.01382,286.10547 L 255.62579,286.10547 L 255.62477,295.31104 C 255.62422,300.37412 255.44499,308.86122 255.22648,314.17126 L 254.82922,323.82589 L 251.61553,323.82589 L 248.40185,323.82589 L 248.40185,304.96569 z" id="path2459" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 263.20971,315.51842 C 263.3453,313.58375 263.62318,306.08985 263.82723,298.86531 L 264.19821,285.72974 L 267.50029,285.89923 C 269.31645,285.99244 270.84157,286.11068 270.88951,286.16193 C 270.93742,286.21322 270.89395,293.63084 270.7929,302.64558 L 270.60919,319.036 L 266.78619,319.036 L 262.96318,319.036 L 263.20971,315.51842 z" id="path2461" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 263.67808,315.21906 C 263.87573,313.28438 264.21004,305.94237 264.42096,298.90348 L 264.80444,286.10547 L 266.4868,286.10547 C 270.33969,286.10547 270.07363,284.88173 270.07363,302.60277 L 270.07363,318.73662 L 266.69615,318.73662 L 263.31865,318.73662 L 263.67808,315.21906 z" id="path2463" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 276.51348,313.03406 C 276.33609,312.69675 276.34679,306.49981 276.53725,299.26311 L 276.88354,286.10547 L 279.04703,286.10538 L 281.21051,286.10529 L 281.05048,298.90338 C 280.96245,305.94233 280.74701,312.13929 280.57169,312.67442 C 280.29917,313.50632 280.00529,313.64737 278.54447,313.64737 C 277.32873,313.64737 276.74296,313.47048 276.51347,313.03406 L 276.51348,313.03406 z" id="path2465" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 277.29756,299.87641 L 277.29756,286.40483 L 279.00853,286.40483 L 280.7195,286.40483 L 280.48297,299.20284 C 280.35288,306.24174 280.11958,312.30395 279.96451,312.67442 C 279.78677,313.09908 279.2419,313.348 278.49007,313.348 C 277.31903,313.348 277.29756,313.10523 277.29756,299.87641 z" id="path2467" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 286.32746,296.56348 L 286.32746,286.06571 L 287.98294,286.16044 C 289.25812,286.2334 289.62854,286.40989 289.59542,286.92874 C 289.57178,287.29921 289.50405,291.98058 289.44492,297.33179 L 289.33743,307.06127 L 287.83245,307.06127 L 286.32746,307.06127 L 286.32746,296.56348 z" id="path2469" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 286.92945,296.58336 C 286.92945,288.08281 287.06769,286.40483 287.76804,286.40483 C 288.22925,286.40483 288.70969,286.57323 288.83567,286.77905 C 288.96165,286.98488 288.96794,291.5652 288.84966,296.95759 C 288.66962,305.1649 288.49571,306.76189 287.78203,306.76189 C 287.06332,306.76189 286.92945,305.16382 286.92945,296.58336 z" id="path2471" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 294.75536,293.92646 C 294.75536,287.82063 295.05281,286.40483 296.3356,286.40483 C 297.01284,286.40483 297.16334,287.60233 297.16334,292.99095 C 297.16334,299.37747 297.12686,299.57705 295.95935,299.57705 C 294.7979,299.57705 294.75536,299.37747 294.75536,293.92646 z" id="path2473" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 295.39967,293.53251 C 295.42294,290.35322 295.6748,287.48257 295.95935,287.15326 C 296.2716,286.79191 296.49351,289.01041 296.51903,292.74875 C 296.54519,296.57863 296.33157,299.01359 295.95935,299.128 C 295.56543,299.24908 295.37199,297.31515 295.39968,293.53251 L 295.39967,293.53251 z" id="path2475" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 249.00385,304.96569 L 249.00385,286.40483 L 252.01382,286.40483 L 255.02379,286.40483 L 255.02255,297.10726 C 255.02188,302.9936 254.84295,311.34597 254.62496,315.66811 L 254.22857,323.52652 L 251.61622,323.52652 L 249.00385,323.52652 L 249.00385,304.96569 z" id="path2477" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 264.26271,313.12347 C 264.47455,310.2009 264.82654,302.9936 265.04492,297.10726 L 265.44195,286.40483 L 266.8697,286.40483 C 267.84838,286.40483 268.4821,286.64637 268.88454,287.17274 C 269.23811,287.6352 269.47163,294.00593 269.47163,303.18896 L 269.47163,318.43726 L 266.67459,318.43726 L 263.87756,318.43726 L 264.26271,313.12347 z" id="path2479" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 268.56865,281.44875 C 258.96685,281.23979 250.50132,281.05699 249.75634,281.04252 C 248.4864,281.01785 248.40185,280.88607 248.40185,278.93105 C 248.40185,277.04257 248.57167,276.7497 250.20206,275.82626 C 252.37059,274.59803 259.08937,272.78715 263.16164,272.33331 C 264.78671,272.1522 268.84712,272.00682 272.18481,272.01026 C 280.62214,272.01895 284.88009,272.71089 291.30184,275.11692 L 296.26035,276.97473 L 296.4352,279.44452 L 296.61003,281.91432 L 291.31824,281.87151 C 288.40777,281.84796 278.17045,281.65771 268.56865,281.44875 z" id="path2481" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.42452079;stroke-opacity:1"/>
+ <path d="M 5.0684144,9.4840814 C 4.2024844,7.2274814 5.4842844,6.3492514 12.192694,4.6028814 C 21.107754,2.2820514 36.595584,2.6492814 44.732594,5.3744214 C 49.033824,6.8149214 51.341964,8.1432914 51.555914,9.3013114 C 51.856234,10.926811 50.235524,11.051311 28.774534,11.051311 C 8.7190944,11.051311 5.5904544,10.844481 5.0684244,9.4840914 L 5.0684144,9.4840814 z" id="path2485" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:1;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 26.232594,12.907211 C 21.282594,12.552941 13.745094,12.215441 9.4825944,12.157201 C 2.7763344,12.065561 1.7432244,11.815631 1.8115444,10.301311 C 1.8549644,9.3388114 2.0902744,9.0322514 2.3344644,9.6200714 C 2.6331944,10.339201 10.376814,10.655561 26.005514,10.587141 C 38.780404,10.531211 47.207594,10.770181 44.732594,11.118181 C 40.373624,11.731101 40.428474,11.755631 46.482594,11.901121 C 49.920094,11.983711 52.732594,12.388811 52.732594,12.801311 C 52.732594,13.721181 38.406014,13.778431 26.232594,12.907201 L 26.232594,12.907211 z" id="path2491" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:1;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 24.732594,11.051311 L 7.2325944,10.479531 L 24.732594,10.280741 C 34.704024,10.167461 42.877904,10.498961 43.732594,11.051311 C 45.065924,11.912981 45.065924,11.998601 43.732594,11.821881 C 42.907594,11.712541 34.357594,11.365781 24.732594,11.051311 z" id="path2493" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:1;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 43.363045,10.129271 C 43.201036,9.9626552 34.689239,9.7467826 24.447939,9.6495554 L 5.827399,9.4727787 L 5.720495,8.5520125 C 5.6276837,7.7525859 5.837355,7.53549 7.3114853,6.9046765 C 18.128473,2.2758742 40.067882,2.8312571 49.209701,7.9653084 C 50.509915,8.6955022 51.11365,9.4791533 50.613941,9.7879892 C 50.080174,10.117872 43.646415,10.420694 43.363045,10.129271 z" id="path2399" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.35355338;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 37.823981,9.6340768 C 34.615484,9.5019363 26.132394,9.3718145 18.972673,9.3449126 L 5.9549964,9.296002 L 6.0679744,8.5011327 C 6.404886,6.1307587 20.016554,3.6472654 29.86903,4.1585495 C 35.486176,4.4500437 39.978245,5.1328578 44.084605,6.3193759 C 46.950343,7.1474227 49.900778,8.5284871 50.347213,9.2508391 C 50.551648,9.5816237 46.940751,10.040267 44.931574,9.9387197 C 44.230899,9.9033007 41.032478,9.7662174 37.823981,9.6340768 z" id="path2401" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.35355338;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 4.9435155,35.282176 L 4.9435155,17.074177 L 7.6522118,17.074177 L 10.360905,17.074177 L 10.128075,30.420817 C 10.000022,37.761469 9.7907183,45.955069 9.6629548,48.628817 L 9.4306596,53.490176 L 7.1870911,53.490176 L 4.9435155,53.490176 L 4.9435155,35.282176 z" id="path2403" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.35355338;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 19.943198,45.446836 C 20.208685,42.199767 21.202983,21.171132 21.205338,18.753555 L 21.206971,17.074177 L 22.453159,17.074177 C 23.457466,17.074177 23.764644,17.245919 24.035759,17.959004 C 24.220788,18.445663 24.481159,25.446017 24.614367,33.515353 L 24.856562,48.186875 L 22.287862,48.186875 L 19.719162,48.186875 L 19.943198,45.446836 z" id="path2405" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.35355338;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 33.44239,42.67788 C 33.324356,42.370296 33.227787,36.483632 33.227787,29.596405 L 33.227787,17.074177 L 34.465224,17.074177 L 35.702661,17.074177 L 35.672913,24.410409 C 35.625809,36.027803 35.263607,42.497996 34.638242,42.893378 C 33.902642,43.358449 33.68876,43.319912 33.44239,42.67788 z" id="path2407" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.35355338;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ <path d="M 5.2970689,35.282176 L 5.2970689,17.42773 L 7.6502672,17.42773 L 10.003469,17.42773 L 9.7657716,31.304701 C 9.6350417,38.937034 9.4277993,46.971535 9.305233,49.159147 L 9.0823812,53.136622 L 7.189725,53.136622 L 5.2970689,53.136622 L 5.2970689,35.282176 z" id="path2409" style="opacity:1;fill:&fill_color;;fill-opacity:1;stroke:&stroke_color;;stroke-width:0.35355338;stroke-opacity:1" transform="translate(244.50394,269.85727)"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..7373e19
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,14 @@
+[Activity]
+
+name = ChimePlay
+
+bundle_id = org.laptop.ChimePlay
+icon = activity-chimeplay
+
+activity_version = 1
+
+host_version = 1
+
+show_launcher = yes
+exec = sugar-activity chimeplay.ChimePlay
+license = CC-by-SA 3.0
diff --git a/chimeplay.py b/chimeplay.py
new file mode 100644
index 0000000..7d48750
--- /dev/null
+++ b/chimeplay.py
@@ -0,0 +1,214 @@
+# CHIMEPLAY - Chime and Bell Player Utilities for Children (2012)
+# Custom versions of SAMPLEPLAY for windchime and bell sample sets
+# Art Hunkins (www.arthunkins.com)
+#
+# ChimePlay is licensed under the Creative Commons Attribution-Share
+# Alike 3.0 Unported License. To view a copy of this license, visit
+# http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to
+# Creative Commons, 171 Second Street, Suite 300, San Francisco,
+# California, 94105, USA.
+#
+# It 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.
+#
+
+import csndsugui
+from sugar.activity import activity
+import gtk
+import os
+
+class ChimePlay(activity.Activity):
+
+ def __init__(self, handle):
+
+ activity.Activity.__init__(self, handle)
+
+ red = (0xDDDD, 0, 0)
+ brown = (0x6600, 0, 0)
+ green = (0, 0x5500, 0)
+
+ win = csndsugui.CsoundGUI(self)
+ width = gtk.gdk.screen_width()
+ height = gtk.gdk.screen_height()
+ if os.path.exists("/etc/olpc-release") or os.path.exists("/sys/power/olpc-pm"):
+ adjust = 78
+ else:
+ adjust = 57
+ screen = win.box()
+ screen.set_size_request(width, height - adjust)
+ scrolled = gtk.ScrolledWindow()
+ scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ screen.pack_start(scrolled)
+ all = gtk.VBox()
+ all.show()
+ scrolled.add_with_viewport(all)
+ scrolled.show()
+
+ win.text("<big><b><big><u>CHIMEPLAY</u> - Chime and Bell Player \
+Utilities for Children (2012)</big></b>\n\
+\t\t\t Art Hunkins (www.arthunkins.com)</big>", all)
+
+ win.text("\
+<b>ChimePlay</b> and <b>ChimePlayAuto</b> are custom versions of SAMPLEPLAY \
+for sets of up to 8 windchimes or bells.\t\t\n\
+Two sets of 6 chimes (plus ambient loop) are included. \
+You are urged to create your own (see ChimePlayReadMe.txt). ", all, brown)
+ win.text("<b>ChimePlay</b> requires MIDI controller, \
+one key/button/pad per active chime and loop (optionally velocity-sensitive);\t\nalso \
+(optionally) an additional key/button/pad and/or 1-2 MIDI knobs/sliders. \
+All samples/MIDI notes are consecutive.\t", all, green)
+ win.text("\
+<i><b>MIDI</b>: plug in controller after boot &amp; before selecting version. \
+Zero controls before start; reset pan to .5 afterward.</i>\t", all, green)
+ win.text("<b>ChimePlayAuto</b> doesn't involve MIDI. \
+You specify the random range in seconds between \
+repeats of a given chime.\t", all, brown)
+
+ nbox = win.box(False, all)
+ self.b2box = win.box(False, all)
+ self.b3box = win.box(False, all)
+ but1 = win.cbbutton(nbox, self.version1, " 1 ChimePlay ")
+ but1.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x7700, 0))
+ but1.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x7700, 0))
+ but2 = win.cbbutton(nbox, self.version2, " 2 ChimePlayAuto ")
+ but2.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x7700, 0))
+ but2.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x7700, 0))
+ win.text("<b> MIDI DEVICE REQUIRED</b> for ChimePlay", nbox, green)
+
+ bbox = win.box(False, all)
+ self.bb = bbox
+ bbox2 = win.box(False, all)
+ self.bb2 = bbox2
+ self.w = win
+ self.r = red
+ self.g = green
+ self.br = brown
+ self.ver = 0
+
+ def playcsd(self, widget):
+ if self.p == False:
+ self.p = True
+ self.w.play()
+ self.but.child.set_label("STOP !")
+ self.but.child.set_use_markup(True)
+ self.but.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0xFFFF, 0, 0))
+ self.but.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF, 0, 0))
+ else:
+ self.p = False
+ self.w.recompile()
+ self.w.channels_reinit()
+ self.but.child.set_label("START !")
+ self.but.child.set_use_markup(True)
+ self.but.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x7700, 0))
+ self.but.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x7700, 0))
+
+ def version1(self, widget):
+ if self.ver != 0:
+ self.box1.destroy()
+ self.box2.destroy()
+ self.box3.destroy()
+ self.ver = 1
+ self.box1 = self.w.box(True, self.bb)
+ self.w.text("", self.box1)
+ self.box2 = self.w.box(True, self.bb)
+ self.f = self.w.framebox(" <b>1 - ChimePlay</b> ", False, self.box2, self.r)
+ self.b1 = self.w.box(True, self.f)
+ self.b2 = self.w.box(True, self.f)
+ self.b3 = self.w.box(True, self.f)
+ self.b4 = self.w.box(True, self.f)
+ self.b5 = self.w.box(True, self.f)
+ self.b6 = self.w.box(True, self.f)
+ self.w.reset()
+ self.w.csd("ChimePlay.csd")
+ self.w.spin(1, 1, 16, 1, 1, self.b1, 0, "Chan", "Channel #")
+ self.w.spin(2, 0, 2, 1, 1, self.b1, 0, "Backgnd", "Background Loop\n\
+[0=none 1=note\n 2=controller]")
+ self.w.spin(10, 0, 20, 1, 1, self.b1, 0, "Bgmax", "Loop Lev [10=norm]")
+ self.w.spin(7, 0, 127, 1, 1, self.b2, 0, "Stctrl", "Loop Controller #")
+ self.w.spin(84, 0, 127, 1, 1, self.b2, 0, "Stnote", " Loop Note\n\
+(start/stop)")
+ self.w.spin(5, 1, 30, 1, 1, self.b2, 0, "Stfade", "Start/Stop Secs")
+ self.w.spin(6, 0, 8, 1, 1, self.b3, 0, "Samps", "# of Samples")
+ self.w.spin(1, 0, 3, 1, 1, self.b3, 0, "Sampamp", "Sample Level Ctrl\n\
+[0=none 1=rand\n2=note vel 3=ctrl]")
+ self.w.spin(21, 0, 127, 1, 1, self.b3, 0, "Smpctrl", "Samp Lev Ctrl #")
+ self.w.spin(10, 10, 100, 1, 1, self.b4, 0, "Rndrange", "Lowest Rand Amp\n\
+ Level [as %]")
+ self.w.spin(2, 2, 20, 1, 1, self.b4, 0, "Sampdur", " Chime Duration\n\
+[2=natural >2=dur\nin secs if < natural]")
+ self.w.spin(60, 0, 120, 1, 1, self.b5, 0, "MIDI1", "1st MIDI Note #")
+ self.w.spin(0, 0, 3, 1, 1, self.b5, 0, "Panpos", " Pan Pos Control\n\
+[0=none 1=rand\n2=note vel 3=ctrl]")
+ self.w.spin(20, 0, 127, 1, 1, self.b5, 0, "Panctrl", "Pan Position Ctrl #")
+ self.w.button(self.b6, "Sset", "Chime Set 2?")
+ self.p = False
+ self.w.text("\n<i>Select options first </i>", self.b6, self.g)
+ self.but = self.w.cbbutton(self.b6, self.playcsd, "START !")
+ self.but.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x7700, 0))
+ self.but.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x7700, 0))
+
+ def version2(self, widget):
+ if self.ver != 0:
+ self.box1.destroy()
+ self.box2.destroy()
+ self.ver = 2
+ self.box1 = self.w.box(True, self.bb)
+ self.w.text(" ", self.box1)
+ self.box2 = self.w.box(True, self.bb)
+ self.f = self.w.framebox(" <b>2 - ChimePlayAuto</b> ", False, self.box2, self.r)
+ self.b1 = self.w.box(True, self.f)
+ self.b2 = self.w.box(True, self.f)
+ self.b3 = self.w.box(True, self.f)
+ self.b4 = self.w.box(True, self.f)
+ self.b5 = self.w.box(True, self.f)
+ self.b6 = self.w.box(True, self.f)
+ self.w.reset()
+ self.w.csd("ChimePlayAuto.csd")
+ self.w.spin(1, 0, 60, 1, 1, self.b1, 0, "Totaldur", "Total Dur (mins)\n\
+ [0=30 secs]")
+ self.w.button(self.b1, "Loop", "Background Loop?", 1)
+ self.w.spin(10, 0, 30, 1, 1, self.b2, 0, "Bgmax", "Loop Lev [10=norm]")
+ self.w.spin(5, 1, 30, 1, 1, self.b2, 0, "Stfade", "Start/Stop Seconds")
+ self.w.spin(6, 0, 8, 1, 1, self.b3, 0, "Samps", "# of Samples")
+ self.w.button(self.b3, "Rndsamp", "Rand Samp Lev?", 1)
+ self.w.spin(10, 0, 100, 1, 1, self.b4, 0, "Rndrange", "Lowest Random\n\
+Amp Lev [as %]")
+ self.w.button(self.b4, "Sset", "Chime Set 2?")
+ self.w.spin(2, 2, 20, 1, 1, self.b5, 0, "Sampdur", " Sample Dur\n [2=natural\n\
+>2=dur in secs\n if < natural]")
+ self.w.button(self.b6, "Panpos", "Rand Pan Pos?")
+ self.w.text("<i> Select options\n\tfirst</i>", self.b6, self.g)
+ self.but = self.w.cbbutton(self.b6, self.playcsd, "START !")
+ self.but.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x7700, 0))
+ self.but.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x7700, 0))
+ self.p = False
+
+ self.box3 = self.w.box(False, self.bb2)
+ self.b7 = self.w.box(True, self.box3)
+ self.b8 = self.w.box(True, self.box3)
+ self.b9 = self.w.box(True, self.box3)
+ self.b10 = self.w.box(True, self.box3)
+ self.b11 = self.w.box(True, self.box3)
+ self.b12 = self.w.box(True, self.box3)
+ self.b13 = self.w.box(True, self.box3)
+ self.b14 = self.w.box(True, self.box3)
+ self.b15 = self.w.box(True, self.box3)
+ self.w.text("Min/Max\nRandom\nSeconds\n\
+between\nChimes", self.b7, self.br)
+ self.w.spin(2, 1, 30, 1, 1, self.b8, 0, "Min1")
+ self.w.spin(5, 1, 30, 1, 1, self.b8, 0, "Max1")
+ self.w.spin(2, 1, 30, 1, 1, self.b9, 0, "Min2")
+ self.w.spin(5, 1, 30, 1, 1, self.b9, 0, "Max2")
+ self.w.spin(2, 1, 30, 1, 1, self.b10, 0, "Min3")
+ self.w.spin(5, 1, 30, 1, 1, self.b10, 0, "Max3")
+ self.w.spin(2, 1, 30, 1, 1, self.b11, 0, "Min4")
+ self.w.spin(5, 1, 30, 1, 1, self.b11, 0, "Max4")
+ self.w.spin(2, 1, 30, 1, 1, self.b12, 0, "Min5")
+ self.w.spin(5, 1, 30, 1, 1, self.b12, 0, "Max5")
+ self.w.spin(2, 1, 30, 1, 1, self.b13, 0, "Min6")
+ self.w.spin(5, 1, 30, 1, 1, self.b13, 0, "Max6")
+ self.w.spin(2, 1, 30, 1, 1, self.b14, 0, "Min7")
+ self.w.spin(5, 1, 30, 1, 1, self.b14, 0, "Max7")
+ self.w.spin(2, 1, 30, 1, 1, self.b15, 0, "Min8")
+ self.w.spin(5, 1, 30, 1, 1, self.b15, 0, "Max8")
diff --git a/csndsugui.py b/csndsugui.py
new file mode 100644
index 0000000..6a476ed
--- /dev/null
+++ b/csndsugui.py
@@ -0,0 +1,816 @@
+# 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.3 06/08/08
+
+import pygtk
+pygtk.require('2.0')
+from sugar.activity import activity
+import gtk, gobject
+import sys
+import csnd
+import math
+import locale
+import os
+import sugar.logger
+import time
+
+class BasicGUI:
+ """Basic GUI with boxes, sliders, spins, buttons etc
+ using pygtk/sugar, from which GUI classes
+ can be derived for Csound use."""
+
+ def scale_font(self, widget):
+ font = widget.get_pango_context().get_font_description()
+
+# The FONT DISPLAY in this activity can be resized (smaller or larger)
+# by changing the value of "resize" below. "Resize" can be positive
+# or negative, and is not limited to integers. A value of 1 equals a
+# point in font size.
+ resize = 0
+
+ font_size = font.get_size() + (resize * 1024)
+ width = gtk.gdk.screen_width()
+ mult = width * .00076
+ if os.path.exists("/etc/olpc-release") or os.path.exists("/etc/power/olpc-pm"):
+ mult = width * .00082
+ elif os.path.exists("/etc/fedora-release"):
+ release = open("/etc/fedora-release").read()
+ if release.find("SoaS release 1 ") != -1:
+ mult = width * .00132
+ elif release.find("SoaS release 2 ") != -1:
+ mult = width * .00085
+ elif release.find("Fedora release ") != -1:
+ mult = width * .00119
+ font.set_size(int(font_size * mult))
+ widget.modify_font(font)
+
+ def set_channel(self,name, val):
+ """basic bus channel setting method,
+ should be overriden for full-functionality."""
+ self.logger.debug("channel:%s, value:%.1f" % (name,val))
+
+ def set_filechannel(self,chan,name):
+ """basic filename channel setting method
+ should be overriden for full-functionality."""
+ self.logger.debug("channel:%s, filename:%s" % (chan,name))
+
+ def set_message(self, mess):
+ """basic message setting method
+ should be overriden for full-functionality."""
+ self.logger.debug(mess)
+
+ def get_slider_value(self,name):
+ """returns the slider value
+ name: slider name (which should also be the attached bus channel name"""
+ for i in self.sliders:
+ if i[1] == name:
+ return i[2]
+ return 0
+
+ def get_button_value(self,name):
+ """returns the button value (0 or 1)
+ name: button name (which should also be the attached bus channel name)"""
+ for i in self.buttons:
+ if i[1] == name:
+ return i[2]
+ return 0
+
+ def get_slider(self,name):
+ """returns the slider widget instance
+ name: slider name"""
+ for i in self.sliders:
+ if i[1] == name:
+ return i[0]
+ return 0
+
+ def get_button(self,name):
+ """returns the button widget instance
+ name: button name"""
+ for i in self.sliders:
+ if i[1] == name:
+ return i[0]
+ return 0
+
+ def set_focus(self):
+ """ called whenever the focus changes """
+ self.logger.debug(self.focus)
+
+ def focus_out(self, widget, event):
+ if(self.focus):
+ self.focus = False
+ self.set_focus()
+
+ def focus_in(self, widget, event):
+ if(not self.focus):
+ self.focus = True
+ self.set_focus()
+
+ def focus_back(self, widget, event):
+ self.window.disconnect(self.fback)
+ self.focus_connect()
+
+ 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(0x8000,0x8000,0x8000, 1))
+ i[0].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0x8000,0x8000,0x8000, 2))
+ else:
+ i[2] = 1
+ i[0].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0,0x7700,0, 1))
+ i[0].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0,0x7700,0, 2))
+ self.set_channel(i[1], i[2])
+
+ def button_setvalue(self, widget, value):
+ if not value:
+ widget.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x0FFF,0,0x00FF, 2))
+ widget.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF,0,0xFFFF, 2))
+ else:
+ widget.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0xFFFF,0,0, 1))
+ widget.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0xFFFF,0,0, 2))
+
+ def mbuttcallback(self, widget, data=None):
+ for i in self.mbuttons:
+ if i[0] == widget:
+ self.set_message(i[2])
+
+ 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
+
+ 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])
+
+ def filecallback(self,widget):
+ name = self.curfile[0].get_filename()
+ self.set_filechannel(self.curfile[2], name)
+ for i in self.buttons:
+ if i[0] == self.curfile[1]:
+ i[2] = name
+ self.filenames.update({self.curfile[2] : name})
+ self.curfile[0].destroy()
+ self.fback = self.window.connect('focus_out_event', self.focus_back)
+
+ def destroy_chooser(self,widget):
+ self.curfile[0].destroy()
+
+ def fbuttcallback(self, widget, data=None):
+ self.focus_disconnect()
+ for i in self.buttons:
+ if i[0] == widget:
+ chooser = gtk.FileSelection(i[1])
+ self.curfile = (chooser, i[0], i[1])
+ chooser.set_filename(self.data_path)
+ chooser.ok_button.connect("clicked", self.filecallback)
+ chooser.cancel_button.connect("clicked", self.destroy_chooser)
+ chooser.show()
+
+ def cbbutton(self,box,callback,title=""):
+ """Creates a callbackbutton
+ box: parent box
+ callback: click callback
+ title: if given, the button name
+ returns the widget instance"""
+ self.cbbutts = self.cbbutts + 1
+ butt = gtk.Button(title)
+ self.scale_font(butt.child)
+ box.pack_start(butt, False, False, 2)
+ self.cbbuttons.append([butt,title,0])
+ butt.connect("clicked", callback)
+ butt.show()
+ return butt
+
+ def button(self,box, title="",label="",value=None):
+ """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"""
+ self.butts = self.butts + 1
+ if title == "":
+ title = "B%d" % self.butts
+ if label == "": name = title
+ else: name = label
+ butt = gtk.Button(" %s " % name)
+ self.scale_font(butt.child)
+ butt.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.Color(0,0x7700,0, 1))
+ butt.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0,0x7700,0, 2))
+ box.pack_start(butt, False, False, 1)
+ self.buttons.append([butt,title,0])
+ butt.connect("clicked", self.buttcallback)
+ if value == 1:
+ butt.clicked()
+ butt.show()
+ return butt
+
+ def mbutton(self,box,mess,title=""):
+ """Creates a mbutton (for 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"""
+ 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.mbuttons.append([butt,title,mess])
+ butt.connect("clicked", self.mbuttcallback)
+ butt.show()
+ return butt
+
+ def box(self,vert=True, parent=None, padding=3):
+ """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"""
+ 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
+
+ def filechooser(self,box,title,label=""):
+ """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."""
+ if label == "": name = title
+ else: name = label
+ butt = gtk.Button(name)
+ box.pack_start(butt, False, False, 5)
+ self.buttons.append([butt,title,"0"])
+ butt.connect("clicked", self.fbuttcallback)
+ self.set_filechannel(title,"0")
+ self.filenames.update({title:"0"})
+ butt.show()
+ return butt
+
+ def slider(self,init, start, end, x, y, box, title="",vert=True,linear=True,dwid=100,label=""):
+ """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"""
+ 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
+
+ def numdisplay(self,box,title="",init=0.0,label=""):
+ self.ndispwids = self.ndispwids + 1
+ entry = gtk.Entry()
+ if label == "": name = title
+ else: name = label
+ entry.set_text("%f" % init)
+ label = gtk.Label(name)
+ box.pack_start(entry, False, False, 2)
+ box.pack_start(label, False, False, 2)
+ self.ndisps.append([entry,title,init])
+ entry.show()
+ label.show()
+ self.set_channel(title,init)
+ return entry
+
+ def setnumdisp(self,title,val):
+ for i in self.ndisps:
+ if i[1] == title:
+ i[2] = val
+ i[0].set_text("%f" % val)
+ self.set_channel(title, val)
+
+ def spin(self,init, start, end, step, page, box, accel=0,title="",label=""):
+ """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"""
+ 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)
+ self.scale_font(spin)
+ spin.set_alignment(.5)
+ if label == "": name = title
+ else: name = label
+ label = gtk.Label(name)
+ self.scale_font(label)
+ box.pack_start(spin, False, False, 3)
+ box.pack_start(label, False, False, 0)
+ self.spins.append([spin,title,init])
+ adj.connect("value_changed", self.spincallback, spin)
+ spin.show()
+ label.show()
+ self.set_channel(title, init)
+ return spin
+
+ def text(self, name, box=None,colour=(0,0,0)):
+ """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"""
+ label = gtk.Label(name)
+ self.scale_font(label)
+ label.set_use_markup(True)
+ label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(colour[0],colour[1],colour[2], 0))
+ if box:
+ box.pack_start(label, False, False, 3)
+ else:
+ self.outbox.pack_start(label, False, False, 3)
+ label.show()
+ return label
+
+ def framebox(self, name, vert=True, parent=None, colour=(0,0,0), padding=5):
+ """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"""
+ frame = gtk.Frame(name)
+ self.scale_font(frame.get_label_widget())
+ 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))
+ frame.get_label_widget().set_use_markup(True)
+ 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
+
+ def vsliderbank(self,items,init, start, end, x, y, 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"""
+ slid = self.slids
+ for i in range(slid, slid+items):
+ cbox = self.box(parent=box)
+ self.slider(init,start,end,x,y,cbox)
+
+ def hsliderbank(self,items,init, start, end, x, y, box):
+ """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"""
+ slid = self.slids
+ for i in range(slid, slid+items):
+ cbox = self.box(False,box)
+ self.slider(init,start,end,x,y,cbox,"",False)
+
+ def buttonbank(self,items, box):
+ """Creates a button bank
+ items: number of sliders
+ box: parent box."""
+ start = self.butts
+ for i in range(start, start+items):
+ self.button(box)
+
+ def delete_event(self, widget, event, data=None):
+ return False
+
+ def get_toolbox(self):
+ """Returns the Activity toolbox"""
+ return self.toolbox
+
+ def channels_reinit(self):
+ """ resets channel to current widget values"""
+ for j in self.buttons:
+ if(j[1] != "pause"):
+ if(j[1] != "play"):
+ if(j[1] != "reset"):
+ self.set_channel(j[1],j[2])
+ for j in self.sliders:
+ if j[4]:
+ self.set_channel(j[1],j[2])
+ pass
+ else:
+ value = j[5]*pow(j[6]/j[5], j[2]/j[6])
+ self.set_channel(j[1], value)
+ for j in self.spins:
+ self.set_channel(j[1],j[2])
+
+ def widgets_reset(self):
+ """ resets widget to channel values"""
+ for j in self.buttons:
+ self.button_setvalue(j[0], j[2])
+ self.set_channel(j[1],j[2])
+ for j in self.sliders:
+ j[0].set_value(j[2])
+ j[0].emit("value_changed")
+ for j in self.spins:
+ j[0].set_value(j[2])
+ j[0].emit("value_changed")
+
+ def channels_save(self):
+ """ Saves a list with channel names and current values.
+ Returns a list of tuples (channel_name, channel_value)"""
+ chan_list = []
+ for i in self.channel_widgets:
+ for j in i:
+ if(j[1] != "pause"):
+ if(j[1] != "play"):
+ if(j[1] != "reset"):
+ chan_list.append((j[1],j[2]));
+ return chan_list
+
+ def channels_load(self, chan_list):
+ """ Loads a list with channel names and values into the
+ current channel list """
+ for i in self.channnel_widgets:
+ for j in i:
+ cnt = 0
+ while(j[1] == chan_list[cnt][0]):
+ j[1] = chann_list[cnt][0]
+ j[2] = chan_list[cnt][1]
+ cnt = cnt+1
+ self.widgets_reset()
+
+ def set_channel_metadata(self):
+ """ Saves channel data as metadata. Can be called in
+ write_file() to save channel/widget data """
+ mdata = self.channels_save()
+ for i in mdata:
+ self.window.metadata['channel-'+i[0]] = str(i[1])
+
+ def get_channel_metadata(self):
+ """ Retrieves channel data from metadata. Can be called after
+ widgets have been created to retrieve channel data and
+ reset widgets """
+ for i in self.channel_widgets:
+ for j in i:
+ mdata = self.window.metadata.get('channel-'+j[1],'0')
+ if mdata is None: continue
+ else:
+ try: j[2] = float(mdata)
+ except: j[2] = mdata
+ self.widgets_reset()
+
+
+ def nofocus(self):
+ pass
+
+ def focus_connect(self):
+ if not self.connected:
+ self.focus = True
+ self.in_id = self.window.connect('focus_in_event', self.focus_in)
+ self.out_id = self.window.connect('focus_out_event', self.focus_out)
+ self.connected = True
+
+ def focus_disconnect(self):
+ if self.connected:
+ self.window.disconnect(self.in_id)
+ self.window.disconnect(self.out_id)
+ self.connected = False
+
+ def __init__(self,act,colour=(-1,-1,-1),vert=True,toolbox=None):
+ """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"""
+ 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.ndisps = []
+ self.ndispwids = 0
+ self.connected = False
+ self.channel_widgets = [self.sliders, self.spins, self.buttons]
+ 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()
+ self.logger = sugar.logger.logging.getLogger('csndsugui')
+
+
+class CsoundGUI(BasicGUI):
+ """A class inheriting from BasicGUI containing a Csound instance and a performance
+ thread instance."""
+
+ def set_channel(self,name,val):
+ """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"""
+ 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)
+
+ def set_filechannel(self,chan,name):
+ """overrides the base method, setting the channel string"""
+ if not self.ready:
+ self.csound.SetChannel(chan,name)
+ else:
+ BasicGUI.set_filechannel(self,chan,name)
+
+ def set_message(self, mess):
+ """overrides the base method, sends a score message"""
+ self.perf.InputMessage(mess)
+
+ def set_focus(self):
+ """overrides the base class method, resetting/recompiling Csound"""
+ if self.focus:
+ self.compile()
+ self.channels_reinit()
+ if self.replay and not self.on:
+ self.play()
+ self.logger.debug("focus_off and playing")
+ else:
+ self.replay = self.on
+ self.logger.debug("focus_out and stopping")
+ self.reset()
+ return 1
+
+ def play(self):
+ """Starts a performance. """
+ if not self.on:
+ if self.paused: return
+ self.on = True
+ self.perf.Play()
+ else:
+ self.on = False
+ self.perf.Pause()
+
+ def pause(self):
+ """Pauses a performance. """
+ if self.on:
+ self.on = False
+ self.paused = True
+ self.perf.Pause()
+ elif self.paused:
+ self.on = True
+ self.paused = False
+ self.perf.Play()
+
+ def csd(self, name):
+ """Sets the source CSD and compiles it.
+ name: CSD filename
+ returns zero if successful"""
+ path = activity.get_bundle_path()
+ if self.ready:
+ res = self.csound.Compile("%s/%s" % (path,name))
+ if not res:
+ self.ready = False
+ self.focus_connect()
+ self.path = path
+ self.name = name
+ return res
+
+ def recompile(self):
+ """Recompiles the set CSD.
+ returns zero if successful"""
+ 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.arglist != None:
+ res = self.csound.Compile(self.arglist.argc(),self.arglist.argv())
+ else:
+ res = self.csound.Compile("%s/%s" % (self.path,self.name))
+ if(res): self.ready = True
+ return res
+
+ def compile(self,name=None,args=[]):
+ """Compiles Csound code.
+ name: CSD filename if given
+ args: list of arguments (as strings)
+ returns 0 if successful , non-zero if not."""
+ if self.ready:
+ if args != []:
+ self.arglist = csnd.CsoundArgVList()
+ self.path = activity.get_bundle_path()
+ if name != None: self.name = name
+ elif self.name == "0": return -1
+ if self.arglist != None:
+ if name != None:
+ self.arglist.Append("csound")
+ self.arglist.Append("%s/%s" % (self.path,self.name))
+ for i in args:
+ self.arglist.Append(i)
+ res = self.csound.Compile(self.arglist.argc(),self.arglist.argv())
+ else: res = self.csound.Compile("%s/%s" % (self.path,self.name))
+ if not res:
+ self.ready = False
+ self.focus_connect()
+ else:
+ self.arglist = None
+ return res
+
+ def reset(self):
+ """Resets Csound, ready for a new CSD"""
+ if not self.ready:
+ self.perf.Stop()
+ self.perf.Join()
+ self.on = False
+ self.paused = False
+ self.perf = csnd.CsoundPerformanceThread(self.csound)
+ self.ready = True
+
+ def close(self, event):
+ self.reset()
+ sys.exit(0)
+
+ def tcallback(self,cbdata):
+ if self.stopcb: return False
+ if self.on and self.sync:
+ self.tcb(cbdata)
+ return True
+
+ def set_timer(self,time,cb,cbdata,sync=True):
+ """Sets a timer callback, called at time intervals.
+ Sync=True makes it start/stop with Csound performance"""
+ if(self.stopcb == True):
+ self.sync = sync
+ self.tcb = cb
+ self.stopcb = False
+ gobject.timeout_add(time,self.tcallback,cbdata)
+
+ def stop_timer(self):
+ """Stops the timer"""
+ self.stopcb = True
+
+ def score_time(self):
+ """Returns the current score time"""
+ return self.csound.GetScoreTime()
+
+ def __init__(self,act,colour=(-1,-1,-1),vert=True):
+ """constructor
+ act: activity object
+ colour: bg colour RGB tuple (R,G, B)
+ vert: True for vertical topmost arrangement, horiz. otherwise."""
+ 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"
+ self.arglist = None
+ self.replay = False
+ self.stopcb = True
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..77fda74
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,4 @@
+#!/usr/bin/env python
+from sugar.activity import bundlebuilder
+if __name__ == "__main__":
+ bundlebuilder.start()
diff --git a/soundin.0 b/soundin.0
new file mode 100644
index 0000000..d77b7d9
--- /dev/null
+++ b/soundin.0
Binary files differ
diff --git a/soundin.1 b/soundin.1
new file mode 100644
index 0000000..193b6a3
--- /dev/null
+++ b/soundin.1
Binary files differ
diff --git a/soundin.10 b/soundin.10
new file mode 100644
index 0000000..7857192
--- /dev/null
+++ b/soundin.10
Binary files differ
diff --git a/soundin.11 b/soundin.11
new file mode 100644
index 0000000..45c1e19
--- /dev/null
+++ b/soundin.11
Binary files differ
diff --git a/soundin.12 b/soundin.12
new file mode 100644
index 0000000..b45281a
--- /dev/null
+++ b/soundin.12
Binary files differ
diff --git a/soundin.13 b/soundin.13
new file mode 100644
index 0000000..a1db87e
--- /dev/null
+++ b/soundin.13
Binary files differ
diff --git a/soundin.14 b/soundin.14
new file mode 100644
index 0000000..544834a
--- /dev/null
+++ b/soundin.14
Binary files differ
diff --git a/soundin.15 b/soundin.15
new file mode 100644
index 0000000..899a74c
--- /dev/null
+++ b/soundin.15
Binary files differ
diff --git a/soundin.16 b/soundin.16
new file mode 100644
index 0000000..fd86d5b
--- /dev/null
+++ b/soundin.16
Binary files differ
diff --git a/soundin.17 b/soundin.17
new file mode 100644
index 0000000..878bf23
--- /dev/null
+++ b/soundin.17
Binary files differ
diff --git a/soundin.18 b/soundin.18
new file mode 100644
index 0000000..878bf23
--- /dev/null
+++ b/soundin.18
Binary files differ
diff --git a/soundin.2 b/soundin.2
new file mode 100644
index 0000000..30499cb
--- /dev/null
+++ b/soundin.2
Binary files differ
diff --git a/soundin.3 b/soundin.3
new file mode 100644
index 0000000..6b74455
--- /dev/null
+++ b/soundin.3
Binary files differ
diff --git a/soundin.4 b/soundin.4
new file mode 100644
index 0000000..e898e73
--- /dev/null
+++ b/soundin.4
Binary files differ
diff --git a/soundin.5 b/soundin.5
new file mode 100644
index 0000000..c0422e8
--- /dev/null
+++ b/soundin.5
Binary files differ
diff --git a/soundin.6 b/soundin.6
new file mode 100644
index 0000000..f0b0d46
--- /dev/null
+++ b/soundin.6
Binary files differ
diff --git a/soundin.7 b/soundin.7
new file mode 100644
index 0000000..878bf23
--- /dev/null
+++ b/soundin.7
Binary files differ
diff --git a/soundin.8 b/soundin.8
new file mode 100644
index 0000000..878bf23
--- /dev/null
+++ b/soundin.8
Binary files differ