Skip to content

Commit

Permalink
add CVCenterKeyboard
Browse files Browse the repository at this point in the history
(semi)automatically create a polyphonic keyboard playable setup from any
SynthDef that has an envelope with a \gate argument

Signed-off-by: Stefan Nussbaumer <st9fan@gmail.com>
  • Loading branch information
nuss committed Aug 2, 2018
1 parent 4ac351a commit 868d757
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 44 deletions.
126 changes: 126 additions & 0 deletions CVCenter/CVCenterKeyboard.sc
@@ -0,0 +1,126 @@
CVCenterKeyboard {
classvar <all;
var <synthDefName, <keyboardArg = \freq, <ampArg = \amp, <bendArg;
var on, off, bend;

*new { |synthDefName, keyboardArg, ampArg, bendArg|
^super.newCopyArgs(synthDefName, keyboardArg, ampArg, bendArg).init;
}

init {
synthDefName = synthDefName.asSymbol;

all ?? {
all = ();
};

all.put(synthDefName, this);

if (CVCenter.scv[synthDefName].isNil) {
CVCenter.scv.put(synthDefName, Array.newClear(128));
} {
Error("Sorry, the given SynthDef name cannot be used.").throw;
};

MIDIClient.init;
// doesn't seem to work properly on Ubuntustudio 16
// rather do it manually in QJackQtl...
// MIDIClient.connectAll;
}

// keyboardArg is the arg that will be set through playing the keyboard
// bendArg will be the arg that's set through the pitch bend wheel
setUpControls { |widgetsPrefix, tab, server|
var testSynth, notesEnv;
var args = [];

server ?? { server = Server.default };

/*if (server.serverRunning.not) {
Error("The server '%' must be running before calling CVCenter:*midiKeyboardGated").throw;
};*/

tab ?? { tab = synthDefName };

server ?? { server = Server.default };
SynthDescLib.at(synthDefName) ?? {
Error(
"The synthDefName '%' does not exist".format(synthDefName)
).throw;
};

if (SynthDescLib.at(synthDefName).hasGate.not) {
Error(
"The given SynthDef does not provide a 'gate' argument and can not be used."
).throw;
};

args = SynthDescLib.at(synthDefName).controlDict.keys.asArray.takeThese({ |it|
it === keyboardArg or: {it === ampArg or: { it === bendArg or: { it === \gate }}}
});

server.waitForBoot {
// SynthDef *should* have an \amp arg, otherwise it will sound for moment
testSynth = Synth(synthDefName);
// \gate will be set internally
testSynth.cvcGui(prefix: widgetsPrefix, excemptArgs: [keyboardArg, \gate], tab: tab);
testSynth.release;
}
}

addWidgetActionsForKeyboard { |notesEnvironment, widgetsPrefix, deactivateDefaultActions = true|
var args = SynthDescLib.at(synthDefName).controlDict.keys.asArray;
var wdgtName, nameString, namesCVs = [];

args.do { |name|
nameString = name.asString;
widgetsPrefix.notNil !? {
nameString = nameString[0].toUpper ++ nameString[1..nameString.size-1];
};
wdgtName = (widgetsPrefix ++ nameString).asSymbol;
CVCenter.cvWidgets[wdgtName] !? {
if (CVCenter.cvWidgets[wdgtName].class == CVWidget2D) {
if (namesCVs.includes(name).not) {
namesCVs = namesCVs.add(name).add(CVCenter.at(wdgtName).asArray);
};
#[lo, hi].do { |slot|
CVCenter.addActionAt(wdgtName, 'keyboard set arg', "{ |cv|
CVCenter.scv['%'].do { |synth| synth !? { synth.set('%', cv.value) }};
}".format(synthDefName, name), slot);
CVCenter.activateActionAt(wdgtName, \default, deactivateDefaultActions.not, slot);
}
} {
if (namesCVs.includes(name).not) {
namesCVs = namesCVs.add(name).add(CVCenter.at(wdgtName));
};
CVCenter.addActionAt(wdgtName, 'keyboard set arg', "{ |cv|
CVCenter.scv['%'].do { |synth| synth !? { synth.set('%', cv.value) }};
}".format(synthDefName, name));
CVCenter.activateActionAt(wdgtName, \default, deactivateDefaultActions.not);
};
}
};

on = MIDIFunc.noteOn({ |veloc, num, chan, src|
var argsValues = [keyboardArg, num.midicps, ampArg, veloc * 0.005] ++ namesCVs.deepCollect(2, _.value);
CVCenter.scv[synthDefName][num] = Synth(synthDefName, argsValues);
});

off = MIDIFunc.noteOff({ |veloc, num, chan, src|
CVCenter.scv[synthDefName][num].release;
});

bend = MIDIFunc.bend({ |bendVal, chan, src|
"bend: %\n".postf(bendVal);
});

}

free {
on !? { on.free };
off !? { off.free };
bend !? { bend.free };
CVCenter.scv[synthDefName].do(_.release);
CVCenter.scv.removeAt(synthDefName);
}
}
16 changes: 8 additions & 8 deletions CVCenter/CVWidgetSpecsEditor.sc
Expand Up @@ -18,11 +18,11 @@
CVWidgetSpecsEditor {
var <window;

*new { |displayDialog, object, wdgtName, controlsDict, prefix, pairs2D, metadata, environment|
^super.new.init(displayDialog, object, wdgtName, controlsDict, prefix, pairs2D, metadata, environment)
*new { |displayDialog, object, wdgtName, controlsDict, prefix, pairs2D, metadata, environment, tab|
^super.new.init(displayDialog, object, wdgtName, controlsDict, prefix, pairs2D, metadata, environment, tab)
}

init { |displayDialog, obj, name, controls, prefix, pairs2D, metadata, environment|
init { |displayDialog, obj, name, controls, prefix, pairs2D, metadata, environment, tab|
var object;
var wdgtName, windowTitle;
var specsList, specsListSpecs, selectMatch, thisSpec;
Expand Down Expand Up @@ -281,14 +281,14 @@ CVWidgetSpecsEditor {

if(object.class == NodeProxy, {
if(object.isPlaying, {
elem.enterTab.string_("NodeProxy ("++object.asNodeID++")");
tab ?? { tab = "NodeProxy ("++object.asNodeID++")" }
}, {
elem.enterTab.string_("NodeProxy");
})
tab ?? { tab = "NodeProxy" }
});
}, {
elem.enterTab.string_(name);
tab ?? { tab = name };
});

elem.enterTab.string_(tab.asString);
};

made = [];
Expand Down
28 changes: 0 additions & 28 deletions CVCenter/extCVCenterMIDI.sc

This file was deleted.

32 changes: 24 additions & 8 deletions CVCenter/extObject.sc
Expand Up @@ -98,14 +98,22 @@

+Synth {

cvcGui { |displayDialog=true, prefix, pairs2D, environment|
cvcGui { |displayDialog=true, prefix, pairs2D, environment, excemptArgs, tab|
var sDef, def, cDict = (), metadata;
var thisType, thisControls, thisSpec, thisSlots, thisName, done=[];
sDef = SynthDescLib.global[this.defName.asSymbol];
sDef.metadata !? { sDef.metadata.specs !? { metadata = sDef.metadata.specs }};
sDef.controlDict.pairsDo({ |n, c| cDict.put(n, c.defaultValue) });
sDef.controlDict.pairsDo({ |n, c|
if (excemptArgs.isNil) {
cDict.put(n, c.defaultValue)
} {
if (excemptArgs.indexOf(n).isNil) {
cDict.put(n, c.defaultValue)
}
}
});
if(displayDialog, {
CVWidgetSpecsEditor(displayDialog, this, this.defName.asSymbol, cDict, prefix, pairs2D, metadata, environment);
CVWidgetSpecsEditor(displayDialog, this, this.defName.asSymbol, cDict, prefix, pairs2D, metadata, environment, tab: tab);
}, {
cDict.pairsDo({ |cName, vals|
block { |break|
Expand Down Expand Up @@ -164,7 +172,7 @@
CVCenter.finishGui(this, cName, nil, (
cName: thisName,
type: thisType,
enterTab: this.defName.asSymbol,
enterTab: if (tab.notNil) { tab.asSymbol } { this.defName.asSymbol },
controls: thisControls,
slots: thisSlots,
specSelect: thisSpec
Expand All @@ -177,17 +185,25 @@

+NodeProxy {

cvcGui { |displayDialog=true, prefix, pairs2D|
cvcGui { |displayDialog=true, prefix, pairs2D, excemptArgs, tab|
var cDict = (), name;
var thisType, thisControls, thisSpec, thisSlots, thisName, done=[];
this.getKeysValues.do({ |pair| cDict.put(pair[0], pair[1]) });
this.getKeysValues.do({ |pair|
if (excemptArgs.isNil) {
cDict.put(pair[0], pair[1])
} {
if (excemptArgs.indexOf(pair[0].isNil)) {
cDict.put(pair[0], pair[1])
}
}
});
if(this.class === Ndef, {
name = this.key;
}, {
name = nil;
});
if(displayDialog, {
CVWidgetSpecsEditor(displayDialog, this, name, cDict, prefix, pairs2D);
CVWidgetSpecsEditor(displayDialog, this, name, cDict, prefix, pairs2D, tab: tab);
}, {
cDict.pairsDo({ |cName, vals|
block { |break|
Expand Down Expand Up @@ -230,7 +246,7 @@
CVCenter.finishGui(this, cName, nil, (
cName: thisName,
type: thisType,
enterTab: name,
enterTab: if (tab.notNil) { tab.asSymbol } { name },
controls: thisControls,
slots: thisSlots,
specSelect: thisSpec
Expand Down

0 comments on commit 868d757

Please sign in to comment.