diff options
Diffstat (limited to 'classes/Bowelyzer.sc')
-rw-r--r-- | classes/Bowelyzer.sc | 267 |
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 + ); + } +} |