diff options
author | Live 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) |
commit | 63b30b57ae2d4c82b43311a8d6ff0288c4480518 (patch) | |
tree | af63c5f5c20db6466a0cc54505b204cb7267cfbc |
Initial commit
-rw-r--r-- | MANIFEST | 35 | ||||
-rw-r--r-- | SamplePlay.csd | 384 | ||||
-rw-r--r-- | SamplePlayASC.csd | 546 | ||||
-rw-r--r-- | SamplePlayReadMe.txt | 154 | ||||
-rw-r--r-- | activity/activity-sampleplay.svg | 15 | ||||
-rw-r--r-- | activity/activity.info | 14 | ||||
-rw-r--r-- | csndsugui.py | 815 | ||||
-rw-r--r-- | sampleplay.py | 285 | ||||
-rw-r--r-- | setup.py | 4 | ||||
-rw-r--r-- | soundin.0 | bin | 0 -> 3666348 bytes | |||
-rw-r--r-- | soundin.1 | bin | 0 -> 527788 bytes | |||
-rw-r--r-- | soundin.10 | bin | 0 -> 309084 bytes | |||
-rw-r--r-- | soundin.11 | bin | 0 -> 305828 bytes | |||
-rw-r--r-- | soundin.12 | bin | 0 -> 344448 bytes | |||
-rw-r--r-- | soundin.13 | bin | 0 -> 666680 bytes | |||
-rw-r--r-- | soundin.14 | bin | 0 -> 332520 bytes | |||
-rw-r--r-- | soundin.15 | bin | 0 -> 335224 bytes | |||
-rw-r--r-- | soundin.16 | bin | 0 -> 462160 bytes | |||
-rw-r--r-- | soundin.17 | bin | 0 -> 406340 bytes | |||
-rw-r--r-- | soundin.18 | bin | 0 -> 372296 bytes | |||
-rw-r--r-- | soundin.19 | bin | 0 -> 467240 bytes | |||
-rw-r--r-- | soundin.2 | bin | 0 -> 554852 bytes | |||
-rw-r--r-- | soundin.20 | bin | 0 -> 767136 bytes | |||
-rw-r--r-- | soundin.21 | bin | 0 -> 501772 bytes | |||
-rw-r--r-- | soundin.22 | bin | 0 -> 485792 bytes | |||
-rw-r--r-- | soundin.23 | bin | 0 -> 394524 bytes | |||
-rw-r--r-- | soundin.24 | bin | 0 -> 452928 bytes | |||
-rw-r--r-- | soundin.25 | bin | 0 -> 529880 bytes | |||
-rw-r--r-- | soundin.3 | bin | 0 -> 399416 bytes | |||
-rw-r--r-- | soundin.4 | bin | 0 -> 373856 bytes | |||
-rw-r--r-- | soundin.5 | bin | 0 -> 344816 bytes | |||
-rw-r--r-- | soundin.6 | bin | 0 -> 267732 bytes | |||
-rw-r--r-- | soundin.7 | bin | 0 -> 320868 bytes | |||
-rw-r--r-- | soundin.8 | bin | 0 -> 267728 bytes | |||
-rw-r--r-- | soundin.9 | bin | 0 -> 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 & before selecting version. \ +Zero controls before start; reset pan & 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 & 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 Binary files differnew file mode 100644 index 0000000..94ea91e --- /dev/null +++ b/soundin.0 diff --git a/soundin.1 b/soundin.1 Binary files differnew file mode 100644 index 0000000..5f37cb6 --- /dev/null +++ b/soundin.1 diff --git a/soundin.10 b/soundin.10 Binary files differnew file mode 100644 index 0000000..7d9f78a --- /dev/null +++ b/soundin.10 diff --git a/soundin.11 b/soundin.11 Binary files differnew file mode 100644 index 0000000..f8f0702 --- /dev/null +++ b/soundin.11 diff --git a/soundin.12 b/soundin.12 Binary files differnew file mode 100644 index 0000000..dada249 --- /dev/null +++ b/soundin.12 diff --git a/soundin.13 b/soundin.13 Binary files differnew file mode 100644 index 0000000..bb25e68 --- /dev/null +++ b/soundin.13 diff --git a/soundin.14 b/soundin.14 Binary files differnew file mode 100644 index 0000000..1348bfe --- /dev/null +++ b/soundin.14 diff --git a/soundin.15 b/soundin.15 Binary files differnew file mode 100644 index 0000000..a000c85 --- /dev/null +++ b/soundin.15 diff --git a/soundin.16 b/soundin.16 Binary files differnew file mode 100644 index 0000000..e1042ea --- /dev/null +++ b/soundin.16 diff --git a/soundin.17 b/soundin.17 Binary files differnew file mode 100644 index 0000000..e7021c0 --- /dev/null +++ b/soundin.17 diff --git a/soundin.18 b/soundin.18 Binary files differnew file mode 100644 index 0000000..f6c807b --- /dev/null +++ b/soundin.18 diff --git a/soundin.19 b/soundin.19 Binary files differnew file mode 100644 index 0000000..d267f03 --- /dev/null +++ b/soundin.19 diff --git a/soundin.2 b/soundin.2 Binary files differnew file mode 100644 index 0000000..d31b2a8 --- /dev/null +++ b/soundin.2 diff --git a/soundin.20 b/soundin.20 Binary files differnew file mode 100644 index 0000000..5126d9c --- /dev/null +++ b/soundin.20 diff --git a/soundin.21 b/soundin.21 Binary files differnew file mode 100644 index 0000000..6aefd1e --- /dev/null +++ b/soundin.21 diff --git a/soundin.22 b/soundin.22 Binary files differnew file mode 100644 index 0000000..e9b7761 --- /dev/null +++ b/soundin.22 diff --git a/soundin.23 b/soundin.23 Binary files differnew file mode 100644 index 0000000..8cbeaee --- /dev/null +++ b/soundin.23 diff --git a/soundin.24 b/soundin.24 Binary files differnew file mode 100644 index 0000000..a938532 --- /dev/null +++ b/soundin.24 diff --git a/soundin.25 b/soundin.25 Binary files differnew file mode 100644 index 0000000..837fb2a --- /dev/null +++ b/soundin.25 diff --git a/soundin.3 b/soundin.3 Binary files differnew file mode 100644 index 0000000..05a479c --- /dev/null +++ b/soundin.3 diff --git a/soundin.4 b/soundin.4 Binary files differnew file mode 100644 index 0000000..f39d33f --- /dev/null +++ b/soundin.4 diff --git a/soundin.5 b/soundin.5 Binary files differnew file mode 100644 index 0000000..09f21d1 --- /dev/null +++ b/soundin.5 diff --git a/soundin.6 b/soundin.6 Binary files differnew file mode 100644 index 0000000..bcf5057 --- /dev/null +++ b/soundin.6 diff --git a/soundin.7 b/soundin.7 Binary files differnew file mode 100644 index 0000000..e80b93b --- /dev/null +++ b/soundin.7 diff --git a/soundin.8 b/soundin.8 Binary files differnew file mode 100644 index 0000000..5224cb7 --- /dev/null +++ b/soundin.8 diff --git a/soundin.9 b/soundin.9 Binary files differnew file mode 100644 index 0000000..1168b04 --- /dev/null +++ b/soundin.9 |