aboutsummaryrefslogtreecommitdiffstats
path: root/BowelyzerConfig.sc
diff options
context:
space:
mode:
Diffstat (limited to 'BowelyzerConfig.sc')
-rw-r--r--BowelyzerConfig.sc402
1 files changed, 226 insertions, 176 deletions
diff --git a/BowelyzerConfig.sc b/BowelyzerConfig.sc
index 4079119..e092b25 100644
--- a/BowelyzerConfig.sc
+++ b/BowelyzerConfig.sc
@@ -21,25 +21,60 @@ BowelyzerConfig{
const <controlsWithRanger = #[ \test];
const <controlsWithKnob = #[ \test];
+ const <hasToBeString = #[
+ \forwardAddress,
+ \hubAddress,
+ \synthServerAddress
+ ];
+
+ const <hasToBeInteger = #[
+ \forwardPort,
+ \hubPort,
+ \synthServerPort,
+ \pitchMedian,
+ \pitchDownSample
+ ];
+ const <hasToBeDictionary = #[
+ \inputs,
+ \controls,
+ \left,
+ \right
+ ];
+ const <hasToBeFloat = #[
+ \amplitudeAttackTime,
+ \amplitudeReleaseTime,
+ \hfHainsworth,
+ \hfFoote,
+ \hfThreshold,
+ \hfWaitTime,
+ \pitchInitFreq,
+ \pitchMinFreq,
+ \pitchMaxFreq,
+ \pitchExecFreq,
+ \pitchMaxBinsPerOctave,
+ \pitchAmpThreshold,
+ \pitchPeakThreshold,
+ \sendReplyFreq
+ ];
+
var <config,
<defaultConfig,
<defaultControls,
- <changed = false,
- <hasToBeString,
- <hasToBeInteger,
- <hasToBeArray,
- <hasToBeDictionary,
- <hasToBeFloat;
+ <changed = false;
+// <hasToBeString,
+// <hasToBeInteger,
+// <hasToBeDictionary,
+// <hasToBeFloat;
*controlContainedIn{
arg control;
- if(BowelyzerConfig.controlsWithSlider.asString.contains(control.asString),{
+ if(BowelyzerConfig.controlsWithSlider.contains(control),{
^\slider;
});
- if(BowelyzerConfig.controlsWithRanger.asString.contains(control.asString),{
+ if(BowelyzerConfig.controlsWithRanger.contains(control),{
^\ranger;
});
- if(BowelyzerConfig.controlsWithKnob.asString.contains(control.asString),{
+ if(BowelyzerConfig.controlsWithKnob.contains(control),{
^\knob;
});
}
@@ -51,91 +86,77 @@ BowelyzerConfig{
init{
arg configFile;
- //TODO: Use ControlSpec to setup standard values/boundaries
- hasToBeString = [
- \forwardAddress,
- \hubAddress,
- \synthServerAddress
- ];
- hasToBeInteger = [
- \forwardPort,
- \hubPort,
- \synthServerPort,
- \pitchMedian,
- \pitchDownSample
- ];
- hasToBeArray = [
- \names
- ];
- hasToBeDictionary = [
- \inputs,
- \controls,
- \left,
- \right
- ];
- hasToBeFloat = [
- \amplitudeAttackTime,
- \amplitudeReleaseTime,
- \hfHainsworth,
- \hfFoote,
- \hfThreshold,
- \hfWaitTime,
- \pitchInitFreq,
- \pitchMinFreq,
- \pitchMaxFreq,
- \pitchExecFreq,
- \pitchMaxBinsPerOctave,
- \pitchAmpThreshold,
- \pitchPeakThreshold,
- \sendReplyFreq
- ];
- config = this.createDefaultConfig;
+ this.addControlSpecs;
+ this.createDefaultConfig;
+ config = Dictionary.new;
if(configFile.notNil,{
- this.readConfigurationFile(configFile)
+ if(this.readConfigurationFile(configFile).not,{
+ error("Reading of configuration file failed. Using default.");
+ config = defaultConfig;
+ });
},{
("No configuration file provided. Using default.").postln;
+ config = defaultConfig;
});
this.showConfig;
}
+ addControlSpecs{
+ ControlSpec.specs[\amplitudeAttackTime] = ControlSpec(0.001, 10, \lin, 0.001, 0.01, units: "s");
+ ControlSpec.specs[\amplitudeReleaseTime] = ControlSpec(0.001, 10, \lin, 0.001, 0.01, units: "s");
+ ControlSpec.specs[\hfHainsworth] = ControlSpec(0.0, 1.0, \lin, 0.001, 0.0, units: "");
+ ControlSpec.specs[\hfFoote] = ControlSpec(0.0, 1.0, \lin, 0.001, 0.0, units: "");
+ ControlSpec.specs[\hfThreshold] = ControlSpec(0.0, 1.0, \lin, 0.001, 1.0, units: "");
+ ControlSpec.specs[\hfWaitTime] = ControlSpec(0.0, 1.0, \lin, 0.001, 0.04, units: "s");
+ ControlSpec.specs[\pitchInitFreq] = ControlSpec(20.0, 20000.0, \exp, 0.01, 440.0, units: "Hz");
+ ControlSpec.specs[\pitchMinFreq] = ControlSpec(20.0, 20000.0, \exp, 0.01, 60.0, units: "Hz");
+ ControlSpec.specs[\pitchMaxFreq] = ControlSpec(20.0, 20000.0, \exp, 0.01, 4000.0, units: "Hz");
+ ControlSpec.specs[\pitchExecFreq] = ControlSpec(20.0, 20000.0, \exp, 0.01, 100.0, units: "Hz");
+ ControlSpec.specs[\pitchMaxBinsPerOctave] = ControlSpec(1, 64, \lin, 1, 16, units: "bins");
+ ControlSpec.specs[\pitchMedian] = ControlSpec(1, 64, \lin, 1, 1, units: "");
+ ControlSpec.specs[\pitchAmpThreshold] = ControlSpec(0.01, 1.0, \lin, 0.01, 0.01, units: "dB");
+ ControlSpec.specs[\pitchPeakThreshold] = ControlSpec(0.01, 1.0, \lin, 0.01, 0.5, units: "dB");
+ ControlSpec.specs[\pitchDownSample] = ControlSpec(0.01, 1.0, \lin, 0.01, 0.5, units: "dB");
+ ControlSpec.specs[\sendReplyFreq] = ControlSpec(1, 100, \exp, 0.1, 20, units: "Hz");
+ }
+
// create the default configuration
createDefaultConfig{
defaultControls = Dictionary.with(*[
- "amplitudeAttackTime" -> 0.01,
- "amplitudeReleaseTime" -> 0.1,
- "hfHainsworth" -> 1.0,
- "hfFoote" -> 0.0,
- "hfThreshold" -> 0.3,
- "hfWaitTime" -> 0.04,
- "pitchInitFreq" -> 440,
- "pitchMinFreq" -> 60,
- "pitchMaxFreq" -> 4000,
- "pitchExecFreq" -> 100,
- "pitchMaxBinsPerOctave" -> 16,
- "pitchMedian" -> 1,
- "pitchAmpThreshold" -> 0.01,
- "pitchPeakThreshold" -> 0.5,
- "pitchDownSample" -> 1,
- "sendReplyFreq" ->20
+ \amplitudeAttackTime -> 0.01,
+ \amplitudeReleaseTime -> 0.1,
+ \hfHainsworth -> 1.0,
+ \hfFoote -> 0.0,
+ \hfThreshold -> 0.3,
+ \hfWaitTime -> 0.04,
+ \pitchInitFreq -> 440,
+ \pitchMinFreq -> 60,
+ \pitchMaxFreq -> 4000,
+ \pitchExecFreq -> 100,
+ \pitchMaxBinsPerOctave -> 16,
+ \pitchMedian -> 1,
+ \pitchAmpThreshold -> 0.01,
+ \pitchPeakThreshold -> 0.5,
+ \pitchDownSample -> 1,
+ \sendReplyFreq ->20
]);
defaultConfig = Dictionary.with(*[
- "inputs" -> Dictionary.with(*[
- "left" -> 0,
- "right" -> 1
+ \inputs -> Dictionary.with(*[
+ \left -> 0,
+ \right -> 1
]),
- "names" -> ["left", "right"],
- "synthServerAddress" -> "127.0.0.1",
- "synthServerPort"->57110,
- "hubAddress" -> "127.0.0.1",
- "hubPort" -> 57120,
- "forwardAddress" -> "127.0.0.1",
- "forwardPort" -> 9999,
- "controls" -> Dictionary.with(*[
- "left" -> defaultControls,
- "right" -> defaultControls
+ //names -> [left, right],
+ \synthServerAddress -> "127.0.0.1",
+ \synthServerPort -> 57110,
+ \hubAddress -> "127.0.0.1",
+ \hubPort -> 57120,
+ \forwardAddress -> "127.0.0.1",
+ \forwardPort -> 57120,
+ \controls -> Dictionary.with(*[
+ \left -> defaultControls,
+ \right -> defaultControls
])
]);
- ^defaultConfig;
}
// read configuration from file
@@ -148,133 +169,162 @@ BowelyzerConfig{
try{
configFromFile = (configFile.asString).parseYAMLFile;
configFromFile.keysValuesDo({|key, value|
- if(config.includesKey(key),{
- config.put(key,value);
- });
+ switch(key.asSymbol,
+ \controls,{
+ // adding names dictionary
+ config.put(key.asSymbol, Dictionary.new(value.size));
+ // going through the names and their associated dictionaries
+ value.keysValuesDo({|name, dictionary|
+ if(dictionary.isKindOf(Dictionary),{
+ config.at(key.asSymbol).put(name.asSymbol, Dictionary.new(dictionary.size));
+ // going through each control dictionary with controls and their values
+ dictionary.keysValuesDo({|control, controlValue|
+ if(defaultControls.includesKey(control.asSymbol),{
+ config.at(key.asSymbol).at(name.asSymbol).put(control.asSymbol, this.getControlValue(control.asSymbol, controlValue));
+ });
+ });
+ },{
+ error("This element should be of type Dictionary: "++dictionary);
+ });
+ });
+ },
+ \inputs,{
+ config.put(key.asSymbol, Dictionary.new());
+ value.keysValuesDo({|name, channel|
+ config.at(\inputs).put(name.asSymbol, channel.asInteger);
+ });
+ },
+ {
+ if(defaultConfig.includesKey(key.asSymbol),{
+ config.put(key.asSymbol, this.getSettingValue(key.asSymbol, value));
+ },{
+ error("Key is not included in known configuration: "++key);
+ });
+ }
+ );
+ });
+ postln("Reading of configuration complete. Now validating...");
+ if(this.validateConfig,{
+ postln("Validation complete.");
+ ^true;
+ },{
+ postln("Validation failed.");
+ ^false;
});
- this.validateConfig;
}{
("Failed parsing the file: "++configFile).error;
("Make sure its JSON syntax is valid!").error;
+ ^false;
};
}, {
error("File not readable:"++configFile.asString);
+ ^false;
});
}
- //check common mistakes in configuration and try fixing them
- validateConfig{
- var broken = false;
- //check for correct types
- config.keysValuesDo({|key, value|
- if(key.isKindOf(String).not,{
- error("Key is no string: "++key);
- broken = true;
+ // return a control value as correct type and within its defined ControlSpec range
+ getControlValue{
+ arg control, value;
+ if(defaultControls.includesKey(control.asSymbol),{
+ if(hasToBeFloat.includes(control.asSymbol),{
+ ^control.asSymbol.asSpec.constrain(value.asFloat).asFloat;
});
- // check if the strings are associated with the correct keys
- if(hasToBeString.includes(key.asSymbol) && value.isKindOf(String).not, {
- config.put(key, value.asString);
+ if(hasToBeInteger.includes(control.asSymbol),{
+ ^control.asSymbol.asSpec.constrain(value.asInteger).asInteger;
});
- // check if the integers are associated with the correct keys
- if(hasToBeInteger.includes(key.asSymbol) && value.isKindOf(Integer).not, {
- config.put(key, value.asInteger);
- });
- // check if the floats are associated with the correct keys
- if(hasToBeFloat.includes(key.asSymbol) && value.isKindOf(Float).not, {
- config.put(key, value.asFloat);
+ },{
+ ^nil;
+ });
+ }
+
+ //get a setting value as correct type
+ getSettingValue{
+ arg setting, value;
+ if(defaultConfig.includesKey(setting.asSymbol),{
+ if(hasToBeString.includes(setting.asSymbol),{
+ ^value.asString;
});
- // check if the dictionaries are associated with the correct keys
- if(hasToBeDictionary.includes(key.asSymbol) && value.isKindOf(Dictionary).not, {
- error("Value ("++value++") of key ("++key++") should be of type Dictionary.");
- broken = true;
+ if(hasToBeInteger.includes(setting.asSymbol),{
+ ^value.asInteger;
});
- //check if arrays are associated with the correct keys
- if(hasToBeArray.includes(key.asSymbol),{
- if(value.isArray.not,{
- error("Value ("++value++") of key ("++key++") should be Array.");
- broken = true;
- },{
- //setting correct types in Arrays
- if((key == "names") && (value.size >= 1) && value[0].isKindOf(String).not,{
- for(0, value.size-1, {|i|
- config.at(key)[i] = value[i].asString;
- });
- });
- });
- });
- // check if controls dictionaries are setup correctly
- if(key == "controls",{
- value.keysValuesDo({|name, controls|
- if(hasToBeDictionary.includes(name.asSymbol) && controls.isKindOf(Dictionary).not, {
- error("Value ("++controls++") of key ("++name++") should be of type Dictionary.");
- broken = true;
- },{
- config.at("controls").at(name).keysValuesDo({|controlKey, controlValue|
- // check if the integers are associated with the correct keys
- if(hasToBeInteger.includes(controlKey.asSymbol) && controlValue.isKindOf(Integer).not, {
- config.at(key).at(name).put(controlKey, controlValue.asInteger);
- });
- // check if the floats are associated with the correct keys
- if(hasToBeFloat.includes(controlKey.asSymbol) && controlValue.isKindOf(Float).not, {
- config.at(key).at(name).put(controlKey, controlValue.asFloat);
- });
- });
- });
+ },{
+ ^nil;
+ });
+ }
+
+ // validate/extend/fix the config and return true if it's useable
+ validateConfig{
+ var broken = false;
+ //fail if there are no inputs defined
+ if(config.includesKey(\inputs).not,{
+ ^false;
+ });
+ // if there are no controls defined at all, add at least a Dictionary for them
+ if(config.includesKey(\controls).not,{
+ config.put(\controls, Dictionary.new(config.at(\inputs).size));
+ });
+ // go through the defaultConfig/defaultControl collection and compare it to the provided config
+ defaultConfig.keysValuesDo({|key, value|
+ if(key != \controls && key != \inputs,{
+ // if a standard setting is not in the configuration, add it from the default
+ if(config.includesKey(key).not,{
+ config.put(key, value);
});
});
- //check if inputs dictionaries are set up correctly
- if(key == "inputs", {
- value.keysValuesDo({|name, input|
- if(input.isKindOf(Integer).not, {
- error("Value ("++input++") of key ("++name++") should be of type Integer.");
- config.at("inputs").put(name -> input.asInteger);
- });
- });
+ });
+ // go through the inputs and add controls, if there are none setup for them
+ config.at(\inputs).keysValuesDo({|name, channel|
+ // if there are no controls defined for the input, add them from default
+ if(config.at(\controls).includesKey(name).not,{
+ config.at(\controls).put(name, defaultControls);
});
});
- // if not completely broken, fix stuff
- if(broken,{
- error("There were serious errors. Reverting to default config.");
- config = this.createDefaultConfig;
- },{
- postln("Fixing stuff");
- // disable and zero-pad channels without inputs
- if(config.at("names").size > config.at("inputs").size,{
- error("More channels than inputs defined. Disabling missing.");
- config.at("names").do({|name,i|
- if(config.at("inputs").includesKey(name).not,{
- config.at("inputs").put(name.asString -> 0);
- //TODO: Disable here.
+ // go through each control dictionary
+ config.at(\controls).keysValuesDo({|name, controlDictionary|
+ if(config.at(\inputs).includesKey(name),{
+ // go through the defaultControl Dictionary and add missing controls to controls from config
+ defaultControls.keysValuesDo({|defaultControl, defaultControlValue|
+ if(controlDictionary.includesKey(defaultControl).not,{
+ config.at(\controls).at(name).put(defaultControl, defaultControlValue);
});
});
+ },{
+ // remove controls for non-existing inputs
+ config.at(\controls).removeAt(name);
});
- //TODO: add defaultControls for channels that have none
- //TODO: fill non-existing keys with default values (in case config file is incomplete)
});
+ ^true;
}
//print the current config
showConfig{
- postln("Configuration is:");
+ postln("Configuration is: ");
config.keysValuesDo{|key, value|
- if(key == "controls",{
- postln(key++" ("++key.class++") ->");
- value.keysValuesDo{|key, value|
- postln( key++" ("++key.class++"):");
- value.keysValuesDo{|key, value|
- postln(" "++key++" ("++key.class++") -> "++value++" ("++value.class++")");
- }
- }
- },{
- postln(key++" ("++key.class++") -> "++value++" ("++value.class++")");
- });
+ switch(key,
+ \controls, {
+ postln(key++" ("++key.class++") -> ("++value.class++")");
+ value.keysValuesDo({|subKey, subValue|
+ postln(" "++subKey++" ("++subKey.class++") -> ("++subValue.class++")");
+ subValue.keysValuesDo({|subSubKey, subSubValue|
+ postln(" "++subSubKey++" ("++subSubKey.class++") -> "++subSubValue++" ("++subSubValue.class++")");
+ });
+ });
+ },
+ \inputs, {
+ postln(key++" ("++key.class++") -> ("++value.class++")");
+ value.keysValuesDo({|subKey, subValue|
+ postln(" "++subKey++" ("++subKey.class++") -> "++subValue++" ("++subValue.class++")");
+ });
+ },
+ {postln(key++" ("++key.class++") -> "++value++" ("++value.class++")");}
+ );
};
}
getSynthControl{
arg name, control;
- if(config.at("controls").includesKey(name) && config.at("controls").at(name).includes(control),{
- ^config.at("controls").at(name).at(control);
+ if(config.at(\controls).includesKey(name) && config.at(\controls).at(name).includes(control),{
+ ^config.at(\controls).at(name).at(control);
},{
^false;
});
@@ -283,8 +333,8 @@ BowelyzerConfig{
// sets a control to a value for a synth
setSynthControl{
arg name, control;
- if(config.at("controls").includesKey(name) && config.at("controls").at(name).includes(control[0]),{
- config.at("controls").at(name).put(control[0], control[1]);
+ if(config.at(\controls).includesKey(name) && config.at(\controls).at(name).includes(control[0]),{
+ config.at(\controls).at(name).put(control[0], control[1]);
^true;
},{
^false;