Skip to content

Instantly share code, notes, and snippets.

@thresholdpeople
Last active July 21, 2021 02:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thresholdpeople/bb584c7bb386babb342b2fe8e8c07813 to your computer and use it in GitHub Desktop.
Save thresholdpeople/bb584c7bb386babb342b2fe8e8c07813 to your computer and use it in GitHub Desktop.
MIDI Touch Automation
// 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