«MIDI arpeggiator demo» by wondersluyter
on 06 Mar'21 05:31 inRoughly based on the stock ableton arpeggiator behavior. A lot of variation is possible combining custom ~chordSort and ~notePat functions.
1 2 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
( /////////////////////// // input parameters // ///////////////////////////////////////////////////////// ~hold = false; ~clock = TempoClock(120/60); ~rate = 1/24; ~swing = 0.1; ~jitter = 0.1; ~legato = 2; //~chordSort = { |a, b| a.time < b.time }; // in order played ~chordSort = { |a, b| a.num < b.num }; // lowest to highest //~chordSort = { |a, b| a.num > b.num }; // highest to lowest ~notePat = { |chord| // play chord forwards and backwards if (chord.size > 1) { chord[0..chord.size-2] ++ chord.reverse[0..chord.size-2] } { chord } }; // ~notePat = { |chord| // interlace first note // var temp; // if (chord.size == 0) { // chord // } { // temp = chord.removeAt(0); // if (chord.size == 0) { // chord // } { // [temp.dup(chord.size), chord].lace // }; // } // }; //~notePat = { |chord| chord }; // play chord forwards //~notePat = { |chord| chord.reverse }; // play chord backwards ~transpose = 9.1; ~steps = 1; // # of transpositions applied -- negative goes up and down ~offset = 3; // offset into note pattern ~repeats = inf; //~velocityFunc = { |vel| vel }; // velocity as played //~velocityFunc = { 64 }; // constant velocity ~velocityFunc = { |vel, timeSincePlayed, beats| // something weirder var ret = vel; if (beats % 1 < 0.1) { ret = (ret * 2) } { if (beats % 0.5 < 0.2) { ret = (ret * 0.5) } { if (beats % 0.33333 < 0.1) { ret = (ret * 1.7) }; }; }; ret = ret * (1 / (1 + (timeSincePlayed * 0.1))); ret; }; ///////////////////////////////////////////////////////// // MIDI MIDIClient.init; MIDIIn.connectAll; ~notes = nil ! 127; MIDIdef.noteOn(\keyOn, { |vel, num| ~notes.do { |note, i| if (note.notNil) { if (note.pressed.not) { ~notes[i] = nil; }; }; }; if (~notes.select(_.notNil).select(_.pressed) == []) { ~repeat_i = 0; }; ~notes[num] = (num: num, vel: vel, time: thisThread.seconds, pressed: true); }); MIDIdef.noteOff(\keyOff, { |vel, num| if (~hold) { if (~notes[num].notNil) { ~notes[num].pressed = false; }; } { ~notes[num] = nil; }; }); // Pattern ~repeat_i = 0; ~ptr = 0; ~i = 0; Pdef(\arp).stop; Pdef(\arp, Pbind( \instrument, \default, \note_obj, Pfunc { // construct chord with chordSort and notePat var chord = ~notePat.(~notes.select(_.notNil).sort(~chordSort)); var ret; var newChord; // apply offset if (~offset > 0) { chord = chord.reverse; }; ~offset.abs.do { var temp = chord.pop; chord = ([temp] ++ chord); }; if (chord == [nil]) { chord = [] }; if (~offset > 0) { chord = chord.reverse; }; // apply transposition steps newChord = chord; ~steps.abs.do { |i| newChord = newChord ++ chord.collect({ |note| note = note.copy; note.num = note.num + (~transpose * (i + 1)) }); }; if (~steps.sign.isNegative) { (~steps.abs - 1).do { |i| i = ~steps.abs - 2 - i; newChord = newChord ++ chord.collect({ |note| note = note.copy; note.num = note.num + (~transpose * (i + 1)) }); } }; chord = newChord; // fetch appropriate note object from chord if (chord.size > 0) { if (~ptr >= chord.size) { ~ptr = ~ptr % chord.size; ~repeat_i = ~repeat_i + 1; }; if (~repeat_i >= ~repeats) { ret = (num: Rest(), vel: 0, time: 0); ~ptr = 0; } { ret = chord[~ptr]; ~ptr = ~ptr + 1; } } { ret = (num: Rest(), vel: 0, time: 0); ~ptr = 0; }; ret; }, \midinote, Pfunc { |event| event[\note_obj].num }, \db, Pfunc { |event| var note = event[\note_obj]; ~velocityFunc.(note.vel, thisThread.seconds - note.time, ~clock.beats).linlin(0, 127, -24, 0); }, \dur, Pfunc { var base = ~rate * 4 * (1 + ~jitter.rand2); var ret = if (~i == 0) { base * (1 + ~swing) } { base * (1 - ~swing) }; ~i = (~i + 1) % 2; ret; }, \legato, Pfunc { ~legato } )).play(~clock); ) Pdef(\arp).stop
reception
awesome, thanks for sharing!