diff options
author | David Runge <dave@sleepmap.de> | 2016-07-03 16:34:58 +0200 |
---|---|---|
committer | David Runge <dave@sleepmap.de> | 2016-07-03 16:34:58 +0200 |
commit | 8c45cbc006d751df91eb637032190ff4a33fc78e (patch) | |
tree | 998a16b254a51a1b0318b8cc789eace82829b57e /classes/BowelyzerConfig.sc | |
parent | 966fa72f9676643b1b56c0d41046055b50b03a41 (diff) | |
download | bowelyzer-0.4.tar.gz bowelyzer-0.4.tar.bz2 bowelyzer-0.4.tar.xz bowelyzer-0.4.zip |
classes/*.sc: Moving all classes to the proper subfolder classes.0.4
Diffstat (limited to 'classes/BowelyzerConfig.sc')
-rw-r--r-- | classes/BowelyzerConfig.sc | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/classes/BowelyzerConfig.sc b/classes/BowelyzerConfig.sc new file mode 100644 index 0000000..287aad4 --- /dev/null +++ b/classes/BowelyzerConfig.sc @@ -0,0 +1,362 @@ +BowelyzerConfig{ + + const <controlsWithSlider = #[ + \amplitudeAttackTime, + \amplitudeReleaseTime, + \hfHainsworth, + \hfFoote, + \hfThreshold, + \hfWaitTime, + \pitchInitFreq, + \pitchMinFreq, + \pitchMaxFreq, + \pitchExecFreq, + \pitchMaxBinsPerOctave, + \pitchMedian, + \pitchAmpThreshold, + \pitchPeakThreshold, + \pitchDownSample, + \sendReplyFreq + ]; + 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 + ]; + + const <hasToBeBool = #[ + \active + ]; + + var <config, + <defaultConfig, + <defaultControls, + <changed = false; + + *controlContainedIn{ + arg control; + if(BowelyzerConfig.controlsWithSlider.includes(control),{ + ^\slider; + }); + if(BowelyzerConfig.controlsWithRanger.includes(control),{ + ^\ranger; + }); + if(BowelyzerConfig.controlsWithKnob.includes(control),{ + ^\knob; + }); + } + + *new{ + arg config; + ^super.new.init(config); + } + + init{ + arg configFile; + this.addControlSpecs; + this.createDefaultConfig; + config = Dictionary.new; + if(configFile.notNil,{ + 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; + } + + // add ControlSpecs to the global Dictionary + 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, 1.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(1, 100, \lin, 1, 1, units: "samples"); + ControlSpec.specs[\sendReplyFreq] = ControlSpec(1, 100, \exp, 0.1, 20, units: "Hz"); + ControlSpec.specs[\input] = ControlSpec(0, Server.default.options.numInputBusChannels-1, \lin, 1, 0, units: "channels"); + ControlSpec.specs[\port] = ControlSpec(1, 65535, \lin, 1, 0, units: "ports"); + } + + // create the default configuration + createDefaultConfig{ + defaultControls = Dictionary.with(*[ + \active -> true, + \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 + ]), + //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 + ]) + ]); + } + +// read configuration from file + readConfigurationFile{ + arg configFile; + var configFromFile, reader, path; + path = PathName.new(configFile.asString); + if(path.isFile,{ + postln("Reading configuration file: "++configFile); + try{ + configFromFile = (configFile.asString).parseYAMLFile; + configFromFile.keysValuesDo({|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; + }); + }{ + ("Failed parsing the file: "++configFile).error; + ("Make sure its JSON syntax is valid!").error; + ^false; + }; + }, { + error("File not readable:"++configFile.asString); + ^false; + }); + } + + //TODO: add writeConfigurationFile + + // 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; + }); + if(hasToBeInteger.includes(control.asSymbol),{ + ^control.asSymbol.asSpec.constrain(value.asInteger).asInteger; + }); + if(hasToBeBool.includes(control.asSymbol),{ + switch(value, + 0,{^false}, + 1,{^true}, + "true",{^true}, + "false",{^false} + ); + }); + },{ + ^nil; + }); + } + + //get a setting value as correct type + getSettingValue{ + arg setting, value; + if(defaultConfig.includesKey(setting.asSymbol),{ + if(hasToBeString.includes(setting.asSymbol),{ + ^value.asString; + }); + if(hasToBeInteger.includes(setting.asSymbol),{ + ^value.asInteger; + }); + },{ + ^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); + }); + }); + }); + // 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); + }); + }); + // 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); + }); + }); + ^true; + } + + //print the current config + showConfig{ + postln("Configuration is: "); + config.keysValuesDo{|key, value| + 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); + },{ + ^false; + }); + } + + // 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]); + ^true; + },{ + ^false; + }); + } + +} |