aboutsummaryrefslogtreecommitdiffstats
path: root/classes/Bowelyzer.sc
diff options
context:
space:
mode:
Diffstat (limited to 'classes/Bowelyzer.sc')
-rw-r--r--classes/Bowelyzer.sc267
1 files changed, 267 insertions, 0 deletions
diff --git a/classes/Bowelyzer.sc b/classes/Bowelyzer.sc
new file mode 100644
index 0000000..cafaf00
--- /dev/null
+++ b/classes/Bowelyzer.sc
@@ -0,0 +1,267 @@
+Bowelyzer{
+
+ var <gui, <server, <analyzer, <config, <hub;
+
+ *new{
+ arg configFile;
+ ^super.new.init(configFile);
+ }
+
+ init{
+ //initialize with configuration, if available (else use default)
+ arg configFile;
+ config = BowelyzerConfig.new(configFile);
+ server = Server.new(
+ \bowelyzer,
+ BowelyzerOSCHub.getNetAddr(
+ config.config.at(\synthServerAddress),
+ config.config.at(\synthServerPort)
+ )
+ );
+ Server.default = server;
+ server.waitForBoot({
+ hub = BowelyzerOSCHub.new(config.config);
+ analyzer = BowelyzerAnalyzer.new(config.config);
+ gui = BowelyzerGUI.new(config.config);
+ this.addGUIListeners;
+ this.addServerListeners;
+ },
+ 5,
+ {"scsynth failed to start!".postln});
+ }
+
+ addGUIListeners{
+ // listen for control changes
+ OSCdef.newMatching(
+ key: \controls,
+ func: {|msg, time, addr, recvPort|
+ postln("Received: "++msg);
+ // if the control exists, change it
+ if(msg[1].notNil && msg[2].notNil && msg[3].notNil,{
+ if(config.config.at(\controls).includesKey(msg[1]),{
+ if(config.config.at(\controls).at(msg[1]).includesKey(msg[2]),{
+ config.config.at(\controls).at(msg[1]).put(msg[2], config.getControlValue(msg[2], msg[3]));
+ });
+ });
+ });
+ },
+ path: "/controls",
+ srcID: NetAddr.new("127.0.0.1", NetAddr.langPort)
+ );
+ // listen for input changes (rename and input channel)
+ OSCdef.newMatching(
+ key: \inputs,
+ func: {|msg, time, addr, recvPort|
+ var name = msg[1],
+ type = msg[2],
+ update = msg[3];
+ postln("Received: "++msg);
+ if(name.notNil && type.notNil && update.notNil,{
+ if(config.config.at(\inputs).includesKey(name) && config.config.at(\controls).includesKey(name),{
+ switch(type,
+ \name,{
+ //if the name exists and the new name is not empty, change it
+ //FIXME: check whether new name exists and only setup then, else reset the textfield
+ if(update != "",{
+ //move the controls
+ config.config.at(\controls).put(update.asSymbol, config.config.at(\controls).at(name));
+ config.config.at(\controls).removeAt(name.asSymbol);
+ // rename the input
+ config.config.at(\inputs).put(update.asSymbol, config.config.at(\inputs).at(name));
+ config.config.at(\inputs).removeAt(name);
+ Routine{
+ // rename the channel View
+ gui.channels.do({|channel|
+ if(channel.name.asSymbol == name.asSymbol, {
+ channel.name = update.asSymbol;
+ });
+ });
+ // OSC indicator: stop old task, remove it and create a new one with updated name
+ gui.indicators.at(name).stop;
+ gui.indicators.removeAt(name);
+ gui.addOSCIndicatorFadeOutTask(update);
+ }.play(AppClock);
+ // stop the listener for LevelIndicator by name and start a new one based upon the updated name
+ OSCdef(\levels_++name).free;
+ this.setupLevelListener(update, hub.synthServer);
+ // free the synth on the server and start a new one according to the config
+ analyzer.freeAnalysisSynth(name.asSymbol);
+ analyzer.synths.removeAt(name);
+ analyzer.addSynthWithName(update);
+ // start the Synth (possibly paused)
+ Routine{
+ 1.wait;
+ analyzer.startSynthWithNameAndControls(update.asSymbol, config.config.at(\controls).at(update), config.config.at(\inputs).at(update));
+ }.play;
+ // rename the hub listener for the Synth
+ hub.freeSynthListener(name);
+ hub.addSynthListener(update);
+ hub.startSynthListener(update);
+ });
+ },
+ \input,{
+ // change the input in configuration
+ config.config.at(\inputs).put(name, update.asInteger);
+ // change the input in the Synth
+ analyzer.setSynthControl(name.asSymbol, \inputChannel, update.asInteger);
+ }
+ );
+ });
+ });
+ },
+ path: "/inputs",
+ srcID: NetAddr.new("127.0.0.1", NetAddr.langPort)
+ );
+ // listen for toggling messages to "mute" channel
+ OSCdef.newMatching(
+ key: \toggle,
+ func: {|msg, time, addr, recvPort|
+ var name = msg[1],
+ toggle = msg[2];
+ postln("Received: "++msg);
+ if(name.notNil && toggle.notNil && toggle.isInteger,{
+ if(config.config.at(\inputs).includesKey(name),{
+ switch(toggle,
+ 0,{
+ config.config.at(\controls).at(name).put(\active, true);
+ analyzer.startAnalysisSynth(name);
+ },
+ 1,{
+ config.config.at(\controls).at(name).put(\active, false);
+ analyzer.stopAnalysisSynth(name);
+ }
+ );
+ });
+ });
+ },
+ path: "/toggle",
+ srcID: NetAddr.new("127.0.0.1", NetAddr.langPort)
+ );
+
+ // listen for address messages to change OSC addresses
+ OSCdef.newMatching(
+ key: \address,
+ func: {|msg, time, addr, recvPort|
+ var type = msg[1],
+ address = msg[2];
+ postln("Received: "++msg);
+ if(type.notNil && config.config.includesKey(type),{
+ config.config.put(type.asSymbol, address.asString);
+ hub.setupNetAddressesFromConfig(config.config);
+ });
+ },
+ path: "/address",
+ srcID: hub.local
+ );
+
+ // listen for port messages to change OSC ports
+ OSCdef.newMatching(
+ key: \port,
+ func: {|msg, time, addr, recvPort|
+ var type = msg[1],
+ port = msg[2];
+ postln("Received: "++msg);
+ if(type.notNil && config.config.includesKey(type),{
+ config.config.put(type.asSymbol, port.asInteger);
+ hub.setupNetAddressesFromConfig(config.config);
+ });
+ },
+ path: "/port",
+ srcID: hub.local
+ );
+
+ // listen for port messages to change OSC ports
+ OSCdef.newMatching(
+ key: \save,
+ func: {|msg, time, addr, recvPort|
+ var path = msg[1];
+ postln("Received: "++msg);
+ //TODO: implement save (write to file) in BowelyzerConfig
+ },
+ path: "/save",
+ srcID: hub.local
+ );
+
+ // listen for port messages to change OSC ports
+ OSCdef.newMatching(
+ key: \load,
+ func: {|msg, time, addr, recvPort|
+ var path = msg[1];
+ postln("Received: "++msg);
+ //TODO: use BowelyzerConfig readFromConfigurationFile
+ //TODO: destroy current GUI elements
+ //TODO: load channels, etc.
+ },
+ path: "/load",
+ srcID: hub.local
+ );
+ }
+
+ // add OSCdefs listening for messages coming from scsynth, to update the GUI
+ addServerListeners{
+ this.setupIndicatorListener;
+ // add and start a listener for each channel's LevelIndicator
+ config.config.at(\inputs).pairsDo({|key,value|
+ this.setupLevelListener(key, hub.synthServer);
+ });
+ }
+
+ // setup a listener for a level indicator by name and source (of synth server)
+ setupIndicatorListener{
+ // listen for indicator messages
+ OSCdef.newMatching(
+ key: \indicate,
+ func: {|msg, time, addr, recvPort|
+ var name = msg[1];
+ //postln("Indicate for "++name);
+ if(config.config.at(\inputs).includesKey(name),{
+ if(gui.indicators.includesKey(name),{
+ gui.indicators.at(name).stop;
+ gui.indicators.at(name).reset;
+ gui.indicators.at(name).start(AppClock);
+ });
+ });
+ },
+ path: "/indicate",
+ srcID: NetAddr.new("127.0.0.1", NetAddr.langPort)
+ );
+ }
+
+ // setup a listener for a level indicator by name and source (of synth server)
+ setupLevelListener{
+ arg name, server;
+ postln("Setting up LevelListener for: "++name);
+ OSCdef.newMatching(
+ key: \levels_++name,
+ func: {|msg, time, addr, recvPort|
+ var name = msg[0].asString.replace("/levels/", "").asSymbol,
+ value = msg[3].ampdb.linlin(-40, 0, 0, 1),
+ peak = msg[4].ampdb.linlin(-40, 0, 0, 1);
+ //postln("Receiving: "++msg);
+ {
+ gui.channels.do({|channel|
+ if(channel.name.asSymbol == name,{
+ channel.children.do({|channelChild|
+ if(channelChild.name.asSymbol == \meterAndControls,{
+ channelChild.children.do({|meterAndControls|
+ if(meterAndControls.name.asSymbol == \meterView, {
+ meterAndControls.children.do({|meterView|
+ if(meterView.isKindOf(LevelIndicator), {
+ //postln("Setting up LevelIndicator for "++name);
+ meterView.value = value;
+ meterView.peakLevel = peak;
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ }.defer;
+ },
+ path: "/levels/"++name,
+ srcID: server
+ );
+ }
+}