//////////////////////////////////////////////////////
//-- 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