-
-
Save thresholdpeople/bb584c7bb386babb342b2fe8e8c07813 to your computer and use it in GitHub Desktop.
MIDI Touch Automation
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
// Sending & Receiving (MIDI Feedback) | |
// ============ | |
// Write data to the fader until a touch is sensed. Use new position to overwrite relevent portions of data. | |
// Upon release, playback new location. | |
// Problem::: If Pseg is an array of pre-recorded automation data, how can I overwrite the value in the postion | |
// in the array that it's currently at? | |
// Playback needs to be abstracted further. | |
// The array needs an index. | |
// The Pbind \val output does not read directly form that array, it uses a Pkey to reference it. | |
// Pdefn writes into that array, at the appropriate index location. | |
// What I came to: | |
// Pdefn, Pkey, etc were not necessary. I created a key - \playhead - to act as the index. | |
// \val, Pn(Pseq(...) are what provides the output the data. | |
// Pseq is reading from the ~fader1Playback area, at the position of ~playhead. It has 1 repetion then exits. | |
// Since it's nested in Pn, with an infinite repeat, the next go around, ~playhead has been incremented, and | |
// Pseq presents the next value. | |
// Meanwhile a MIDIFunc has been made, that updates ~fader1Playback at the ~playhead position, if the fader has | |
// been touched. | |
// The only quirk is that for some reason, Pseq rejects ~fader1Playback unless the actual array of data is nested | |
// in another array. | |
// Perhaps I don't even need Pn? and can use Pseq with an infinite repeat??? | |
// Yes, that's correct! | |
( | |
// house keeping: | |
( | |
MIDIIn.connectAll | |
// reference a MIDI output device by name, and set latency to match the server's: | |
~mOut = MIDIOut.newByName("D 400", "Port 1").latency_(Server.default.latency); | |
) | |
// record: | |
// original automation: | |
// ~fader1Playback = [(0..127).select(_.even).mirror.linlin(0, 127, 0, 16383).asInteger]; | |
~fader1Playback = (0..127).select(_.even).mirror.linlin(0, 127, 0, 16383).asInteger; | |
~fader1Playback.size; | |
( | |
// listen for overdub: | |
~mIn = MIDIFunc.bend({ |val, chan, src| | |
// ~fader1Playback[0][~playhead] = val; | |
~fader1Playback[~playhead] = val; | |
}, 0); // chan 1 (fader 1) | |
) | |
// playback: | |
( | |
// playhead | |
~playhead = 0; | |
p = Pbind( | |
\dur, 0.125, | |
\type, \midi, | |
\midicmd, \bend, | |
\midiout, ~mOut, | |
\chan, 0, | |
// \val, Pn(Pseq(~fader1Playback[~playhead], 1), inf).trace(prefix: "fader "), | |
\val, Pseq(~fader1Playback, inf).trace(prefix: "fader "), | |
\playhead, Pfunc({ ~playhead = (~playhead + 1) % ~fader1Playback.size }).trace(prefix: "position "), | |
).play | |
) | |
p.stop | |
~mIn.free | |
) | |
// Seems to be working! | |
// Using noteOn touch sensing to continue to write values of the fader's current position to the array. | |
// This is done via a Task which is triggered upon noteOn, and stopped on noteOff. | |
// house keeping and initialization: | |
( | |
MIDIIn.connectAll; | |
// reference a MIDI output device by name, and set latency to match the server's: | |
~mOut = MIDIOut.newByName("D 400", "Port 1").latency_(Server.default.latency); | |
// record: | |
// original automation: | |
~fader1Playback = 0 ! 2; // blank array, whatever size | |
Pdefn(\fader1, Pseq(~fader1Playback, inf)); | |
// ~fader1Playback.size; | |
) | |
( | |
// or populated array & Pdefn update | |
~fader1Playback = (0..127).select(_.even).mirror.linlin(0, 127, 0, 16383).asInteger; // or populated array | |
Pdefn(\fader1, Pseq(~fader1Playback, inf)); | |
) | |
// playback: | |
( | |
~playhead = 0; | |
p = Pbind( | |
\dur, 0.125, | |
\type, \midi, | |
\midicmd, \bend, | |
\midiout, ~mOut, | |
\chan, 0, | |
\val, Pdefn(\fader1), | |
\playhead, Pfunc({ ~playhead = (~playhead + 1) % ~fader1Playback.size }), | |
).play | |
); | |
// TempoClock.default.tempo = 3 | |
p.stop | |
( | |
var oldVal = 0; | |
var t = Task({ | |
inf.do({ | |
~fader1Playback[~playhead] = oldVal; | |
// "writing!!!".postln; | |
(TempoClock.default.tempo / 16).wait; // needs a wait time, but can likely be shorter | |
}); | |
}); | |
MIDIdef.noteOn(\touch1, { |vel, num, chan, src| | |
"Touched!".postln; | |
t.start; | |
}, 104); | |
MIDIdef.noteOff(\rel1, { |vel, num, chan, src| | |
t.stop; | |
"Released!!".postln; | |
Pdefn(\fader1, Pseq(~fader1Playback, inf)); | |
}, 104); | |
MIDIdef.bend(\fader1, { |val, chan, src| | |
~fader1Playback[~playhead] = val; | |
oldVal = val; | |
~oldValz = val; | |
}, 0); | |
) | |
// feedback loop (for testing) | |
( | |
~debug = { | |
inf.do({ | |
// ["old val:", ~oldValz].postln; | |
// ["playhead pos", ~playhead].postln; | |
0.25.wait; | |
["fader1 val", ~fader1Playback[~playhead]].postln; | |
0.25.wait; | |
}); | |
}.fork | |
) | |
~debug.stop; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment