diff --git a/MusicBeam/Effect.pde b/MusicBeam/Effect.pde index 4468f4a..de6c938 100644 --- a/MusicBeam/Effect.pde +++ b/MusicBeam/Effect.pde @@ -37,7 +37,7 @@ public abstract class Effect stg = controller.stage; frameRate = stg.frameRate; - int posy = 115+(i*50); + int posy = 115+(i*45); controlGroup = cp5.addGroup(getName()+"SettingsGroup").hide().setPosition(10,195).setWidth(395).setHeight(30); controlGroup.disableCollapse(); @@ -46,7 +46,7 @@ public abstract class Effect ctrl.activeEffect.addItem("("+triggeredByKey() + ") " + getName(),i); ctrl.activeSetting.addItem("settings"+getName(),i); - randomToggle = cp5.addToggle("random"+getName()).setSize(45, 45).setPosition(670, posy); + randomToggle = cp5.addToggle("random"+getName()).setSize(45, 40).setPosition(670, posy); randomToggle.getCaptionLabel().set("RND").align(ControlP5.CENTER, ControlP5.CENTER); randomToggle.setState(true); } @@ -157,4 +157,13 @@ public abstract class Effect if (key == 't') effect_manual_triggered = false; } -} \ No newline at end of file + + void midiMessage(MidiMessage message, long timestamp, String bus_name) { + int msg = (int)(message.getMessage()[0] & 0xFF) ; + int note = (int)(message.getMessage()[1] & 0xFF) ; + int vel = (int)(message.getMessage()[2] & 0xFF); + + // println("Effect midi: Bus " + bus_name + ": Msg: " + msg + " Note "+ note + ", vel " + vel); + + } +} diff --git a/MusicBeam/Midi_Effect.pde b/MusicBeam/Midi_Effect.pde new file mode 100644 index 0000000..26f9c16 --- /dev/null +++ b/MusicBeam/Midi_Effect.pde @@ -0,0 +1,847 @@ +import java.util.Iterator; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; + +class Midi_Effect extends Effect +{ + JSONObject jsonconfig; + JSONObject fxconfig; + JSONObject curveconfig; + + Midi_Effect(MusicBeam controller, int y) + { + super(controller, y); + + weightSlider = cp5.addSlider("weight"+getName()).setPosition(0, 5).setSize(395, 45).setRange(0, 100).setGroup(controlGroup); + weightSlider.getCaptionLabel().set("Weight").align(ControlP5.RIGHT, ControlP5.CENTER); + weightSlider.setValue(20); + + speedSlider = cp5.addSlider("speed"+getName()).setPosition(0, 55).setSize(395, 45).setRange(0, 1).setGroup(controlGroup); + speedSlider.getCaptionLabel().set("speed").align(ControlP5.RIGHT, ControlP5.CENTER); + speedSlider.setValue(0.3); + + hueSlider = cp5.addSlider("hue"+getName()).setRange(0, 360).setSize(345, 45).setPosition(50, 105).setGroup(controlGroup); + hueSlider.getCaptionLabel().set("hue").align(ControlP5.RIGHT, ControlP5.CENTER); + hueSlider.setValue(0); + HueControlListener hL = new HueControlListener(); + hueSlider.addListener(hL); + + aHueToggle = cp5.addToggle("ahue"+getName()).setPosition(0, 105).setSize(45, 45).setGroup(controlGroup); + aHueToggle.getCaptionLabel().set("A").align(ControlP5.CENTER, ControlP5.CENTER); + aHueToggle.setState(true); + + addLineUp = cp5.addButton("LnUp"+getName()).setSize(45, 45).setPosition(0, 155).setGroup(controlGroup); + addLineUp.getCaptionLabel().set("LnUp").align(ControlP5.CENTER, ControlP5.CENTER); + + addLineDown = cp5.addButton("LnDown"+getName()).setSize(45, 45).setPosition(50, 155).setGroup(controlGroup); + addLineDown.getCaptionLabel().set("LnDown").align(ControlP5.CENTER, ControlP5.CENTER); + + reloadConfigButton = cp5.addButton("reloadConfig").setSize(195, 95).setPosition(0, 205).setGroup(controlGroup).setValue(0); + reloadConfigButton.getCaptionLabel().set("Reload config").align(ControlP5.CENTER, ControlP5.CENTER); + + + fxBuffer.add(new ScreenFx()); + + reloadConfig(); + } + + Button reloadConfigButton; + + public void controlEvent(ControlEvent theEvent) { + println(theEvent.getController().getName()); + } + + public void reloadConfig() { + println("Reloading config"); + try { + jsonconfig = loadJSONObject("fxconfig.json"); + fxconfig = jsonconfig.getJSONObject("fx"); + curveconfig = jsonconfig.getJSONObject("curves"); + } catch(Exception ex) { + ex.printStackTrace(); + } + } + + public String getName() + { + return "Midi"; + } + + char triggeredByKey() { + return '0'; + } + + float rotation = 0.0f; + + Slider weightSlider, speedSlider, hueSlider; + + Toggle aHueToggle, bwToggle; + Button addLineUp; + Button addLineDown; + + int hue, weight; + float speed; + + public LinkedList fxBuffer = new LinkedList(); + + void draw() + { + //if (reloadConfigButton.isOn()) { + // reloadConfigButton.setOff(); + // reloadConfig(); + //} + + //println("rotation: "+ (rotation / PI)); + hue = int(hueSlider.getValue()); + weight = int(weightSlider.getValue()); + speed = speedSlider.getValue(); + + stg.stroke(hue, 100, 100); + stg.strokeWeight(weight); + stg.noFill(); + + rotation = (rotation+speed); + + + for(int i=0; i= 2 ) this.remove = true; + } + } + + class CirclePumpOutFx extends Fx { + public CirclePumpOutFx() {} + public void draw() { + super.draw(); + stg.stroke(hue, 100, 100); + stg.strokeWeight(weight); + stg.fill(0); + float r = 100+stg.getMaxRadius()*sin(this.rotation/2); + stg.ellipse(0,0,r,r); + if(this.rotation >= 2 ) this.remove = true; + } + } + + class WaveFx extends Fx { + public WaveFx() { + } + public void draw() { + super.draw(); + stg.stroke(hue, 100, 100); + stg.strokeWeight(weight); + stg.fill(0); + float r = 400*sin(this.rotation*4); + + float h = 300; + float w = stg.width/2; + float x = w/6; + stg.ellipse(-x,r+h,100,100); + stg.ellipse(x,h-r,100,100); + + stg.bezier( + -w,h, + -x,r+h, + x,h-r, + w,0+h + ); + if(this.rotation >= 24 ) this.remove = true; + } + } + + class WaveFlowFx extends Fx { + public WaveFlowFx() { + } + public void draw() { + super.draw(); + stg.stroke(hue, 100, 100); + stg.strokeWeight(weight); + stg.fill(0); + float r = 300;//*sin(this.rotation*4); + + float h = 300+50*sin(this.rotation*6); + float w = stg.width/2;//+stg.width*1/3; + float x = w/3;//stg.width*1/3; + float wd = x*this.rotation%(x/20*rate); + + stg.ellipse(wd,h+200,100,100); + //stg.ellipse(x,h-r,100,100); + + stg.bezier( + -w+wd,h, + -w+x+wd, h+r, + -w+x+x+wd, h-r, + 0+wd,0+h + ); + stg.bezier( + w+wd,h, + w-x+wd, h-r, + w-x-x+wd, h+r, + 0+wd,0+h + ); + stg.bezier( + -w-w+wd,h, + -w-w+x+wd, h+r, + -w-w+x+x+wd, h-r, + -w-0+wd,0+h + ); + if(this.rotation >= 24 ) this.remove = true; + } + } + + class ScreenFx extends Fx { + public ScreenFx() {} + public void draw() { + super.draw(); + stg.stroke(hue, 100, 100); + stg.strokeWeight(weight); + stg.noFill(); + + float h = 300+50*sin(this.rotation*6); + float w = stg.width/2;//+stg.width*1/3; + float x = w/3;//stg.width*1/3; + float wd = x*this.rotation%(x/20*rate); + float wi = stg.width; + float hi = stg.height; + + float s = sin(this.rotation); + float s1 = sin(this.rotation); + float s2 = sin(this.rotation*2); + float s3 = sin(this.rotation*3); + float s4 = sin(this.rotation*4); + float s5 = sin(this.rotation*5); + + float xmv1 = wi/3*s1; + float xmv2 = wi/3*s2; + float xmv3 = wi/3*s3; + float xmv4 = wi/3*s4; + float xmv5 = wi/3*s5; + + stg.stroke(hue, 100, 100); + + float[] coords = {-wi/2,0, -wi/2,0, -xmv1,s5*hi/3, 0+xmv4,-s2*hi/5, xmv3,s1*-hi/2, wi/2,0, wi/2,0}; + stg.smooth(); + stg.beginShape(); + for(int i=0; i= 5 ) this.remove = true; + } + } + + class SnowStormFx extends Fx { + public SnowStormFx() { + calcPoints(); + }; + LinkedList lr, lx, ly; + + int px, py, pts; + + int lauf = 0; + float radiusSliderValue = 80; // 50-200 + int hueSliderValue = 0; // 0-360 + boolean bwToggleState = true; + + void draw() + { + translate(-stg.width/2-lauf*speedSlider.getValue()*10, -stg.height/2); + for (int i=0;i=(2*radiusSliderValue/(speedSlider.getValue()*10))-1) { + lx.add(lx.remove()); + ly.add(ly.remove()); + lr.add(lr.remove()); + lauf=0; + } + else + lauf++; + + if (aHueToggle.getState()&& (isKick()&&isSnare())) + hueSlider.setValue((hueSlider.getValue()+60)%360); + } + + void calcPoints() { + px = int(stg.width/(2*radiusSliderValue))+2; + py = int(stg.height/(2*radiusSliderValue))+1; + pts = px*py; + lx = new LinkedList(); + ly = new LinkedList(); + lr = new LinkedList(); + for (int i=0;i it = fxconfig.keyIterator(); it.hasNext(); ) { + JSONObject o = fxconfig.getJSONObject(it.next()); + if(keyCode == o.getInt("keyCode")) { + fxBuffer.add(createObject(o.getJSONObject("FX"))); + } + } + + if (key == CODED) { + if (keyCode == LEFT) { + fxBuffer.add( + (new GoboFx()) + .gobo( + (new CurveGobo()) + .curve(PARABOLA_GOBO).smooth() + ) + .duration(2) + .start(0,0,0,1) + .end(0,0,2,2) + ); + } else if (keyCode == RIGHT) { + // fxBuffer.add(new LineDownFx()); + fxBuffer.add( + (new GoboFx()).gobo( + (new CurveGobo()).curve(LINE_GOBO).gobosize(1/7).smooth() + ) + .duration(4) + .start(-0.5,-0.5,0,1) + .end(1,1,-1,7) + ); + } else if (keyCode == 119) { + fxBuffer.add(new CirclePumpFx()); + } else if (keyCode == DOWN) { + fxBuffer.add( + (new GoboFx()).gobo( + (new CurveGobo()).curve(CIRCLE_GOBO).gobosize(1/7).nosmooth() + ) + .duration(4) + .start(0,0,0,1) + .end(0,0,0.5,7) + ); + } else if (keyCode == UP) { + Mod mod = new ModRotate(); + try { + Class classRef = Class.forName("Mod"); + mod = (Mod)classRef.newInstance(); + } catch(Exception e) {} + + fxBuffer.add( + (new GoboFx()).gobo( + (new CurveGobo()).curve(CIRCLE_GOBO).gobosize(1/50).smooth() + ) + .duration(2) + .addMod(mod) + .start(0,0,0,1) + //.end(0.5,0.5,0,1) + .end(1-random(1),1-random(1),0,2) + ); + } + } + } + + /* + { + "midinote": 48, + "keyCode": 65, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "CIRCLE_GOBO", + "gobosize": 0.02, + "smooth": null + } + }, + "duration": 2, + "addMod": {"Mod": null} + "start": [0,0,0,1], + "end": [0.5,0.5,0,1] + } + } + } + */ + Object createObject(JSONObject o) { + Object obj = null; + try { + + String className = (String)o.keyIterator().next(); + if (className!=null) { + // println("class: "+className); + Class c = Class.forName(this.getClass().getName()+"$"+className); + if(className.startsWith("MusicBeam$Midi_Effect")) { + Constructor constructor = c.getConstructor(Midi_Effect.class); + obj = constructor.newInstance(this); + } else if(className.startsWith("MusicBeam")) { + Constructor constructor = c.getConstructor(MusicBeam.class); + obj = constructor.newInstance(musicBeam); + } else { + Constructor constructor = c.getConstructor(Midi_Effect.class); + obj = constructor.newInstance(this); + } + + + JSONObject params = o.getJSONObject(className); + for (Iterator it = params.keyIterator(); it.hasNext(); ) { + String param = it.next(); + Object val = params.get(param); + if (val!=null && !params.isNull(param)) { + // println("PARAM: "+param+" = "+val); + if(val instanceof JSONObject) { + val = createObject((JSONObject)val); + } else if(val instanceof JSONArray) { + val = ((JSONArray)val).getFloatArray(); + } else if(val instanceof Number) { + val = params.getFloat(param); + } else { + val = params.getString(param); + } + try { + Class[] cArg; + if(val.getClass().isArray()) { + int ln = ((float[])val).length; + cArg = new Class[4]; + for(int i=0; i<4; i++) cArg[i] = float.class; + Method method = c.getMethod(param, float.class, float.class, float.class, float.class); + float[] valarr = (float[])val; + method.invoke(obj, valarr[0], valarr[1], valarr[2], valarr[3]); + } else { + cArg = new Class[1]; + cArg[0] = (val instanceof Number)?float.class:val.getClass(); + + if (val.getClass().getName().equals("MusicBeam$Midi_Effect$CurveGobo") + || val.getClass().getName().equals("MusicBeam$Midi_Effect$DotGobo")) { + cArg[0]=Gobo.class; + } + Method method = c.getMethod(param, cArg); + method.invoke(obj, val); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + try { + Method method = c.getMethod(param); + method.invoke(obj); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + } + + } catch(Exception e) { + e.printStackTrace(); + } + return obj; + } + + void midiMessage(MidiMessage message, long timestamp, String bus_name) { + // 144 - note, 176 = CC + int msg = (int)(message.getMessage()[0] & 0xFF) ; + int note = (int)(message.getMessage()[1] & 0xFF) ; + int vel = (int)(message.getMessage()[2] & 0xFF); + + if (msg==144) { // Note on + for (Iterator it = fxconfig.keyIterator(); it.hasNext(); ) { + JSONObject o = fxconfig.getJSONObject(it.next()); + if(note == o.getInt("midinote")) { + fxBuffer.add(createObject(o.getJSONObject("FX"))); + } + } + } + + } + abstract class Mod { + public float x = 1; + public float y = 1; + public float scaleX = 1; + public float scaleY = 1; + public Mod() {} + abstract public Fx mod(Fx fx); + } + class ModRotate extends Mod { + public ModRotate() { + } + public ModRotate(float x, float y, float scaleX, float scaleY) { + this.x = x; + this.y = y; + this.scaleX=scaleX; + this.scaleY=scaleY; + } + public Fx mod(Fx fx) { + float r = fx.rotation*2*PI/fx.duration; + fx.x = fx.x*this.scaleX*cos(r*this.x); + fx.y = fx.y*this.scaleY*sin(r*this.y); + return fx; + } + } + class ModRandom extends Mod { + public ModRandom() { + } + public ModRandom(float x, float y, float scaleX, float scaleY) { + this.x = x/2-random(x); + this.y = y/2-random(y); + this.scaleX=1+random(scaleX); + this.scaleY=1+random(scaleY); + } + public Fx mod(Fx fx) { + //float r = fx.rotation*2*PI/fx.duration; + fx.x = fx.x*this.scaleX+this.x; + fx.y = fx.y*this.scaleY+this.y; + return fx; + } + } + class Fx { + float x = 0; + float y = 0; + float scale = 1; + float angle = 0; + + float startx = x; + float starty = y; + float startscale = scale; + float startangle = angle; + + float finalx = startx; + float finaly = starty; + float finalscale = startscale; + float finalangle = startangle; + + float fxhue = hue; + float fxbw = 100; + float fillHue = 0; + float fillBw = -1; + + float rotation = 0; + float bpm = 120; + float framerate = 30; + float duration = 1; + float loop = duration; + boolean remove = false; + + public LinkedList modificators = new LinkedList(); + + public Fx() { + } + + public Fx addMod(Mod mod) { + modificators.push(mod); + return this; + } + public Fx modRotate(float x, float y, float scaleX, float scaleY) { + this.addMod(new ModRotate(x,y,scaleX,scaleY)); + return this; + } + public Fx modRandom(float x, float y, float scaleX, float scaleY) { + this.addMod(new ModRandom(x,y,scaleX,scaleY)); + return this; + } + + public Fx applyMod() { + this.rotation = this.rotation+getStep(); + if(this.rotation >= this.duration) this.remove = true; + + this.x = startx + ( (finalx-startx) * rotation ); + this.y = starty + ( (finaly-starty) * rotation );; + this.angle = startangle + ( (finalangle-startangle) * rotation ); + this.scale = startscale + ( (finalscale-startscale) * rotation ); + + Fx fx = this; + for(int i=0; i 0 ) { + // if (key == effectArray[i].triggeredByKey()) + // effectArray[i].activate(); + //} + if (effectArray[i].isActive()) + effectArray[i].midiMessage(message, timestamp, bus_name); + } + } +} void draw() { if (stage==null) @@ -224,25 +258,25 @@ void initControls() } void initRandomControls() { - randomToggle = cp5.addToggle("random").setSize(135, 45).setPosition(415, 10); + randomToggle = cp5.addToggle("random").setSize(135, 40).setPosition(415, 10); randomToggle.getCaptionLabel().set("Play Random").align(ControlP5.CENTER, ControlP5.CENTER); - randomTimeSlider = cp5.addSlider("randomTime").setSize(210, 45).setPosition(555, 10).setRange(1, 60); + randomTimeSlider = cp5.addSlider("randomTime").setSize(210, 40).setPosition(555, 10).setRange(1, 60); randomTimeSlider.getCaptionLabel().set("Random Time (s)").align(ControlP5.CENTER, ControlP5.CENTER); randomTimeSlider.setValue(20); - nextButton = cp5.addButton("next").setSize(350, 45).setPosition(415, 60); + nextButton = cp5.addButton("next").setSize(350, 40).setPosition(415, 60); nextButton.getCaptionLabel().set("Next Effect").align(ControlP5.CENTER, ControlP5.CENTER); - activeEffect = cp5.addRadioButton("activeEffects").setPosition(415, 115).setSize(250, 45).setItemsPerRow(1).setSpacingRow(5).setNoneSelectedAllowed(true); - activeSetting = cp5.addRadioButton("activeSettings").setPosition(720, 115).setSize(45, 45).setItemsPerRow(1).setSpacingRow(5); + activeEffect = cp5.addRadioButton("activeEffects").setPosition(415, 115).setSize(250, 40).setItemsPerRow(1).setSpacingRow(5).setNoneSelectedAllowed(true); + activeSetting = cp5.addRadioButton("activeSettings").setPosition(720, 115).setSize(45, 40).setItemsPerRow(1).setSpacingRow(5); } void initEffects() { initRandomControls(); - effectArray = new Effect[9]; + effectArray = new Effect[10]; effectArray[0] = new Blackout_Effect(this, 0); effectArray[1] = new Strobe_Effect(this, 1); effectArray[2] = new Scanner_Effect(this, 2); @@ -252,6 +286,7 @@ void initEffects() effectArray[6] = new Snowstorm_Effect(this, 6); effectArray[7] = new LaserBurst_Effect(this, 7); effectArray[8] = new Polygon_Effect(this, 8); + effectArray[9] = new Midi_Effect(this, 9); activeSetting.activate(0); @@ -287,6 +322,7 @@ void checkForUpdate() void keyPressed() { + println("KeyPressed: key: " + key + " keyCode: " + keyCode); if (effectArray!=null) for (int i = 0; i < effectArray.length; i++) { @@ -334,7 +370,7 @@ float getLevel() private boolean hasEnoughScreenDevices() { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); //<>// //<>// + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); //<>// GraphicsDevice[] gs = ge.getScreenDevices(); return gs.length > 1; } @@ -356,4 +392,8 @@ private void initAudioInput() bdFreq = new BeatDetect(in.bufferSize(), in.sampleRate()); bdSound = new BeatDetect(); -} \ No newline at end of file +} + +public void reloadConfig(int v) { + ((Midi_Effect)effectArray[9]).reloadConfig(); +} diff --git a/MusicBeam/Strobe_Effect.pde b/MusicBeam/Strobe_Effect.pde index 2419b10..e722078 100644 --- a/MusicBeam/Strobe_Effect.pde +++ b/MusicBeam/Strobe_Effect.pde @@ -109,4 +109,38 @@ public class Strobe_Effect extends Effect delaySlider.setValue(delaySlider.getValue()+1); } } -} \ No newline at end of file + + int midiHueH = 0; + int midiHueL = 0; + void midiMessage(MidiMessage message, long timestamp, String bus_name) { + int msg = (int)(message.getMessage()[0] & 0xFF) ; + int note = (int)(message.getMessage()[1] & 0xFF) ; + int vel = (int)(message.getMessage()[2] & 0xFF); + + println("StrobeEffect: Bus " + bus_name + ": Msg: " + msg + " Note "+ note + ", vel " + vel); + if (msg == 144) { + if(note==48) effect_manual_triggered = !effect_manual_triggered; + if(note==49) effect_manual_triggered = true; + else if(note==54) hatToggle.setState(!hatToggle.getState()); + else if(note==56) snareToggle.setState(!snareToggle.getState()); + else if(note==58) kickToggle.setState(!kickToggle.getState()); + else if(note==51) onsetToggle.setState(!onsetToggle.getState()); + else if(note==50) aHueToggle.setState(!aHueToggle.getState()); + else if(note==52) bwToggle.setState(!bwToggle.getState()); + + } else if (msg == 128) { + if(note==49) effect_manual_triggered = false; + } else if (msg == 176) + if (note == 20 ) { + int v = Math.round(vel * 30/127); + println("Strobo freq value: "+v); + delaySlider.setValue(v); + } else if(note == 21) { + midiHueH = vel; + } else if(note == 22) { + midiHueL = vel; + } + if(note == 21 || note == 22) hueSlider.setValue((midiHueL + midiHueH*127) * 360/(127*127)); + } + +} diff --git a/MusicBeam/fxconfig.json b/MusicBeam/fxconfig.json new file mode 100644 index 0000000..e717cf7 --- /dev/null +++ b/MusicBeam/fxconfig.json @@ -0,0 +1,524 @@ +{ + "curves": { + "LINE_GOBO": [-100,0, -100,0, 100,0, 100,0], + "TRIANGEL_GOBO": [0,100, -86,-50, 86,-50, 0,100], + "SQUARE_GOBO": [0,100, 100,0, 0,-100, -100,0, 0,100], + "CIRCLE_GOBO": [-70,70, 0,100, 70,70, 100,0, 70,-70, 0,-100, -70,-70, -100,0, -70,70, 0,100, 70,70], + "PARABOLA_GOBO": [ + -110,0, 0,100, 90,0, 0,-80, -70,0, + 0, 60, 50,0, 0,-40, -30,0, + 0, 20, 10,0, 0, 0, 0,0 + ] + }, + "fx": { + "CircleRotate": { + "midinote": 48, + "key": "a", + "keyCode": 65, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "CIRCLE_GOBO", + "gobosize": 0.02 + } + }, + "duration": 2, + "modRotate": [1.5, 1.5, 1.5, -0.4], + "start": [0, 0, 0, 1], + "end": [0.5, 0.5, 0, 2] + } + } + }, + + "PolyCircleGrow": { + "midinote": 49, + "key": "s", + "keyCode": 83, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "CIRCLE_GOBO", + "gobosize": 0.14, + "nosmooth": null + } + }, + "hue": 220, + "duration": 4, + "start": [0, 0, 0, 1], + "end": [0, 0, 1, 7] + } + } + }, + "PolyCircleGrowDot": { + "midinote": 61, + "key": "s", + "keyCode": 83, + "FX": { + "GoboFx": { + "gobo": { + "DotGobo": { + "curve": "CIRCLE_GOBO", + "gobosize": 0.14, + "nosmooth": null + } + }, + "bw": 0, + "fillbw": 0, + "duration": 4, + "start": [0, 0, 0, 1], + "end": [0, 0, 2, 7] + } + } + }, + + "Parabola": { + "midinote": 50, + "key": "d", + "keyCode": 68, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "PARABOLA_GOBO", + "gobosize": 0.04, + "smooth": null + } + }, + "duration": 2.0, + "start": [1.0, -0.5, 0.0, 1.0], + "end": [-0.0, 0.0, 5.0, 5.0] + } + } + }, + "ParabolaDot": { + "midinote": 62, + "key": "d", + "keyCode": 68, + "FX": { + "GoboFx": { + "gobo": { + "DotGobo": { + "curve": "PARABOLA_GOBO", + "gobosize": 0.04, + "smooth": null + } + }, + "bw": 0, + "fillbw": 0, + "duration": 2.0, + "start": [1.0, -0.5, 0.0, 1.0], + "end": [-0.0, 0.0, 5.0, 8.0] + } + } + }, + + "LineFlyLeft": { + "midinote": 51, + "key": "f", + "keyCode": 70, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 0.05, + "nosmooth": null + } + }, + "duration": 4.0, + "start": [-0.5, -1.0, 0.0, 1.0], + "end": [1.0, 1.0, -1.0,17.0] + } + } + }, + + "LineFlyRight": { + "midinote": 52, + "key": "g", + "keyCode": 71, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 0.05, + "nosmooth": null + } + }, + "duration": 4.0, + "start": [0.5, -1.0, 0.0, 1.0], + "end": [-1.0, 1.0, 1.0,10.0] + } + } + }, + + "LineTopDownSlow": { + "midinote": 53, + "key": "h", + "keyCode": 72, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 1.0, + "nosmooth": null + } + }, + "duration": 4.0, + "start": [0.0, -1.0, 0.0, 1.0], + "end": [0.0, 1.0, 0.0,1.0] + } + } + }, + + "LineDownTopSlow": { + "midinote": 54, + "key": "j", + "keyCode": 74, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 1.0, + "nosmooth": null + } + }, + "duration": 4.0, + "start": [0.0, 1.0, 0.0, 1.0], + "end": [0.0, -1.0, 0.0,1.0] + } + } + }, + + "LineCenterRotateRight": { + "midinote": 55, + "key": "k", + "keyCode": 75, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 1.0, + "nosmooth": null + } + }, + "modRotate": [0.1, 0.1, 1.3, 1], + "duration": 2, + "start": [-0.3, 0, 0, 1], + "end": [0.3, 0.0, 0.4, 1.0] + } + } + }, + + "LineCenterRotateLeft": { + "midinote": 56, + "key": "l", + "keyCode": 76, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 1.0, + "nosmooth": null + } + }, + "duration": 4.0, + "modRotate": [0, 10, 1, 0.3], + "start": [0, 0.3, 0, 3], + "end": [0.0, 0.3, 0.0, 3] + } + } + }, + + "Square": { + "midinote": 63, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "SQUARE_GOBO", + "gobosize": 0.5, + "nosmooth": null + } + }, + "duration": 2, + "start": [-0.3, 0, 0, 0.5], + "end": [0, 0, 1, 0.5] + } + } + }, + "SquareZoom": { + "midinote": 64, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "SQUARE_GOBO", + "gobosize": 0.2, + "nosmooth": null + } + }, + "duration": 2, + "start": [0, 0, 0.5, 0.5], + "end": [0, 0, 0.5, 4] + } + } + }, + + "Triangel": { + "midinote": 65, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "TRIANGEL_GOBO", + "gobosize": 0.5, + "nosmooth": null + } + }, + "duration": 2, + "modRotate": [0, 2, 1, 0.3], + "start": [0.5, 0, 0, 0.5], + "end": [-0.5, 0, 2, 0.7] + } + } + }, + "TriangelZoom": { + "midinote": 66, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "TRIANGEL_GOBO", + "gobosize": 0.2, + "nosmooth": null + } + }, + "duration": 2, + "start": [0, 0, 0.5, 0.5], + "end": [0, 0, 0.5, 7] + } + } + }, + + "TriangelRandom": { + "midinote": 67, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "TRIANGEL_GOBO", + "gobosize": 0.3, + "nosmooth": null + } + }, + "duration": 0.5, + "modRandom": [3, 2, 0, 0], + "start": [0, 0, 0, 1], + "end": [0, 0, 1, 1] + } + } + }, + + "CircleDotRandom": { + "midinote": 68, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "DotGobo": { + "curve": "CIRCLE_GOBO", + "gobosize": 0.3, + "nosmooth": null + } + }, + "bw": 0, + "fillbw": 0, + "duration": 0.5, + "modRandom": [3, 2, 0, 0], + "start": [0.3, 0, 1, 1], + "end": [-0.3, 0, 0, 1.5] + } + } + }, + + "LineRandomLR": { + "midinote": 69, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 0.3, + "nosmooth": null + } + }, + "duration": 1, + "modRandom": [3, 2, 1, 1], + "start": [0.5, 0, 0, 1], + "end": [-0.5, 0, 0.5, 1] + } + } + }, + + "LineRandomRL": { + "midinote": 70, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 0.3, + "nosmooth": null + } + }, + "duration": 1, + "modRandom": [3, 2, 1, 1], + "start": [-0.5, 0, 0, 1], + "end": [0.5, 0, 0.5, 1] + } + } + }, + + "Cross1": { + "midinote": 71, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 1, + "nosmooth": null + } + }, + "duration": 2, + "start": [0, 0, 0, 1], + "end": [0, 0, 0.5, 1] + } + } + }, + "Cross2": { + "midinote": 72, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "CurveGobo": { + "curve": "LINE_GOBO", + "gobosize": 1, + "nosmooth": null + } + }, + "duration": 2, + "start": [0, 0, 1, 1], + "end": [0, 0, 0.5, 1] + } + } + }, + + "DotLineRandomRL": { + "midinote": 73, + "key": "return", + "keyCode": 13, + "FX": { + "GoboFx": { + "gobo": { + "DotGobo": { + "curve": "CIRCLE_GOBO", + "gobosize": 0.3, + "nosmooth": null + } + }, + "bw": 0, + "fillbw": 60, + "duration": 2, + "modRandom": [0, 2, 1, 1], + "start": [-1.5, 0, 0, 1], + "end": [1.5, 0, 0, 1] + } + } + }, + + + "ScreenFx": { + "midinote": 57, + "key": "m", + "keyCode": 77, + "FX": { + "ScreenFx": { + "duration": 4.0, + "modRotate": [1,1,1,1], + "start": [0, 0.3, 0, 1], + "end": [0, 0.3, -0.5, 1.0] + } + } + }, + + "CirclePumpFx": { + "midinote": 58, + "key": "m", + "keyCode": 77, + "FX": { + "CirclePumpFx": { + "duration": 4.0, + "modRotate": [1,1,1,1], + "start": [0, 0.3, 0, 1], + "end": [0, 0.3, -0.5, 1.0] + } + } + }, + + "CirclePumpOutFx": { + "midinote": 59, + "key": "m", + "keyCode": 77, + "FX": { + "CirclePumpOutFx": { + "duration": 4.0, + "modRotate": [1,1,1,1], + "start": [0, 0.3, 0, 1], + "end": [0, 0.3, -0.5, 1.0] + } + } + }, + + "SnowStormFx": { + "midinote": 60, + "key": "m", + "keyCode": 77, + "FX": { + "SnowStormFx": { + "duration": 4, + "modRotate": [1,1,1,1], + "start": [0, 0.3, 0, 1], + "end": [0, 0.3, -0.5, 1.0] + } + } + } + + } +} \ No newline at end of file