X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=inline;f=MarkSlee.pde;h=c6d9eae7f0706d3ade4e12baf332258111097d14;hb=0137237dffbb4ffdfa3a995dd7daee5f1f15c982;hp=55f09227316d7491bb759e6d829d331e951fc795;hpb=cc8b3f8210cea5377cc7e28116626e7bc4defa7a;p=SugarCubes.git diff --git a/MarkSlee.pde b/MarkSlee.pde index 55f0922..c6d9eae 100644 --- a/MarkSlee.pde +++ b/MarkSlee.pde @@ -1,15 +1,221 @@ -class Flitters extends SCPattern { +class Pulley extends SCPattern { - static final int NUM_FLITTERS = 6; + final int NUM_DIVISIONS = 16; + private final Accelerator[] gravity = new Accelerator[NUM_DIVISIONS]; + private final Click[] delays = new Click[NUM_DIVISIONS]; - class Flitter { + private final Click reset = new Click(9000); + private boolean isRising = false; + + Pulley(GLucose glucose) { + super(glucose); + for (int i = 0; i < NUM_DIVISIONS; ++i) { + addModulator(gravity[i] = new Accelerator(0, 0, 0)); + addModulator(delays[i] = new Click(0)); + } + addModulator(reset).start(); + trigger(); + } + + private void trigger() { + isRising = !isRising; + int i = 0; + for (Accelerator g : gravity) { + if (isRising) { + g.setSpeed(random(40, 50), 0).start(); + } else { + g.setVelocity(0).setAcceleration(-420); + delays[i].setDuration(random(0, 500)).trigger(); + } + ++i; + } + } + + public void run(double deltaMs) { + if (reset.click()) { + trigger(); + } + int j = 0; + for (Click d : delays) { + if (d.click()) { + gravity[j].start(); + d.stop(); + } + ++j; + } + + for (Accelerator g : gravity) { + if (isRising) { + if (g.getValuef() > model.yMax) { + g.stop(); + } else if (g.getValuef() > model.yMax*.55) { + if (g.getVelocityf() > 10) { + g.setAcceleration(-16); + } else { + g.setAcceleration(0); + } + } + } else { + if (g.getValuef() < 0) { + g.setValue(-g.getValuef()); + g.setVelocity(-g.getVelocityf() * random(0.74, 0.84)); + } + } + } + + for (Point p : model.points) { + int i = (int) constrain((p.x - model.xMin) * NUM_DIVISIONS / (model.xMax - model.xMin), 0, NUM_DIVISIONS-1); + colors[p.index] = color( + (lx.getBaseHuef() + abs(p.x - model.cx)*.8 + p.y*.4) % 360, + constrain(130 - p.y*.8, 0, 100), + max(0, 100 - abs(p.y - gravity[i].getValuef())*4.) + ); + } + } +} + +class ViolinWave extends SCPattern { + + BasicParameter level = new BasicParameter("LVL", 0.45); + BasicParameter range = new BasicParameter("RNG", 0.5); + BasicParameter edge = new BasicParameter("EDG", 0.5); + BasicParameter release = new BasicParameter("RLS", 0.5); + BasicParameter speed = new BasicParameter("SPD", 0.5); + BasicParameter amp = new BasicParameter("AMP", 0.25); + BasicParameter period = new BasicParameter("WAVE", 0.5); + BasicParameter pSize = new BasicParameter("PSIZE", 0.5); + BasicParameter pSpeed = new BasicParameter("PSPD", 0.5); + BasicParameter pDensity = new BasicParameter("PDENS", 0.25); + + LinearEnvelope dbValue = new LinearEnvelope(0, 0, 10); + + ViolinWave(GLucose glucose) { + super(glucose); + addParameter(level); + addParameter(edge); + addParameter(range); + addParameter(release); + addParameter(speed); + addParameter(amp); + addParameter(period); + addParameter(pSize); + addParameter(pSpeed); + addParameter(pDensity); + + addModulator(dbValue); + } + + final List particles = new ArrayList(); + + class Particle { + + LinearEnvelope x = new LinearEnvelope(0, 0, 0); + LinearEnvelope y = new LinearEnvelope(0, 0, 0); + + Particle() { + addModulator(x); + addModulator(y); + } + + Particle trigger(boolean direction) { + float xInit = random(model.xMin, model.xMax); + float time = 3000 - 2500*pSpeed.getValuef(); + x.setRange(xInit, xInit + random(-40, 40), time).trigger(); + y.setRange(model.cy + 10, direction ? model.yMax + 50 : model.yMin - 50, time).trigger(); + return this; + } + + boolean isActive() { + return x.isRunning() || y.isRunning(); + } + + public void run(double deltaMs) { + if (!isActive()) { + return; + } + + float pFalloff = (30 - 27*pSize.getValuef()); + for (Point p : model.points) { + float b = 100 - pFalloff * (abs(p.x - x.getValuef()) + abs(p.y - y.getValuef())); + if (b > 0) { + colors[p.index] = blendColor(colors[p.index], color( + lx.getBaseHuef(), 20, b + ), ADD); + } + } + } + } + + float[] centers = new float[30]; + double accum = 0; + boolean rising = true; + + void fireParticle(boolean direction) { + boolean gotOne = false; + for (Particle p : particles) { + if (!p.isActive()) { + p.trigger(direction); + return; + } + } + particles.add(new Particle().trigger(direction)); + } + + public void run(double deltaMs) { + accum += deltaMs / (1000. - 900.*speed.getValuef()); + for (int i = 0; i < centers.length; ++i) { + centers[i] = model.cy + 30*amp.getValuef()*sin((float) (accum + (i-centers.length/2.)/(1. + 9.*period.getValuef()))); + } + + float zeroDBReference = pow(10, (50 - 190*level.getValuef())/20.); + float dB = 20*GraphicEQ.log10(lx.audioInput().mix.level() / zeroDBReference); + if (dB > dbValue.getValuef()) { + rising = true; + dbValue.setRangeFromHereTo(dB, 10).trigger(); + } else { + if (rising) { + for (int j = 0; j < pDensity.getValuef()*3; ++j) { + fireParticle(true); + fireParticle(false); + } + } + rising = false; + dbValue.setRangeFromHereTo(max(dB, -96), 50 + 1000*release.getValuef()).trigger(); + } + float edg = 1 + edge.getValuef() * 40; + float rng = (78 - 64 * range.getValuef()) / (model.yMax - model.cy); + float val = max(2, dbValue.getValuef()); + + for (Point p : model.points) { + int ci = (int) lerp(0, centers.length-1, (p.x - model.xMin) / (model.xMax - model.xMin)); + float rFactor = 1.0 - 0.9 * abs(p.x - model.cx) / (model.xMax - model.cx); + colors[p.index] = color( + (lx.getBaseHuef() + abs(p.x - model.cx)) % 360, + min(100, 20 + 8*abs(p.y - centers[ci])), + constrain(edg*(val*rFactor - rng * abs(p.y-centers[ci])), 0, 100) + ); + } + + for (Particle p : particles) { + p.run(deltaMs); + } + } +} + +class BouncyBalls extends SCPattern { + + static final int NUM_BALLS = 6; + + class BouncyBall { Accelerator yPos; TriangleLFO xPos = new TriangleLFO(0, model.xMax, random(8000, 19000)); + float zPos; - Flitter(int i) { + BouncyBall(int i) { addModulator(xPos).setBasis(random(0, TWO_PI)).start(); addModulator(yPos = new Accelerator(0, 0, 0)); + zPos = lerp(model.zMin, model.zMax, (i+2.) / (NUM_BALLS + 4.)); } void bounce(float midiVel) { @@ -33,8 +239,11 @@ class Flitters extends SCPattern { } } float falloff = 130.f / (12 + blobSize.getValuef() * 36); + float xv = xPos.getValuef(); + float yv = yPos.getValuef(); + for (Point p : model.points) { - float d = dist(p.x, p.y, xPos.getValuef(), yPos.getValuef()); + float d = sqrt((p.x-xv)*(p.x-xv) + (p.y-yv)*(p.y-yv) + .1*(p.z-zPos)*(p.z-zPos)); float b = constrain(130 - falloff*d, 0, 100); if (b > 0) { colors[p.index] = blendColor(colors[p.index], color( @@ -47,16 +256,16 @@ class Flitters extends SCPattern { } } - final Flitter[] flitters = new Flitter[NUM_FLITTERS]; + final BouncyBall[] balls = new BouncyBall[NUM_BALLS]; final BasicParameter bounce = new BasicParameter("BNC", .8); final BasicParameter flr = new BasicParameter("FLR", 0); final BasicParameter blobSize = new BasicParameter("SIZE", 0.5); - Flitters(GLucose glucose) { + BouncyBalls(GLucose glucose) { super(glucose); - for (int i = 0; i < flitters.length; ++i) { - flitters[i] = new Flitter(i); + for (int i = 0; i < balls.length; ++i) { + balls[i] = new BouncyBall(i); } addParameter(bounce); addParameter(flr); @@ -65,14 +274,14 @@ class Flitters extends SCPattern { public void run(double deltaMs) { setColors(#000000); - for (Flitter f : flitters) { - f.run(deltaMs); + for (BouncyBall b : balls) { + b.run(deltaMs); } } public boolean noteOnReceived(Note note) { - int pitch = (note.getPitch() + note.getChannel()) % NUM_FLITTERS; - flitters[pitch].bounce(note.getVelocity()); + int pitch = (note.getPitch() + note.getChannel()) % NUM_BALLS; + balls[pitch].bounce(note.getVelocity()); return true; } }