aboutsummaryrefslogtreecommitdiffstats
path: root/classes/BowelyzerGUI.sc
diff options
context:
space:
mode:
Diffstat (limited to 'classes/BowelyzerGUI.sc')
-rw-r--r--classes/BowelyzerGUI.sc520
1 files changed, 520 insertions, 0 deletions
diff --git a/classes/BowelyzerGUI.sc b/classes/BowelyzerGUI.sc
new file mode 100644
index 0000000..e26798e
--- /dev/null
+++ b/classes/BowelyzerGUI.sc
@@ -0,0 +1,520 @@
+BowelyzerGUI{
+
+ var mainView, <settingsView, <channelContainerView,
+ <channels,
+ <indicators,
+ //TODO: move to BowelyzerConfig
+ fadeOutTime = 0.3,
+ fadeOutSteps = 20,
+ minWidth=1280,
+ minHeight=720,
+ channelViewHeight = 700,
+ channelViewWidth = 300,
+ channelViewSize,
+ controlMeterContainerViewHeight = 700,
+ controlMeterContainerViewWidth = 300,
+ controlMeterContainerViewSize,
+ buttonHeight = 20,
+ buttonWidth = 48,
+ settingsSubViewMargins = #[2,2,2,2],
+ settingsSubViewSize,
+ settingsViewSize,
+ configViewSize,
+ meterViewWidth = 54,
+ meterViewHeight = 700,
+ headViewHeight = 24,
+ headViewWidth = 300,
+ controlsViewWidth = 246,
+ controlsViewHeight = 700
+ ;
+
+ *new{
+ arg config;
+ ^super.new.init(config)
+ }
+
+ init{
+ arg config;
+ postln("Launching GUI.");
+ settingsViewSize = 496@64;
+ settingsSubViewSize = 144@64;
+ configViewSize = 64@64;
+ controlMeterContainerViewSize = controlMeterContainerViewWidth@controlMeterContainerViewHeight;
+ channelViewSize = channelViewWidth@channelViewHeight;
+ channels = Set.new(config.at(\inputs).size);
+ indicators = Dictionary.new(config.at(\inputs).size);
+ this.setupMainView(config);
+ this.setupChannelViews(config);
+ }
+
+ //setup the main view, in which all other views reside
+ setupMainView{
+ arg config;
+ var channelScrollView, forwardView, hubView, synthServerView, configView, layout;
+ mainView = PageLayout.new("Bowelyzer");
+ mainView.asView.background = Color.fromHexString("#DBDBDB");
+ layout = mainView.asView.addFlowLayout(0@0, 0@0);
+ settingsView = View(mainView.asView, Rect(0, 0, settingsViewSize.x, settingsViewSize.y));
+ settingsView.asView.background = Color.fromHexString("#99EF99");
+ settingsView.layout = HLayout();
+ settingsView.layout.spacing = 0;
+ settingsView.layout.margins = [0,0,0,0];
+
+ //config
+ configView = View(settingsView.asView);
+ configView.asView.background = Color.fromHexString("#DDDDEF");
+ configView.layout = VLayout();
+ configView.layout.spacing = 0;
+ configView.layout.margins = settingsSubViewMargins;
+ configView.name = "config";
+ configView.maxSize_(configViewSize);
+ this.setupSaveButton(configView);
+ this.setupSaveAsButton(configView);
+ this.setupLoadButton(configView);
+
+ //synthServer
+ synthServerView = View(settingsView.asView);
+ synthServerView.asView.background = Color.fromHexString("#DDDDEF");
+ synthServerView.layout = VLayout();
+ synthServerView.layout.spacing = 0;
+ synthServerView.layout.margins = settingsSubViewMargins;
+ synthServerView.name = "synthServer";
+ synthServerView.maxSize_(settingsSubViewSize);
+ StaticText(synthServerView, Rect(0, 0, 140@20)).string_("synthServer").align_(\center);
+ this.setupEZText(synthServerView, "address", config.at(\synthServerAddress)).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(TextField),{item.align_(\right)});
+ });
+ this.setupEZNumber(synthServerView, "port", config.at(\synthServerPort)).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(NumberBox),{item.align_(\right)});
+ });
+
+ //hub
+ hubView = View(settingsView.asView);
+ hubView.asView.background = Color.fromHexString("#DDDDEF");
+ hubView.layout = VLayout();
+ hubView.layout.spacing = 0;
+ hubView.layout.margins = settingsSubViewMargins;
+ hubView.name = "hub";
+ hubView.maxSize_(settingsSubViewSize);
+ StaticText(hubView, Rect(0, 0, 140@20)).string_("hub").align_(\center);
+ this.setupEZText(hubView, "address", config.at(\hubAddress)).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(TextField),{item.align_(\right)});
+ });
+ this.setupEZNumber(hubView, "port", config.at(\hubPort)).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(NumberBox),{item.align_(\right)});
+ });
+
+ //forward
+ forwardView = View(settingsView.asView);
+ forwardView.asView.background = Color.fromHexString("#DDDDEF");
+ forwardView.layout = VLayout();
+ forwardView.layout.spacing = 0;
+ forwardView.layout.margins = settingsSubViewMargins;
+ forwardView.name = "forward";
+ forwardView.maxSize_(settingsSubViewSize);
+ StaticText(forwardView, Rect(0, 0, 140@20)).string_("forward").align_(\center);
+ this.setupEZText(forwardView, "address", config.at(\forwardAddress)).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(TextField),{item.align_(\right)});
+ });
+ this.setupEZNumber(forwardView, "port", config.at(\forwardPort)).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(NumberBox),{item.align_(\right)});
+ });
+
+ // go to next line in layout
+ layout.nextLine;
+ channelScrollView = ScrollView(mainView.asView, Rect(0,0,mainView.bounds.width, mainView.bounds.height-settingsView.bounds.height)).autohidesScrollers_(false).hasBorder_(true);
+ // container for channelViews
+ channelContainerView = View(parent: channelScrollView, bounds: Rect(0, 0, channelViewWidth*config.at(\inputs).size, channelViewHeight));
+ channelContainerView.asView.background = Color.fromHexString("#FEFEFE");
+ channelContainerView.layout = HLayout();
+ channelContainerView.layout.spacing = 0;
+ channelContainerView.layout.margins = [0,0,0,0];
+ channelContainerView.maxSize_((channelViewWidth*config.at(\inputs).size)@channelViewHeight);
+ }
+
+ //setup channel views
+ setupChannelViews{
+ arg config;
+ var channelView, headView, controlMeterContainerView, meterView, controlsView, controlsFromConfig, levelIndicator;
+ config.at(\inputs).keysValuesDo({|name, input|
+ //channelView = View(mainView.asView, Rect(0, 0, mainView.bounds.width/config.at(\inputs).size, mainView.bounds.height));
+ channelView = View(mainView.asView, Rect(0, 0, channelViewWidth, channelViewHeight));
+ channelView.asView.background = Color.fromHexString("#FEEFEF");
+ channelView.name = name;
+ channelView.layout = VLayout();
+ channelView.layout.spacing = 0;
+ channelView.layout.margins = [2,0,2,0];
+ channelView.maxSize_(300@700);
+ // adding name textfield of input
+ headView = View(channelView.asView, Rect(0, 0, headViewWidth, headViewHeight));
+ headView.asView.background = Color.fromHexString("#DDEFDD");
+ headView.name = \inputs;
+ headView.layout = HLayout();
+ headView.layout.spacing = 0;
+ headView.layout.margins = [2,0,2,0];
+ headView.maxHeight_(buttonHeight);
+ this.setupEZText(headView, "name", name.asString).children.do({|item|
+ if(item.isKindOf(StaticText),{item.align_(\left)});
+ if(item.isKindOf(TextField),{item.align_(\right)});
+ });
+ this.setupEZNumber(headView, "input", config.at(\inputs).at(name)).children.do({|item|
+ item.postln; if(item.isKindOf(StaticText),{item.align_(\left)});
+ item.postln; if(item.isKindOf(NumberBox),{item.align_(\right)});
+ });
+
+ controlMeterContainerView = View(channelView.asView, Rect(0, 0, controlMeterContainerViewWidth, controlMeterContainerViewHeight));
+ controlMeterContainerView.asView.background = Color.fromHexString("#DDDDEF");
+ controlMeterContainerView.name = \meterAndControls;
+ controlMeterContainerView.layout = HLayout();
+ controlMeterContainerView.layout.spacing = 0;
+ controlMeterContainerView.layout.margins = [0,0,0,0];
+
+ meterView = View(controlMeterContainerView.asView, Rect(0,0, meterViewWidth, meterViewHeight));
+ meterView.asView.background = Color.fromHexString("#EEEFEE");
+ meterView.name = \meterView;
+ meterView.layout = VLayout();
+ meterView.maxWidth = meterViewWidth;
+ meterView.layout.spacing = 0;
+ meterView.layout.margins = [2,0,2,0];
+
+ //setup a toggle button for each channel
+ this.setupPauseButton(meterView);
+
+ // setup a small View as indicator for incoming/outgoing OSC messages for each input
+ this.setupOSCIndicator(meterView);
+ this.addOSCIndicatorFadeOutTask(name);
+
+ // setup LevelIndicator for each input
+ this.setupLevelIndicator(meterView);
+
+ controlsView = View(controlMeterContainerView.asView, Rect(0,0, controlsViewWidth, controlsViewHeight));
+ controlsView.asView.background = Color.fromHexString("#EEEFEE");
+ controlsView.name = \controls;
+ controlsView.maxWidth = controlsViewWidth;
+ controlsView.layout = VLayout();
+ controlsView.layout.spacing = 0;
+ controlsView.layout.margins = [2,0,2,0];
+
+ //TODO: add ranger for amplitude and pitch threshold/region
+ //TODO: rearrange sliders/rangers/knobs in groups (maybe even tabs)
+ config.at(\controls).at(name).order.do({|control, i|
+ var unit;
+ var value = config.at(\controls).at(name).at(control), controlIs = BowelyzerConfig.controlContainedIn(control);
+ switch(
+ controlIs.asSymbol,
+ \knob, {this.setupEZKnob(controlsView, control, value, \controls, name).view.children.do({|item| if(item.isKindOf(NumberBox),{item.align_(\right)})})},
+ \slider, {this.setupEZSlider(controlsView, control, value).view.children.do({|item| if(item.isKindOf(NumberBox),{item.align_(\right)})})},
+ \ranger, {this.setupEZRanger(controlsView, control, value, \controls, name).view.children.do({|item| if(item.isKindOf(NumberBox),{item.align_(\right)})})}
+ );
+ });
+ // add channelView to the container and the global Dictionary for better access
+ channelContainerView.layout.add(channelView);
+ channels.add(channelView);
+ });
+ }
+
+ // setup a OSC indicator view (one on each channel)
+ setupOSCIndicator{
+ arg parent;
+ ^View(parent, Rect(0, 0, buttonWidth, buttonHeight))
+ .name_(\OSCIndicator)
+ .background_(Color.fromHexString("#EEEFEE"))
+ .maxSize_(buttonWidth@buttonHeight)
+ .visible_(true)
+ ;
+ }
+
+ // setup tasks for changing the OSC indicator color (on receiving a message)
+ addOSCIndicatorFadeOutTask{
+ arg name;
+ indicators.put(
+ name.asSymbol,
+ Task({
+ 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(View) && meterView.name.asSymbol == \OSCIndicator, {
+ meterView.background_(Color.fromHexString("#99FF99"));
+ fadeOutSteps.do({|item,i|
+ meterView.background_(meterView.background.blend(Color.fromHexString("#EEEFEE"), (fadeOutTime/fadeOutSteps)));
+ (fadeOutTime/fadeOutSteps).wait;
+ });
+ meterView.background_(Color.fromHexString("#EEEFEE"));
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ })
+ );
+ }
+
+ freeOSCIndicatorFadeOutTask{
+
+ }
+
+ setupLevelIndicator{
+ arg parent;
+ ^LevelIndicator(
+ parent
+ ).maxSize_(buttonWidth@600)
+ .style_(\led)
+ .drawsPeak_(true);
+ }
+
+ // create a load button, that launches a FileDialog on press
+ setupLoadButton{
+ arg parent;
+ ^Button(parent, Rect(0, 0, buttonWidth, buttonHeight))
+ .states_([
+ ["load", Color.black, Color.fromHexString("#99FF99")]
+ ])
+ .action_({
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/load";
+ FileDialog.new(
+ okFunc: {|path|
+ postln("Sending: ["++type++", "++path++"]");
+ address.sendMsg(type, path.asString);
+ },
+ cancelFunc: {},
+ fileMode: 1,
+ acceptMode: 0,
+ stripResult: true
+ );
+ })
+ .maxSize_(buttonWidth@buttonHeight)
+ ;
+ }
+
+ // create a save button, that launches a FileDialog on press
+ setupSaveButton{
+ arg parent;
+ ^Button(parent, Rect(0, 0, buttonWidth, buttonHeight))
+ .states_([
+ ["save", Color.black, Color.fromHexString("#99FF99")],
+ ])
+ .action_({
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/save";
+ postln("Sending: ["++type++"]");
+ address.sendMsg(type);
+ })
+ .maxSize_(buttonWidth@buttonHeight)
+ ;
+ }
+
+ // create a save button, that launches a FileDialog on press
+ setupSaveAsButton{
+ arg parent;
+ ^Button(parent, Rect(0, 0, buttonWidth, buttonHeight))
+ .states_([
+ ["save as", Color.black, Color.fromHexString("#99FF99")],
+ ])
+ .action_({
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/saveas";
+ FileDialog.new(
+ okFunc: {|path|
+ postln("Sending: ["++type++", "++path++"]");
+ address.sendMsg(type, path.asString);
+ },
+ cancelFunc: {},
+ fileMode: 1,
+ acceptMode: 1,
+ stripResult: true
+ );
+ })
+ .maxSize_(buttonWidth@buttonHeight)
+ ;
+ }
+
+ // setup a button to pause the Synth for a channel
+ setupPauseButton{
+ arg parent;
+ ^Button(parent, Rect(0, 0, buttonWidth, buttonHeight))
+ .states_([
+ ["on", Color.black, Color.fromHexString("#99FF99")],
+ ["off", Color.black, Color.fromHexString("#FF9999")]
+ ])
+ .action_({
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/toggle",
+ name = controlUnit.parent.parent.parent.name.asSymbol,
+ controlValue = controlUnit.value;
+ address.sendMsg(type, name, controlValue);
+ })
+ .maxSize_(buttonWidth@buttonHeight)
+ ;
+ }
+
+ // setup a StaticText and a TextField
+ setupEZText{
+ arg parent, control, value;
+ var bounds = 144@buttonHeight,
+ labelWidth= 48,
+ textWidth = 96;
+ // resize, depending on surrounding
+ if(control == "address",{
+ bounds = 140@buttonHeight;
+ labelWidth = 60;
+ textWidth = 80;
+ });
+ ^EZText(
+ parent: parent,
+ bounds: bounds,
+ label: control,
+ action: {
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/"++controlUnit.view.parent.name.asString,
+ name = controlUnit.view.parent.parent.name.asSymbol,
+ controlName = controlUnit.labelView.string.asSymbol,
+ controlValue = controlUnit.value;
+ if((type == "/synthServer") || (type == "/hub") || (type == "/forward"), {
+ type = (type++"Address").replace("/","").asSymbol;
+ name = "/"++controlName;
+ postln("Sending: "++"["++name++", "++type++", "++controlValue++"]");
+ address.sendMsg(name, type, controlValue);
+ },{
+ postln("Sending: "++"["++type++", "++name++", "++controlName++", "++controlValue++"]");
+ address.sendMsg(type, name, controlName, controlValue);
+ });
+ },
+ labelWidth: labelWidth,
+ textWidth: textWidth,
+ initVal:value.asString,
+ layout: \horz,
+ margin: nil
+ )
+ .view.maxHeight_(buttonHeight)
+ ;
+ }
+
+ // setup a StaticText and a NumberBox
+ setupEZNumber{
+ arg parent, control, value;
+ var bounds = 144@buttonHeight,
+ labelWidth = 48,
+ numberWidth = 96;
+ // resize, depending on surrounding
+ if(control == "port",{
+ bounds = 140@buttonHeight;
+ labelWidth = 70;
+ numberWidth = 70;
+ });
+ ^EZNumber(
+ parent: parent,
+ bounds: bounds,
+ label: control,
+ controlSpec: control.asSymbol,
+ action: {
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/"++controlUnit.view.parent.name.asString,
+ name = controlUnit.view.parent.parent.name.asSymbol,
+ controlName = controlUnit.labelView.string.asSymbol,
+ controlValue = controlUnit.value;
+ if((type == "/synthServer") || (type == "/hub") || (type == "/forward"), {
+ type = (type++"Port").replace("/", "").asSymbol;
+ name = "/"++controlName;
+ postln("Sending: "++"["++name++", "++type++", "++controlValue++"]");
+ address.sendMsg(name, type, controlValue);
+ },{
+ postln("Sending: "++"["++type++", "++name++", "++controlName++", "++controlValue++"]");
+ address.sendMsg(type, name, controlName, controlValue);
+ });
+ },
+ initVal:value,
+ labelWidth: labelWidth,
+ numberWidth: numberWidth,
+ layout: \horz,
+ margin: nil
+ )
+ .view.maxHeight_(buttonHeight)
+ ;
+ }
+
+ // setup a Slider, a StaticText and a NumberBox for a Synth setting
+ setupEZSlider{
+ arg parent, control, value;
+ ^EZSlider(
+ parent: parent,
+ bounds: 236@40,
+ label: control,
+ controlSpec: control.asSymbol,
+ action: {
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/"++controlUnit.view.parent.name.asString,
+ name = controlUnit.view.parent.parent.parent.name.asSymbol,
+ controlName = controlUnit.labelView.string.asSymbol,
+ controlValue = controlUnit.value;
+ address.sendMsg(type, name, controlName, controlValue);
+ },
+ numberWidth: 70,
+ layout: \line2,
+ margin: nil
+ );
+ }
+
+ setupEZRanger{
+ arg parent, control, value;
+ ^EZRanger(
+ parent: parent,
+ bounds: 300@16,
+ label: control,
+ controlSpec: control,
+ action: {
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/"++controlUnit.view.parent.name.asString,
+ name = controlUnit.view.parent.parent.parent.name.asSymbol,
+ controlName = controlUnit.labelView.string.asSymbol,
+ controlValue = controlUnit.value;
+ address.sendMsg(type, name, controlName, controlValue);
+ },
+ labelWidth: 120,
+ unitWidth:30
+ );
+ }
+
+ setupEZKnob{
+ arg parent, control, value, type, name;
+ ^EZKnob(
+ parent: parent,
+ bounds: 300@16,
+ label: control,
+ controlSpec: \freq,
+ action: {
+ arg controlUnit;
+ var address = NetAddr.new("127.0.0.1", NetAddr.langPort),
+ type = "/"++controlUnit.view.parent.name.asString,
+ name = controlUnit.view.parent.parent.parent.name.asSymbol,
+ controlName = controlUnit.labelView.string.asSymbol,
+ controlValue = controlUnit.value;
+ address.sendMsg(type, name, controlName, controlValue);
+ },
+ labelWidth: 120,
+ unitWidth:30
+ );
+ }
+}
+