************* 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); 

)