-
-
Save swannodette/0b5dc24ac43be48e91d1611836364d72 to your computer and use it in GitHub Desktop.
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
// 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