Skip to content

Instantly share code, notes, and snippets.

@scztt
Last active November 4, 2019 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save scztt/713892be1ba4fed95ba0872cd7fa6f23 to your computer and use it in GitHub Desktop.
Save scztt/713892be1ba4fed95ba0872cd7fa6f23 to your computer and use it in GitHub Desktop.
// Twister devices are expected to be named in this form:
// classvar <endpointDevice="Midi Fighter Twister %", <endpointName="Midi Fighter Twister";
// Where "Midi Fighter Twister 1" is TwisterDevice(\default) and "Midi Fighter Twister 2" is TwisterDevice(\secondary)
// A twister device. These are singletons - there is only ever one registered per device. It works ala Ndef, Pdef, etc, see Singleton help file.
~device = TwisterDevice(\default);
// If your MIDI Fighter is named something other than the above, you can register it via:
this.registerDevice(\myDevice, "endpoint device", "endpoint name");
// And then access it via TwisterDevice(\myDevice)
// Set state directly on device
~device.knobs[0].ledHue = 0.25;
~device.knobs[0].ledBrightness = 0.75;
~device.knobs[0].ringBrightness = 0.8;
~device.knobs[0].value = 0.5;
// Twister is a front-end connection to a particular device. You can have multiple Twister objects for a given device, but only one
// connected at a time. This allows for multiple performance setups / "pages" that can be swapped on a single device. Twister objects
// are still functional when they are not connected to a device, and will keep their state. Specifying a device or device name
//
~t1 = Twister(); // to connect automatically, you could have used Twister(\default)
~t1.connect(\default); // connect
// Accessing knobs
~t1.knobs[7]; // 8th knob
~t1.rows[0]; // top row of knobs
~t1.rows(2, 2); // knob at row 2, column 2 (zero indexed, so nominally the third row/col)
~t1.cols(1); // knobs in column 1
~t1.rows(0, 0).enable;
~t1.rows(0, 0).disable;
// Knobs are normally enabled / disabled if they have a value attached to them.
// These are set via knobCV and buttonCV setters. NumericControlValue or BusControlValue
// are generally used here, but these should be backwards compatible with the CV
// class from the Conductor quark as well.
// Example: Connect to a Synth and some UI
(
~c1 = NumericControlValue(spec:ControlSpec(20, 1000, \exp, 10));
~t2 = Twister(\default);
~t2.rows(0, 0).knobCV = ~c1;
Server.default.waitForBoot {
// a sound
~synth = {
|lpFreq=100|
LPF.ar(LFSaw.ar(200), lpFreq);
}.play;
// a number box
~view = View(bounds:Rect(200, 200, 100, 40)).layout_(HLayout(
~num = NumberBox().scroll_step_(10);
)).front;
// connect them up to ~c1
~c1.signal(\value).connectTo(~synth.argSlot(\lpFreq)).freeAfter(~synth).trace;
~c1.signal(\value).connectTo(~num.valueSlot).freeAfter(~view).trace;
~num.signal(\value).connectTo(~c1.valueSlot).freeAfter(~view).trace;
~synth.freeAfter(~view);
}
)
// Similar example, but use buttonCV to trigger also
(
Server.default.waitForBoot {
~t3 = Twister(\default);
~synths = ();
~t3.rows.reverse.flatten.do {
|knob, i|
knob.knobCV = BusControlValue(0.2, spec:ControlSpec(100, 1000, \exp, 10));
knob.buttonCV = OnOffControlValue();
knob.ledColor = Color.hsv(1.0.rand, 1, 1);
knob.toggle = true; // This means knob state is toggled between on/off once per button push. toggle==false means down is on, up is off.
knob.buttonCV.signal(\on).connectTo({
"Playing note %".format(i).postln;
~synths[i] = {
|gate=1|
LPF.ar(
in: LFSaw.ar(\freq.kr),
freq: \lpFreq.kr(lag:3)
) * Env.adsr().kr(gate:gate, doneAction:2);
}.play(args:[
\freq, (50 + i).midicps,
\lpFreq, knob.knobCV.asMap
]);
});
knob.buttonCV.signal(\off).connectTo({
"Stopping note %".format(i).postln;
~synths[i] !? { |n| n.set(\gate, 0) };
})
};
}
)
// If you still have the window from the earlier example open, we can swap between each twister configuration by connecting them:
~t2.connect(\default);
~t3.connect(\default);
// Random sequencer example
(
~t4 = Twister(\default);
~t4.knobs.do({
|k|
k.knobCV = NumericControlValue(spec:[0, 1]);
k.toggle = true;
});
SynthDef(\wn, {
|vel=0|
var sig;
sig = WhiteNoise.ar(vel.linexp(0.01, 1, 0.3, 1));
sig = sig * Env.perc(0.01, vel.linlin(0, 1, 0.05, 1)).kr(doneAction:2);
Out.ar(0, sig);
}).add;
Pdef(\wn, Pbind(
\instrument, \wn,
\index, Pseries(),
\dur, 0.125,
\vel, Pfunc({
|e|
var knob = ~t4.knobs.wrapAt(e.index);
{ knob.ledColor = Color.green }.defer(s.latency);
{ knob.ledColor = Color.blue }.defer(s.latency + 0.2);
if (knob.buttonCV.value == \on) {
knob.knobCV.value
} {
Rest(0)
}
})
)).play;
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment