To answer your general questions first…
Is there a better way to alternate between 0 and 1, which I use as an index for an array with two values, holding the current value and the previous value, so that I can compare both values in order to decide whether a value change has happened (which would require send a MIDI value to the encoder’s LED) or not.
I think the way you are checking historical values is fine, if you find the code clear for yourself (I’ll usually implement this as a kind of if (newValue != value) { value = newValue; sendUpdate() }
thing, but it’s functionally pretty identical to what you’re doing).
I would question whether it’s worth worrying about not sending an update in case the value does not change - I seem to recall that on every MIDI encoder device I’ve used, sending an identical value BACK to the device when a MIDI cc is received works without any problems. Without this, your code gets much simpler. It’s not likely to be worth it to optimize out one channel of MIDI sends - the most computationally expensive part of what you’re doing is almost surely the checking code and not sending a MIDI message.
- As I need an index variable i for every MIDIdef, how can I make sure that this i is only valid for this specific MIDIdef? While just putting {} around code below did not do the trick.
I would suggest storing values in an IdentityDictionary - it’s easy to use either the CC number or the MIDIdef name as a key, e.g.
~values = ();
// in MIDIdef...
if (value != ~values[\cc0_cutoff_dec_inc]) {
~values[\cc0_cutoff_dec_inc] = value;
doUpdateStuff();
}
If you don’t want to roll your own MIDI interface, you might try this quark: GitHub - scztt/Twister.quark: MIDIFighter Twister control class (Quarks.install("https://github.com/scztt/Twister.quark")
).
An example linking some Twister knobs to buses, and then using the buses in a pattern:
(
////////////////////////////////////////////////////////////
// These will be my control values
~c = ~c ?? { ControlValueEnvir() };
// Set up my controls
~c.use {
~detune.spec = ControlSpec(-4, 4);
~amp.spec = ControlSpec(0, 1);
~dur.spec = ControlSpec(1/8, 4, \exp);
};
////////////////////////////////////////////////////////////
// Create a Twister
// Device is expected to have this naming:
// <endpointDevice="Midi Fighter Twister %", <endpointName="Midi Fighter Twister";
// ...where % is 1 or 2. This can be set in Audio MIDI Settings on mac.
~t = Twister(\primary);
// Connect knobs to controls
~t.knobs[0].knobCV = ~c[\detune];
~t.knobs[1].knobCV = ~c[\amp];
~t.knobs[2].knobCV = ~c[\dur];
~t.knobs[3].buttonCV.signal(\on).connectToUnique({
Pdef(\pat).set(\scale, Scale.lydian)
});
~t.knobs[3].buttonCV.signal(\off).connectToUnique({
Pdef(\pat).set(\scale, Scale.aeolian)
});
////////////////////////////////////////////////////////////
// Connect controls to a pattern - these can be used directly as synth args also
Pdef(\pat, Pbind(
\amp, ~c[\amp],
\dur, ~c[\dur],
\detune, ~c[\detune],
\octave, 4,
\strum, 1/8,
\degree, [0, 4, 2, 8, 7]
).trace).play;
)
Some caveats …
- I have used this class for years, but strictly speaking it’s beta and may have some issues.
- It’s also undocumented, but should support basically every feature of the device, including led colors, side buttons etc.
- iirc you need to configure your Twister to send relative messages, with cc numbers starting from 0.
- happy to answer questions