////////////////////////////////////////////////////// //-- scale->beat /f0 031221 updated 071029 //"no one cares about pitches any more, only beats.." -jmc ( //--settings var path= "sounds/a11wlk01.wav"; //replace with your own drumloop var tempo= 125; //the drumloop's tempo var beats= 8; //length of drumloop in beats /* GUI.cocoa; GUI.swing; */ //--this section by jmc/jrh. copied from http://swiki.hfbk-hamburg.de:8888/MusicTechnology/601 // a scale dictionary // some of these names are the names that musicians give to the scales // and have no accurate relation to their actual origin. // no microtuning here, all equal tempered. z = ( // 5 note scales minorPentatonic: [0,3,5,7,10], majorPentatonic: [0,2,4,7,9], ritusen: [0,2,5,7,9], // another mode of major pentatonic egyptian: [0,2,5,7,10], // another mode of major pentatonic kumoi: [0,2,3,7,9], hirajoshi: [0,2,3,7,8], iwato: [0,1,5,6,10], // mode of hirajoshi chinese: [0,4,6,7,11], // mode of hirajoshi indian: [0,4,5,7,10], pelog: [0,1,3,7,8], prometheus: [0,2,4,6,11], scriabin: [0,1,4,7,9], // 6 note scales whole: (0,2..10), augmented: [0,3,4,7,8,11], augmented2: [0,1,4,5,8,9], // hexatonic modes with no tritone hexMajor7: [0,2,4,7,9,11], hexDorian: [0,2,3,5,7,10], hexPhrygian: [0,1,3,5,8,10], hexSus: [0,2,5,7,9,10], hexMajor6: [0,2,4,5,7,9], hexAeolian: [0,3,5,7,8,10], // 7 note scales ionian: [0,2,4,5,7,9,11], dorian: [0,2,3,5,7,9,10], phrygian: [0,1,3,5,7,8,10], lydian: [0,2,4,6,7,9,11], mixolydian: [0,2,4,5,7,9,10], aeolian: [0,2,3,5,7,8,10], locrian: [0,1,3,5,6,8,10], harmonicMinor: [0,2,3,5,7,8,11], harmonicMajor: [0,2,4,5,7,8,11], melodicMinor: [0,2,3,5,7,9,11], bartok: [0,2,4,5,7,8,10], // jazzers call this the hindu scale // raga modes todi: [0,1,3,6,7,8,11], // maqam ahar kurd purvi: [0,1,4,6,7,8,11], marva: [0,1,4,6,7,9,11], bhairav: [0,1,4,5,7,8,11], ahirbhairav: [0,1,4,5,7,9,10], superLocrian: [0,1,3,4,6,8,10], romanianMinor: [0,2,3,6,7,9,10], // maqam nakriz hungarianMinor: [0,2,3,6,7,8,11], neapolitanMinor: [0,1,3,5,7,8,11], enigmatic: [0,1,4,6,8,10,11], spanish: [0,1,4,5,7,8,10], // modes of whole tones with added note: leadingWhole: [0,2,4,6,8,10,11], lydianMinor: [0,2,4,6,7,8,10], neapolitanMajor: [0,1,3,5,7,9,11], locrianMajor: [0,2,4,5,6,8,10], // 8 note scales diminished: [0,1,3,4,6,7,9,10], diminished2: [0,2,3,5,6,8,9,11], // 12 note scales chromatic: (0..11), // some raga modes from asawari thata // without pakads (movements) or vakras (twists) aswari_aroh: [ 0, 2, 5, 7, 9, 0 ], aswari_avaroh: [ 0, 2, 4, 3, 5, 7, 9, 10 ], jonpuri_aroh: [ 0, 2, 5, 7, 8, 10 ], jonpuri_avaroh: [ 0, 2, 3, 5, 7, 8, 10 ], durbai_kandra: [ 0, 2, 3, 5, 7, 8, 10 ], desi_aroh: [ 0, 2, 5, 7, 10 ], desi_avaroh: [ 0, 1, 3, 5, 7, 8, 10 ], gandhari_aroh: [ 0, 2, 5, 7, 10 ], gandhari_avaroh: [ 0, 1, 3, 5, 7, 9, 10 ], khut_aroh: [ 0, 3, 5, 7, 8, 10 ], khut_avaroh: [ 0, 1, 3, 5, 7, 8, 9, 10 ], jeelaf_aroh: [ 0, 3, 5, 7, 8, 11 ], jeelaf_avaroh: [ 0, 2, 4, 5, 7, 9, 10 ], gopika_basant_aroh: [ 0, 3, 5, 7, 9, 11 ], gopika_basant_avaroh: [ 0, 4, 5, 7, 9, 11 ], abheeri_aroh: [ 0, 3, 5, 7, 10 ], abheeri_avaroh: [ 0, 1, 3, 5, 7, 8, 10 ] ); //--drum machine playing the above scales Routine.run{ var win, popScale, popVersion, butSteps; var buf, clk, main, order= (0..11), mark= false.dup(12); var hang= Condition.new; s.bootSync(hang); SynthDef("playbuf-segment", {|out= 0, bufnum= 0, offset= 0.0, length= 0.5, rate= 1.0| var e= EnvGen.kr(Env.linen(0.005, length, 0.01), doneAction: 2); var z= PlayBuf.ar(1, bufnum, BufRateScale.ir(bufnum)*rate, 1, BufFrames.ir(bufnum)*offset); Out.ar(out, Pan2.ar(z*e)); }).send(s); s.sync(hang); buf= Buffer.readChannel(s, path, channels:[0]); //force mono clk= TempoClock(160/60); s.sync(hang); { win= GUI.window.new("scale->beat2", Rect(200, 500, 270, 200)); GUI.numberBox.new(win, Rect(30, 10, 40, 20)).value_(clk.tempo*60) .action_{|x| clk.tempo_(x.value/60)}; GUI.staticText.new(win, Rect(80, 10, 90, 20)).string_("bpm"); popVersion= GUI.popUpMenu.new(win, Rect(10, 50, 180, 20)) .items_(#["version1-glued", "version2-timed"]); popScale= GUI.popUpMenu.new(win, Rect(10, 90, 180, 20)) .items_(z.keys.asArray) .action_{|x| mark= false.dup(12); z[x.items[x.value]].do{|y| mark= mark.put(y, true)}; butSteps.do{|x, i| if(mark[i], { x.value= x.value%12+12; }, { x.value= x.value%12; }); }; } .valueAction_(1); butSteps= {|i| GUI.button.new(win, Rect(i*20+10, 140, 20, 20)) .states_( {|j| [order[j].asString, Color.black, Color.clear]}.dup(12)++ {|j| [order[j].asString, Color.black, Color.grey]}.dup(12)++ {|j| [order[j].asString, Color.white, Color.grey]}.dup(12) ) .value_(order[i]) .action_{|x, mod| if(mod&131072==131072, { if(x.value<=12, { x.value= x.value-1%12+12; }, { x.value= x.value-1%12; }); }, { if(x.value==12, {x.value= 0}); if(x.value==24, {x.value= 12}); }); mark= mark.put(i, x.value>=12); order= order.put(i, x.value%12); } }.dup(12); GUI.popUpMenu.new(win, Rect(130, 10, 110, 20)) .items_(#[ "-order-", "shuffle order", "randomize order", "default order", "set all to 0", "set all to 4", "set all to 8", "toggle 3 and 7", "shift left", "shift right", "invert", "transpose up", "transpose down" ]) .action_{|x| switch(x.value, 1, {order= order.scramble}, 2, {order= {12.rand}.dup(12)}, 3, {order= (0..11)}, 4, {order= 0.dup(12)}, 5, {order= 4.dup(12)}, 6, {order= 8.dup(12)}, 7, {order= {|i| #[3, 7][i%2]}.dup(12)}, 8, {order= order.rotate(1)}, 9, {order= order.rotate(-1)}, 10, {order= order.invert}, 11, {order= order+1%12}, 12, {order= order-1%12} ); butSteps.do{|x, i| if(mark[i], { x.value_(order[i]+12); }, { x.value_(order[i]); }); }; x.value= 0; }; GUI.staticText.new(win, Rect(20, 165, 250, 20)) .string_("click to increase index, shift-click to mark"); win.front; win.onClose_{ main.stop; buf.free; }; CmdPeriod.doOnce{ if(win.isClosed.not, {win.close}); buf.free; }; //--main loop main= Routine({ inf.do{|i| var delta, index, candidates; delta= clk.beatDur*beats/12; butSteps.do{|x| if(x.value>=24, {x.value= x.value-12})}; if(mark.any{|x| x}, { index= i%12; if(popVersion.value==0, { //version1 disregard pauses candidates= []; mark.do{|x, j| if(x, {candidates= candidates.add(j)})}; index= candidates.wrapAt(i); }); if(mark[index], { Synth.grain('playbuf-segment', [ \bufnum, buf.bufnum, \offset, order[index]/12, \length, delta, \rate, clk.tempo*60/tempo ]); butSteps[index].value= butSteps[index].value+12; win.refresh; }); }); delta.wait; }; }).play(AppClock); }.defer; }; )
/redFrik