Created
March 27, 2020 17:14
-
-
Save shimpe/6bc0bfb297be6f38bfe8a87c33be5050 to your computer and use it in GitHub Desktop.
code for piday project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
( | |
s.waitForBoot({ | |
var deg_to_bass = ( | |
1: "c3", | |
2: "d3", | |
3: "e3", | |
4: "f3", | |
5: "g3", | |
6: "a3", | |
7: "b3", | |
8: "c3", | |
9: "d3", | |
0: "e3" | |
); | |
var w = Window("MeloPi", Rect(0,0,1000,200)); | |
var cstCHORDMODE = 0; | |
var cstSEQMODE = 1; | |
var cstSTRUM = 0.0; | |
var notes = StaticText(); | |
var screenlayout = VLayout(); | |
var tempo_lbl = StaticText().string_("Tempo"); | |
var tempo_edit = TextField().action_({|field|TempoClock.default.tempo_(field.value.asString.asFloat/60.0)}); | |
var basedur_lbl = StaticText().string_("Base duration (beats)"); | |
var basedur_edit = TextField().string_("1").action_{|field| | |
~base_dur = field.value.asString.asFloat; | |
if (~base_dur == 0) { | |
~base_dur = 1; | |
}; | |
}; | |
var gen_amp_lbl = StaticText().string_("Generated amplitude (0.0-1.0)"); | |
var gen_amp_edit = TextField().action_({|field| ~gen_amp = field.value.asString.asFloat.debug; }); | |
var autoadvance_cbx = CheckBox().string_("Auto Advance Interval (seconds)").value_(false).action_({ | |
| checked | | |
if (checked.value == false) { | |
~autoadvance_active = 0; | |
} { | |
~autoadvance_active = 1; | |
~autoadvance_interval = 4*60.0/tempo_edit.value.asString.asFloat; | |
}; | |
}); | |
var temporow = HLayout(tempo_lbl, tempo_edit, basedur_lbl, basedur_edit, nil); | |
var advancerow = HLayout(autoadvance_cbx, /*autoadvance_edit,*/ gen_amp_lbl, gen_amp_edit, nil); | |
var first_pi_lbl = StaticText().string_("31415"); | |
var pi_digit = TextField(w, Rect(10, 10, 20, 20)).string_("9"); | |
var second_pi_lbl = StaticText().string_("265"); | |
var pirow = HLayout(nil, nil, nil, first_pi_lbl, pi_digit, second_pi_lbl, nil, nil, nil); | |
var mode_btn = Button().states_([ | |
["chord mode", Color.blue, Color.grey(0.9)], | |
["sequence mode", Color.blue, Color.grey(0.9)], | |
]).action_({ |button| | |
~music_mode = button.value; | |
on_new_digit.(pi_digit.value.asString.asInteger); | |
}); | |
var voicelead = { | |
|from_chord_midi, to_chord_midi | | |
var resulting_chord = []; | |
var new_second_chord = []; | |
to_chord_midi.do({ | |
|secondmidi | | |
var distances = (); | |
var extended_notes_second_chord = [secondmidi, secondmidi-12, secondmidi+12]; | |
var new_second_note = 0; | |
var candidate_new_second_notes = Dictionary.new(); | |
var best_new_second_note; | |
from_chord_midi.do({ | |
| firstmidi | | |
var d = (extended_notes_second_chord - firstmidi).abs; | |
var copyd = d.deepCopy(); | |
var min_dist = copyd.sort.first; | |
var idx_of_min = d.indexOf(min_dist); | |
candidate_new_second_notes[min_dist] = extended_notes_second_chord[idx_of_min]; | |
}); | |
best_new_second_note = candidate_new_second_notes.asSortedArray.first[1]; | |
new_second_chord = new_second_chord.add(best_new_second_note); | |
}); | |
new_second_chord | |
}; | |
var play = { | |
| newpattern | | |
if (~player.notNil) { | |
~player.stop; | |
}; | |
~player = newpattern.play; | |
}; | |
var lookup_bass = { | digit | | |
if (digit.isRest) { | |
Rest(); | |
} { | |
TheoryNote(deg_to_bass[digit]).asMidi; | |
}; | |
}; | |
var digit_to_dir = { | |
| digit | | |
if (digit == 0) { | |
~base_dur; | |
} { | |
~base_dur/digit; | |
}; | |
}; | |
var on_oneshot_digit = { | digit | | |
if (~music_mode == cstCHORDMODE) { | |
var notes = ~current_chord.deepCopy; | |
var durdigit = digit ?? 1; | |
var rhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pfin(digit, Pseq([notes], inf)), | |
\dur, ~base_dur, | |
\strum, cstSTRUM, | |
\legato, 0.99, | |
\amp, Pseq([~gen_amp],inf), | |
); | |
var lhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pseq([lookup_bass.(digit)], digit*digit), | |
\dur, digit_to_dir.(digit), | |
\legato, 1.0, | |
\amp, Pseq([~gen_amp],inf) | |
); | |
play.(Ppar([rhs, lhs])); | |
} /*else*/ { | |
var notes = ~current_chord.deepCopy; | |
var rhs; | |
var lhs; | |
if (seqrange.value == 1) { | |
notes = ~current_chord ++ (~current_chord + 12); | |
}; | |
if (seqrange.value == 2) { | |
notes = (~current_chord - 12) ++ ~current_chord ++ (~current_chord + 12); | |
}; | |
if (seqtype.value == 1) { | |
notes = notes.reverse; | |
}; | |
if (seqtype.value == 2) { | |
notes = notes ++ notes.reverse; | |
}; | |
if (seqtype.value == 3) { | |
notes = notes.scramble; | |
}; | |
rhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pfin(digit, Pseq(notes, inf)), | |
\dur, ~base_dur, | |
\legato, 0.99, | |
\mykey, Pseq(digits), | |
\amp, Pseq([~gen_amp],inf) | |
); | |
lhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pseq([lookup_bass.(digit)], digit*digit), | |
\dur, digit_to_dir.(digit), | |
\legato, 1.0, | |
\amp, Pseq([~gen_amp],inf) | |
); | |
play.(Ppar([rhs, lhs])); | |
}; | |
}; | |
var on_new_digit = { | digit | | |
var new_chord = deg_to_chord[digit].split($ ).collect({|el| TheoryNote(el).asMidi; }); | |
~current_chord = voicelead.(~current_chord, new_chord); | |
notes.string_(~current_chord.asString); | |
if (~music_mode == cstCHORDMODE) { | |
var notes = ~current_chord.deepCopy; | |
var rhs, lhs; | |
if (play_btn.value == 1) { notes = Rest(); digit = Rest(); }; | |
rhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pseq([notes], inf), | |
\dur, ~base_dur, | |
\legato, 0.99, | |
\amp, Pseq([~gen_amp],inf), | |
\strum, cstSTRUM, | |
); | |
lhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pseq([lookup_bass.(digit)], inf), | |
\dur, digit_to_dir.(digit), | |
\legato, 1.0, | |
\amp, Pseq([~gen_amp],inf) | |
); | |
play.(Ppar([rhs, lhs])); | |
} /*else*/ { | |
var notes = ~current_chord.deepCopy; | |
var lhs, rhs; | |
if (seqrange.value == 1) { | |
notes = ~current_chord ++ (~current_chord + 12); | |
}; | |
if (seqrange.value == 2) { | |
notes = (~current_chord - 12) ++ ~current_chord ++ (~current_chord + 12); | |
}; | |
if (seqtype.value == 1) { | |
notes = notes.reverse; | |
}; | |
if (seqtype.value == 2) { | |
notes = notes ++ notes.reverse; | |
}; | |
if (seqtype.value == 3) { | |
notes = notes.scramble; | |
}; | |
if (play_btn.value == 1) { | |
notes = [Rest()]; | |
digit = Rest(); | |
}; | |
rhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pseq(notes, inf), | |
\dur, ~base_dur/notes.size, | |
\legato, 0.99, | |
\mykey, Pseq(digits), | |
\amp, Pseq([~gen_amp],inf) | |
); | |
lhs = Pbind( | |
\type, \midi, | |
\midicmd, \noteOn, | |
\midiout, ~p.midi_out, | |
\chan, 0, | |
\midinote, Pseq([lookup_bass.(digit)], inf), | |
\dur, digit_to_dir.(digit), | |
\legato, 1.0, | |
\amp, Pseq([~gen_amp],inf) | |
); | |
play.(Ppar([rhs, lhs])); | |
}; | |
}; | |
var goto_index = { | idx | | |
var prefix, postfix, digit; | |
if (idx < 0) { idx = 0; }; | |
if (idx >= digits.size) { idx = digits.size - 1; }; | |
prefix = digits.copyRange(idx-50, idx-1); | |
digit = digits.copyRange(idx, idx); | |
postfix = digits.copyRange(idx+1, idx+50); | |
first_pi_lbl.string_(prefix); | |
pi_digit.string_(digit); | |
second_pi_lbl.string_(postfix); | |
~current_index = idx; | |
on_new_digit.(digit.asString.asInteger); | |
}; | |
var parser = TheoryNoteParser(); | |
var deg_to_chord = ( | |
1 : "c4 e4 g4 b4 d5", | |
2 : "d4 f4 a4 c5 e5", | |
3 : "e4 g4 b4 d5 f5", | |
4 : "f4 a4 c5 e5 g5", | |
5 : "g4 b4 d5 f4 a4", | |
6 : "a4 c5 e5 g5 b5", | |
7 : "b4 d5 f5 a5 c6", | |
8 : "c5 e5 g5 b5 d6", | |
9 : "d5 f5 a5 c5 e5", | |
0 : "e5 g5 b5 d5 f5" | |
); | |
var reset_btn = Button().string_("Reset").action_({goto_index.(0);}); | |
var left_btn = Button().string_("<=").action_({goto_index.(~current_index - 1);}); | |
var play_btn = Button().states_([["play", Color.red, Color.grey(0.9)], ["pause", Color.blue, Color.grey(0.9)]]).action_({ | |
on_new_digit.(pi_digit.value.asString.asInteger); | |
}); | |
var oneshot_btn = Button().string_("OneShot").action_({on_oneshot_digit.(pi_digit.value.asString.asInteger)}); | |
var right_btn = Button().string_("=>").action_({goto_index.(~current_index + 1);}); | |
var transport_row = HLayout(nil, mode_btn, reset_btn, left_btn, play_btn, oneshot_btn, right_btn, nil); | |
var seqtype = PopUpMenu().items_([ "Up", "Down", "Up+Down", "Random" ]).action_({ | |
on_new_digit.(pi_digit.value.asString.asInteger); | |
}); | |
var seqrange = PopUpMenu().items_([ "1 oct", "2 oct", "3 oct" ]).action_({ | |
on_new_digit.(pi_digit.value.asString.asInteger); | |
}); | |
var property_row = HLayout(seqtype, seqrange, nil); | |
var notes_row = HLayout(nil,notes,nil); | |
var digits = "314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198"; | |
screenlayout = screenlayout.add(temporow).add(advancerow).add(pirow).add(transport_row).add(property_row)./*add(amp_row).add(dur_row).*/add(notes_row).add(nil); | |
w.layout_(screenlayout); | |
w.front; | |
if (~p.isNil) { | |
~p = ScProphetRev2(); | |
~p.connect; | |
~p.midi_out.latency_(0); | |
CmdPeriod.add( | |
{ | |
16.do { | |
|i| | |
~p.midi_out.allNotesOff(i); | |
}; | |
}); | |
}; | |
~current_chord = deg_to_chord[0].split($ ).collect({|el| TheoryNote(el).asMidi; }); | |
~music_mode = cstCHORDMODE; | |
~player = nil; | |
tempo_edit.valueAction_(100); | |
basedur_edit.valueAction_(0.5); | |
play_btn.valueAction_(1); | |
seqtype.valueAction_(3); | |
autoadvance_cbx.valueAction_(0); | |
gen_amp_edit.valueAction_(0.33); | |
notes.string_(~current_chord.asString); | |
goto_index.(0); | |
fork { | |
while ({true}) { | |
if (~autoadvance_active == 1) { | |
~current_index = ~current_index + 1; | |
{ goto_index.(~current_index) }.defer; | |
}; | |
~autoadvance_interval.wait; | |
} | |
}; | |
}); | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment