Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLive System User <liveuser@localhost.localdomain>2011-10-07 02:19:35 (GMT)
committer Live System User <liveuser@localhost.localdomain>2011-10-07 02:19:35 (GMT)
commit63b30b57ae2d4c82b43311a8d6ff0288c4480518 (patch)
treeaf63c5f5c20db6466a0cc54505b204cb7267cfbc
Initial commit
-rw-r--r--MANIFEST35
-rw-r--r--SamplePlay.csd384
-rw-r--r--SamplePlayASC.csd546
-rw-r--r--SamplePlayReadMe.txt154
-rw-r--r--activity/activity-sampleplay.svg15
-rw-r--r--activity/activity.info14
-rw-r--r--csndsugui.py815
-rw-r--r--sampleplay.py285
-rw-r--r--setup.py4
-rw-r--r--soundin.0bin0 -> 3666348 bytes
-rw-r--r--soundin.1bin0 -> 527788 bytes
-rw-r--r--soundin.10bin0 -> 309084 bytes
-rw-r--r--soundin.11bin0 -> 305828 bytes
-rw-r--r--soundin.12bin0 -> 344448 bytes
-rw-r--r--soundin.13bin0 -> 666680 bytes
-rw-r--r--soundin.14bin0 -> 332520 bytes
-rw-r--r--soundin.15bin0 -> 335224 bytes
-rw-r--r--soundin.16bin0 -> 462160 bytes
-rw-r--r--soundin.17bin0 -> 406340 bytes
-rw-r--r--soundin.18bin0 -> 372296 bytes
-rw-r--r--soundin.19bin0 -> 467240 bytes
-rw-r--r--soundin.2bin0 -> 554852 bytes
-rw-r--r--soundin.20bin0 -> 767136 bytes
-rw-r--r--soundin.21bin0 -> 501772 bytes
-rw-r--r--soundin.22bin0 -> 485792 bytes
-rw-r--r--soundin.23bin0 -> 394524 bytes
-rw-r--r--soundin.24bin0 -> 452928 bytes
-rw-r--r--soundin.25bin0 -> 529880 bytes
-rw-r--r--soundin.3bin0 -> 399416 bytes
-rw-r--r--soundin.4bin0 -> 373856 bytes
-rw-r--r--soundin.5bin0 -> 344816 bytes
-rw-r--r--soundin.6bin0 -> 267732 bytes
-rw-r--r--soundin.7bin0 -> 320868 bytes
-rw-r--r--soundin.8bin0 -> 267728 bytes
-rw-r--r--soundin.9bin0 -> 303324 bytes
35 files changed, 2252 insertions, 0 deletions
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..ca629f9
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,35 @@
+csndsugui.py
+SamplePlay.csd
+SamplePlayASC.csd
+sampleplay.py
+activity/activity.info
+activity/activity-sampleplay.svg
+setup.py
+soundin.0
+soundin.1
+soundin.2
+soundin.3
+soundin.4
+soundin.5
+soundin.6
+soundin.7
+soundin.8
+soundin.9
+soundin.10
+soundin.11
+soundin.12
+soundin.13
+soundin.14
+soundin.15
+soundin.16
+soundin.17
+soundin.18
+soundin.19
+soundin.20
+soundin.21
+soundin.22
+soundin.23
+soundin.24
+soundin.25
+SamplePlayReadMe.txt
+
diff --git a/SamplePlay.csd b/SamplePlay.csd
new file mode 100644
index 0000000..f079580
--- /dev/null
+++ b/SamplePlay.csd
@@ -0,0 +1,384 @@
+; SAMPLEPLAY (2011) for realtime Csound5 - by Arthur B. Hunkins
+; Requires MIDI device with up to 25 keys, buttons or pads
+; optionally, keys/button/pads velocity sensitive
+; optionally, 1 additional key/button/pad and/or 1-4 MIDI knobs or sliders
+; 0-1 background loop, 1-25 single-shot samples.
+; Files may be mono or stereo; can have different sample rates, 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.
+; Background loop must be named soundin.0, and samples labeled soundin.1 and up.
+; They must be placed in the same folder as this file or they may be loaded
+; through the Journal (with Sugar 0.84/Strawberry or later).
+
+<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
+ga1 init 0
+ga2 init 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
+gisampamp chnexport "Sampamp", 1
+gisampmax chnexport "Sampmax", 1
+gismpctrl chnexport "Smpctrl", 1
+gimidi1 chnexport "MIDI1", 1
+gireplace chnexport "Replace", 1
+gismpfreq chnexport "Smpfreq", 1
+gifrqctrl chnexport "Frqctrl", 1
+gipanpos chnexport "Panpos", 1
+gipanctrl chnexport "Panctrl", 1
+gifilter chnexport "Filter", 1
+gicutoff chnexport "Cutoff", 1
+
+ instr 1
+
+gkfreq init 0
+gkpan init .5
+kflag init 0
+isampmax = gisampmax * .1
+ if ((gibackgnd == 0) || (kflag == 1)) goto skip
+ event "i", 2, 0, -1
+kflag = 1
+skip:
+gkstat,gkchan,gkd1,gkd2 midiin
+ if ((gkstat == 0) || (gkchan != gichan)) goto end
+ if ((gkstat != 144) && (gkstat != 128)) goto end
+ if ((gireplace != 2) && ((gkstat == 128) || ((gkstat == 144) && (gkd2 == 0)))) goto end
+ if ((gkd1 < gimidi1) || (gkd1 > (gimidi1 + (gisamps - 1)))) goto end
+ksamp = gkd1 - gimidi1 + 1
+kinstr = ksamp + 2
+ if gisampamp > 0 goto skip2
+kamp = 1
+ goto skip3
+skip2:
+ if gisampamp > 1 goto skip4
+kamp random .1, 1
+ goto skip3
+skip4:
+ if gisampamp > 2 goto skip5
+kamp = gkd2 / 127
+ goto skip3
+skip5:
+kamp ctrl7 gichan, gismpctrl, 0, 1
+skip3:
+ if gismpfreq == 0 goto skip6
+ if gismpfreq > 1 goto skip7
+gkfreq trirand .05
+ goto skip6
+skip7:
+ if gismpfreq > 2 goto skip8
+gkfreq = ((gkd2 / 64) - 1) * .05
+ goto skip6
+skip8:
+gkfreq ctrl7 gichan, gifrqctrl, -.05, .05
+skip6:
+ if gipanpos = 0 goto skip9
+ if gipanpos > 1 goto skip10
+gkpan linrand 1
+ goto skip9
+skip10:
+ if gipanpos > 2 goto skip11
+gkpan = gkd2 / 127
+ goto skip9
+skip11:
+gkpan ctrl7 gichan, gipanctrl, 0, 1
+skip9:
+ if gireplace > 0 goto skip12
+ goto skip13
+skip14:
+ilen filelen i(ksamp)
+ rireturn
+skip13:
+ reinit skip14
+ event "i", kinstr, 0, ilen, kamp * isampmax, gkfreq, gkpan
+ goto end
+skip12:
+ if (((gkstat == 144) && (gkd2 == 0)) || (gkstat == 128)) goto skip15
+ event "i", kinstr, 0, -1, kamp * isampmax, gkfreq, gkpan
+ goto end
+skip15:
+ event "i", -kinstr, 0, 1
+
+end: endin
+
+ instr 2
+
+kamp init 0
+ibgmax = gibgmax * .1
+Sname chnget "file0"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont
+Sname = "soundin.0"
+cont:
+ichans filenchnls Sname
+ 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 Sname, 1, 0, 1
+ga1 = aout * kamp2
+ga2 = aout * kamp2
+ goto end
+skip5:
+a1, a2 diskin2 Sname, 1, 0, 1
+ga1 = a1 * kamp2
+ga2 = a2 * kamp2
+
+end: endin
+
+ instr 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
+
+ if p1 != 3 goto cont
+Sname chnget "file1"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.1"
+ goto cont2
+cont:
+ if p1 != 4 goto cont3
+Sname chnget "file2"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.2"
+ goto cont2
+cont3:
+ if p1 != 5 goto cont4
+Sname chnget "file3"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.3"
+ goto cont2
+cont4:
+ if p1 != 6 goto cont5
+Sname chnget "file4"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.4"
+ goto cont2
+cont5:
+ if p1 != 7 goto cont6
+Sname chnget "file5"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.5"
+ goto cont2
+cont6:
+ if p1 != 8 goto cont7
+Sname chnget "file6"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.6"
+ goto cont2
+cont7:
+ if p1 != 9 goto cont8
+Sname chnget "file7"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.7"
+ goto cont2
+cont8:
+ if p1 != 10 goto cont9
+Sname chnget "file8"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.8"
+ goto cont2
+cont9:
+ if p1 != 11 goto cont10
+Sname chnget "file9"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.9"
+ goto cont2
+cont10:
+ if p1 != 12 goto cont11
+Sname chnget "file10"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.10"
+ goto cont2
+cont11:
+ if p1 != 13 goto cont12
+Sname chnget "file11"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.11"
+ goto cont2
+cont12:
+ if p1 != 14 goto cont13
+Sname chnget "file12"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.12"
+ goto cont2
+cont13:
+ if p1 != 15 goto cont14
+Sname chnget "file13"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.13"
+ goto cont2
+cont14:
+ if p1 != 16 goto cont15
+Sname chnget "file14"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.14"
+ goto cont2
+cont15:
+ if p1 != 17 goto cont16
+Sname chnget "file15"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.15"
+ goto cont2
+cont16:
+ if p1 != 18 goto cont17
+Sname chnget "file16"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.16"
+ goto cont2
+cont17:
+ if p1 != 19 goto cont18
+Sname chnget "file17"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.17"
+ goto cont2
+cont18:
+ if p1 != 20 goto cont19
+Sname chnget "file18"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.18"
+ goto cont2
+cont19:
+ if p1 != 21 goto cont20
+Sname chnget "file19"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.19"
+ goto cont2
+cont20:
+ if p1 != 22 goto cont21
+Sname chnget "file20"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.20"
+ goto cont2
+cont21:
+ if p1 != 23 goto cont22
+Sname chnget "file21"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.21"
+ goto cont2
+cont22:
+ if p1 != 24 goto cont23
+Sname chnget "file22"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.22"
+ goto cont2
+cont23:
+ if p1 != 25 goto cont24
+Sname chnget "file23"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.23"
+ goto cont2
+cont24:
+ if p1 != 26 goto cont25
+Sname chnget "file24"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.24"
+ goto cont2
+cont25:
+Sname chnget "file25"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.25"
+cont2:
+ichans filenchnls Sname
+ilen filelen Sname
+ if gireplace == 2 goto skip
+kamp linseg 0, .025, p4, ilen - .35, p4, .325, 0
+ goto skip2
+skip:
+kamp linsegr 0, .025, p4, ilen - .35, p4, .325, 0
+skip2:
+ if ichans == 2 goto skip3
+aout diskin2 Sname, 1 + p5, 0, 0
+a1,a2,a3,a4 pan aout, p6, 1, 1, 1
+ga1 = ga1 + (a1 * kamp)
+ga2 = ga2 + (a2 * kamp)
+ goto skip4
+skip3:
+aout,aout2 diskin2 Sname, 1 + p5, 0, 0
+a1,a2,a3,a4 pan aout, p6, 1, 1, 1
+a5,a6,a7,a8 pan aout2, p6, 1, 1, 1
+ga1 = ga1 + ((a1 + a5) * kamp)
+ga2 = ga2 + ((a2 + a6) * kamp)
+skip4:
+ktime timeinsts
+ if ((gireplace < 2) || (ktime < (ilen - .2))) goto end
+ turnoff
+
+end: endin
+
+ instr 100
+
+ if gifilter == 0 goto skip
+a1 atonex ga1, gicutoff
+a2 atonex ga2, gicutoff
+ outs a1, a2
+ goto skip2
+skip:
+ outs ga1, ga2
+skip2:
+ga1 = 0
+ga2 = 0
+
+end: endin
+
+</CsInstruments>
+
+<CsScore>
+
+f1 0 8193 9 .25 1 0
+i1 0 3600
+i100 0 3600
+
+e
+
+</CsScore>
+</CsoundSynthesizer>
diff --git a/SamplePlayASC.csd b/SamplePlayASC.csd
new file mode 100644
index 0000000..7520bf6
--- /dev/null
+++ b/SamplePlayASC.csd
@@ -0,0 +1,546 @@
+; SAMPLEPLAYASC (2011) for realtime Csound5 - by Arthur B. Hunkins
+; SamplePlayASC.csd - ASCII keyboard only (no MIDI)
+; 0-1 background loop, 1-25 single-shot samples. Mono or stereo, any sample rate.
+; 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. Background loop must be named soundin.0,
+; and samples labeled soundin.1 and up.
+; They must be placed in the same folder as this file or they may be loaded
+; through the Journal (with Sugar 0.84/Strawberry or later).
+; Note: in Sugar version, ` key triggers background loop.
+
+<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
+ga1 init 0
+ga2 init 0
+gkold init 0
+
+gibackgnd chnexport "Backgnd", 1
+gibgmax chnexport "Bgmax", 1
+gistfade chnexport "Stfade", 1
+gisamps chnexport "Samps", 1
+gisampamp chnexport "Sampamp", 1
+gisampmax chnexport "Sampmax", 1
+gireplace chnexport "Replace", 1
+gismpfreq chnexport "Smpfreq", 1
+gipanpos chnexport "Panpos", 1
+gifilter chnexport "Filter", 1
+gicutoff chnexport "Cutoff", 1
+gkasc chnexport "ascii", 1
+
+ instr 1
+
+kflag init 0
+gkamp init 1
+gkfreq init 0
+gkpan init .5
+kamp init gisampamp
+kfreq init gismpfreq
+kpan init gipanpos
+isampmax = gisampmax * .1
+
+ if ((gibackgnd == 0) || (kflag == 1)) goto skip
+ event "i", 2, 0, -1
+kflag = 1
+ kgoto end
+skip:
+ if ((gkasc == gkold) || (gkasc == 96)) goto end
+gkold = gkasc
+ if gkold == 0 goto end
+ if kamp == 0 goto skip2
+ if kamp > 1 goto skip3
+gkamp random .1, 1
+ kgoto skip2
+skip3:
+ if ((gkasc < 48) || (gkasc > 57)) goto skip2
+gkamp = (gkasc - 48) * .1
+gkamp = (gkasc == 48? gkamp + 1: gkamp)
+ kgoto end
+skip2:
+ if kfreq == 0 goto skip4
+ if kfreq > 1 goto skip5
+gkfreq trirand .05
+ kgoto skip4
+skip5:
+ if gkasc != 33 goto skip6
+gkfreq = -.05
+ kgoto end
+skip6:
+ if gkasc != 64 goto skip7
+gkfreq = -.043
+ kgoto end
+skip7:
+ if gkasc != 35 goto skip8
+gkfreq = -.035
+ kgoto end
+skip8:
+ if gkasc != 36 goto skip9
+gkfreq = -.026
+ kgoto end
+skip9:
+ if gkasc != 37 goto skip10
+gkfreq = -.016
+ kgoto end
+skip10:
+ if gkasc != 94 goto skip11
+gkfreq = -.005
+ kgoto end
+skip11:
+ if gkasc != 38 goto skip12
+gkfreq = .007
+ kgoto end
+skip12:
+ if gkasc != 42 goto skip13
+gkfreq = .02
+ kgoto end
+skip13:
+ if gkasc != 40 goto skip14
+gkfreq = .034
+ kgoto end
+skip14:
+ if gkasc != 41 goto skip4
+gkfreq = .05
+ kgoto end
+skip4:
+ if kpan == 0 goto skip15
+ if kpan > 1 goto skip16
+gkpan linrand 1
+ kgoto skip15
+skip16:
+ if gkasc != 122 goto skip17
+gkpan = 0
+ kgoto end
+skip17:
+ if gkasc != 120 goto skip18
+gkpan = .1111
+ kgoto end
+skip18:
+ if gkasc != 99 goto skip19
+gkpan = .2222
+ kgoto end
+skip19:
+ if gkasc != 118 goto skip20
+gkpan = .3333
+ kgoto end
+skip20:
+ if gkasc != 98 goto skip21
+gkpan = .4444
+ kgoto end
+skip21:
+ if gkasc != 110 goto skip22
+gkpan = .5555
+ kgoto end
+skip22:
+ if gkasc != 109 goto skip23
+gkpan = .6666
+ kgoto end
+skip23:
+ if gkasc != 44 goto skip24
+gkpan = .7777
+ kgoto end
+skip24:
+ if gkasc != 46 goto skip25
+gkpan = .8888
+ kgoto end
+skip25:
+ if gkasc != 47 goto skip15
+gkpan = 1
+ kgoto end
+skip15:
+ if gkasc != 113 goto skip26
+ksamp = 1
+ kgoto skip27
+skip26:
+ if gisamps < 2 kgoto end
+ if gkasc != 119 goto skip28
+ksamp = 2
+ kgoto skip27
+skip28:
+ if gisamps < 3 kgoto end
+ if gkasc != 101 goto skip29
+ksamp = 3
+ kgoto skip27
+skip29:
+ if gisamps < 4 kgoto end
+ if gkasc != 114 goto skip30
+ksamp = 4
+ kgoto skip27
+skip30:
+ if gisamps < 5 kgoto end
+ if gkasc != 116 goto skip31
+ksamp = 5
+ kgoto skip27
+skip31:
+ if gisamps < 6 kgoto end
+ if gkasc != 121 goto skip32
+ksamp = 6
+ kgoto skip27
+skip32:
+ if gisamps < 7 kgoto end
+ if gkasc != 117 goto skip33
+ksamp = 7
+ kgoto skip27
+skip33:
+ if gisamps < 8 kgoto end
+ if gkasc != 105 goto skip34
+ksamp = 8
+ kgoto skip27
+skip34:
+ if gisamps < 9 kgoto end
+ if gkasc != 111 goto skip35
+ksamp = 9
+ kgoto skip27
+skip35:
+ if gisamps < 10 kgoto end
+ if gkasc != 112 goto skip36
+ksamp = 10
+ kgoto skip27
+skip36:
+ if gisamps < 11 kgoto end
+ if gkasc != 91 goto skip37
+ksamp = 11
+ kgoto skip27
+skip37:
+ if gisamps < 12 kgoto end
+ if gkasc != 93 goto skip38
+ksamp = 12
+ kgoto skip27
+skip38:
+ if gisamps < 13 kgoto end
+ if gkasc != 97 goto skip39
+ksamp = 13
+ kgoto skip27
+skip39:
+ if gisamps < 14 kgoto end
+ if gkasc != 115 goto skip40
+ksamp = 14
+ kgoto skip27
+skip40:
+ if gisamps < 15 kgoto end
+ if gkasc != 100 goto skip41
+ksamp = 15
+ kgoto skip27
+skip41:
+ if gisamps < 16 kgoto end
+ if gkasc != 102 goto skip42
+ksamp = 16
+ kgoto skip27
+skip42:
+ if gisamps < 17 kgoto end
+ if gkasc != 103 goto skip43
+ksamp = 17
+ kgoto skip27
+skip43:
+ if gisamps < 18 kgoto end
+ if gkasc != 104 goto skip44
+ksamp = 18
+ kgoto skip27
+skip44:
+ if gisamps < 19 kgoto end
+ if gkasc != 106 goto skip45
+ksamp = 19
+ kgoto skip27
+skip45:
+ if gisamps < 20 kgoto end
+ if gkasc != 107 goto skip46
+ksamp = 20
+ kgoto skip27
+skip46:
+ if gisamps < 21 kgoto end
+ if gkasc != 108 goto skip47
+ksamp = 21
+ kgoto skip27
+skip47:
+ if gisamps < 22 kgoto end
+ if gkasc != 59 goto skip48
+ksamp = 22
+ kgoto skip27
+skip48:
+ if gisamps < 23 kgoto end
+ if gkasc != 39 goto skip49
+ksamp = 23
+ kgoto skip27
+skip49:
+ if gisamps < 24 kgoto end
+ if gkasc != 45 goto skip50
+ksamp = 24
+ kgoto skip27
+skip50:
+ if gisamps < 25 kgoto end
+ if gkasc != 61 goto end
+ksamp = 25
+skip27:
+ if gireplace == 1 goto skip51
+ event "i", ksamp + 2, 0, .01, gkamp * isampmax, gkfreq, gkpan
+ kgoto end
+skip51:
+ event "i", ksamp + 2, 0, -1, gkamp * isampmax, gkfreq, gkpan
+
+end: endin
+
+ instr 2
+
+kamp init 0
+ibgmax = gibgmax * .1
+Sname chnget "file0"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont
+Sname = "soundin.0"
+cont:
+ichans filenchnls Sname
+ if gkasc != 96 goto skip
+ if gkasc == gkold goto skip
+gkold = gkasc
+; in Sugar version, ` triggers background loop
+kamp = (kamp == 0? ibgmax: 0)
+skip:
+kamp2 lineto kamp, gistfade
+kamp2 = (kamp2 < .01? 0: kamp2)
+ if ichans == 2 goto skip2
+aout diskin2 Sname, 1, 0, 1
+ga1 = aout * kamp2
+ga2 = aout * kamp2
+ goto end
+skip2:
+a1, a2 diskin2 Sname, 1, 0, 1
+ga1 = a1 * kamp2
+ga2 = a2 * kamp2
+
+end: endin
+
+ instr 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
+
+ if p1 != 3 goto cont
+Sname chnget "file1"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.1"
+ goto cont2
+cont:
+ if p1 != 4 goto cont3
+Sname chnget "file2"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.2"
+ goto cont2
+cont3:
+ if p1 != 5 goto cont4
+Sname chnget "file3"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.3"
+ goto cont2
+cont4:
+ if p1 != 6 goto cont5
+Sname chnget "file4"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.4"
+ goto cont2
+cont5:
+ if p1 != 7 goto cont6
+Sname chnget "file5"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.5"
+ goto cont2
+cont6:
+ if p1 != 8 goto cont7
+Sname chnget "file6"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.6"
+ goto cont2
+cont7:
+ if p1 != 9 goto cont8
+Sname chnget "file7"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.7"
+ goto cont2
+cont8:
+ if p1 != 10 goto cont9
+Sname chnget "file8"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.8"
+ goto cont2
+cont9:
+ if p1 != 11 goto cont10
+Sname chnget "file9"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.9"
+ goto cont2
+cont10:
+ if p1 != 12 goto cont11
+Sname chnget "file10"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.10"
+ goto cont2
+cont11:
+ if p1 != 13 goto cont12
+Sname chnget "file11"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.11"
+ goto cont2
+cont12:
+ if p1 != 14 goto cont13
+Sname chnget "file12"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.12"
+ goto cont2
+cont13:
+ if p1 != 15 goto cont14
+Sname chnget "file13"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.13"
+ goto cont2
+cont14:
+ if p1 != 16 goto cont15
+Sname chnget "file14"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.14"
+ goto cont2
+cont15:
+ if p1 != 17 goto cont16
+Sname chnget "file15"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.15"
+ goto cont2
+cont16:
+ if p1 != 18 goto cont17
+Sname chnget "file16"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.16"
+ goto cont2
+cont17:
+ if p1 != 19 goto cont18
+Sname chnget "file17"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.17"
+ goto cont2
+cont18:
+ if p1 != 20 goto cont19
+Sname chnget "file18"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.18"
+ goto cont2
+cont19:
+ if p1 != 21 goto cont20
+Sname chnget "file19"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.19"
+ goto cont2
+cont20:
+ if p1 != 22 goto cont21
+Sname chnget "file20"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.20"
+ goto cont2
+cont21:
+ if p1 != 23 goto cont22
+Sname chnget "file21"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.21"
+ goto cont2
+cont22:
+ if p1 != 24 goto cont23
+Sname chnget "file22"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.22"
+ goto cont2
+cont23:
+ if p1 != 25 goto cont24
+Sname chnget "file23"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.23"
+ goto cont2
+cont24:
+ if p1 != 26 goto cont25
+Sname chnget "file24"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.24"
+ goto cont2
+cont25:
+Sname chnget "file25"
+i1 strcmp Sname, "0"
+ if i1 != 0 goto cont2
+Sname = "soundin.25"
+cont2:
+ichans filenchnls Sname
+ilen filelen Sname
+ if gireplace == 1 goto skip
+ xtratim ilen - .01
+skip:
+kamp linseg 0, .025, p4, ilen - .35, p4, .325, 0
+ if ichans == 2 goto skip2
+aout diskin2 Sname, 1 + p5, 0, 0
+a1,a2,a3,a4 pan aout, p6, 1, 1, 1
+ga1 = ga1 + (a1 * kamp)
+ga2 = ga2 + (a2 * kamp)
+ goto end
+skip2:
+aout,aout2 diskin2 Sname, 1 + p5, 0, 0
+a1,a2,a3,a4 pan aout, p6, 1, 1, 1
+a5,a6,a7,a8 pan aout2, p6, 1, 1, 1
+ga1 = ga1 + ((a1 + a5) * kamp)
+ga2 = ga2 + ((a2 + a6) * kamp)
+
+end: endin
+
+ instr 100
+
+ if gifilter == 0 goto skip
+a1 atonex ga1, gicutoff
+a2 atonex ga2, gicutoff
+ outs a1, a2
+ goto skip2
+skip:
+ outs ga1, ga2
+skip2:
+ga1 = 0
+ga2 = 0
+
+end: endin
+
+</CsInstruments>
+
+<CsScore>
+
+f1 0 8193 9 .25 1 0
+i1 0 3600
+i100 0 3600
+
+e
+
+</CsScore>
+</CsoundSynthesizer>
diff --git a/SamplePlayReadMe.txt b/SamplePlayReadMe.txt
new file mode 100644
index 0000000..d6cef8e
--- /dev/null
+++ b/SamplePlayReadMe.txt
@@ -0,0 +1,154 @@
+SAMPLEPLAY - Sugar Activity/Linux version - Notes
+Art Hunkins
+abhunkin@uncg.edu
+www.arthunkins.com
+
+
+Working with User Soundfiles/Objects
+
+The SamplePlay utility series includes SamplePlay (requiring a
+MIDI controller) and SamplePlayASC (performed on the ASCII keyboard
+alone). Both can handle mono or stereo soundfiles, and up to 25
+samples and a single 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 nature soundscapes. (This is the primary intent
+behind these utilities. The 25 bird samples and background loop
+included here are collectively called OISEAUX ORDINAIRES, in honor of
+the French composer Olivier Messiaen, his fascination with nature -
+especially unique bird calls, and his piano composition, Oiseaux
+Exotiques.)
+
+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 9/2011) 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 SamplePlay.
+
+Soundfiles must be moved into the folder where this file resides,
+and be renamed soundin.0 (for the background loop) and soundin.1
+through soundin.25 (for the samples). Alternatively, and more
+practically, however, user soundfiles may be loaded/imported from the
+Journal (Sugar 0.84 and later). In this case, only wav and ogg/vorbis
+formats are allowed.
+
+Unfortunately, no other Sugar activity (including TimeLapse,
+ShowNTell, and most importantly, Etoys) produces soundfiles useable
+by SamplePlay. Either they write files other than Ogg Vorbis or wav,
+are restricted to Sugar 0.82, or their output is inaccessible to the
+Journal and other activities (the case with Etoys).
+
+More advanced users may wish to record their soundfiles on some other
+system, and import their wav or ogg vorbis files into the Journal via
+a USB drive. (Display USB contents in Journal view, and drag your
+file onto the Journal icon.)
+
+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.
+Exit audacity. In the Journal, display the contents of your USB drive,
+and drag your newly-recorded file onto the Journal icon. It is now
+ready to import into SamplePlay.
+
+It may be of interest that Oiseaux Ordinaires (the default soundfile
+collection in SamplePlay) was recorded on the front stoop of the
+author's home in Burlington, North Carolina, USA - early on a series
+of summer mornings. He used a hand-held digital recorder, then
+selected, edited and looped his sounds in Audacity. 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 extraneous sounds
+(for example, rumble and traffic noise). Use of the low-cut filter
+option within SamplePlay also aided "homogenization."
+
+
+MIDI Controller Hints (SamplePlay 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.
+
+SamplePlay was specifically designed for two-octave or more (25+ key)
+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
+SamplePlay; its 18 (not 25) buttons are not velocity-sensitive (it has
+no pads or keys), and one of its four "Scenes" must be significantly
+reprogrammed by the Korg Kontrol Editor to function with SamplePlay.
+Though it has a multitude of programmable sliders and knobs,
+unfortunately the buttons are not laid out well for SamplePlay
+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.
+
+
+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). Reducing the Sample Rate to 32000 or even 24000 may be
+necessary. A more drastic solution is to reduce textural density.
+
+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
+SamplePlay.txt on the author's website. (It is the text file
+associated with the *all-platform* non-Sugar version of SamplePlay.)
+With respect to this document, it is perhaps worth noting one
+difference between the Sugar and non-Sugar versions of
+SamplePlayASC: the key that triggers the background loop in the
+Sugar version is "`" (to the left of numeral 1); in the all-platform
+version it is the ENTER key.
+
+Also, please be aware of one significant option available in
+SamplePlay but not in SamplePlayASC: the "play sample only as long
+as key is pressed" option. (In the ASC version, samples are always
+played for their full duration, unless the "replace" function is
+enabled.)
diff --git a/activity/activity-sampleplay.svg b/activity/activity-sampleplay.svg
new file mode 100644
index 0000000..3b8f8ce
--- /dev/null
+++ b/activity/activity-sampleplay.svg
@@ -0,0 +1,15 @@
+<?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="48" id="svg2" version="1.0" width="48" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <defs id="defs10"/>
+ <path d="M 9.4647608,4.0702459 C 8.7117238,3.0387764 7.7902795,3.1708991 6.9653207,3.6244087 C 5.0887315,4.683664 2.799342,5.6767879 3.4577132,6.5063054 C 4.1681773,7.7567968 4.6250771,8.5669628 5.9730539,10.494526 C 6.5259155,11.317811 9.053524,13.096259 6.9153389,14.764349 C 4.731018,16.468636 2.3928234,16.127243 1.9895015,14.568723 C 1.4609893,12.417249 4.7112094,11.841067 4.4073804,11.107444 C 3.463849,8.8923414 1.4704485,6.9497803 0.35832352,4.7888759 C 0.31470837,4.704132 0.54766406,4.4336423 0.70601611,4.3003128 C 1.0891693,3.9179142 6.9260294,0.5381985 7.4328665,0.46272023 C 7.5912173,0.32939087 7.9728262,0.31380298 8.0869963,0.31438438 C 9.0466261,0.31927601 10.264751,2.2195406 10.488419,2.6427778 C 11.198887,3.893266 11.639218,4.7070303 12.987192,6.6345934 C 13.540058,7.4578817 16.084232,9.2327302 13.946047,10.900822 C 11.761726,12.605107 9.4235294,12.263715 9.0202075,10.705194 C 8.4916965,8.5537196 11.725348,7.981137 11.421522,7.2475116 C 10.949755,6.1399596 10.217793,5.1017167 9.4647608,4.0702459 z" id="path2391" style="fill:&fill_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 26.206087,4.1716944 C 25.45305,3.1402249 24.531605,3.2723476 23.706646,3.7258572 C 21.830057,4.7851125 19.540668,5.7782366 20.199039,6.6077536 C 20.909503,7.8582456 21.366403,8.6684116 22.71438,10.595974 C 23.267241,11.419259 25.79485,13.197707 23.656665,14.865797 C 21.472344,16.570084 19.134149,16.228691 18.730827,14.670171 C 18.202315,12.518697 21.452535,11.942515 21.148706,11.208892 C 20.205175,8.9937896 18.211774,7.0512286 17.099649,4.8903244 C 17.056034,4.8055805 17.28899,4.5350908 17.447342,4.4017613 C 17.830495,4.0193627 23.667355,0.63964704 24.174192,0.56416874 C 24.332543,0.43083944 24.714152,0.41525154 24.828322,0.41583294 C 25.787952,0.42072454 27.006077,2.3209891 27.229745,2.7442263 C 27.940213,3.9947145 28.380544,4.8084788 29.728518,6.7360416 C 30.281384,7.5593306 32.825558,9.3341786 30.687373,11.00227 C 28.503052,12.706555 26.164855,12.365163 25.761533,10.806642 C 25.233022,8.6551686 28.466674,8.0825856 28.162848,7.3489606 C 27.691081,6.2414086 26.959119,5.2031652 26.206087,4.1716944 z" id="path2404" style="fill:&stroke_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 42.413879,4.1716945 C 41.660842,3.140225 40.739398,3.2723477 39.914439,3.7258573 C 38.03785,4.7851126 35.748461,5.7782365 36.406832,6.607754 C 37.117296,7.8582454 37.574196,8.6684114 38.922173,10.595975 C 39.475034,11.41926 42.002643,13.197708 39.864458,14.865798 C 37.680137,16.570085 35.341942,16.228692 34.93862,14.670172 C 34.410108,12.518698 37.660328,11.942516 37.356499,11.208893 C 36.412968,8.99379 34.419567,7.0512289 33.307442,4.8903245 C 33.263827,4.8055806 33.496783,4.5350909 33.655135,4.4017614 C 34.038288,4.0193628 39.875148,0.63964707 40.381985,0.56416877 C 40.540336,0.43083947 40.921945,0.41525157 41.036115,0.41583297 C 41.995745,0.42072457 43.21387,2.3209892 43.437538,2.7442264 C 44.148006,3.9947146 44.588337,4.8084789 45.936311,6.736042 C 46.489177,7.5593303 49.033351,9.3341788 46.895166,11.002271 C 44.710845,12.706556 42.372648,12.365164 41.969326,10.806643 C 41.440815,8.6551682 44.674467,8.0825856 44.370641,7.3489602 C 43.898874,6.2414082 43.166912,5.2031653 42.413879,4.1716945 z" id="path2406" style="fill:&fill_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 6.0017051,27.20493 C 6.7547421,28.236399 7.6761864,28.104277 8.5011452,27.650767 C 10.377734,26.591512 12.667124,25.598388 12.008753,24.76887 C 11.298289,23.518379 10.841389,22.708213 9.493412,20.78065 C 8.9405504,19.957365 6.4129419,18.178917 8.551127,16.510827 C 10.735448,14.80654 13.073642,15.147933 13.476964,16.706453 C 14.005477,18.857927 10.755256,19.434109 11.059085,20.167732 C 12.002617,22.382834 13.996017,24.325395 15.108142,26.4863 C 15.151757,26.571044 14.918802,26.841533 14.76045,26.974863 C 14.377297,27.357261 8.5404365,30.736977 8.0335994,30.812455 C 7.8752486,30.945785 7.4936397,30.961373 7.3794696,30.960791 C 6.4198398,30.9559 5.2017148,29.055635 4.9780468,28.632398 C 4.2675788,27.38191 3.8272478,26.568145 2.4792738,24.640582 C 1.9264078,23.817294 -0.61776619,22.042445 1.5204188,20.374354 C 3.7047398,18.670069 6.0429365,19.011461 6.4462584,20.569982 C 6.9747694,22.721456 3.7411178,23.294039 4.0449438,24.027664 C 4.5167108,25.135216 5.2486728,26.173459 6.0017051,27.20493 z" id="path2408" style="fill:&stroke_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 9.6866067,35.75611 C 8.9335697,34.72464 8.0121254,34.856763 7.1871666,35.310273 C 5.3105774,36.369528 3.0211879,37.362652 3.6795591,38.192169 C 4.3900232,39.442661 4.846923,40.252827 6.1948998,42.18039 C 6.7477614,43.003675 9.2753699,44.782123 7.1371848,46.450213 C 4.9528639,48.1545 2.6146693,47.813107 2.2113474,46.254587 C 1.6828352,44.103113 4.9330553,43.526931 4.6292263,42.793308 C 3.6856949,40.578205 1.6922944,38.635644 0.58016939,36.47474 C 0.53655424,36.389996 0.76950993,36.119506 0.92786198,35.986177 C 1.3110152,35.603778 7.1478753,32.224062 7.6547124,32.148584 C 7.8130632,32.015255 8.1946721,31.999667 8.3088422,32.000248 C 9.268472,32.00514 10.486597,33.905404 10.710265,34.328642 C 11.420733,35.57913 11.861064,36.392894 13.209038,38.320457 C 13.761904,39.143746 16.306078,40.918594 14.167893,42.586686 C 11.983572,44.290971 9.6453753,43.949579 9.2420534,42.391058 C 8.7135424,40.239583 11.947194,39.667001 11.643368,38.933375 C 11.171601,37.825823 10.439639,36.787581 9.6866067,35.75611 z" id="path2410" style="fill:&fill_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 22.417289,27.308826 C 23.170326,28.340295 24.091771,28.208173 24.916729,27.754663 C 26.793319,26.695408 29.082708,25.702284 28.424337,24.872766 C 27.713873,23.622275 27.256973,22.812109 25.908996,20.884546 C 25.356135,20.061261 22.828526,18.282813 24.966711,16.614723 C 27.151032,14.910436 29.489227,15.251829 29.892549,16.810349 C 30.421061,18.961823 27.170841,19.538005 27.47467,20.271628 C 28.418201,22.48673 30.411602,24.429291 31.523727,26.590196 C 31.567342,26.67494 31.334386,26.945429 31.176034,27.078759 C 30.792881,27.461158 24.956021,30.840873 24.449184,30.916352 C 24.290833,31.049681 23.909224,31.065269 23.795054,31.064687 C 22.835424,31.059796 21.617299,29.159531 21.393631,28.736294 C 20.683163,27.485806 20.242832,26.672041 18.894858,24.744478 C 18.341992,23.92119 15.797818,22.146342 17.936003,20.47825 C 20.120324,18.773965 22.458521,19.115357 22.861843,20.673878 C 23.390354,22.825352 20.156702,23.397935 20.460528,24.13156 C 20.932295,25.239112 21.664257,26.277355 22.417289,27.308826 z" id="path2412" style="fill:&fill_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 38.521186,27.204929 C 39.274223,28.236399 40.195667,28.104276 41.020626,27.650767 C 42.897215,26.591511 45.186604,25.598387 44.528233,24.76887 C 43.817769,23.518379 43.360869,22.708213 42.012893,20.780649 C 41.460031,19.957364 38.932422,18.178916 41.070608,16.510826 C 43.254928,14.806539 45.593123,15.147932 45.996445,16.706452 C 46.524957,18.857926 43.274737,19.434108 43.578566,20.167731 C 44.522097,22.382834 46.515498,24.325395 47.627623,26.486299 C 47.671238,26.571043 47.438282,26.841533 47.27993,26.974863 C 46.896777,27.357261 41.059917,30.736977 40.55308,30.812455 C 40.394729,30.945785 40.01312,30.961372 39.89895,30.960791 C 38.93932,30.955899 37.721195,29.055635 37.497527,28.632398 C 36.787059,27.381909 36.346728,26.568145 34.998754,24.640582 C 34.445888,23.817294 31.901714,22.042445 34.039899,20.374353 C 36.22422,18.670068 38.562417,19.01146 38.965739,20.569981 C 39.49425,22.721456 36.260598,23.294038 36.564424,24.027664 C 37.036191,25.135216 37.768153,26.173459 38.521186,27.204929 z" id="path2414" style="fill:&stroke_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 25.790502,35.860006 C 25.037465,34.828537 24.116021,34.960659 23.291062,35.414169 C 21.414473,36.473424 19.125084,37.466548 19.783455,38.296066 C 20.493919,39.546557 20.950819,40.356723 22.298796,42.284286 C 22.851657,43.107571 25.379266,44.886019 23.241081,46.554109 C 21.05676,48.258396 18.718565,47.917003 18.315243,46.358483 C 17.786731,44.207009 21.036951,43.630827 20.733122,42.897204 C 19.789591,40.682102 17.79619,38.739541 16.684065,36.578636 C 16.64045,36.493892 16.873406,36.223403 17.031758,36.090073 C 17.414911,35.707675 23.251771,32.327959 23.758608,32.252481 C 23.916959,32.119151 24.298568,32.103563 24.412738,32.104145 C 25.372368,32.109036 26.590493,34.009301 26.814161,34.432538 C 27.524629,35.683026 27.96496,36.496791 29.312934,38.424354 C 29.8658,39.247642 32.409974,41.022491 30.271789,42.690582 C 28.087468,44.394867 25.749271,44.053475 25.345949,42.494954 C 24.817438,40.34348 28.05109,39.770897 27.747264,39.037272 C 27.275497,37.92972 26.543535,36.891477 25.790502,35.860006 z" id="path2416" style="fill:&stroke_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+ <path d="M 42.206088,35.75611 C 41.453051,34.72464 40.531606,34.856763 39.706648,35.310272 C 37.830058,36.369528 35.540669,37.362652 36.19904,38.192169 C 36.909504,39.442661 37.366404,40.252827 38.714381,42.18039 C 39.267242,43.003675 41.794851,44.782123 39.656666,46.450213 C 37.472345,48.1545 35.13415,47.813107 34.730828,46.254587 C 34.202316,44.103113 37.452536,43.526931 37.148707,42.793308 C 36.205176,40.578205 34.211775,38.635644 33.09965,36.47474 C 33.056035,36.389996 33.288991,36.119506 33.447343,35.986177 C 33.830496,35.603778 39.667356,32.224062 40.174193,32.148584 C 40.332544,32.015255 40.714153,31.999667 40.828323,32.000248 C 41.787953,32.00514 43.006078,33.905404 43.229746,34.328642 C 43.940214,35.57913 44.380545,36.392894 45.728519,38.320457 C 46.281385,39.143745 48.825559,40.918594 46.687374,42.586686 C 44.503053,44.290971 42.164856,43.949579 41.761534,42.391058 C 41.233023,40.239583 44.466675,39.667001 44.162849,38.933375 C 43.691082,37.825823 42.95912,36.78758 42.206088,35.75611 z" id="path2418" style="fill:&fill_color;;fill-rule:evenodd;stroke:&stroke_color;;stroke-width:0.72668952"/>
+</svg> \ No newline at end of file
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..f30f3bc
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,14 @@
+[Activity]
+
+name = SamplePlay
+
+bundle_id = org.laptop.SamplePlay
+icon = activity-sampleplay
+
+activity_version = 2
+
+host_version = 1
+
+show_launcher = yes
+exec = sugar-activity sampleplay.SamplePlay
+license = CC-by-SA 3.0
diff --git a/csndsugui.py b/csndsugui.py
new file mode 100644
index 0000000..2058d0e
--- /dev/null
+++ b/csndsugui.py
@@ -0,0 +1,815 @@
+# 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=""):
+ """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)
+ 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/sampleplay.py b/sampleplay.py
new file mode 100644
index 0000000..ef5daac
--- /dev/null
+++ b/sampleplay.py
@@ -0,0 +1,285 @@
+# SAMPLEPLAY - Audio Sample Player Utilities for Children (2011)
+# Art Hunkins (www.arthunkins.com)
+#
+# Sampleplay 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.
+#
+# version 2:
+# GUI tweaks
+
+import csndsugui
+from sugar.activity import activity
+from sugar.graphics.objectchooser import ObjectChooser
+from sugar import mime
+import gtk
+import os
+
+class SamplePlay(activity.Activity):
+
+ def __init__(self, handle):
+
+ activity.Activity.__init__(self, handle)
+
+ red = (0xDDDD, 0, 0)
+ brown = (0x6600, 0, 0)
+ green = (0, 0x5500, 0)
+ self.paths = ["0"]*26
+ self.jobjects = [None]*26
+ self.buts = [None]*26
+
+ 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>SAMPLEPLAY</u> - Audio Sample Player \
+Utilities for Children (2011)</big></b>\n\
+\t\t\t Art Hunkins (www.arthunkins.com)</big>", all)
+
+ win.text("\
+<b>SamplePlay</b> and <b>SamplePlayASC</b> play up to 25 mono/stereo samples and \
+0 - 1 audio loops at the same time;\n\
+ wav and ogg vorbis formats only (no ogg vorbis on Sugar 0.84).\n\
+ User samples must be placed in Journal (Record activity \
+does this). <b>No user files on Sugar 0.82</b> (original XO-1).\n\
+ The default samples are those from the author's \
+<b>OISEAUX ORDINAIRES</b>. You are urged to create your own!\t ", all, brown)
+ win.text("<b>SamplePlay</b> requires a MIDI controller, \
+one key/button/pad per active sample (optionally velocity-sensitive); \t\n also \
+(optionally) an additional key/button/pad and/or 1-3 MIDI knobs/sliders. \
+All samples/MIDI notes are consecutive.", all, green)
+ win.text("\
+<i><b>MIDI</b>: plug in controller after boot &amp; before selecting version. \
+Zero controls before start; reset pan &amp; pitch \
+to .5 after.</i>", all, green)
+ win.text("<b>SamplePlayASC</b> doesn't involve MIDI; \
+control is via one or more ASCII keyboards.\n\
+ <b>ASCII keys</b> used: (sample amplitude) 1-0(10); (pitch change, both + and -) \
+SHIFTED 1-0(10);\n\
+ (pan position, left/right) Z to / [all the above take effect with next keypress]; \
+(samples 1-12 trigger) Q to ];\n\
+ (samples 13-23) A to '; (sample 24) the - key, and \
+(sample 25) the = key. The ` key starts/stops background loop. ", 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 SamplePlay ")
+ 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 SamplePlayASC ")
+ 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 SamplePlay", nbox, green)
+
+ try:
+ from jarabe import config
+ version = [int(i) for i in config.version.split('.')][:2]
+ except ImportError:
+ version = [0, 82]
+ if version >= [0, 84]:
+ win.text(" Optionally, <b>before choosing version</b>, \
+select your own <b>audio</b> sample(s) and/or loop from Journal \n\
+ Deselect by closing Journal. Create soundfiles with Record activity \
+or Audacity (see ReadMe.txt).", self.b2box, brown)
+ win.text(" Load Loop\n &amp; Samples", self.b2box, brown)
+ self.buts[0] = win.cbbutton(self.b2box, self.choose0, "Loop")
+ self.buts[0].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x6600, 0, 0))
+ win.text("", self.b3box, brown)
+ for i in range(1, 26):
+ self.buts[i] = win.cbbutton(self.b3box, self.choose, "%2d" %i)
+ self.buts[i].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x6600, 0, 0))
+
+ bbox = win.box(False, all)
+ self.bb = bbox
+ self.w = win
+ self.r = red
+ self.g = green
+ self.br = brown
+ self.ver = 0
+ self.kp = []
+
+ def choose0(self, widget):
+ chooser = ObjectChooser(parent=self, what_filter=mime.GENERIC_TYPE_AUDIO)
+ result = chooser.run()
+ if result == gtk.RESPONSE_ACCEPT:
+ self.jobjects[0] = chooser.get_selected_object()
+ self.paths[0] = str(self.jobjects[0].get_file_path())
+ self.buts[0].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x8800, 0))
+ self.buts[0].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x8800, 0))
+ else:
+ self.paths[0] = "0"
+ self.jobjects[0] = None
+ self.buts[0].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x6600, 0, 0))
+ self.buts[0].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0x6600, 0, 0))
+
+ def choose(self, widget):
+ chooser = ObjectChooser(parent=self, what_filter=mime.GENERIC_TYPE_AUDIO)
+ result = chooser.run()
+ index = self.b3box.child_get_property(widget, "position")
+ if result == gtk.RESPONSE_ACCEPT:
+ self.jobjects[index] = chooser.get_selected_object()
+ self.paths[index] = str(self.jobjects[index].get_file_path())
+ self.buts[index].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0x8800, 0))
+ self.buts[index].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0, 0x8800, 0))
+ else:
+ self.paths[index] = "0"
+ self.jobjects[index] = None
+ self.buts[index].modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x6600, 0, 0))
+ self.buts[index].modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(0x6600, 0, 0))
+
+ def send_data(self):
+ for i in range(26):
+ self.w.set_filechannel("file%d" % i, self.paths[i])
+
+ def onKeyPress(self, widget, event):
+ if self.p:
+ keyval = event.keyval
+ if keyval in self.kp:
+ return True
+ self.kp.append(keyval)
+ self.w.set_channel("ascii", keyval)
+ return True
+
+ def onKeyRelease(self, widget, event):
+ self.kp.remove(event.keyval)
+ self.w.set_channel("ascii", 0)
+ return True
+
+ 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))
+ if self.ver > 1:
+ self.connect("key-press-event", self.onKeyPress)
+ self.connect("key-release-event", self.onKeyRelease)
+ else:
+ self.p = False
+ self.w.recompile()
+ self.w.channels_reinit()
+ self.send_data()
+ 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()
+ else:
+ self.b2box.destroy()
+ self.b3box.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 - Sampleplay</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("SamplePlay.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, 30, 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(25, 0, 25, 1, 1, self.b3, 0, "Samps", "# of Samples")
+ self.w.spin(2, 0, 3, 1, 1, self.b3, 0, "Sampamp", "Sample Level Ctrl\n\
+[0=none/1=rand\n2=note vel/3=ctrl]")
+ self.w.spin(10, 0, 30, 1, 1, self.b3, 0, "Sampmax", "Overall Samp Lev\n\
+ [10=norm]")
+ self.w.spin(21, 0, 127, 1, 1, self.b4, 0, "Smpctrl", "Samp Lev Ctrl #")
+ self.w.spin(60, 0, 103, 1, 1, self.b4, 0, "MIDI1", "1st MIDI Note #")
+ self.w.spin(1, 0, 2, 1, 1, self.b4, 0, "Replace", " Replace Samps?\n\
+ [0=overlap\n1=replace samp\n 2=sustain\n keypress]")
+ self.w.spin(0, 0, 3, 1, 1, self.b5, 0, "Smpfreq", "Samp Pitch Change\n\
+ [0=none/1=rand\n 2=note vel/3=ctrl]")
+ self.w.spin(22, 0, 127, 1, 1, self.b5, 0, "Frqctrl", "Pitch Controller #")
+ self.w.spin(1, 0, 3, 1, 1, self.b5, 0, "Panpos", " Pan Pos Control\n\
+[0=none/1=rand\n2=note vel/3=ctrl]")
+ self.w.spin(23, 0, 127, 1, 1, self.b6, 0, "Panctrl", "Pan Position Ctrl #")
+ self.w.button(self.b6, "Filter", "Low-cut Filter?")
+ self.w.text("(for rumble/hum)", self.b6)
+ self.w.spin(400, 50, 2000, 10, 100, self.b6, 0, "Cutoff", "Filt Cut Freq (Hz)")
+ self.p = False
+ self.w.text("\n<i>Select options first </i>", self.b6, self.g)
+ self.send_data()
+ 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()
+ else:
+ self.b2box.destroy()
+ self.b3box.destroy()
+ self.ver = 2
+ self.box1 = self.w.box(True, self.bb)
+ self.w.text("\t\t\t ", self.box1)
+ self.box2 = self.w.box(True, self.bb)
+ self.f = self.w.framebox(" <b>2 - SamplePlayASC</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.w.reset()
+ self.w.csd("SamplePlayASC.csd")
+ self.w.text("", self.b1)
+ self.w.button(self.b1, "Backgnd", "Background Loop?")
+ self.w.text("(start/stop w/ ` key)", self.b1, self.g)
+ self.w.spin(10, 0, 30, 1, 1, self.b1, 0, "Bgmax", "Loop Lev [10=norm]")
+ self.w.spin(5, 1, 30, 1, 1, self.b1, 0, "Stfade", "Start/Stop Seconds")
+ self.w.spin(25, 0, 25, 1, 1, self.b2, 0, "Samps", "# of Samples")
+ self.w.spin(0, 0, 2, 1, 1, self.b2, 0, "Sampamp", "Sample Lev Ctrl\n\
+[0=none/1=rand\n2=nums (0=10)]")
+ self.w.spin(10, 0, 30, 1, 1, self.b2, 0, "Sampmax", "Overall Samp Lev\n\
+ [10=norm]")
+ self.w.button(self.b3, "Replace", "Replace Samps?")
+ self.w.text("(0=overlap samps)", self.b3, self.g)
+ self.w.spin(0, 0, 2, 1, 1, self.b3, 0, "Smpfreq", "Samp Pitch Change\n\
+[0=none/1=rand/2=\nSHFT nums (0=10)]")
+ self.w.spin(1, 0, 2, 1, 1, self.b3, 0, "Panpos", "Pan Position Control\n\
+ [0=none/1=rand\n 2=bottom keys]")
+ self.w.text("", self.b4)
+ self.w.button(self.b4, "Filter", "Low-cut Filter?")
+ self.w.text("(for rumble/hum)", self.b4)
+ self.w.spin(400, 50, 2000, 10, 100, self.b4, 0, "Cutoff", "Filt Cut Freq (Hz)")
+ self.p = False
+ self.w.text("\n<i>Select options first </i>", self.b4, self.g)
+ self.send_data()
+ self.but = self.w.cbbutton(self.b4, 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))
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..94ea91e
--- /dev/null
+++ b/soundin.0
Binary files differ
diff --git a/soundin.1 b/soundin.1
new file mode 100644
index 0000000..5f37cb6
--- /dev/null
+++ b/soundin.1
Binary files differ
diff --git a/soundin.10 b/soundin.10
new file mode 100644
index 0000000..7d9f78a
--- /dev/null
+++ b/soundin.10
Binary files differ
diff --git a/soundin.11 b/soundin.11
new file mode 100644
index 0000000..f8f0702
--- /dev/null
+++ b/soundin.11
Binary files differ
diff --git a/soundin.12 b/soundin.12
new file mode 100644
index 0000000..dada249
--- /dev/null
+++ b/soundin.12
Binary files differ
diff --git a/soundin.13 b/soundin.13
new file mode 100644
index 0000000..bb25e68
--- /dev/null
+++ b/soundin.13
Binary files differ
diff --git a/soundin.14 b/soundin.14
new file mode 100644
index 0000000..1348bfe
--- /dev/null
+++ b/soundin.14
Binary files differ
diff --git a/soundin.15 b/soundin.15
new file mode 100644
index 0000000..a000c85
--- /dev/null
+++ b/soundin.15
Binary files differ
diff --git a/soundin.16 b/soundin.16
new file mode 100644
index 0000000..e1042ea
--- /dev/null
+++ b/soundin.16
Binary files differ
diff --git a/soundin.17 b/soundin.17
new file mode 100644
index 0000000..e7021c0
--- /dev/null
+++ b/soundin.17
Binary files differ
diff --git a/soundin.18 b/soundin.18
new file mode 100644
index 0000000..f6c807b
--- /dev/null
+++ b/soundin.18
Binary files differ
diff --git a/soundin.19 b/soundin.19
new file mode 100644
index 0000000..d267f03
--- /dev/null
+++ b/soundin.19
Binary files differ
diff --git a/soundin.2 b/soundin.2
new file mode 100644
index 0000000..d31b2a8
--- /dev/null
+++ b/soundin.2
Binary files differ
diff --git a/soundin.20 b/soundin.20
new file mode 100644
index 0000000..5126d9c
--- /dev/null
+++ b/soundin.20
Binary files differ
diff --git a/soundin.21 b/soundin.21
new file mode 100644
index 0000000..6aefd1e
--- /dev/null
+++ b/soundin.21
Binary files differ
diff --git a/soundin.22 b/soundin.22
new file mode 100644
index 0000000..e9b7761
--- /dev/null
+++ b/soundin.22
Binary files differ
diff --git a/soundin.23 b/soundin.23
new file mode 100644
index 0000000..8cbeaee
--- /dev/null
+++ b/soundin.23
Binary files differ
diff --git a/soundin.24 b/soundin.24
new file mode 100644
index 0000000..a938532
--- /dev/null
+++ b/soundin.24
Binary files differ
diff --git a/soundin.25 b/soundin.25
new file mode 100644
index 0000000..837fb2a
--- /dev/null
+++ b/soundin.25
Binary files differ
diff --git a/soundin.3 b/soundin.3
new file mode 100644
index 0000000..05a479c
--- /dev/null
+++ b/soundin.3
Binary files differ
diff --git a/soundin.4 b/soundin.4
new file mode 100644
index 0000000..f39d33f
--- /dev/null
+++ b/soundin.4
Binary files differ
diff --git a/soundin.5 b/soundin.5
new file mode 100644
index 0000000..09f21d1
--- /dev/null
+++ b/soundin.5
Binary files differ
diff --git a/soundin.6 b/soundin.6
new file mode 100644
index 0000000..bcf5057
--- /dev/null
+++ b/soundin.6
Binary files differ
diff --git a/soundin.7 b/soundin.7
new file mode 100644
index 0000000..e80b93b
--- /dev/null
+++ b/soundin.7
Binary files differ
diff --git a/soundin.8 b/soundin.8
new file mode 100644
index 0000000..5224cb7
--- /dev/null
+++ b/soundin.8
Binary files differ
diff --git a/soundin.9 b/soundin.9
new file mode 100644
index 0000000..1168b04
--- /dev/null
+++ b/soundin.9
Binary files differ