From 830f1d296e402a89c6146e4183e1a2490ca64406 Mon Sep 17 00:00:00 2001 From: David Runge Date: Sun, 19 Jun 2016 19:33:36 +0200 Subject: Bowelyzer.sc, BowelyzerAnalyzer.sc, BowelyzerConfig.sc, BowelyzerOSCHub.sc: Moving from String based identifiers to Symbols. Further refining the configuration parsing and validation process. darmstadt.json: Moving names into inputs Dictionary, holding channel number (offsets are not required/feasible) and name. --- BowelyzerConfig.sc | 402 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 226 insertions(+), 176 deletions(-) (limited to 'BowelyzerConfig.sc') diff --git a/BowelyzerConfig.sc b/BowelyzerConfig.sc index 4079119..e092b25 100644 --- a/BowelyzerConfig.sc +++ b/BowelyzerConfig.sc @@ -21,25 +21,60 @@ BowelyzerConfig{ const 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; -- cgit v1.2.3-70-g09d2