X-Git-Url: https://git.piment-noir.org/?p=SugarCubes.git;a=blobdiff_plain;f=TimBavaro.pde;h=3fcd5b160353986498ff01793cd8cf64c5d05bf9;hp=d0fc6e5f7c0863c35674da2cb2af46501318e5f2;hb=8f4e6c99775f2724edf3cec488860eb68b06491c;hpb=5bbef307441c1c5d31ef1dc58cb824f5e904c4e2 diff --git a/TimBavaro.pde b/TimBavaro.pde index d0fc6e5..3fcd5b1 100644 --- a/TimBavaro.pde +++ b/TimBavaro.pde @@ -3,8 +3,9 @@ */ class TimSpheres extends SCPattern { private BasicParameter hueParameter = new BasicParameter("RAD", 1.0); + private BasicParameter periodParameter = new BasicParameter("PERIOD", 4000.0, 200.0, 10000.0); private final SawLFO lfo = new SawLFO(0, 1, 10000); - private final SinLFO sinLfo = new SinLFO(0, 1, 4000); + private final SinLFO sinLfo = new SinLFO(0, 1, periodParameter); private final float centerX, centerY, centerZ; class Sphere { @@ -18,6 +19,7 @@ class TimSpheres extends SCPattern { public TimSpheres(GLucose glucose) { super(glucose); addParameter(hueParameter); + addParameter(periodParameter); addModulator(lfo).trigger(); addModulator(sinLfo).trigger(); centerX = (model.xMax + model.xMin) / 2; @@ -41,7 +43,7 @@ class TimSpheres extends SCPattern { spheres[1].radius = 50; } - public void run(int deltaMs) { + public void run(double deltaMs) { // Access the core master hue via this method call float hv = hueParameter.getValuef(); float lfoValue = lfo.getValuef(); @@ -53,16 +55,16 @@ class TimSpheres extends SCPattern { spheres[0].radius = 100 * hueParameter.getValuef(); spheres[1].radius = 100 * hueParameter.getValuef(); - for (Point p : model.points) { + for (LXPoint p : model.points) { float value = 0; - color c = color(0, 0, 0); + color c = lx.hsb(0, 0, 0); for (Sphere s : spheres) { float d = sqrt(pow(p.x - s.x, 2) + pow(p.y - s.y, 2) + pow(p.z - s.z, 2)); float r = (s.radius); // * (sinLfoValue + 0.5)); value = max(0, 1 - max(0, d - r) / 10); - c = blendColor(c, color(((s.hue + lfoValue) % 1) * 360, 100, min(1, value) * 100), ADD); + c = blendColor(c, lx.hsb(((s.hue + lfoValue) % 1) * 360, 100, min(1, value) * 100), ADD); } colors[p.index] = c; @@ -124,8 +126,8 @@ class Vector3 { return distanceTo(v.x, v.y, v.z); } - float distanceTo(Point p) { - return distanceTo(p.fx, p.fy, p.fz); + float distanceTo(LXPoint p) { + return distanceTo(p.x, p.y, p.z); } void add(Vector3 other, float multiplier) { @@ -224,8 +226,8 @@ class TimRaindrops extends SCPattern { } // returns TRUE when this should die - boolean age(int ms) { - p.add(v, ms / 1000.0); + boolean age(double ms) { + p.add(v, (float) (ms / 1000.0)); return this.p.y < (0 - this.radius); } } @@ -239,26 +241,26 @@ class TimRaindrops extends SCPattern { raindrops = new LinkedList(); } - public void run(int deltaMs) { + public void run(double deltaMs) { leftoverMs += deltaMs; while (leftoverMs > msPerRaindrop) { leftoverMs -= msPerRaindrop; raindrops.add(new Raindrop()); } - for (Point p : model.points) { + for (LXPoint p : model.points) { color c = blendColor( - color(210, 20, (float)Math.max(0, 1 - Math.pow((model.yMax - p.fy) / 10, 2)) * 50), - color(220, 60, (float)Math.max(0, 1 - Math.pow((p.fy - model.yMin) / 10, 2)) * 100), + lx.hsb(210, 20, (float)Math.max(0, 1 - Math.pow((model.yMax - p.y) / 10, 2)) * 50), + lx.hsb(220, 60, (float)Math.max(0, 1 - Math.pow((p.y - model.yMin) / 10, 2)) * 100), ADD); for (Raindrop raindrop : raindrops) { - if (p.fx >= (raindrop.p.x - raindrop.radius) && p.fx <= (raindrop.p.x + raindrop.radius) && - p.fy >= (raindrop.p.y - raindrop.radius) && p.fy <= (raindrop.p.y + raindrop.radius)) { + if (p.x >= (raindrop.p.x - raindrop.radius) && p.x <= (raindrop.p.x + raindrop.radius) && + p.y >= (raindrop.p.y - raindrop.radius) && p.y <= (raindrop.p.y + raindrop.radius)) { float d = raindrop.p.distanceTo(p) / raindrop.radius; // float value = (float)Math.max(0, 1 - Math.pow(Math.min(0, d - raindrop.radius) / 5, 2)); if (d < 1) { - c = blendColor(c, color(raindrop.hue, 80, (float)Math.pow(1 - d, 0.01) * 100), ADD); + c = blendColor(c, lx.hsb(raindrop.hue, 80, (float)Math.pow(1 - d, 0.01) * 100), ADD); } } } @@ -300,16 +302,16 @@ class TimCubes extends SCPattern { } // returns TRUE if this should die - boolean age(int ms) { + boolean age(double ms) { if (!hasPeaked) { - value = value + (ms / 1000.0f * ((attackParameter.getValuef() + 0.01) * 5)); + value = value + (float) (ms / 1000.0f * ((attackParameter.getValuef() + 0.01) * 5)); if (value >= 1.0) { value = 1.0; hasPeaked = true; } return false; } else { - value = value - (ms / 1000.0f * ((decayParameter.getValuef() + 0.01) * 10)); + value = value - (float) (ms / 1000.0f * ((decayParameter.getValuef() + 0.01) * 10)); return value <= 0; } } @@ -329,7 +331,7 @@ class TimCubes extends SCPattern { flashes = new LinkedList(); } - public void run(int deltaMs) { + public void run(double deltaMs) { leftoverMs += deltaMs; float msPerFlash = 1000 / ((rateParameter.getValuef() + .01) * 100); while (leftoverMs > msPerFlash) { @@ -337,14 +339,14 @@ class TimCubes extends SCPattern { flashes.add(new CubeFlash()); } - for (Point p : model.points) { + for (LXPoint p : model.points) { colors[p.index] = 0; } for (CubeFlash flash : flashes) { float hue = (hueParameter.getValuef() + (hueVarianceParameter.getValuef() * flash.hue)) % 1.0; - color c = color(hue * 360, saturationParameter.getValuef() * 100, (flash.value) * 100); - for (Point p : flash.c.points) { + color c = lx.hsb(hue * 360, saturationParameter.getValuef() * 100, (flash.value) * 100); + for (LXPoint p : flash.c.points) { colors[p.index] = c; } } @@ -416,7 +418,7 @@ class TimPlanes extends SCPattern { float prevRamp = 0; float[] wobbleSpeeds = { 1.0/8, 1.0/4, 1.0/2, 1.0 }; - public void run(int deltaMs) { + public void run(double deltaMs) { float ramp = (float)lx.tempo.ramp(); if (ramp < prevRamp) { beat = (beat + 1) % 32; @@ -456,7 +458,7 @@ class TimPlanes extends SCPattern { Vector3 normalizedPoint = new Vector3(); - for (Point p : model.points) { + for (LXPoint p : model.points) { if (random(1.0) < derez) { continue; } @@ -464,19 +466,19 @@ class TimPlanes extends SCPattern { color c = 0; for (Plane plane : planes) { - normalizedPoint.x = p.fx - plane.center.x; - normalizedPoint.y = p.fy - plane.center.y; - normalizedPoint.z = p.fz - plane.center.z; + normalizedPoint.x = p.x - plane.center.x; + normalizedPoint.y = p.y - plane.center.y; + normalizedPoint.z = p.z - plane.center.z; float v = plane.rotation.rotatedY(normalizedPoint); float d = abs(v); final color planeColor; if (d <= thickness) { - planeColor = color(plane.hue, saturation, 100); + planeColor = lx.hsb(plane.hue, saturation, 100); } else if (d <= thickness * 2) { float value = 1 - ((d - thickness) / thickness); - planeColor = color(plane.hue, saturation, value * 100); + planeColor = lx.hsb(plane.hue, saturation, value * 100); } else { planeColor = 0; } @@ -496,15 +498,34 @@ class TimPlanes extends SCPattern { } /** - * Not very flushed out but pretty. + * Two spinning wheels, basically XORed together, with a color palette that should + * be pretty easy to switch around. Timed to the beat; also introduces "clickiness" + * which makes the movement non-linear throughout a given beat, giving it a nice + * dance feel. I'm not 100% sure that it's actually going to look like it's _on_ + * the beat, but that should be easy enough to adjust. + * + * It's particularly nice to turn down the clickiness and turn up derez during + * slow/beatless parts of the music and then revert them at the drop :) But maybe + * I shouldn't be listening to so much shitty dubstep while making these... */ class TimPinwheels extends SCPattern { + private BasicParameter horizSpreadParameter = new BasicParameter("HSpr", 0.75); + private BasicParameter vertSpreadParameter = new BasicParameter("VSpr", 0.5); + private BasicParameter vertOffsetParameter = new BasicParameter("VOff", 1.0); + private BasicParameter zSlopeParameter = new BasicParameter("ZSlp", 0.6); + private BasicParameter sharpnessParameter = new BasicParameter("Shrp", 0.25); + private BasicParameter derezParameter = new BasicParameter("Drez", 0.25); + private BasicParameter clickinessParameter = new BasicParameter("Clic", 0.5); + private BasicParameter hueParameter = new BasicParameter("Hue", 0.667); + private BasicParameter hueSpreadParameter = new BasicParameter("HSpd", 0.667); + float phase = 0; - private final int NUM_BLADES = 16; + private final int NUM_BLADES = 12; class Pinwheel { Vector2 center; int numBlades; + float realPhase; float phase; float speed; @@ -514,15 +535,22 @@ class TimPinwheels extends SCPattern { this.speed = speed; } - void age(int deltaMs) { - phase = (phase + deltaMs / 1000.0 * speed) % 1.0; + void age(float numBeats) { + int numSteps = numBlades; + + realPhase = (realPhase + numBeats / numSteps) % 2.0; + + float phaseStep = floor(realPhase * numSteps); + float phaseRamp = (realPhase * numSteps) % 1.0; + phase = (phaseStep + pow(phaseRamp, (clickinessParameter.getValuef() * 10) + 1)) / (numSteps * 2); +// phase = (phase + deltaMs / 1000.0 * speed) % 1.0; } boolean isOnBlade(float x, float y) { x = x - center.x; y = y - center.y; - float normalizedAngle = (atan2(x, y) / (2 * PI) + 1.5 + phase) % 1; + float normalizedAngle = (atan2(x, y) / (2 * PI) + 1 + phase) % 1; float v = (normalizedAngle * 4 * numBlades); int blade_num = floor((v + 2) / 4); return (blade_num % 2) == 0; @@ -530,35 +558,101 @@ class TimPinwheels extends SCPattern { } private final List pinwheels; + private final float[] values; TimPinwheels(GLucose glucose) { super(glucose); + addParameter(horizSpreadParameter); +// addParameter(vertSpreadParameter); + addParameter(vertOffsetParameter); + addParameter(zSlopeParameter); + addParameter(sharpnessParameter); + addParameter(derezParameter); + addParameter(clickinessParameter); + addParameter(hueParameter); + addParameter(hueSpreadParameter); + + pinwheels = new ArrayList(); + pinwheels.add(new Pinwheel(0, 0, NUM_BLADES, 0.1)); + pinwheels.add(new Pinwheel(0, 0, NUM_BLADES, -0.1)); + + this.updateHorizSpread(); + this.updateVertPositions(); + + values = new float[model.points.size()]; + } + + public void onParameterChanged(LXParameter parameter) { + if (parameter == horizSpreadParameter) { + updateHorizSpread(); + } else if (parameter == vertSpreadParameter || parameter == vertOffsetParameter) { + updateVertPositions(); + } + } + + private void updateHorizSpread() { float xDist = model.xMax - model.xMin; float xCenter = (model.xMin + model.xMax) / 2; - float yCenter = (model.yMin + model.yMax) / 2; + + float spread = horizSpreadParameter.getValuef() - 0.5; + pinwheels.get(0).center.x = xCenter - xDist * spread; + pinwheels.get(1).center.x = xCenter + xDist * spread; + } + + private void updateVertPositions() { + float yDist = model.yMax - model.yMin; + float yCenter = model.yMin + yDist * vertOffsetParameter.getValuef(); - pinwheels = new ArrayList(); - pinwheels.add(new Pinwheel(xCenter - xDist * 0.4, yCenter, NUM_BLADES, 0.1)); - pinwheels.add(new Pinwheel(xCenter + xDist * 0.4, yCenter, NUM_BLADES, -0.1)); + float spread = vertSpreadParameter.getValuef() - 0.5; + pinwheels.get(0).center.y = yCenter - yDist * spread; + pinwheels.get(1).center.y = yCenter + yDist * spread; } - public void run(int deltaMs) { + private float prevRamp = 0; + + public void run(double deltaMs) { + float ramp = lx.tempo.rampf(); + float numBeats = (1 + ramp - prevRamp) % 1; + prevRamp = ramp; + + float hue = hueParameter.getValuef() * 360; + // 0 -> -180 + // 0.5 -> 0 + // 1 -> 180 + float hueSpread = (hueSpreadParameter.getValuef() - 0.5) * 360; + + float fadeAmount = (float) (deltaMs / 1000.0) * pow(sharpnessParameter.getValuef() * 10, 1); + for (Pinwheel pw : pinwheels) { - pw.age(deltaMs); + pw.age(numBeats); } - for (Point p : model.points) { + float derez = derezParameter.getValuef(); + + float zSlope = (zSlopeParameter.getValuef() - 0.5) * 2; + + int i = -1; + for (LXPoint p : model.points) { + ++i; + int value = 0; for (Pinwheel pw : pinwheels) { - value += (pw.isOnBlade(p.fx, p.fy) ? 1 : 0); + value += (pw.isOnBlade(p.x, p.y - p.z * zSlope) ? 1 : 0); } if (value == 1) { - colors[p.index] = color(120, 0, 100); + values[i] = 1; +// colors[p.index] = lx.hsb(120, 0, 100); } else { - color c = colors[p.index]; - colors[p.index] = color(max(0, hue(c) - 10), min(100, saturation(c) + 10), brightness(c) - 5 ); + values[i] = max(0, values[i] - fadeAmount); + //color c = colors[p.index]; + //colors[p.index] = lx.hsb(max(0, lx.h(c) - 10), min(100, lx.s(c) + 10), lx.b(c) - 5 ); } + + if (random(1.0) >= derez) { + float v = values[i]; + colors[p.index] = lx.hsb((360 + hue + pow(v, 2) * hueSpread) % 360, 30 + pow(1 - v, 0.25) * 60, v * 100); + } } } } @@ -571,25 +665,25 @@ class TimPinwheels extends SCPattern { * it but there may be useful code here. */ class TimTrace extends SCPattern { - private Map> pointToNeighbors; - private Map pointToStrip; + private Map> pointToNeighbors; + private Map pointToStrip; // private final Map> stripToNearbyStrips; int extraMs; class MovingPoint { - Point currentPoint; + LXPoint currentPoint; float hue; private Strip currentStrip; private int currentStripIndex; private int direction; // +1 or -1 - MovingPoint(Point p) { + MovingPoint(LXPoint p) { this.setPointOnNewStrip(p); hue = random(360); } - private void setPointOnNewStrip(Point p) { + private void setPointOnNewStrip(LXPoint p) { this.currentPoint = p; this.currentStrip = pointToStrip.get(p); for (int i = 0; i < this.currentStrip.points.size(); ++i) { @@ -611,9 +705,9 @@ class TimTrace extends SCPattern { } void step() { - List neighborsOnOtherStrips = pointToNeighbors.get(this.currentPoint); + List neighborsOnOtherStrips = pointToNeighbors.get(this.currentPoint); - Point nextPointOnCurrentStrip = null; + LXPoint nextPointOnCurrentStrip = null; this.currentStripIndex += this.direction; if (this.currentStripIndex >= 0 && this.currentStripIndex < this.currentStrip.points.size()) { nextPointOnCurrentStrip = this.currentStrip.points.get(this.currentStripIndex); @@ -653,8 +747,8 @@ class TimTrace extends SCPattern { Map stripToCenter = new HashMap(); for (Strip s : model.strips) { Vector3 v = new Vector3(); - for (Point p : s.points) { - v.add(p.fx, p.fy, p.fz); + for (LXPoint p : s.points) { + v.add(p.x, p.y, p.z); } v.divide(s.points.size()); stripToCenter.put(s, v); @@ -678,24 +772,24 @@ class TimTrace extends SCPattern { return stripToNeighbors; } - private Map> buildPointToNeighborsMap() { - Map> m = new HashMap(); + private Map> buildPointToNeighborsMap() { + Map> m = new HashMap(); Map> stripToNearbyStrips = this.buildStripToNearbyStripsMap(); for (Strip s : model.strips) { List nearbyStrips = stripToNearbyStrips.get(s); - for (Point p : s.points) { - Vector3 v = new Vector3(p.fx, p.fy, p.fz); + for (LXPoint p : s.points) { + Vector3 v = new Vector3(p.x, p.y, p.z); - List neighbors = new ArrayList(); + List neighbors = new ArrayList(); for (Strip nearbyStrip : nearbyStrips) { - Point closestPoint = null; + LXPoint closestPoint = null; float closestPointDistance = 100000; - for (Point nsp : nearbyStrip.points) { - float distance = v.distanceTo(nsp.fx, nsp.fy, nsp.fz); + for (LXPoint nsp : nearbyStrip.points) { + float distance = v.distanceTo(nsp.x, nsp.y, nsp.z); if (closestPoint == null || distance < closestPointDistance) { closestPoint = nsp; closestPointDistance = distance; @@ -714,25 +808,94 @@ class TimTrace extends SCPattern { return m; } - private Map buildPointToStripMap() { - Map m = new HashMap(); + private Map buildPointToStripMap() { + Map m = new HashMap(); for (Strip s : model.strips) { - for (Point p : s.points) { + for (LXPoint p : s.points) { m.put(p, s); } } return m; } - public void run(int deltaMs) { - for (Point p : model.points) { + public void run(double deltaMs) { + for (LXPoint p : model.points) { color c = colors[p.index]; - colors[p.index] = color(hue(c), saturation(c), brightness(c) - 3); + colors[p.index] = lx.hsb(lx.h(c), lx.s(c), lx.b(c) - 3); } for (MovingPoint mp : movingPoints) { mp.step(); - colors[mp.currentPoint.index] = blendColor(colors[mp.currentPoint.index], color(mp.hue, 10, 100), ADD); + colors[mp.currentPoint.index] = blendColor(colors[mp.currentPoint.index], lx.hsb(mp.hue, 10, 100), ADD); + } + } +} + +class TimMetronome extends SCPattern { + private BasicParameter clickyParameter = new BasicParameter("CLICK", 0, 0, 10.0); + private BasicParameter derezParameter = new BasicParameter("DREZ", 0.5, 0, 1.0); + private BasicParameter driftParameter = new BasicParameter("DRIFT", 0, 0, 1.0); + private BasicParameter fadeParameter = new BasicParameter("FADE", 0.05, 0, 0.2); + private float modelWidth; + private int beatNum; + private float prevTempoRamp; + private LXProjection projection; + private float[] values; + private float[] hues; + + TimMetronome(GLucose glucose) { + super(glucose); + addParameter(clickyParameter); + addParameter(derezParameter); + addParameter(driftParameter); + addParameter(fadeParameter); + modelWidth = model.xMax - model.xMin; + projection = new LXProjection(model); + beatNum = 0; + prevTempoRamp = 0; + values = new float[model.points.size()]; + hues = new float[model.points.size()]; + } + + public void run(double deltaMs) { + float tempoRamp = lx.tempo.rampf(); + if (tempoRamp < prevTempoRamp) { + beatNum = (beatNum + 1) % 1000; + } + prevTempoRamp = tempoRamp; + + float phase = beatNum + pow(tempoRamp, 1.0 + clickyParameter.getValuef()); + + projection.reset(); + projection.translateCenter(model.xMin, model.yMin, model.cz); + projection.rotate(phase * 0.5 * PI, 0, 0, 1); + + projection.translate(driftParameter.getValuef() * tempoRamp * modelWidth * 0.5, 0, 0); + + float derezCutoff = derezParameter.getValuef(); + + float fadeMultiplier = (1.0 - fadeParameter.getValuef()); + + float armRadius = modelWidth * 0.1; + for (LXVector p : projection) { + boolean onArm = false; + if (abs(p.x) < armRadius) { + onArm = (p.y > 0) || (sqrt(pow(p.x, 2) + pow(p.y, 2)) < armRadius); + } + if (onArm) { + values[p.index] = 1.0; + hues[p.index] = (floor(phase / 4) * 90) % 360; + } else { + values[p.index] *= fadeMultiplier; + } + + float saturation = pow(1 - values[p.index], 0.5) * 0.7 + 0.3; + float brightness = values[p.index]; + + if (random(1.0) > derezCutoff) { + colors[p.index] = lx.hsb(hues[p.index], saturation * 100, brightness * 100); + } } } } +