Update to new libraries, add knobs for effects and transitions
authorMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Sun, 26 May 2013 21:09:08 +0000 (14:09 -0700)
committerMark Slee <mcslee@Mark-Slees-MacBook-Pro.local>
Sun, 26 May 2013 21:09:33 +0000 (14:09 -0700)
MarkSlee.pde
SugarCubes.pde
_Internals.pde
_Overlay.pde
code/GLucose.jar
code/HeronLX.jar

index 2df823a38efb823884e082a7995254aa7e86af69..07c8ce214728ac48ba66e4efe6ea28c8ef6b0cc0 100644 (file)
@@ -3,10 +3,10 @@ class SpaceTime extends SCPattern {
   SinLFO pos = new SinLFO(0, 15, 3000);
   SinLFO rate = new SinLFO(1000, 9000, 13000);
   SinLFO falloff = new SinLFO(10, 70, 5000);
-  float sat = 0;
-  
-  BasicKnob rateKnob = new BasicKnob("RATE", 0.5);
-  BasicKnob sizeKnob = new BasicKnob("SIZE", 0.5);
+  float angle = 0;
+
+  BasicParameter rateParameter = new BasicParameter("RATE", 0.5);
+  BasicParameter sizeParameter = new BasicParameter("SIZE", 0.5);
 
   public SpaceTime(GLucose glucose) {
     super(glucose);
@@ -14,22 +14,22 @@ class SpaceTime extends SCPattern {
     addModulator(rate).trigger();
     addModulator(falloff).trigger();    
     pos.modulateDurationBy(rate);
-    addKnob(rateKnob);
-    addKnob(sizeKnob);
+    addParameter(rateParameter);
+    addParameter(sizeParameter);
   }
-  
-  public void onKnobChange(Knob knob) {
-    if (knob == rateKnob) {
-        rate.stop().setValue(9000 - 8000*knob.getValuef());
-    } else if (knob == sizeKnob) {
-        falloff.stop().setValue(70 - 60*knob.getValuef());
+
+  public void onParameterChanged(LXParameter parameter) {
+    if (parameter == rateParameter) {
+      rate.stop().setValue(9000 - 8000*parameter.getValuef());
+    }  else if (parameter == sizeParameter) {
+      falloff.stop().setValue(70 - 60*parameter.getValuef());
     }
   }
 
   void run(int deltaMs) {    
-    sat += deltaMs * 0.00004;
-    float sVal1 = Strip.list.size() * (0.5 + 0.5*sin(sat));
-    float sVal2 = Strip.list.size() * (0.5 + 0.5*cos(sat));
+    angle += deltaMs * 0.0007;
+    float sVal1 = Strip.list.size() * (0.5 + 0.5*sin(angle));
+    float sVal2 = Strip.list.size() * (0.5 + 0.5*cos(angle));
 
     float pVal = pos.getValuef();
     float fVal = falloff.getValuef();
@@ -39,12 +39,13 @@ class SpaceTime extends SCPattern {
       int i = 0;
       for (Point p : strip.points) {
         colors[p.index] = color(
-        (lx.getBaseHuef() + s*.2 + i*3) % 360, 
-        min(100, min(abs(s - sVal1), abs(s - sVal2))), 
+        (lx.getBaseHuef() + 360 - p.fy*.2 + p.fz * .3) % 360, 
+        constrain(.4 * min(abs(s - sVal1), abs(s - sVal2)), 20, 100),
         max(0, 100 - fVal*abs(i - pVal))
           );
         ++i;
       }
+      ++s;
     }
   }
 }
@@ -99,21 +100,27 @@ class Swarm extends SCPattern {
 }
 
 class SwipeTransition extends SCTransition {
+  
+  final BasicParameter bleed = new BasicParameter("WIDTH", 0.5);
+  
   SwipeTransition(GLucose glucose) {
     super(glucose);
     setDuration(5000);
+    addParameter(bleed);
   }
 
   void computeBlend(int[] c1, int[] c2, double progress) {
-    float bleed = 50.;
-    float yPos = (float) (-bleed + progress * (255. + bleed));
+    float bleedf = 10 + bleed.getValuef() * 200.;
+    float yPos = (float) (-bleedf + progress * (255. + bleedf));
     for (Point p : Point.list) {
-      float d = (p.fy - yPos) / 50.;
+      float d = (p.fy - yPos) / bleedf;
       if (d < 0) {
         colors[p.index] = c2[p.index];
-      } else if (d > 1) {
+      } 
+      else if (d > 1) {
         colors[p.index] = c1[p.index];
-      } else {
+      } 
+      else {
         colors[p.index] = lerpColor(c2[p.index], c1[p.index], d, RGB);
       }
     }
@@ -126,23 +133,23 @@ class CubeEQ extends SCPattern {
   private LinearEnvelope[] bandVals = null;
   private int avgSize;
 
-  private final BasicKnob thrsh = new BasicKnob("LVL", 0.35);
-  private final BasicKnob range = new BasicKnob("RANG", 0.45);
-  private final BasicKnob edge = new BasicKnob("EDGE", 0.5);
-  private final BasicKnob speed = new BasicKnob("SPD", 0.5);
-  private final BasicKnob tone = new BasicKnob("TONE", 0.5);
-  private final BasicKnob clr = new BasicKnob("CLR", 0.5);
+  private final BasicParameter thrsh = new BasicParameter("LVL", 0.35);
+  private final BasicParameter range = new BasicParameter("RANG", 0.45);
+  private final BasicParameter edge = new BasicParameter("EDGE", 0.5);
+  private final BasicParameter speed = new BasicParameter("SPD", 0.5);
+  private final BasicParameter tone = new BasicParameter("TONE", 0.5);
+  private final BasicParameter clr = new BasicParameter("CLR", 0.5);
 
   public CubeEQ(GLucose glucose) {
     super(glucose);
-    addKnob(thrsh);
-    addKnob(range);
-    addKnob(edge);
-    addKnob(speed);
-    addKnob(tone);
-    addKnob(clr);
+    addParameter(thrsh);
+    addParameter(range);
+    addParameter(edge);
+    addParameter(speed);
+    addParameter(tone);
+    addParameter(clr);
   }
-  
+
   protected void onActive() {
     if (this.fft == null) {
       this.fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate());
@@ -160,7 +167,7 @@ class CubeEQ extends SCPattern {
     this.fft.forward(this.lx.audioInput().mix);
     float toneConst = .35 + .4 * (tone.getValuef() - 0.5);
     float edgeConst = 2 + 30*(edge.getValuef()*edge.getValuef()*edge.getValuef());
-    
+
     for (int i = 0; i < avgSize; ++i) {
       float value = this.fft.getAvg(i);
       value = 20*log(1 + sqrt(value));
@@ -169,11 +176,12 @@ class CubeEQ extends SCPattern {
       value *= 6;
       if (value > this.bandVals[i].getValue()) {
         this.bandVals[i].setEndVal(value, 40).trigger();
-      } else {
+      } 
+      else {
         this.bandVals[i].setEndVal(value, 1000 - 900*speed.getValuef()).trigger();
       }
     }
-    
+
     float jBase = 120 - 360*thrsh.getValuef();
     float jConst = 300.*(1-range.getValuef());
     float clrConst = 1.1 + clr.getValuef();
@@ -183,16 +191,87 @@ class CubeEQ extends SCPattern {
       int avgFloor = (int) avgIndex;
       float j = jBase + jConst * (p.fz / 128.);
       float value = lerp(
-        this.bandVals[avgFloor].getValuef(),
-        this.bandVals[avgFloor+1].getValuef(),
-        avgIndex-avgFloor
-      );
-      
+      this.bandVals[avgFloor].getValuef(), 
+      this.bandVals[avgFloor+1].getValuef(), 
+      avgIndex-avgFloor
+        );
+
       float b = constrain(edgeConst * (value - j), 0, 100);
       colors[p.index] = color(
-        (480 + lx.getBaseHuef() - min(clrConst*p.fz, 120)) % 360, 
-        100, 
-        b);
+      (480 + lx.getBaseHuef() - min(clrConst*p.fz, 120)) % 360, 
+      100, 
+      b);
+    }
+  }
+}
+
+class BoomEffect extends SCEffect {
+
+  final BasicParameter falloff = new BasicParameter("WIDTH", 0.5);
+  final BasicParameter speed = new BasicParameter("SPD", 0.5);
+  final BasicParameter bright = new BasicParameter("BRT", 1.0);
+  final BasicParameter sat = new BasicParameter("SAT", 0.2);
+  List<Layer> layers = new ArrayList<Layer>();
+
+  class Layer {
+    LinearEnvelope boom = new LinearEnvelope(-40, 500, 1300);
+
+    Layer() {
+      addModulator(boom);
+      trigger();
+    }
+
+    void trigger() {
+      float falloffv = falloffv();
+      boom.setRange(-100 / falloffv, 500 + 100/falloffv, 4000 - speed.getValuef() * 3300);
+      boom.trigger();
+    }
+
+    void doApply(int[] colors) {
+      float brightv = 100 * bright.getValuef();
+      float falloffv = falloffv();
+      float satv = sat.getValuef() * 100;
+      float huev = lx.getBaseHuef();
+      for (Point p : Point.list) {
+        colors[p.index] = blendColor(
+        colors[p.index], 
+        color(huev, satv, constrain(brightv - falloffv*abs(boom.getValuef() - dist(2*p.fx, p.fy, 2*p.fz, 128, 128, 128)), 0, 100)), 
+        ADD);
+      }
+    }
+  }
+
+  BoomEffect(GLucose glucose) {
+    super(glucose, true);
+    addParameter(falloff);
+    addParameter(speed);
+    addParameter(bright);
+    addParameter(sat);
+  }
+
+  public void onEnable() {
+    for (Layer l : layers) {
+      if (!l.boom.isRunning()) {
+        l.trigger();
+        return;
+      }
+    }
+    layers.add(new Layer());
+  }
+
+  private float falloffv() {
+    return 20 - 19 * falloff.getValuef();
+  }
+
+  public void onTrigger() {
+    onEnable();
+  }
+
+  public void doApply(int[] colors) {
+    for (Layer l : layers) {
+      if (l.boom.isRunning()) {
+        l.doApply(colors);
+      }
     }
   }
 }
index 8428367fd1e209e9bf78489f8fb8b24a9f55ca63..3a5354c95d266cc58118ed952ae63de99f56156d 100644 (file)
@@ -39,15 +39,16 @@ LXPattern[] patterns(GLucose glucose) {
 
 LXTransition[] transitions(GLucose glucose) {
   return new LXTransition[] {
-    new DissolveTransition(lx).setDuration(3000),
+    new DissolveTransition(lx),
     new SwipeTransition(glucose),
-    new FadeTransition(lx).setDuration(2000),
+    new FadeTransition(lx),
   };
 }
 
 LXEffect[] effects(GLucose glucose) {
   return new LXEffect[] {
     new FlashEffect(lx),
+    new BoomEffect(glucose),
     new DesaturationEffect(lx),
   };
 }
index d040f119426b9a9095b09fa75b4dc14d55cb17ed..c93129f958becf2fb399afd4d6bb00c6455e7c7e 100644 (file)
@@ -6,10 +6,12 @@
 
 import glucose.*;
 import glucose.control.*;
+import glucose.effect.*;
 import glucose.pattern.*;
 import glucose.transition.*;
 import glucose.model.*;
 import heronarts.lx.*;
+import heronarts.lx.control.*;
 import heronarts.lx.effect.*;
 import heronarts.lx.pattern.*;
 import heronarts.lx.modulator.*;
@@ -30,7 +32,6 @@ LXPattern[] patterns;
 LXTransition[] transitions;
 LXEffect[] effects;
 OverlayUI ui;
-int activeTransitionIndex = 0;
 
 void setup() {
   startMillis = lastMillis = millis();
@@ -38,6 +39,7 @@ void setup() {
   // Initialize the Processing graphics environment
   size(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, OPENGL);
   frameRate(TARGET_FRAMERATE);
+  noSmooth();
   // hint(ENABLE_OPENGL_4X_SMOOTH); // no discernable improvement?
   logTime("Created viewport");
 
@@ -59,8 +61,8 @@ void setup() {
   logTime("Built overlay UI");
   
   // MIDI devices
-  MidiKnobController.initializeStandardDevices(glucose);
-  logTime("Setup MIDI controllers");
+  SCMidiDevices.initializeStandardDevices(glucose);
+  logTime("Setup MIDI devices");
   
   println("Total setup: " + (millis() - startMillis) + "ms");
 }
@@ -86,9 +88,15 @@ void drawUI() {
 }
 
 boolean uiOn = true;
+boolean knobsOn = true;
 void keyPressed() {
-  if (key == 'u') {
-    uiOn = !uiOn;
+  switch (key) {
+    case 'u':
+      uiOn = !uiOn;
+      break;
+    case 'k':
+      knobsOn = !knobsOn;
+      break;
   }
 }
 
index e212e1e6e72f4dda3df1e5d4268462edd7a85d20..e21c9cdff0f5f4bd222ace65c4d2b770e7680edd 100644 (file)
@@ -6,15 +6,17 @@
 class OverlayUI {
   
   private final PFont titleFont = createFont("Myriad Pro", 10);
-  private final PFont itemFont = createFont("Myriad Pro", 11);
+  private final PFont itemFont = createFont("Lucida Grande", 11);
   private final PFont knobFont = titleFont;
   private final int w = 140;
   private final int leftPos;
   private final int leftTextPos;
   private final int lineHeight = 20;
   private final int sectionSpacing = 12;
+  private final int controlSpacing = 18;
   private final int tempoHeight = 20;
   private final int knobSize = 28;
+  private final float knobIndent = .4;  
   private final int knobSpacing = 6;
   private final int knobLabelHeight = 14;
   private final color lightBlue = #666699;
@@ -27,23 +29,45 @@ class OverlayUI {
   private PImage logo;
   
   private int firstPatternY;
+  private int firstPatternKnobY;
   private int firstTransitionY;
+  private int firstTransitionKnobY;
   private int firstEffectY;
-  private int firstKnobY;
+  private int firstEffectKnobY;
+
   private int tempoY;
   
   private Method patternStateMethod;
   private Method transitionStateMethod;
   private Method effectStateMethod;
   
+  private final int NUM_TRANSITION_KNOBS = 4;
+  private final int NUM_EFFECT_KNOBS = 4;
+  
+  private int activeTransitionIndex = 0;
+  private int activeEffectIndex = 0;
+  
+  private final VirtualTransitionKnob[] transitionKnobs;
+  private final VirtualEffectKnob[] effectKnobs;
+    
   OverlayUI() {
     leftPos = width - w;
     leftTextPos = leftPos + 4;
     logo = loadImage("logo-sm.png");
     
-    patternNames = classNameArray(patterns);
-    transitionNames = classNameArray(transitions);
-    effectNames = classNameArray(effects);    
+    patternNames = classNameArray(patterns, "Pattern");
+    transitionNames = classNameArray(transitions, "Transition");
+    effectNames = classNameArray(effects, "Effect");
+
+    transitionKnobs = new VirtualTransitionKnob[NUM_TRANSITION_KNOBS];
+    for (int i = 0; i < transitionKnobs.length; ++i) {
+      transitionKnobs[i] = new VirtualTransitionKnob(i);
+    }
+
+    effectKnobs = new VirtualEffectKnob[NUM_EFFECT_KNOBS];
+    for (int i = 0; i < effectKnobs.length; ++i) {
+      effectKnobs[i] = new VirtualEffectKnob(i);
+    }
 
     try {
       patternStateMethod = getClass().getMethod("getState", LXPattern.class);
@@ -71,11 +95,8 @@ class OverlayUI {
     int yPos = 0;    
     firstPatternY = yPos + lineHeight + 6;
     yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod);
-
-    yPos += sectionSpacing;
-    yPos = drawObjectList(yPos, "CONTROL", null, null, null);
-    yPos += 6;
-    firstKnobY = yPos;
+    yPos += controlSpacing;
+    firstPatternKnobY = yPos;
     int xPos = leftTextPos;
     for (int i = 0; i < glucose.NUM_PATTERN_KNOBS/2; ++i) {
       drawKnob(xPos, yPos, knobSize, glucose.patternKnobs[i]);
@@ -87,10 +108,26 @@ class OverlayUI {
     yPos += sectionSpacing;
     firstTransitionY = yPos + lineHeight + 6;
     yPos = drawObjectList(yPos, "TRANSITION", transitions, transitionNames, transitionStateMethod);
+    yPos += controlSpacing;
+    firstTransitionKnobY = yPos;
+    xPos = leftTextPos;
+    for (int i = 0; i < transitionKnobs.length; ++i) {
+      drawKnob(xPos, yPos, knobSize, transitionKnobs[i]);
+      xPos += knobSize + knobSpacing;
+    }
+    yPos += knobSize + knobLabelHeight;
     
     yPos += sectionSpacing;
     firstEffectY = yPos + lineHeight + 6;
     yPos = drawObjectList(yPos, "FX", effects, effectNames, effectStateMethod);
+    yPos += controlSpacing;
+    firstEffectKnobY = yPos;    
+    xPos = leftTextPos;
+    for (int i = 0; i < effectKnobs.length; ++i) {
+      drawKnob(xPos, yPos, knobSize, effectKnobs[i]);
+      xPos += knobSize + knobSpacing;
+    }
+    yPos += knobSize + knobLabelHeight;
     
     yPos += sectionSpacing;
     yPos = drawObjectList(yPos, "TEMPO", null, null, null);
@@ -110,7 +147,7 @@ class OverlayUI {
     text("Tap 'u' to hide UI (~+3FPS)", leftTextPos, height-6);
   }
   
-  public Knob getOrNull(List<Knob> items, int index) {
+  public LXParameter getOrNull(List<LXParameter> items, int index) {
     if (index < items.size()) {
       return items.get(index);
     }
@@ -138,7 +175,12 @@ class OverlayUI {
   }
   
   public int getState(LXEffect e) {
-    return e.isEnabled() ? STATE_ACTIVE : STATE_DEFAULT;
+    if (e.isEnabled()) {
+      return STATE_PENDING;
+    } else if (effects[activeEffectIndex] == e) {
+      return STATE_ACTIVE;
+    }
+    return STATE_DEFAULT;
   }
   
   public int getState(LXTransition t) {
@@ -151,7 +193,7 @@ class OverlayUI {
   }
 
   protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) {
-    return drawObjectList(yPos, title, items, classNameArray(items), stateMethod);
+    return drawObjectList(yPos, title, items, classNameArray(items, null), stateMethod);
   }
   
   private int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod) {
@@ -195,25 +237,42 @@ class OverlayUI {
     return yPos;
   }
   
-  private void drawKnob(int xPos, int yPos, int knobSize, Knob knob) {
-    final float knobIndent = .4;
+  private void drawKnob(int xPos, int yPos, int knobSize, LXParameter knob) {
+    if (!knobsOn) {
+      return;
+    }
     final float knobValue = knob.getValuef();
     String knobLabel = knob.getLabel();
-    if (knobLabel.length() > 4) {
-      knobLabel = knobLabel.substring(0, 4);
-    } else if (knobLabel.length() == 0) {
+    if (knobLabel == null) {
       knobLabel = "-";
+    } else if (knobLabel.length() > 4) {
+      knobLabel = knobLabel.substring(0, 4);
     }
     
     ellipseMode(CENTER);
     fill(#222222);
-    arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent));
-
+    // For some reason this arc call really crushes drawing performance. Presumably
+    // because openGL is drawing it and when we overlap the second set of arcs it
+    // does a bunch of depth buffer intersection tests? Ellipse with a trapezoid cut out is faster
+    // arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent));
+    ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize);
+    
+    float endArc = HALF_PI + knobIndent + (TWO_PI-2*knobIndent)*knobValue;
     fill(lightGreen);
-    arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent)*knobValue);
-
+    arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, endArc);
+    
+    // Center circle of knob
     fill(#333333);
     ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize/2, knobSize/2);
+
+    // Mask notch out of knob
+    fill(color(0, 0, 30));
+    beginShape();
+    vertex(xPos + knobSize/2 - 3, yPos + knobSize - 8);
+    vertex(xPos + knobSize/2 - 5, yPos + knobSize);
+    vertex(xPos + knobSize/2 + 5, yPos + knobSize);
+    vertex(xPos + knobSize/2 + 3, yPos + knobSize - 8);
+    endShape();
     
     fill(0);
     rect(xPos, yPos + knobSize + 2, knobSize, knobLabelHeight - 2);
@@ -224,62 +283,103 @@ class OverlayUI {
 
   }
   
-  private String[] classNameArray(Object[] objects) {
+  private String[] classNameArray(Object[] objects, String suffix) {
     if (objects == null) {
       return null;
     }
     String[] names = new String[objects.length];
     for (int i = 0; i < objects.length; ++i) {
-      names[i] = className(objects[i]);
+      names[i] = className(objects[i], suffix);
     }
     return names;
   }
   
-  private String className(Object p) {
+  private String className(Object p, String suffix) {
     String s = p.getClass().getName();
     int li;
     if ((li = s.lastIndexOf(".")) > 0) {
       s = s.substring(li + 1);
     }
     if (s.indexOf("SugarCubes$") == 0) {
-      return s.substring("SugarCubes$".length());
+      s = s.substring("SugarCubes$".length());
+    }
+    if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) {
+      s = s.substring(0, li);
     }
     return s;
   }
+
+  class VirtualTransitionKnob extends LXVirtualParameter {
+    private final int index;
+    
+    VirtualTransitionKnob(int index) {
+      this.index = index;
+    }
+    
+    public LXParameter getRealParameter() {
+      List<LXParameter> parameters = transitions[activeTransitionIndex].getParameters();
+      if (index < parameters.size()) {
+        return parameters.get(index);
+      }
+      return null;
+    }
+  }
+
+  class VirtualEffectKnob extends LXVirtualParameter {
+    private final int index;
+    
+    VirtualEffectKnob(int index) {
+      this.index = index;
+    }
+    
+    public LXParameter getRealParameter() {
+      List<LXParameter> parameters = effects[activeEffectIndex].getParameters();
+      if (index < parameters.size()) {
+        return parameters.get(index);
+      }
+      return null;
+    }
+  }
+  
+  private int patternKnobIndex = -1;
+  private int transitionKnobIndex = -1;
+  private int effectKnobIndex = -1;
   
-  private int knobIndex = -1;
   private int lastY;
   private int releaseEffect = -1;
   private boolean tempoDown = false;
 
   public void mousePressed() {
     lastY = mouseY;
-    knobIndex = -1;
+    patternKnobIndex = transitionKnobIndex = effectKnobIndex = -1;
     releaseEffect = -1;
     if (mouseY > tempoY) {
       if (mouseY - tempoY < tempoHeight) {
         lx.tempo.tap();
         tempoDown = true;
       }
+    } else if ((mouseY >= firstEffectKnobY) && (mouseY < firstEffectKnobY + knobSize + knobLabelHeight)) {
+      effectKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
     } else if (mouseY > firstEffectY) {
       int effectIndex = (mouseY - firstEffectY) / lineHeight;
       if (effectIndex < effects.length) {
-        if (effects[effectIndex].isMomentary()) {
+        if (activeEffectIndex == effectIndex) {
           effects[effectIndex].enable();
           releaseEffect = effectIndex;
-        } else {
-          effects[effectIndex].toggle();
         }
+        activeEffectIndex = effectIndex;        
       }
+    } else if ((mouseY >= firstTransitionKnobY) && (mouseY < firstTransitionKnobY + knobSize + knobLabelHeight)) {
+      transitionKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
     } else if (mouseY > firstTransitionY) {
       int transitionIndex = (mouseY - firstTransitionY) / lineHeight;
       if (transitionIndex < transitions.length) {
         activeTransitionIndex = transitionIndex;
       }
-    } else if ((mouseY >= firstKnobY) && (mouseY < firstKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) {
-      knobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
-      if (mouseY >= firstKnobY + knobSize + knobLabelHeight + knobSpacing) {
-        knobIndex += glucose.NUM_PATTERN_KNOBS / 2;
+    } else if ((mouseY >= firstPatternKnobY) && (mouseY < firstPatternKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) {
+      patternKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
+      if (mouseY >= firstPatternKnobY + knobSize + knobLabelHeight + knobSpacing) {
+        patternKnobIndex += glucose.NUM_PATTERN_KNOBS / 2;
       }      
     } else if (mouseY > firstPatternY) {
       int patternIndex = (mouseY - firstPatternY) / lineHeight;
@@ -293,9 +393,15 @@ class OverlayUI {
   public void mouseDragged() {
     int dy = lastY - mouseY;
     lastY = mouseY;
-    if (knobIndex >= 0 && knobIndex < glucose.NUM_PATTERN_KNOBS) {
-      Knob k = glucose.patternKnobs[knobIndex];
-      k.setValue(k.getValuef() + dy*.01);
+    if (patternKnobIndex >= 0 && patternKnobIndex < glucose.NUM_PATTERN_KNOBS) {
+      LXParameter p = glucose.patternKnobs[patternKnobIndex];
+      p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
+    } else if (effectKnobIndex >= 0 && effectKnobIndex < NUM_EFFECT_KNOBS) {
+      LXParameter p = effectKnobs[effectKnobIndex];
+      p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
+    } else if (transitionKnobIndex >= 0 && transitionKnobIndex < NUM_TRANSITION_KNOBS) {
+      LXParameter p = transitionKnobs[transitionKnobIndex];
+      p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
     }
   }
     
@@ -306,6 +412,7 @@ class OverlayUI {
       releaseEffect = -1;      
     }
   }
+  
 }
 
 void mousePressed() {
index 6ae9494db03c46ef1760edf5d567daf30ae4c0f4..48c8de6a9c2ad6f105c054cd2a66ee553cbbe686 100644 (file)
Binary files a/code/GLucose.jar and b/code/GLucose.jar differ
index 2724cc6f9ac1e35c17c8e5a0db2f16386395f128..e6ac53e47ae04653ee7759bff74f262a8011fd44 100644 (file)
Binary files a/code/HeronLX.jar and b/code/HeronLX.jar differ