--- /dev/null
+KeySynth {
+ var <midihandler, <>synthName, <>bendRadius, <>panAcross, <>params, <>amp, <>group;
+ var <bend, <notes, madeNewGroup;
+
+ *new {|midihandler, synthName=\default, bendRadius=1, panAcross=false, params=nil, amp=1.0, group=nil|
+ ^super.newCopyArgs(midihandler, synthName, bendRadius, panAcross, params, amp, group).allInit;
+ }
+
+ allInit {
+ bend = 0;
+ notes = Array.newClear(128);
+ group = group ?? {madeNewGroup = true; Group.new()};
+ params = nil ? ();
+
+ midihandler.key_{|d, v, n|
+ var panParam=#[];
+ if (d) {
+ if (panAcross) {
+ panParam = [\pan, n.bilin(63, 0, 127, 0, -0.7, 0.7)];
+ };
+ notes[n] = Synth(synthName, params.asPairs++[
+ \gate, 1,
+ \freq, n.midicps,
+ \amp, amp * v.dbamp,
+ ]++panParam, group);
+ } {
+ notes[n].set(\gate, 0);
+ notes[n] = nil;
+ };
+ };
+
+ midihandler.bend_{|v|
+ bend = v * bendRadius;
+ notes.do{|item, i|
+ item.set(\freq, (i+bend).midicps);
+ };
+ };
+ }
+
+ free {
+ notes.do{|item|
+ item.free;
+ };
+ if (madeNewGroup) {
+ group.free;
+ };
+ }
+}
+
+// example
+/*
+
+~kedi = MidiRemote25SL();
+~m = KeySynth(~kedi, \dyti, amp: 0.2, panAcross: true);
+(
+~m.params[\modAmp] = 0.0;
+~kedi.touch_{|v|
+ ~m.group.set(\modAmp, v);
+ ~m.params[\modAmp] = v;
+};
+)
+
+~m.free
+
+*/
\ No newline at end of file