************* Not updated for new JITGuis yet! ****************
PDKtl a MIDIKtl class for the Doepfer PocketDial
The Doepfer PocketDial has 16 rotating knobs that can be switched between two modes.
a regular mode - values from 0 to 127 - and
an endless mode - in/decrementing values of 64 + 1, + 2, + 3 etc, -1, -2, etc,
depending on rotation speed.
The PocketDial has 4 preset scenes, so its ccDict is structured by scenes,
and one uses the mapCCS(scene, name, action) method for mapping.
The layout is:
kn01 kn02 kn03 kn04 kn05 kn06 kn07 kn08
kn09 kn10 kn11 kn12 kn13 kn14 kn15 kn16
see also PFKtl, MIDIKtl, NanoKtl
first example
// make a new PDKtl
f = PDKtl.new;
f.endless
( // in scene 1, map a single knob's action in normal mode
f.mapCCS(1, \kn08, { |chan, ccnum, val|
"PDKtl test: ch % cc % val % \n".postf(chan, ccnum, val);
"map val here with a spec..."
});
)
( // in scene one, map a single knob's action in endless mode
f.endless = true;
f.mapCCS(1, \kn08, { |chan, ccnum, val|
var midiNudge = 64 - val;
var normedNudge = midiNudge * f.step;
"PDKtl test: ch % cc % val % - midinudge: % normedNudge: % \n"
.postf(chan, ccnum, val, midiNudge, normedNudge);
"map here with a spec..."
});
)
// fails if no midi info for that key
f.mapCCS(1, \wrongKey, { |chan, ccnum, val| "PDKtl test: ch % cc % val %\n".postf(chan, ccnum, val) });
Class Variables
*verbose // a flag whether the class posts extended info
PDKtl.verbose = true;
PDKtl.verbose = false;
Instance Variables
softWithin sets how close the controller must be to the proxy's param value for soft takeover.
in normalised range, 0.02 is within 2 percent of current value. see also softSet.
lastVals keep last values sent from controller, so one can keep control when doing fast changes.
endless a flag whether PocketDial is expected to be in endless mode
step a step size for a single increment in endless mode. 0.01 means steps of 1 percent.
Methods
*new(uid, ccDict, endless, step) make a new PDKtl. uid is an optional ID for the MIDI port to listen to.
f = PDKtl.new;
mapCCS(scene, ctl, action)
// map a single knob's action
f.mapCCS(1, \kn08, { |chan, ccnum, val| "PDKtl test: ch % cc % val %\n".postf(chan, ccnum, val) });
// the valid names are:
f.ctlNames[1].keys.asArray.sort;
f.endless
mapToPxEdit(editor, indices, lastIsVol) - map to a NodeProxyEditor.
editor the editor
indices which knobs to map; default is [1, 2 .. 8].
lastIsVol flag whether the last slider becomes a volume control for that editor.
So by default, the first e.g. 7 knobs map to the proxy editor's param controls,
and the last knob (kn08) goes to the proxy's volume.
( // adapt from PFKtl for testing
f.ctlNames.put(1, (
'kn01': '0_7', 'kn02': '1_7', 'kn03': '2_7', 'kn04': '3_7',
'kn05': '4_7', 'kn06': '5_7', 'kn07': '6_7', 'kn08': '7_7',
'kn09': '8_7', 'kn10': '9_7', 'kn11': '10_7', 'kn12': '11_7',
'kn13': '12_7', 'kn14': '13_7', 'kn15': '14_7', 'kn16': '15_7' ));
)
( // make an Ndef and its editor first
Spec.add(\harm, [2, 200, \exp]);
Ndef(\a, { |freq = 20, harm = 20, pan, amp, rate, rq, detune| Blip.ar(freq, harm) });
o = NodeProxyEditor(Ndef(\a));
// them map the PFKtl to it
f.mapToPxEdit(o, 1);
)
// switch PocketDial to endless mode, then try this:
(
f.endless = true;
f.mapToPxEdit(o, 1);
)
mapToPxMix(mixer, splitIndex, lastEdIsVol, lastIsMaster) map to a proxymixer.
mixer is the mixer to map to.
the left hand sliders (sliders 1 to splitIndex) are mapped to volumes;
the right hand sliders map to the mixer.editor parameters.
lastIsMaster: if true, the rightmost control maps to server volume.
lastEdIsVol: if true, the last free slider on the right side is used for
the edited proxy's volume.
( // make an NdefMixer and some more Ndefs
m = NdefMixer();
m.openEditZone;
m.editor.proxy_(Ndef(\a));
// test many proxies
Spec.add(\freqScale, [0.1, 10, \exp]);
Spec.add(\rateScale, [0.1, 10, \exp]);
7.do { |i|
Ndef(("test" ++ i).asSymbol, { |rateScale = 1, freqScale = 1|
Pan2.ar(Ringz.ar(Impulse.ar(exprand(0.5, 4) * rateScale), exprand(300, 3000) * freqScale, 0.02), 1.0.rand2, 0.2)
}).play(vol: 0.2)
;
};
)
// non-endless
(
f.endless = false;
f.mapToPxMix(m, 1);
)
// endless
(
f.endless = true;
f.mapToPxMix(m, 1);
)