1 import processing
.core
.*;
2 import processing
.data
.*;
3 import processing
.event
.*;
4 import processing
.opengl
.*;
8 import processing
.serial
.*;
9 import java
.util
.LinkedHashMap
;
10 import toxi
.geom
.Vec3D
;
11 import toxi
.geom
.Matrix4x4
;
13 import heronarts
.lx
.font
.*;
14 import heronarts
.lx
.transition
.*;
15 import glucose
.transform
.*;
17 import heronarts
.lx
.pattern
.*;
18 import glucose
.pattern
.*;
19 import heronarts
.lx
.model
.*;
20 import toxi
.geom
.mesh2d
.*;
21 import heronarts
.lx
.client
.*;
23 import toxi
.util
.datatypes
.*;
24 import toxi
.math
.waves
.*;
25 import heronarts
.lx
.kinet
.*;
28 import toxi
.util
.events
.*;
29 import heronarts
.lx
.modulator
.*;
31 import glucose
.transition
.*;
32 import glucose
.effect
.*;
33 import glucose
.model
.*;
34 import toxi
.math
.conversion
.*;
35 import heronarts
.lx
.effect
.*;
36 import heronarts
.lx
.control
.*;
37 import glucose
.control
.*;
38 import toxi
.math
.noise
.*;
40 import heronarts
.lx
.*;
42 import heronarts
.lx
.audio
.*;
44 import java
.util
.HashMap
;
45 import java
.util
.ArrayList
;
47 import java
.io
.BufferedReader
;
48 import java
.io
.PrintWriter
;
49 import java
.io
.InputStream
;
50 import java
.io
.OutputStream
;
51 import java
.io
.IOException
;
53 public class SugarCubes
extends PApplet
{
56 * +-+-+-+-+-+ +-+-+-+-+-+
59 * +-+-+-+-+-+ | +-+-+-+-+ | +-+-+-+-+-+
61 * + THE + / / \ \ + CUBES +
62 * | |/ +-+-+-+-+-+-+-+ \| |
63 * +-+-+-+-+-+ | | +-+-+-+-+-+
70 * Welcome to the Sugar Cubes! This Processing sketch is a fun place to build
71 * animations, effects, and interactions for the platform. Most of the icky
72 * code guts are embedded in the GLucose library extension. If you're an
73 * artist, you shouldn't need to worry about any of that.
75 * Below, you will find definitions of the Patterns, Effects, and Interactions.
76 * If you're an artist, create a new tab in the Processing environment with
77 * your name. Implement your classes there, and add them to the list below.
80 public LXPattern
[] patterns(GLucose glucose
) {
81 return new LXPattern
[] {
85 new Cathedrals(glucose
),
86 new MidiMusic(glucose
),
89 new ViolinWave(glucose
),
90 new BouncyBalls(glucose
),
91 new SpaceTime(glucose
),
92 new ShiftingPlane(glucose
),
93 new AskewPlanes(glucose
),
94 new Blinders(glucose
),
95 new CrossSections(glucose
),
96 new Psychedelia(glucose
),
98 new Traktor(glucose
).setEligible(false),
99 new BassPod(glucose
).setEligible(false),
100 new CubeEQ(glucose
).setEligible(false),
101 new PianoKeyPattern(glucose
).setEligible(false),
110 new SineSphere(glucose
),
111 // new CubeCurl(glucose),
114 new HelixPattern(glucose
).setEligible(false),
117 new GlitchPlasma(glucose
),
118 new FireEffect(glucose
).setEligible(false),
119 new StripBounce(glucose
),
120 new SoundRain(glucose
).setEligible(false),
121 new SoundSpikes(glucose
).setEligible(false),
122 new FaceSync(glucose
),
126 new Balance(glucose
),
129 new TimPlanes(glucose
),
130 new TimPinwheels(glucose
),
131 new TimRaindrops(glucose
),
132 new TimCubes(glucose
),
133 // new TimTrace(glucose),
134 new TimSpheres(glucose
),
137 // new Sandbox(glucose),
138 new TowerParams(glucose
),
139 new DriveableCrossSections(glucose
),
140 new GranimTestPattern2(glucose
),
146 new JazzRainbow(glucose
),
149 new TelevisionStatic(glucose
),
150 new AbstractPainting(glucose
),
151 new Spirality(glucose
),
153 // Basic test patterns for reference, not art
154 new TestCubePattern(glucose
),
155 new TestTowerPattern(glucose
),
156 new TestProjectionPattern(glucose
),
157 new TestStripPattern(glucose
),
158 new TestBassMapping(glucose
),
159 new TestFloorMapping(glucose
),
160 new TestSpeakerMapping(glucose
),
161 new TestPerformancePattern(glucose
),
162 // new TestHuePattern(glucose),
163 // new TestXPattern(glucose),
164 // new TestYPattern(glucose),
165 // new TestZPattern(glucose),
170 public LXTransition
[] transitions(GLucose glucose
) {
171 return new LXTransition
[] {
172 new DissolveTransition(lx
),
173 new AddTransition(glucose
),
174 new MultiplyTransition(glucose
),
175 new OverlayTransition(glucose
),
176 new DodgeTransition(glucose
),
177 new SwipeTransition(glucose
),
178 new FadeTransition(lx
),
179 // new SubtractTransition(glucose), // similar to multiply - dh
180 // new BurnTransition(glucose), // similar to multiply - dh
181 // new ScreenTransition(glucose), // same as add -dh
182 // new SoftLightTransition(glucose), // same as overlay -dh
186 // Handles to globally triggerable effects
188 FlashEffect flash
= new FlashEffect(lx
);
189 BoomEffect boom
= new BoomEffect(glucose
);
190 BlurEffect blur
= new BlurEffect(glucose
);
191 QuantizeEffect quantize
= new QuantizeEffect(glucose
);
192 ColorFuckerEffect colorFucker
= new ColorFuckerEffect(glucose
);
197 colorFucker
.enable();
201 class SineSphere
extends SCPattern
{
202 private SinLFO yrot
= new SinLFO(0, TWO_PI
, 2000);
203 public final Projection sinespin
;
204 float modelrad
= sqrt((model
.xMax
)*(model
.xMax
) + (model
.yMax
)*(model
.yMax
) + (model
.zMax
)*(model
.zMax
));
208 float f1xcenter
, f1ycenter
, f1zcenter
, f2xcenter
, f2ycenter
, f2zcenter
; //second three are for an ellipse with two foci
209 private SinLFO vibration
;
210 private SinLFO surface
;
212 private SinLFO xbounce
;
213 public SinLFO ybounce
;
214 private SinLFO zbounce
;
215 float vibration_min
, vibration_max
, vperiod
;
216 public BasicParameter widthparameter
;
217 public BasicParameter huespread
;
218 public BasicParameter bouncerate
;
219 public BasicParameter bounceamp
;
223 public Sphery(float f1xcenter
, float f1ycenter
, float f1zcenter
, float vibration_min
, float vibration_max
, float vperiod
)
225 this.f1xcenter
= f1xcenter
;
226 this.f1ycenter
= f1ycenter
;
227 this.f1zcenter
= f1zcenter
;
228 this.vibration_min
= vibration_min
;
229 this.vibration_max
= vibration_max
;
230 this.vperiod
= vperiod
;
231 addParameter(bounceamp
= new BasicParameter("Amp", .5f
));
232 addParameter(bouncerate
= new BasicParameter("Rate", .5f
)); //ybounce.modulateDurationBy(bouncerate);
233 addParameter(widthparameter
= new BasicParameter("Width", .1f
));
234 addParameter(huespread
= new BasicParameter("Hue", .2f
));
236 addModulator( vx
= new SinLFO(-4000, 10000, 100000)).trigger() ;
237 //addModulator(xbounce = new SinLFO(model.xMax/3, 2*model.yMax/3, 2000)).trigger();
238 addModulator(ybounce
= new SinLFO(model
.yMax
/3, 2*model
.yMax
/3, 240000.f
/lx
.tempo
.bpm())).trigger(); //ybounce.modulateDurationBy
240 //addModulator(bounceamp); //ybounce.setMagnitude(bouncerate);
241 addModulator( vibration
= new SinLFO(vibration_min
, vibration_max
, 240000.f
/lx
.tempo
.bpm())).trigger(); //vibration.modulateDurationBy(vx);
244 public Sphery(float f1xcenter
, float f1ycenter
, float f1zcenter
, float f2xcenter
, float f2ycenter
, float f2zcenter
,
245 float vibration_min
, float vibration_max
, float vperiod
)
247 this.f1xcenter
= f1xcenter
;
248 this.f1ycenter
= f1ycenter
;
249 this.f1zcenter
= f1zcenter
;
250 this.f2xcenter
= f2xcenter
;
251 this.f2ycenter
= f2ycenter
;
252 this.f2zcenter
= f2zcenter
;
253 this.vibration_min
= vibration_min
;
254 this.vibration_max
= vibration_max
;
255 this.vperiod
= vperiod
;
256 //addModulator(xbounce = new SinLFO(model.xMax/3, 2*model.yMax/3, 2000)).trigger();
257 addModulator(ybounce
).trigger();
258 addModulator( vibration
= new SinLFO(vibration_min
, vibration_max
, lx
.tempo
.rampf())).trigger(); //vibration.modulateDurationBy(vx);
259 addParameter(widthparameter
= new BasicParameter("Width", .1f
));
260 addParameter(huespread
= new BasicParameter("Hue", .2f
));
268 public float distfromcirclecenter(float px
, float py
, float pz
, float f1x
, float f1y
, float f1z
)
270 return dist(px
, py
, pz
, f1x
, f1y
, f1z
);
272 //void updatespherey(deltaMs, )
273 public int spheryvalue (float px
, float py
, float pz
, float f1xc
, float f1yc
, float f1zc
)
275 //switch(sShpape.cur() ) {}
276 return lx
.hsb(constrain(huespread
.getValuef()*5*px
, 0, 360) , dist(px
, py
, pz
, f1xc
, f1yc
, f1zc
) ,
277 max(0, 100 - 100*widthparameter
.getValuef()*abs(dist(px
, py
, pz
, f1xcenter
, ybounce
.getValuef(), f1zcenter
)
278 - vibration
.getValuef() ) ) );
280 public int ellipsevalue(float px
, float py
, float pz
, float f1xc
, float f1yc
, float f1zc
, float f2xc
, float f2yc
, float f2zc
)
282 //switch(sShpape.cur() ) {}
283 return lx
.hsb(huespread
.getValuef()*5*px
, dist(model
.xMax
-px
, model
.yMax
-py
, model
.zMax
-pz
, f1xc
, f1yc
, f1zc
) ,
284 max(0, 100 - 100*widthparameter
.getValuef() *
285 abs( (dist(px
, py
, pz
, f1xc
, ybounce
.getValuef(), f1zc
) +
286 (dist(px
, py
, pz
, f2xc
, ybounce
.getValuef(), f2zc
) ) )/2
287 - 1.2f
*vibration
.getValuef() ) ) ) ;
290 public void run(double deltaMs
) {
291 float vv
= vibration
.getValuef();
292 float ybv
= ybounce
.getValuef();
299 final Sphery
[] spherys
;
300 SineSphere(GLucose glucose
)
303 sinespin
= new Projection(model
);
304 addModulator(yrot
).trigger();
305 //Sshape = addPick("Shape", , 1);
306 spherys
= new Sphery
[] {
307 new Sphery(model
.xMax
/4, model
.yMax
/2, model
.zMax
/2, modelrad
/16, modelrad
/8, 3000),
308 new Sphery(.75f
*model
.xMax
, model
.yMax
/2, model
.zMax
/2, modelrad
/20, modelrad
/10, 2000),
309 new Sphery(model
.xMax
/2, model
.yMax
/2, model
.zMax
/2, modelrad
/4, modelrad
/8, 2300),
314 // public void onParameterChanged(LXParameter parameter)
318 // for (Sphery s : spherys) {
319 // if (s == null) continue;
320 // double bampv = s.bounceamp.getValue();
321 // double brv = s.bouncerate.getValue();
322 // double tempobounce = lx.tempo.bpm();
323 // if (parameter == s.bounceamp)
325 // s.ybounce.setRange(bampv*model.yMax/3 , bampv*2*model.yMax/3, brv);
327 // else if ( parameter == s.bouncerate )
329 // s.ybounce.setDuration(120000./tempobounce);
334 public void run( double deltaMs
) {
335 float t
= lx
.tempo
.rampf();
336 float bpm
= lx
.tempo
.bpmf();
337 //spherys[1].run(deltaMs);
338 //spherys[2].run(deltaMs);
339 //spherys[3].run(deltaMs);]
340 sinespin
.reset(model
)
342 // Translate so the center of the car is the origin, offset by yPos
343 .translateCenter(model
, 0, 0, 0)
345 // Rotate around the origin (now the center of the car) about an X-vector
346 .rotate(yrot
.getValuef(), 0, 1, 0);
350 for (Point p
: model
.points
){
352 c
= blendColor(c
, spherys
[1].spheryvalue(p
.x
, p
.y
, p
.z
, .75f
*model
.xMax
, model
.yMax
/2, model
.zMax
/2), ADD
);
353 c
= blendColor(c
, spherys
[0].spheryvalue(p
.x
, p
.y
, p
.z
, model
.xMax
/4, model
.yMax
/4, model
.zMax
/2), ADD
);
354 c
= blendColor(c
, spherys
[2].spheryvalue(p
.x
, p
.y
, p
.z
, model
.xMax
/2, model
.yMax
/2, model
.zMax
/2),ADD
);
356 colors
[p
.index
] = lx
.hsb(lx
.h(c
), lx
.s(c
), lx
.b(c
));
365 // void keyPressed() {
369 // color CalcPoint(PVector Px)
371 // // if (spheremode == 0 )
375 // else if (spheremode == 1)
379 // c = blendColor(c, spherys[3].ellipsevalue(Px.x, Px.y, Px.z, model.xMax/4, model.yMax/4, model.zMax/4, 3*model.xMax/4, 3*model.yMax/4, 3*model.zMax/4),ADD);
382 // return lx.hsb(0,0,0);
383 // // else if(spheremode ==2)
385 // return lx.hsb(CalcCone( (xyz by = new xyz(0,spherys[2].ybounce.getValuef(),0) ), Px, mid) );
394 class CubeCurl
extends SCPattern
{
396 ArrayList
<PVector
> cubeorigin
= new ArrayList
<PVector
>();
397 ArrayList
<PVector
> centerlist
= new ArrayList
<PVector
>();
398 private SinLFO curl
= new SinLFO(0, Cube
.EDGE_HEIGHT
, 5000 );
400 private SinLFO bg
= new SinLFO(180, 220, 3000);
402 CubeCurl(GLucose glucose
){
404 addModulator(curl
).trigger();
405 addModulator(bg
).trigger();
406 this.CH
= Cube
.EDGE_HEIGHT
;
407 this.CW
= Cube
.EDGE_WIDTH
;
408 this.diag
= sqrt(CW
*CW
+ CW
*CW
);
411 ArrayList
<PVector
> centerlistrelative
= new ArrayList
<PVector
>();
412 for (int i
= 0; i
< model
.cubes
.size(); i
++){
413 Cube a
= model
.cubes
.get(i
);
414 cubeorigin
.add(new PVector(a
.x
, a
.y
, a
.z
));
415 centerlist
.add(centerofcube(i
));
420 //there is definitely a better way of doing this!
421 public PVector
centerofcube(int i
) {
422 Cube c
= model
.cubes
.get(i
);
424 println(" cube #: " + i
+ " c.x " + c
.x
+ " c.y " + c
.y
+ " c.z " + c
.z
);
425 PVector cubeangle
= new PVector(c
.rx
, c
.ry
, c
.rz
);
426 //println("raw x" + cubeangle.x + "raw y" + cubeangle.y + "raw z" + cubeangle.z);
427 PVector cubecenter
= new PVector(c
.x
+ CW
/2, c
.y
+ CH
/2, c
.z
+ CW
/2);
428 println("cubecenter unrotated: " + cubecenter
.x
+ " " +cubecenter
.y
+ " " +cubecenter
.z
);
429 PVector centerrot
= new PVector(cos(c
.rx
)*CW
/2 - sin(c
.rx
)*CW
/2, 0, cos(c
.rz
)*CW
/2 + sin(c
.rz
)*CW
/2);
430 // nCos*(y-o.y) - nSin*(z-o.z) + o.y
431 cubecenter
= PVector
.add(cubecenter
, centerrot
);
432 println( " cubecenter.x " + cubecenter
.x
+ " cubecenter.y " + cubecenter
.y
+ " cubecenter.z " + cubecenter
.z
+ " ");
439 public void run(double deltaMs
){
440 for (int i
=0; i
< model
.cubes
.size(); i
++) {
441 Cube c
= model
.cubes
.get(i
);
446 // for (Point p : c.points ){
447 // // colors[p.index]=color(0,0,0);
448 // //float dif = (p.y - c.y);
449 // //colors[p.index] = color( bg.getValuef() , 80 , dif < curl.getValuef() ? 80 : 0, ADD);
453 // else if (i%3 == 1) {
455 // for (Point p: c.points){
456 // colors[p.index]=color(0,0,0);
457 // float dif = (p.y - c.y);
458 // // colors[p.index] =
459 // // color(bg.getValuef(),
460 // // map(curl.getValuef(), 0, Cube.EDGE_HEIGHT, 20, 100),
461 // // 100 - 10*abs(dif - curl.getValuef()), ADD );
464 // else if (i%3 == 2){
465 // centerlist[i].sub(cubeorigin(i);
466 for (Point p
: c
.points
) {
467 PVector pv
= new PVector(p
.x
, p
.y
, p
.z
);
468 colors
[p
.index
] =color( constrain(4* pv
.dist(centerlist
.get(i
)), 0, 360) , 50, 100 );
469 // colors[p.index] =color(constrain(centerlist[i].x, 0, 360), constrain(centerlist[i].y, 0, 100), );
481 class HueTestHSB
extends SCPattern
{
482 BasicParameter HueT
= new BasicParameter("Hue", .5f
);
483 BasicParameter SatT
= new BasicParameter("Sat", .5f
);
484 BasicParameter BriT
= new BasicParameter("Bright", .5f
);
486 HueTestHSB(GLucose glucose
) {
492 public void run(double deltaMs
){
494 for (Point p
: model
.points
) {
496 c
= blendColor(c
, lx
.hsb(360*HueT
.getValuef(), 100*SatT
.getValuef(), 100*BriT
.getValuef()), ADD
);
500 if (now
% 1000 <= 20)
502 println("Hue: " + 360*HueT
.getValuef() + "Sat: " + 100*SatT
.getValuef() + "Bright: " + 100*BriT
.getValuef());
508 class TelevisionStatic
extends SCPattern
{
509 BasicParameter brightParameter
= new BasicParameter("BRIGHT", 1.0f
);
510 BasicParameter saturationParameter
= new BasicParameter("SAT", 1.0f
);
511 BasicParameter hueParameter
= new BasicParameter("HUE", 1.0f
);
512 SinLFO direction
= new SinLFO(0, 10, 3000);
514 public TelevisionStatic(GLucose glucose
) {
516 addModulator(direction
).trigger();
517 addParameter(brightParameter
);
518 addParameter(saturationParameter
);
519 addParameter(hueParameter
);
522 public void run(double deltaMs
) {
523 boolean d
= direction
.getValuef() > 5.0f
;
524 for (Point p
: model
.points
) {
525 colors
[p
.index
] = lx
.hsb((lx
.getBaseHuef() + random(hueParameter
.getValuef() * 360))%360, random(saturationParameter
.getValuef() * 100), random(brightParameter
.getValuef() * 100));
530 class AbstractPainting
extends SCPattern
{
534 SinLFO colorMod
= new SinLFO(0, 360, 5000);
535 SinLFO brightMod
= new SinLFO(0, model
.zMax
, 2000);
537 public AbstractPainting(GLucose glucose
) {
539 addModulator(colorMod
).trigger();
540 addModulator(brightMod
).trigger();
542 img
= loadImage("abstract.jpg");
546 public void run(double deltaMs
) {
547 for (Point p
: model
.points
) {
548 int c
= img
.get((int)((p
.x
/ model
.xMax
) * img
.width
), img
.height
- (int)((p
.y
/ model
.yMax
) * img
.height
));
549 colors
[p
.index
] = lx
.hsb(hue(c
) + colorMod
.getValuef()%360, saturation(c
), brightness(c
) - ((p
.z
- brightMod
.getValuef())/p
.z
));
554 class Spirality
extends SCPattern
{
555 final BasicParameter r
= new BasicParameter("RADIUS", 0.5f
);
561 Spirality(GLucose glucose
) {
564 for (Point p
: model
.points
) {
565 colors
[p
.index
] = lx
.hsb(0, 0, 0);
569 public void run(double deltaMs
) {
570 angle
+= deltaMs
* 0.007f
;
571 rad
+= deltaMs
* .025f
* direction
;
572 float x
= model
.xMax
/ 2 + cos(angle
) * rad
;
573 float y
= model
.yMax
/ 2 + sin(angle
) * rad
;
574 for (Point p
: model
.points
) {
575 float b
= dist(x
,y
,p
.x
,p
.y
);
577 colors
[p
.index
] = blendColor(
579 lx
.hsb(lx
.getBaseHuef() + 25, 10, map(b
, 0, 10, 100, 0)),
582 colors
[p
.index
] = blendColor(
584 lx
.hsb(25, 10, map(b
, 0, 10, 0, 15)),
588 if (rad
> model
.xMax
/ 2 || rad
<= .001f
) {
598 * This is a reusable equalizer class that lets you get averaged
599 * bands with dB scaling and smoothing.
601 public static class GraphicEQ
{
605 public final BasicParameter level
= new BasicParameter("LVL", 0.5f
);
606 public final BasicParameter range
= new BasicParameter("RNGE", 0.5f
);
607 public final BasicParameter slope
= new BasicParameter("SLOP", 0.5f
);
608 public final BasicParameter attack
= new BasicParameter("ATK", 0.5f
);
609 public final BasicParameter release
= new BasicParameter("REL", 0.5f
);
611 private final FFT fft
;
612 private final int numBands
;
614 private final LinearEnvelope
[] bandVals
;
616 public final static int DEFAULT_NUM_BANDS
= 16;
618 public GraphicEQ(LX lx
) {
619 this(lx
, DEFAULT_NUM_BANDS
);
623 * Note that the number of bands is a suggestion. Due to the FFT implementation
624 * the actual number may be slightly different.
626 public GraphicEQ(LX lx
, int num
) {
628 fft
= new FFT(lx
.audioInput().bufferSize(), lx
.audioInput().sampleRate());
629 fft
.window(FFT
.HAMMING
);
630 fft
.logAverages(50, num
/8);
631 numBands
= this.fft
.avgSize();
632 bandVals
= new LinearEnvelope
[numBands
];
633 for (int i
= 0; i
< bandVals
.length
; ++i
) {
634 (bandVals
[i
] = new LinearEnvelope(0, 0, 500)).trigger();
638 static final float logTen
= log(10);
639 public static float log10(float val
) {
640 return log(val
) / logTen
;
643 public float getLevel(int band
) {
644 return bandVals
[band
].getValuef();
647 public float getAverageLevel(int minBand
, int numBands
) {
649 for (int i
= minBand
; i
< minBand
+ numBands
; ++i
) {
650 avg
+= bandVals
[i
].getValuef();
656 public void run(double deltaMs
) {
657 fft
.forward(lx
.audioInput().mix
);
658 float zeroDBReference
= pow(10, 100*(1-level
.getValuef())/20.f
);
659 float decibelRange
= 12 + range
.getValuef() * 60;
660 float decibelSlope
= slope
.getValuef() * 60.f
/ numBands
;
661 for (int i
= 0; i
< numBands
; ++i
) {
662 float raw
= fft
.getAvg(i
);
663 float decibels
= 20*log10(raw
/ zeroDBReference
);
664 float positiveDecibels
= decibels
+ decibelRange
;
665 positiveDecibels
+= i
*decibelSlope
;
666 float value
= constrain(positiveDecibels
/ decibelRange
, 0, 1);
668 if (value
> bandVals
[i
].getValuef()) {
669 bandVals
[i
].setRangeFromHereTo(value
, attack
.getValuef() * 20).trigger();
672 for (LinearEnvelope band
: bandVals
) {
674 if (!band
.isRunning() && band
.getValuef() > 0) {
675 band
.setRangeFromHereTo(0, release
.getValuef() * 1600).trigger();
682 class TowerParams
extends SCPattern
684 BasicParameter hueoff
= new BasicParameter("Hueoff", 0.0f
);
685 BasicParameter hueSpan
= new BasicParameter("HueRange", 0.0f
);
686 BasicParameter t1
= new BasicParameter("T1", 0.0f
);
687 BasicParameter t2
= new BasicParameter("T2", 0.0f
);
688 BasicParameter t3
= new BasicParameter("T3", 0.0f
);
689 BasicParameter t4
= new BasicParameter("T4", 0.0f
);
690 BasicParameter t5
= new BasicParameter("T5", 0.0f
);
691 BasicParameter t6
= new BasicParameter("T6", 0.0f
);
692 BasicParameter t7
= new BasicParameter("T7", 0.0f
);
693 BasicParameter t8
= new BasicParameter("T8", 0.0f
);
694 BasicParameter t9
= new BasicParameter("T9", 0.0f
);
695 BasicParameter t10
= new BasicParameter("T10", 0.0f
);
696 BasicParameter t11
= new BasicParameter("T11", 0.0f
);
697 BasicParameter t12
= new BasicParameter("T12", 0.0f
);
698 BasicParameter t13
= new BasicParameter("T13", 0.0f
);
699 BasicParameter t14
= new BasicParameter("T14", 0.0f
);
700 BasicParameter t15
= new BasicParameter("T15", 0.0f
);
701 BasicParameter t16
= new BasicParameter("T16", 0.0f
);
703 ArrayList
<BasicParameter
> towerParams
;
706 TowerParams(GLucose glucose
) {
709 towerParams
= new ArrayList
<BasicParameter
>();
710 addParameter(hueoff
);
711 addParameter(hueSpan
);
721 towerParams
.add(t10
);
722 towerParams
.add(t11
);
723 towerParams
.add(t12
);
724 towerParams
.add(t13
);
725 towerParams
.add(t14
);
726 towerParams
.add(t15
);
727 towerParams
.add(t16
);
728 for(BasicParameter p
: towerParams
)
732 towerSize
= model
.towers
.size();
733 colorSpan
= 255 / towerSize
;
736 public void run(double deltaMs
)
740 for(int i
=0; i
<towerSize
;i
++)
742 t
= model
.towers
.get(i
);
743 for(Point p
: t
.points
)
745 if(p
.y
<towerParams
.get(i
).getValuef()*200)
747 colors
[p
.index
]=lx
.hsb(255 * hueoff
.getValuef()+colorSpan
* hueSpan
.getValuef() * i
, 255, 255);
754 public void clearALL()
756 for(Point p
: model
.points
)
763 class Sandbox
extends SCPattern
768 int pointrange
= model
.points
.size();
769 int striprange
= model
.strips
.size();
770 int facerange
= model
.faces
.size();
771 int cuberange
= model
.cubes
.size();
772 int towerrange
= model
.towers
.size();
775 Sandbox(GLucose glucose
) {
777 println("points "+pointrange
);
778 println("strips "+striprange
);
779 println("faces "+facerange
);
780 println("cubes "+cuberange
);
781 println("towers "+towerrange
);
784 public void run(double deltaMs
) {
790 c
= (c
+ 1) % towerrange
;
791 long col
= lx
.hsb(Math
.round(Math
.random()*255),255,255) ;
798 public void doDraw(int c
,long col
)
800 Tower t
= model
.towers
.get((int) c
);
801 for(Point p
: t
.points
)
803 colors
[p
.index
] = (int) col
;
808 class GranimTestPattern
extends GranimPattern
810 GranimTestPattern(GLucose glucose
)
813 addGraphic("myReds",new RedsGraphic(100));
814 int[] dots
= {0,128,0,128,0,128,0,128,0,128,0,128};
815 addGraphic("myOtherColors",new ColorDotsGraphic(dots
));
817 getGraphicByName("myOtherColors").position
=100;
820 public void run(double deltaMs
)
827 Graphic reds
= getGraphicByName("myReds");
828 Graphic others
= getGraphicByName("myOtherColors");
829 reds
.position
= reds
.position
+ 1 % 19000;
830 others
.position
= others
.position
+ 10 % 19000;
833 public void clearALL()
835 for(int i
= 0; i
< colors
.length
; i
++)
844 class GranimTestPattern2
extends GranimPattern
846 GranimTestPattern2(GLucose glucose
)
849 /*for(int i = 0;i < 100; i++)
851 Graphic g = addGraphic("myReds_"+i,new RedsGraphic(Math.round(Math.random() * 100)));
854 Graphic g
= addGraphic("myRandoms",new RandomsGranim(50));
860 public void run(double deltaMs
)
864 Graphic randomsGraphic
= getGraphicByName("myRandoms");
865 randomsGraphic
.position
= Math
.round(sin(count
)*1000)+5000;
868 public void clearALL()
870 for(Point p
: model
.points
)
879 class DriveableCrossSections
extends CrossSections
886 DriveableCrossSections(GLucose glucose
) {
890 public void addParams()
892 mode
= new BasicParameter("Mode", 0.0f
);
893 xd
= new BasicParameter("XD", 0.0f
);
894 yd
= new BasicParameter("YD", 0.0f
);
895 zd
= new BasicParameter("ZD", 0.0f
);
904 public void onParameterChanged(LXParameter p
) {
916 public void copyValuesToKnobs()
918 xd
.setValue(x
.getValue()/200);
919 yd
.setValue(y
.getValue()/115);
920 zd
.setValue(z
.getValue()/100);
923 public void copyKnobsToValues()
925 x
.setValue(xd
.getValue()*200);
926 y
.setValue(yd
.getValue()*115);
927 z
.setValue(zd
.getValue()*100);
930 public boolean interactive()
932 return Math
.round(mode
.getValuef())>0.5f
;
935 public void updateXYZVals()
939 xv
= xd
.getValuef()*200;
940 yv
= yd
.getValuef()*115;
941 zv
= zd
.getValuef()*100;
943 super.updateXYZVals();
949 //----------------------------------------------------------------------------------------------------------------------------------
950 public class Pong
extends DPat
{
951 SinLFO x
,y
,z
,dx
,dy
,dz
;
952 float cRad
; BasicParameter pSize
;
954 PVector v
= new PVector(), vMir
= new PVector();
956 Pong(GLucose glucose
) {
959 addModulator(dx
= new SinLFO(6000, 500, 30000 )).trigger();
960 addModulator(dy
= new SinLFO(3000, 500, 22472 )).trigger();
961 addModulator(dz
= new SinLFO(1000, 500, 18420 )).trigger();
962 addModulator(x
= new SinLFO(cRad
, mMax
.x
- cRad
, 0)).trigger(); x
.modulateDurationBy(dx
);
963 addModulator(y
= new SinLFO(cRad
, mMax
.y
- cRad
, 0)).trigger(); y
.modulateDurationBy(dy
);
964 addModulator(z
= new SinLFO(cRad
, mMax
.z
- cRad
, 0)).trigger(); z
.modulateDurationBy(dz
);
965 pSize
= addParam ("Size" , 0.4f
);
966 pChoose
= addPick ("Animiation" , 2, 2, new String
[] {"Pong", "Ball", "Cone"} );
969 public void StartRun(double deltaMs
) { cRad
= mMax
.x
*val(pSize
)/6; }
970 public int CalcPoint(PVector p
) {
971 v
.set(x
.getValuef(), y
.getValuef(), z
.getValuef());
972 v
.z
=0;p
.z
=0;// ignore z dimension
973 switch(pChoose
.Cur()) {
974 case 0: vMir
.set(mMax
); vMir
.sub(p
);
975 return lx
.hsb(lxh(),100,c1c(1 - min(v
.dist(p
), v
.dist(vMir
))*.5f
/cRad
)); // balls
976 case 1: return lx
.hsb(lxh(),100,c1c(1 - v
.dist(p
)*.5f
/cRad
)); // ball
977 case 2: vMir
.set(mMax
.x
/2,0,mMax
.z
/2);
978 return lx
.hsb(lxh(),100,c1c(1 - calcCone(p
,v
,vMir
) * max(.02f
,.45f
-val(pSize
)))); // spot
980 return lx
.hsb(0,0,0);
983 //----------------------------------------------------------------------------------------------------------------------------------
985 float xz
, yz
, zz
, hue
, speed
, angle
, den
;
986 float xoff
,yoff
,zoff
;
987 float sinAngle
, cosAngle
;
989 NDat () { isActive
=false; }
990 public boolean Active() { return isActive
; }
991 public void set (float _hue
, float _xz
, float _yz
, float _zz
, float _den
, float _speed
, float _angle
) {
993 hue
=_hue
; xz
=_xz
; yz
=_yz
; zz
=_zz
; den
=_den
; speed
=_speed
; angle
=_angle
;
994 xoff
= random(100e3f
); yoff
= random(100e3f
); zoff
= random(100e3f
);
998 public class Noise
extends DPat
1001 int XSym
=1,YSym
=2,RadSym
=3;
1002 float zTime
, zTheta
=0, zSin
, zCos
, rtime
, ttime
;
1003 BasicParameter pSpeed
, pDensity
, pSharp
;
1004 Pick pChoose
, pSymm
;
1006 NDat N
[] = new NDat
[_ND
];
1008 Noise(GLucose glucose
) {
1010 pSpeed
= addParam("Fast" , .55f
);
1011 pDensity
= addParam("Dens" , .5f
);
1012 pSharp
= addParam("Shrp" , 0);
1013 pSymm
= addPick("Symmetry" , 0, 3, new String
[] {"None", "X", "Y", "Radial"} );
1014 pChoose
= addPick("Animation", 6, 7, new String
[] {"Drip", "Cloud", "Rain", "Fire", "Machine", "Spark","VWave", "Wave"} );
1015 for (int i
=0; i
<_ND
; i
++) N
[i
] = new NDat();
1018 public void onActive() { zTime
= random(500); zTheta
=0; rtime
= 0; ttime
= 0; }
1020 public void StartRun(double deltaMs
) {
1021 zTime
+= deltaMs
*(val(pSpeed
)-.5f
)*.002f
;
1022 zTheta
+= deltaMs
*(spin()-.5f
)*.01f
;
1024 iSymm
= pSymm
.Cur();
1028 if (pChoose
.Cur() != CurAnim
) {
1029 CurAnim
= pChoose
.Cur(); ttime
= rtime
;
1030 pSpin
.reset(); zTheta
= 0;
1031 pDensity
.reset(); pSpeed
.reset();
1032 for (int i
=0; i
<_ND
; i
++) { N
[i
].isActive
= false; }
1035 // hue xz yz zz den mph angle
1036 case 0: N
[0].set(0 ,75 ,75 ,150,45 ,3 ,0 ); pSharp
.setValue(1 ); break; // drip
1037 case 1: N
[0].set(0 ,100,100,200,45 ,3 ,180); pSharp
.setValue(0 ); break; // clouds
1038 case 2: N
[0].set(0 ,2 ,400,2 ,20 ,3 ,0 ); pSharp
.setValue(.5f
); break; // rain
1039 case 3: N
[0].set(40 ,100,100,200,10 ,1 ,180);
1040 N
[1].set(0 ,100,100,200,10 ,5 ,180); pSharp
.setValue(0 ); break; // fire 1
1041 case 4: N
[0].set(0 ,40 ,40 ,40 ,15 ,2.5f
,180);
1042 N
[1].set(20 ,40 ,40 ,40 ,15 ,4 ,0 );
1043 N
[2].set(40 ,40 ,40 ,40 ,15 ,2 ,90 );
1044 N
[3].set(60 ,40 ,40 ,40 ,15 ,3 ,-90); pSharp
.setValue(.5f
); break; // machine
1045 case 5: N
[0].set(0 ,400,100,2 ,15 ,3 ,90 );
1046 N
[1].set(20 ,400,100,2 ,15 ,2.5f
,0 );
1047 N
[2].set(40 ,100,100,2 ,15 ,2 ,180);
1048 N
[3].set(60 ,100,100,2 ,15 ,1.5f
,270); pSharp
.setValue(.5f
); break; // spark
1052 for (int i
=0; i
<_ND
; i
++) if (N
[i
].Active()) {
1053 N
[i
].sinAngle
= sin(radians(N
[i
].angle
));
1054 N
[i
].cosAngle
= cos(radians(N
[i
].angle
));
1058 public int CalcPoint(PVector p
) {
1060 rotateZ(p
, mCtr
, zSin
, zCos
);
1062 if (CurAnim
== 6 || CurAnim
== 7) {
1064 return lx
.hsb(lxh(),100, 100 * (
1065 constrain(1-50*(1-val(pDensity
))*abs(p
.y
-sin(zTime
*10 + p
.x
*(300))*.5f
- .5f
),0,1) +
1066 (CurAnim
== 7 ?
constrain(1-50*(1-val(pDensity
))*abs(p
.x
-sin(zTime
*10 + p
.y
*(300))*.5f
- .5f
),0,1) : 0))
1070 if (iSymm
== XSym
&& p
.x
> mMax
.x
/2) p
.x
= mMax
.x
-p
.x
;
1071 if (iSymm
== YSym
&& p
.y
> mMax
.y
/2) p
.y
= mMax
.y
-p
.y
;
1073 for (int i
=0;i
<_ND
; i
++) if (N
[i
].Active()) {
1075 float zx
= zTime
* n
.speed
* n
.sinAngle
,
1076 zy
= zTime
* n
.speed
* n
.cosAngle
;
1078 float b
= (iSymm
==RadSym ?
noise(zTime
*n
.speed
+n
.xoff
-p
.dist(mCtr
)/n
.xz
)
1079 : noise(p
.x
/n
.xz
+zx
+n
.xoff
,p
.y
/n
.yz
+zy
+n
.yoff
,p
.z
/n
.zz
+n
.zoff
))
1082 b
+= n
.den
/100 -.4f
+ val(pDensity
) -1;
1083 c
= blendColor(c
,lx
.hsb(lxh()+n
.hue
,100,c1c(b
)),ADD
);
1088 //----------------------------------------------------------------------------------------------------------------------------------
1089 public class Play
extends DPat
1091 public class rAngle
{
1092 float prvA
, dstA
, c
;
1093 float prvR
, dstR
, r
;
1094 float _cos
, _sin
, x
, y
;
1095 public float fixAngle (float a
, float b
) { return a
<b ?
1096 (abs(a
-b
) > abs(a
+2*PI
-b
) ? a
: a
+2*PI
) :
1097 (abs(a
-b
) > abs(a
-2*PI
-b
) ? a
: a
-2*PI
) ; }
1098 public float getX(float r
) { return mCtr
.x
+ _cos
*r
; }
1099 public float getY(float r
) { return mCtr
.y
+ _sin
*r
; }
1100 public void move() { c
= interp(t
,prvA
,dstA
);
1101 r
= interp(t
,prvR
,dstR
);
1102 _cos
= cos(c
); _sin
= sin(c
);
1103 x
= getX(r
); y
= getY(r
); }
1104 public void set() { prvA
= dstA
; dstA
= random(2*PI
); prvA
= fixAngle(prvA
, dstA
);
1105 prvR
= dstR
; dstR
= random(mCtr
.y
); }
1108 BasicParameter pAmp
, pRadius
, pBounce
;
1109 Pick pTimePattern
, pTempoMult
, pShape
;
1111 ArrayList
<rWave
> waves
= new ArrayList
<rWave
>(10);
1114 float t
,amp
,rad
,bnc
,zTheta
=0;
1116 rAngle a1
= new rAngle(), a2
= new rAngle(),
1117 a3
= new rAngle(), a4
= new rAngle();
1118 PVector cPrev
= new PVector(), cRand
= new PVector(),
1119 cMid
= new PVector(), V
= new PVector(),
1120 theta
= new PVector(), tSin
= new PVector(),
1121 tCos
= new PVector(), cMidNorm
= new PVector(),
1123 float LastBeat
=3, LastMeasure
=3;
1124 int curRandTempo
= 1, curRandTPat
= 1;
1126 Play(GLucose glucose
) {
1128 pRadius
= addParam("Rad" , .1f
);
1129 pBounce
= addParam("Bnc" , .2f
);
1130 pAmp
= addParam("Amp" , .2f
);
1131 pTempoMult
= addPick ("TMult" , 5 , 5 , new String
[] {"1x", "2x", "4x", "8x", "16x", "Rand" } );
1132 pTimePattern
= addPick ("TPat" , 7 , 7 , new String
[] {"Bounce", "Sin", "Roll", "Quant", "Accel", "Deccel", "Slide", "Rand"} );
1133 pShape
= addPick ("Shape" , 7 , 15 , new String
[] {"Line", "Tap", "V", "RandV",
1134 "Pyramid", "Wings", "W2", "Clock",
1135 "Triangle", "Quad", "Sphere", "Cone",
1136 "Noise", "Wave", "?", "?"} );
1139 public class rWave
{
1140 float v0
, a0
, x0
, t
,damp
,a
;
1141 boolean bDone
=false;
1143 rWave(float _x0
, float _a0
, float _v0
, float _damp
) { x0
=_x0
*len
; a0
=_a0
; v0
=_v0
; t
=0; damp
= _damp
; }
1144 public void move(double deltaMs
) {
1146 if (t
>4) bDone
=true;
1148 public float val(float _x
) {
1150 float dist
= t
*v0
- abs(_x
-x0
);
1151 if (dist
<0) { a
=1; return 0; }
1152 a
= a0
*exp(-dist
*damp
) * exp(-abs(_x
-x0
)/(.2f
*len
)); // * max(0,1-t/dur)
1153 return -a
*sin(dist
);
1157 public void onReset() { zTheta
=0; super.onReset(); }
1158 public void onActive() {
1160 while (lx
.tempo
.bpm() > 40) lx
.tempo
.setBpm(lx
.tempo
.bpm()/2);
1163 int KeyPressed
= -1;
1164 public boolean noteOn(Note note
) {
1165 int row
= note
.getPitch(), col
= note
.getChannel();
1166 if (row
== 57) {KeyPressed
= col
; return true; }
1167 return super.noteOn(note
);
1170 public void StartRun(double deltaMs
) {
1171 t
= lx
.tempo
.rampf();
1172 amp
= pAmp
.getValuef();
1173 rad
= pRadius
.getValuef();
1174 bnc
= pBounce
.getValuef();
1175 zTheta
+= deltaMs
*(val(pSpin
)-.5f
)*.01f
;
1177 theta
.set(val(pRotX
)*PI
*2, val(pRotY
)*PI
*2, val(pRotZ
)*PI
*2 + zTheta
);
1178 tSin
.set(sin(theta
.x
), sin(theta
.y
), sin(theta
.z
));
1179 tCos
.set(cos(theta
.x
), cos(theta
.y
), cos(theta
.z
));
1181 if (t
<LastMeasure
) {
1182 if (random(3) < 1) { curRandTempo
= PApplet
.parseInt(random(4)); if (curRandTempo
== 3) curRandTempo
= PApplet
.parseInt(random(4)); }
1183 if (random(3) < 1) { curRandTPat
= pShape
.Cur() > 6 ?
2+PApplet
.parseInt(random(5)) : PApplet
.parseInt(random(7)); }
1186 int nTempo
= pTempoMult
.Cur(); if (nTempo
== 5) nTempo
= curRandTempo
;
1187 int nTPat
= pTimePattern
.Cur(); if (nTPat
== 7) nTPat
= curRandTPat
;
1190 case 0: t
= t
; break;
1191 case 1: t
= (t
*2.f
)%1.f
; break;
1192 case 2: t
= (t
*4.f
)%1.f
; break;
1193 case 3: t
= (t
*8.f
)%1.f
; break;
1194 case 4: t
= (t
*16.f
)%1.f
; break;
1197 int i
=0; while (i
< waves
.size()) {
1198 rWave w
= waves
.get(i
);
1199 w
.move(deltaMs
); if (w
.bDone
) waves
.remove(i
); else i
++;
1202 if ((t
<LastBeat
&& pShape
.Cur()!=14) || KeyPressed
>-1) {
1203 waves
.add(new rWave(
1204 KeyPressed
>-1 ?
map(KeyPressed
,0,7,0,1) : random(1), // location
1205 bnc
*10, // bounciness
1207 2*(1-amp
))); // dampiness
1209 if (waves
.size() > 5) waves
.remove(0);
1213 cPrev
.set(cRand
); setRand(cRand
);
1214 a1
.set(); a2
.set(); a3
.set(); a4
.set();
1218 case 0: t
= sin(PI
*t
); break; // bounce
1219 case 1: t
= norm(sin(2*PI
*(t
+PI
/2)),-1,1); break; // sin
1220 case 2: t
= t
; break; // roll
1221 case 3: t
= constrain(PApplet
.parseInt(t
*8)/7.f
,0,1); break; // quant
1222 case 4: t
= t
*t
*t
; break; // accel
1223 case 5: t
= sin(PI
*t
*.5f
); break; // deccel
1224 case 6: t
= .5f
*(1-cos(PI
*t
)); break; // slide
1227 cMid
.set (cPrev
); interpolate(t
,cMid
,cRand
);
1228 cMidNorm
.set (cMid
); setNorm(cMidNorm
);
1229 a1
.move(); a2
.move(); a3
.move(); a4
.move();
1232 public int CalcPoint(PVector Px
) {
1233 if (theta
.x
!= 0) rotateX(Px
, mCtr
, tSin
.x
, tCos
.x
);
1234 if (theta
.y
!= 0) rotateY(Px
, mCtr
, tSin
.y
, tCos
.y
);
1235 if (theta
.z
!= 0) rotateZ(Px
, mCtr
, tSin
.z
, tCos
.z
);
1237 Pn
.set(Px
); setNorm(Pn
);
1239 float mp
= min(Pn
.x
, Pn
.z
);
1240 float yt
= map(t
,0,1,.5f
-bnc
/2,.5f
+bnc
/2);
1243 switch (pShape
.Cur()) {
1244 case 0: V
.set(Pn
.x
, yt
, Pn
.z
); break; // bouncing line
1245 case 1: V
.set(Pn
.x
, map(cos(PI
*t
* Pn
.x
),-1,1,0,1) , Pn
.z
); break; // top tap
1246 case 2: V
.set(Pn
.x
, bnc
*map(Pn
.x
<.5f?Pn
.x
:1-Pn
.x
,0,.5f
,0,t
-.5f
)+.5f
, Pn
.z
); break; // V shape
1247 case 3: V
.set(Pn
.x
, Pn
.x
< cMidNorm
.x ?
map(Pn
.x
,0,cMidNorm
.x
, .5f
,yt
) :
1248 map(Pn
.x
,cMidNorm
.x
,1, yt
,.5f
), Pn
.z
); break; // Random V shape
1250 case 4: V
.set(Pn
.x
, .5f
*(Pn
.x
< cMidNorm
.x ?
map(Pn
.x
,0,cMidNorm
.x
, .5f
,yt
) :
1251 map(Pn
.x
,cMidNorm
.x
,1, yt
,.5f
)) +
1252 .5f
*(Pn
.z
< cMidNorm
.z ?
map(Pn
.z
,0,cMidNorm
.z
, .5f
,yt
) :
1253 map(Pn
.z
,cMidNorm
.z
,1, yt
,.5f
)), Pn
.z
); break; // Random Pyramid shape
1255 case 5: V
.set(Pn
.x
, bnc
*map((Pn
.x
-.5f
)*(Pn
.x
-.5f
),0,.25f
,0,t
-.5f
)+.5f
, Pn
.z
); break; // wings
1256 case 6: V
.set(Pn
.x
, bnc
*map((mp
-.5f
)*(mp
-.5f
),0,.25f
,0,t
-.5f
)+.5f
, Pn
.z
); break; // wings
1259 distToSeg(Px
.x
, Px
.y
, a1
.getX(70),a1
.getY(70), mCtr
.x
, mCtr
.y
),
1260 distToSeg(Px
.x
, Px
.y
, a2
.getX(40),a2
.getY(40), mCtr
.x
, mCtr
.y
));
1261 d
= constrain(30*(rad
*40-d
),0,100);
1262 return lx
.hsb(lxh(),100, d
); // clock
1264 case 8: r
= amp
*200 * map(bnc
,0,1,1,sin(PI
*t
));
1266 distToSeg(Px
.x
, Px
.y
, a1
.getX(r
),a1
.getY(r
), a2
.getX(r
),a2
.getY(r
)),
1267 distToSeg(Px
.x
, Px
.y
, a2
.getX(r
),a2
.getY(r
), a3
.getX(r
),a3
.getY(r
)),
1268 distToSeg(Px
.x
, Px
.y
, a3
.getX(r
),a3
.getY(r
), a1
.getX(r
),a1
.getY(r
)) // triangle
1270 d
= constrain(30*(rad
*40-d
),0,100);
1271 return lx
.hsb(lxh(),100, d
); // clock
1273 case 9: r
= amp
*200 * map(bnc
,0,1,1,sin(PI
*t
));
1275 distToSeg(Px
.x
, Px
.y
, a1
.getX(r
),a1
.getY(r
), a2
.getX(r
),a2
.getY(r
)),
1276 distToSeg(Px
.x
, Px
.y
, a2
.getX(r
),a2
.getY(r
), a3
.getX(r
),a3
.getY(r
)),
1277 distToSeg(Px
.x
, Px
.y
, a3
.getX(r
),a3
.getY(r
), a4
.getX(r
),a4
.getY(r
)),
1278 distToSeg(Px
.x
, Px
.y
, a4
.getX(r
),a4
.getY(r
), a1
.getX(r
),a1
.getY(r
)) // quad
1280 d
= constrain(30*(rad
*40-d
),0,100);
1281 return lx
.hsb(lxh(),100, d
); // clock
1284 r
= map(bnc
,0,1,a1
.r
,amp
*200*sin(PI
*t
));
1285 return lx
.hsb(lxh(),100,c1c(.9f
+2*rad
- dist(Px
.x
,Px
.y
,a1
.getX(r
),a1
.getY(r
))*.03f
) ); // sphere
1288 Px
.z
=mCtr
.z
; cMid
.z
=mCtr
.z
;
1289 return lx
.hsb(lxh(),100,c1c(1 - calcCone(Px
,cMid
,mCtr
) * 0.02f
> .5f?
1:0)); // cone
1291 case 12: return lx
.hsb(lxh() + noise(Pn
.x
,Pn
.y
,Pn
.z
+ (NoiseMove
+50000)/1000.f
)*200,
1292 85,c1c(Pn
.y
< noise(Pn
.x
+ NoiseMove
/2000.f
,Pn
.z
)*(1+amp
)-amp
/2.f
-.1f ?
1 : 0)); // noise
1295 case 14: float y
=0; for (rWave w
: waves
) y
+= .5f
*w
.val(Pn
.x
); // wave
1296 V
.set(Pn
.x
, .7f
+y
, Pn
.z
);
1299 default: return lx
.hsb(0,0,0);
1302 return lx
.hsb(lxh(), 100, c1c(1 - V
.dist(Pn
)/rad
));
1305 //----------------------------------------------------------------------------------------------------------------------------------
1306 boolean dDebug
= false;
1308 dVertex vCur
, vNext
, vDest
;
1310 int posStop
, pos
,posNext
; // 0 - 65535
1315 public boolean isDone () { return pos
==posStop
; }
1316 public boolean atDest () { return vCur
.s
==vDest
.s
||
1317 xyDist(vCur
.getPoint(0), vDest
.getPoint(0)) < 12 ||
1318 xyDist(vCur
.getPoint(0), vDest
.getPoint(15))< 12;}
1319 public void setCur (dVertex _v
, int _p
) { p2
=null; vCur
=_v
; pos
=_p
; pickNext(); }
1320 public void setCur (dPixel _p
) { setCur(_p
.v
, _p
.pos
); }
1321 public void setNext (dVertex _v
, int _p
, int _s
) { vNext
= _v
; posNext
= _p
<<12; posStop
= _s
<<12; }
1322 public void setDest (dVertex _v
, float _speed
) { vDest
= _v
; destSpeed
= _speed
; }
1323 public void onDone () { setCur(vNext
, posNext
); pickNext(); }
1329 public void evaluate(dVertex v
, int p
, int s
) {
1330 if (v
== null) return; ++nTurns
;
1332 if (random(nTurns
) < 1) setNext(v
,p
,s
); return; }
1334 float d
= xyDist(v
.getPoint(15), vDest
.getPoint(0));
1335 if (d
< minDist
) { minDist
=d
; setNext(v
,p
,s
); }
1336 if (d
== minDist
&& random(2)<1) { minDist
=d
; setNext(v
,p
,s
); }
1340 public void evalTurn(dTurn t
) {
1341 if (t
== null || t
.pos0
<<12 <= pos
) return;
1342 evaluate(t
.v
, t
.pos1
, t
.pos0
);
1343 evaluate(t
.v
.opp
, 16-t
.pos1
, t
.pos0
);
1346 public void pickNext() {
1347 bRandEval
= random(.05f
+destSpeed
) < .05f
; minDist
=500; nTurns
=0;
1348 evaluate(vCur
.c0
, 0, 16); evaluate(vCur
.c1
, 0, 16);
1349 evaluate(vCur
.c2
, 0, 16); evaluate(vCur
.c3
, 0, 16);
1350 evalTurn(vCur
.t0
); evalTurn(vCur
.t1
);
1351 evalTurn(vCur
.t2
); evalTurn(vCur
.t3
);
1354 Point p1
, p2
; int i2
;
1356 public int draw(int nAmount
, SCPattern pat
) {
1357 int nFrom
= (pos
) >> 12;
1358 int nMv
= min(nAmount
, posStop
-pos
);
1359 int nTo
= min(15,(pos
+nMv
) >> 12);
1362 if (dDebug
) { p1
= v
.getPoint(nFrom
); float d
= (p2
== null ?
0 : pointDist(p1
,p2
)); if (d
>5) { println("too wide! quitting: " + d
); exit(); }}
1363 for (int i
= nFrom
; i
<= nTo
; i
++) { pat
.getColors()[v
.ci
+ v
.dir
*i
] = clr
; }
1364 if (v
.same
!= null) for (int i
= nFrom
; i
<= nTo
; i
++) { pat
.getColors()[v
.same
.ci
+ v
.same
.dir
*i
] = clr
; }
1366 if (dDebug
) { p2
= v
.getPoint(nTo
); i2
= nTo
; }
1368 pos
+= nMv
; return nAmount
- nMv
;
1372 //----------------------------------------------------------------------------------------------------------------------------------
1373 class Worms
extends SCPattern
{
1374 float StripsPerSec
= 10;
1375 float TrailTime
= 3000;
1376 int numCursors
= 50;
1377 ArrayList
<dCursor
> cur
= new ArrayList
<dCursor
>(30);
1379 private GraphicEQ eq
= null;
1381 private BasicParameter pBeat
= new BasicParameter("BEAT", 0);
1382 private BasicParameter pSpeed
= new BasicParameter("FAST", .2f
);
1383 private BasicParameter pBlur
= new BasicParameter("BLUR", .3f
);
1384 private BasicParameter pWorms
= new BasicParameter("WRMS", .3f
);
1385 private BasicParameter pConfusion
= new BasicParameter("CONF", .1f
);
1386 private BasicParameter pEQ
= new BasicParameter("EQ" , 0);
1387 private BasicParameter pSpawn
= new BasicParameter("DIR" , 0);
1388 private BasicParameter pColor
= new BasicParameter("CLR" , .1f
);
1390 float zMidLat
= 82.f
;
1392 private final Click moveChase
= new Click(1000);
1395 public int AnimNum() { return floor(pSpawn
.getValuef()*(4-.01f
)); }
1396 public float randX() { return random(model
.xMax
-model
.xMin
)+model
.xMin
; }
1397 public float randY() { return random(model
.yMax
-model
.yMin
)+model
.yMin
; }
1398 public PVector
randEdge() {
1399 return random(2) < 1 ?
new PVector(random(2)<1 ? model
.xMin
:model
.xMax
, randY(), zMidLat
) :
1400 new PVector(randX(), random(2)<1 ? model
.yMin
:model
.yMax
, zMidLat
) ;
1403 Worms(GLucose glucose
) {
1405 addModulator(moveChase
).start();
1406 addParameter(pBeat
); addParameter(pSpeed
);
1407 addParameter(pBlur
); addParameter(pWorms
);
1408 addParameter(pEQ
); addParameter(pConfusion
);
1409 addParameter(pSpawn
); addParameter(pColor
);
1411 middle
= new PVector(1.5f
*model
.cx
, 1.5f
*model
.cy
, 71);
1412 if (lattice
== null) lattice
= new dLattice();
1413 for (int i
=0; i
<numCursors
; i
++) { dCursor c
= new dCursor(); reset(c
); cur
.add(c
); }
1414 onParameterChanged(pEQ
); setNewDest();
1417 public void onParameterChanged(LXParameter parameter
) {
1418 super.onParameterChanged(parameter
);
1419 nConfusion
= 1-pConfusion
.getValuef();
1420 for (int i
=0; i
<numCursors
; i
++) {
1421 if (parameter
==pSpawn
) reset(cur
.get(i
));
1422 cur
.get(i
).destSpeed
= nConfusion
;
1426 public float getClr() { return lx
.getBaseHuef() + random(pColor
.getValuef()*300); }
1427 public void reset(dCursor c
) {
1429 case 0: c
.clr
= lx
.hsb(getClr(),100,100); // middle to edges
1430 c
.setDest(lattice
.getClosest(randEdge()).v
, nConfusion
);
1431 c
.setCur (lattice
.getClosest(middle
));
1434 case 1: c
.clr
= lx
.hsb(getClr(),100,100); // top to bottom
1435 float xLin
= randX();
1436 c
.setDest(lattice
.getClosest(new PVector(xLin
, 0 , zMidLat
)).v
, nConfusion
);
1437 c
.setCur (lattice
.getClosest(new PVector(xLin
, model
.yMax
, zMidLat
)));
1440 case 2: c
.clr
= lx
.hsb(getClr(),100,100); break; // chase a point around
1442 case 3: boolean bLeft
= random(2)<1;
1443 c
.clr
= lx
.hsb(getClr()+random(120),100,100); // sideways
1444 float yLin
= randX();
1445 c
.setDest(lattice
.getClosest(new PVector(bLeft ?
0 : model
.xMax
,yLin
,zMidLat
)).v
, nConfusion
);
1446 c
.setCur (lattice
.getClosest(new PVector(bLeft ? model
.xMax
: 0,yLin
,zMidLat
)));
1449 if (pBlur
.getValuef() == 1 && random(2)<1) c
.clr
= lx
.hsb(0,0,0);
1452 public void setNewDest() {
1453 if (AnimNum() != 2) return;
1454 PVector dest
= new PVector(randX(), randY(), zMidLat
);
1455 for (int i
=0; i
<numCursors
; i
++) {
1456 cur
.get(i
).setDest(lattice
.getClosest(dest
).v
, nConfusion
);
1457 cur
.get(i
).clr
= lx
.hsb(getClr()+75,100,100); // chase a point around
1461 public void run(double deltaMs
) {
1462 if (deltaMs
> 100) return;
1463 if (moveChase
.click()) setNewDest();
1465 float fBass
=0, fTreble
=0;
1466 if (pEQ
.getValuef()>0) { // EQ
1468 fBass
= eq
.getAverageLevel(0, 4);
1469 fTreble
= eq
.getAverageLevel(eq
.numBands
-7, 7);
1472 if (pBlur
.getValuef() < 1) { // trails
1473 for (int i
=0,s
=model
.points
.size(); i
<s
; i
++) {
1474 int c
= colors
[i
]; float b
= lx
.b(c
);
1475 if (b
>0) colors
[i
] = lx
.hsb(lx
.h(c
), lx
.s(c
), constrain((float)(b
-100*deltaMs
/(pBlur
.getValuef()*TrailTime
)),0,100));
1479 int nWorms
= floor(pWorms
.getValuef() * numCursors
*
1480 map(pEQ
.getValuef(),0,1,1,constrain(2*fTreble
,0,1)));
1482 for (int i
=0; i
<nWorms
; i
++) {
1483 dCursor c
= cur
.get(i
);
1484 int nLeft
= floor((float)deltaMs
*.001f
*StripsPerSec
* 65536 * (5*pSpeed
.getValuef()));
1485 nLeft
*= (1 - lx
.tempo
.rampf()*pBeat
.getValuef());
1487 nLeft
= c
.draw(nLeft
,this); if (!c
.isDone()) continue;
1488 c
.onDone(); if (c
.atDest()) reset(c
);
1494 public void onActive() { if (eq
== null) {
1495 eq
= new GraphicEQ(lx
, 16); eq
.slope
.setValue(0.6f
);
1496 eq
.level
.setValue(0.65f
); eq
.range
.setValue(0.35f
);
1497 eq
.release
.setValue(0.4f
);
1500 //----------------------------------------------------------------------------------------------------------------------------------
1501 class GenericController
{
1502 GenericController(){}
1503 public void RotateKnob(int type
, int num
, float val
){
1504 LXParameter p
= null;
1506 p
= glucose
.patternKnobs
.get(num
);
1507 if(p
!=null) { p
.setValue(val
); }
1510 p
= glucose
.transitionKnobs
.get(num
);
1511 if(p
!=null) { p
.setValue(val
); }
1514 p
= glucose
.effectKnobs
.get(num
);
1515 if(p
!=null) { p
.setValue(val
); }
1520 class MidiController
extends GenericController
{
1525 //PApplet xparent; // be sure to set
1531 //listener = new OscP5(this,7022);
1533 //boolean[] noteState = new boolean[16];
1535 //void controllerChangeReceived(rwmidi.Controller cc) {
1537 // println("CC: " + cc.toString());
1539 // if(cc.getCC()==1){
1540 // for(int i=0; i<16; i++){
1541 // if(noteState[i] && i<8) { LXParameter p = glucose.patternKnobs.get(i); p.setValue(cc.getValue()/127.0); }
1542 // else if(noteState[i] && i<12) { LXParameter p = glucose.transitionKnobs.get(i-8); p.setValue(cc.getValue()/127.0); }
1543 // else if(noteState[i] && i<16) { LXParameter p = glucose.effectKnobs.get(i-12); p.setValue(cc.getValue()/127.0); }
1548 //void noteOnReceived(Note note) {
1550 // println("Note On: " + note.toString());
1552 // int pitch = note.getPitch();
1553 // if(pitch>=36 && pitch <36+16){
1554 // noteState[pitch-36]=true;
1558 //void noteOffReceived(Note note) {
1560 // println("Note Off: " + note.toString());
1562 // int pitch = note.getPitch();
1563 // if(pitch>=36 && pitch <36+16){
1564 // noteState[pitch-36]=false;
1568 //void oscEvent(OscMessage theOscMessage) {
1569 // println(theOscMessage);
1570 // LXPattern currentPattern = lx.getPattern();
1571 // if (currentPattern instanceof OSCPattern) {
1572 // ((OSCPattern)currentPattern).oscEvent(theOscMessage);
1578 class ObjectMuckerEffect
extends SCEffect
{
1579 ObjectMuckerEffect(GLucose glucose
) {
1582 public void apply(int[] colors
){
1583 /*for(Strip s: model.strips){
1584 for(int i=0; i<s.points.size(); i++){
1585 int index = s.points.get(i).index;
1586 color c = colors[index];
1587 colors[index] = lx.hsb((i*22.5), saturation(c), brightness(c));
1593 class BlendFrames
extends SCEffect
{
1598 BlendFrames(GLucose glucose
) {
1603 frames
= new int[maxfbuf
][];
1604 for(int i
=0; i
<maxfbuf
; i
++){
1605 frames
[i
] = new int[model
.points
.size()];
1608 public void apply(int[] colors
) {
1610 for(int i
=0; i
<colors
.length
; i
++){
1611 frames
[(maxfbuf
-1)-fcount
][i
]=colors
[i
];
1616 for(int i
=maxfbuf
-1; i
>0; i
--){
1617 frames
[i
] = frames
[i
-1];
1619 frames
[0] = new int[model
.points
.size()];
1621 for(int i
=0; i
<colors
.length
; i
++){
1624 for(int j
=0; j
<blendfactor
; j
++){
1625 if(j
==0) { frames
[0][i
] = colors
[i
]; }
1626 r
+= ((frames
[j
][i
] >> 16) & 0xFF);
1627 g
+= ((frames
[j
][i
] >> 8) & 0xFF);
1628 b
+= ((frames
[j
][i
] >> 0) & 0xFF);
1634 colors
[i
] = (0xFF << 24) | (r
<< 16) | (g
<< 8) | b
;
1648 abstract class OSCPattern
extends SCPattern
{
1649 public OSCPattern(GLucose glucose
){super(glucose
);}
1650 public abstract void oscEvent(OscMessage msg
);
1654 public int lastSeen
;
1661 class OSC_Balls
extends OSCPattern
{
1663 public OSC_Balls(GLucose glucose
){
1665 balls
= new Ball
[20];
1666 for(int i
=0; i
<balls
.length
; i
++) { balls
[i
] = new Ball(); }
1668 public void oscEvent(OscMessage msg
){
1669 String pattern
[] = split(msg
.addrPattern(), "/");
1670 int ballnum
= PApplet
.parseInt(pattern
[3]);
1671 balls
[ballnum
].lastSeen
=millis();
1672 balls
[ballnum
].x
= msg
.get(0).floatValue();
1673 balls
[ballnum
].y
= msg
.get(1).floatValue();
1676 public void run(double deltaMs
){
1677 for(Point p
: model
.points
){ colors
[p
.index
]=0; }
1678 for(int i
=1; i
<balls
.length
; i
++){
1679 if(millis() - balls
[i
].lastSeen
< 1000) {
1680 for(Point p
: model
.points
){
1681 int x
= PApplet
.parseInt(balls
[i
].x
* 255.0f
);
1682 int y
= PApplet
.parseInt(balls
[i
].y
* 127.0f
);
1683 if(p
.x
< x
+4 && p
.x
> x
-4 && p
.y
< y
+4 && p
.y
> y
-4) { colors
[p
.index
] = 0xffFF0000; }
1693 /*class ScreenScrape extends SCPattern {
1696 public ScreenScrape(GLucose glucose) {
1698 System.loadLibrary("ScreenShot");
1699 pret = new PImage(8, 128, ARGB);
1700 ss = new ScreenShot();
1702 void run(double deltaMs){
1707 pret.pixels = ss.getScreenShotJNI2(x, y, w, h);
1708 //for(int i=0; i<px.length; i++){ pret.pixels[i] = px[i]; }
1709 //println(pret.get(10,10));
1710 for(Point p: model.points){
1711 colors[p.index] = pret.get((int(p.x)/8)*8, 128-int(p.y));
1716 //----------------------------------------------------------------------------------------------------------------------------------
1717 int NumApcRows
=4, NumApcCols
=8;
1719 public boolean btwn (int a
,int b
,int c
) { return a
>= b
&& a
<= c
; }
1720 public boolean btwn (double a
,double b
,double c
) { return a
>= b
&& a
<= c
; }
1721 public float interp (float a
, float b
, float c
) { return (1-a
)*b
+ a
*c
; }
1722 public float randctr (float a
) { return random(a
) - a
*.5f
; }
1723 public float min (float a
, float b
, float c
, float d
) { return min(min(a
,b
),min(c
,d
)); }
1724 public float pointDist(Point p1
, Point p2
) { return dist(p1
.x
,p1
.y
,p1
.z
,p2
.x
,p2
.y
,p2
.z
); }
1725 public float xyDist (Point p1
, Point p2
) { return dist(p1
.x
,p1
.y
,p2
.x
,p2
.y
); }
1726 public float distToSeg(float x
, float y
, float x1
, float y1
, float x2
, float y2
) {
1727 float A
= x
- x1
, B
= y
- y1
, C
= x2
- x1
, D
= y2
- y1
;
1728 float dot
= A
* C
+ B
* D
, len_sq
= C
* C
+ D
* D
;
1729 float xx
, yy
,param
= dot
/ len_sq
;
1731 if (param
< 0 || (x1
== x2
&& y1
== y2
)) { xx
= x1
; yy
= y1
; }
1732 else if (param
> 1) { xx
= x2
; yy
= y2
; }
1733 else { xx
= x1
+ param
* C
;
1734 yy
= y1
+ param
* D
; }
1735 float dx
= x
- xx
, dy
= y
- yy
;
1736 return sqrt(dx
* dx
+ dy
* dy
);
1740 int NumPicks
, Default
,
1743 String tag
, Desc
[] ;
1745 Pick (String label
, int _Def
, int _Num
, int nStart
, String d
[]) {
1746 NumPicks
= _Num
; Default
= _Def
;
1747 StartRow
= nStart
; EndRow
= StartRow
+ floor((NumPicks
-1) / NumApcCols
);
1748 tag
= label
; Desc
= d
;
1752 public int Cur() { return (CurRow
-StartRow
)*NumApcCols
+ CurCol
; }
1753 public String
CurDesc() { return Desc
[Cur()]; }
1754 public void reset() { CurCol
= Default
% NumApcCols
; CurRow
= StartRow
+ Default
/ NumApcCols
; }
1756 public boolean set(int r
, int c
) {
1757 if (!btwn(r
,StartRow
,EndRow
) || !btwn(c
,0,NumApcCols
-1) ||
1758 !btwn((r
-StartRow
)*NumApcCols
+ c
,0,NumPicks
-1)) return false;
1759 CurRow
=r
; CurCol
=c
; return true;
1763 public class DBool
{
1767 public void reset() { b
= def
; }
1768 public boolean set (int r
, int c
, boolean val
) { if (r
!= row
|| c
!= col
) return false; b
= val
; return true; }
1769 DBool(String _tag
, boolean _def
, int _row
, int _col
) {
1770 def
= _def
; b
= _def
; tag
= _tag
; row
= _row
; col
= _col
;
1773 //----------------------------------------------------------------------------------------------------------------------------------
1774 public class DPat
extends SCPattern
1776 ArrayList
<Pick
> picks
= new ArrayList
<Pick
> ();
1777 ArrayList
<DBool
> bools
= new ArrayList
<DBool
> ();
1779 PVector mMax
, mCtr
, mHalf
;
1784 float[] xWaveNz
, yWaveNz
;
1785 int nPoint
, nPoints
;
1786 PVector xyzJog
= new PVector(), modmin
;
1788 float NoiseMove
= random(10000);
1789 BasicParameter pSpark
, pWave
, pRotX
, pRotY
, pRotZ
, pSpin
, pTransX
, pTransY
;
1790 DBool pXsym
, pYsym
, pRsym
, pXdup
, pXtrip
, pJog
, pGrey
;
1792 public float lxh () { return lx
.getBaseHuef(); }
1793 public int c1c (float a
) { return round(100*constrain(a
,0,1)); }
1794 public float interpWv(float i
, float[] vals
) { return interp(i
-floor(i
), vals
[floor(i
)], vals
[ceil(i
)]); }
1795 public void setNorm (PVector vec
) { vec
.set(vec
.x
/mMax
.x
, vec
.y
/mMax
.y
, vec
.z
/mMax
.z
); }
1796 public void setRand (PVector vec
) { vec
.set(random(mMax
.x
), random(mMax
.y
), random(mMax
.z
)); }
1797 public void setVec (PVector vec
, Point p
) { vec
.set(p
.x
, p
.y
, p
.z
); }
1798 public void interpolate(float i
, PVector a
, PVector b
) { a
.set(interp(i
,a
.x
,b
.x
), interp(i
,a
.y
,b
.y
), interp(i
,a
.z
,b
.z
)); }
1799 public void StartRun(double deltaMs
) { }
1800 public float val (BasicParameter p
) { return p
.getValuef(); }
1801 public int CalcPoint(PVector p
) { return lx
.hsb(0,0,0); }
1802 public int blend3(int c1
, int c2
, int c3
) { return blendColor(c1
,blendColor(c2
,c3
,ADD
),ADD
); }
1804 public void rotateZ (PVector p
, PVector o
, float nSin
, float nCos
) { p
.set( nCos
*(p
.x
-o
.x
) - nSin
*(p
.y
-o
.y
) + o
.x
, nSin
*(p
.x
-o
.x
) + nCos
*(p
.y
-o
.y
) + o
.y
,p
.z
); }
1805 public void rotateX (PVector p
, PVector o
, float nSin
, float nCos
) { p
.set(p
.x
,nCos
*(p
.y
-o
.y
) - nSin
*(p
.z
-o
.z
) + o
.y
, nSin
*(p
.y
-o
.y
) + nCos
*(p
.z
-o
.z
) + o
.z
); }
1806 public void rotateY (PVector p
, PVector o
, float nSin
, float nCos
) { p
.set( nSin
*(p
.z
-o
.z
) + nCos
*(p
.x
-o
.x
) + o
.x
,p
.y
, nCos
*(p
.z
-o
.z
) - nSin
*(p
.x
-o
.x
) + o
.z
); }
1808 public BasicParameter
addParam(String label
, double value
) { BasicParameter p
= new BasicParameter(label
, value
); addParameter(p
); return p
; }
1810 PVector vT1
= new PVector(), vT2
= new PVector();
1811 public float calcCone (PVector v1
, PVector v2
, PVector c
) { vT1
.set(v1
); vT2
.set(v2
); vT1
.sub(c
); vT2
.sub(c
);
1812 return degrees(PVector
.angleBetween(vT1
,vT2
)); }
1814 public Pick
addPick(String name
, int def
, int _max
, String
[] desc
) {
1815 Pick P
= new Pick(name
, def
, _max
+1, nMaxRow
, desc
);
1816 nMaxRow
= P
.EndRow
+ 1;
1821 public boolean noteOff(Note note
) {
1822 int row
= note
.getPitch(), col
= note
.getChannel();
1823 for (int i
=0; i
<bools
.size(); i
++) if (bools
.get(i
).set(row
, col
, false)) { presetManager
.dirty(this); return true; }
1824 updateLights(); return false;
1827 public boolean noteOn(Note note
) {
1828 int row
= note
.getPitch(), col
= note
.getChannel();
1829 for (int i
=0; i
<picks
.size(); i
++) if (picks
.get(i
).set(row
, col
)) { presetManager
.dirty(this); return true; }
1830 for (int i
=0; i
<bools
.size(); i
++) if (bools
.get(i
).set(row
, col
, true)) { presetManager
.dirty(this); return true; }
1831 println("row: " + row
+ " col: " + col
); return false;
1834 public void onInactive() { uiDebugText
.setText(""); }
1835 public void onReset() {
1836 for (int i
=0; i
<bools
.size(); i
++) bools
.get(i
).reset();
1837 for (int i
=0; i
<picks
.size(); i
++) picks
.get(i
).reset();
1838 presetManager
.dirty(this);
1842 DPat(GLucose glucose
) {
1845 pSpark
= addParam("Sprk", 0);
1846 pWave
= addParam("Wave", 0);
1847 pTransX
= addParam("TrnX", .5f
);
1848 pTransY
= addParam("TrnY", .5f
);
1849 pRotX
= addParam("RotX", .5f
);
1850 pRotY
= addParam("RotY", .5f
);
1851 pRotZ
= addParam("RotZ", .5f
);
1852 pSpin
= addParam("Spin", .5f
);
1854 nPoints
= model
.points
.size();
1855 pXsym
= new DBool("X-SYM", false, 48, 0); bools
.add(pXsym
);
1856 pYsym
= new DBool("Y-SYM", false, 48, 1); bools
.add(pYsym
);
1857 pRsym
= new DBool("R-SYM", false, 48, 2); bools
.add(pRsym
);
1858 pXdup
= new DBool("X-DUP", false, 48, 3); bools
.add(pXdup
);
1859 pJog
= new DBool("JOG" , false, 48, 4); bools
.add(pJog
);
1860 pGrey
= new DBool("GREY" , false, 48, 5); bools
.add(pGrey
);
1862 modmin
= new PVector(model
.xMin
, model
.yMin
, model
.zMin
);
1863 mMax
= new PVector(model
.xMax
, model
.yMax
, model
.zMax
); mMax
.sub(modmin
);
1864 mCtr
= new PVector(); mCtr
.set(mMax
); mCtr
.mult(.5f
);
1865 mHalf
= new PVector(.5f
,.5f
,.5f
);
1866 xWaveNz
= new float[ceil(mMax
.y
)+1];
1867 yWaveNz
= new float[ceil(mMax
.x
)+1];
1869 //println (model.xMin + " " + model.yMin + " " + model.zMin);
1870 //println (model.xMax + " " + model.yMax + " " + model.zMax);
1871 //for (MidiOutputDevice o: RWMidi.getOutputDevices()) { if (o.toString().contains("APC")) { APCOut = o.createOutput(); break;}}
1874 public float spin() {
1875 float raw
= val(pSpin
);
1878 } else if (raw
>= 0.55f
) {
1884 public void setAPCOutput(MidiOutput output
) {
1888 public void updateLights() { if (APCOut
== null) return;
1889 for (int i
= 0; i
< NumApcRows
; ++i
)
1890 for (int j
= 0; j
< 8; ++j
) APCOut
.sendNoteOn(j
, 53+i
, 0);
1891 for (int i
=0; i
<picks
.size(); i
++) APCOut
.sendNoteOn(picks
.get(i
).CurCol
, picks
.get(i
).CurRow
, 3);
1892 for (int i
=0; i
<bools
.size(); i
++) if (bools
.get(i
).b
) APCOut
.sendNoteOn (bools
.get(i
).col
, bools
.get(i
).row
, 1);
1893 else APCOut
.sendNoteOff (bools
.get(i
).col
, bools
.get(i
).row
, 0);
1896 public void run(double deltaMs
)
1898 if (deltaMs
> 100) return;
1900 if (this == midiEngine
.getFocusedDeck().getActivePattern()) {
1901 String Text1
="", Text2
="";
1902 for (int i
=0; i
<bools
.size(); i
++) if (bools
.get(i
).b
) Text1
+= " " + bools
.get(i
).tag
+ " ";
1903 for (int i
=0; i
<picks
.size(); i
++) Text1
+= picks
.get(i
).tag
+ ": " + picks
.get(i
).CurDesc() + " ";
1904 uiDebugText
.setText(Text1
, Text2
);
1907 NoiseMove
+= deltaMs
; NoiseMove
= NoiseMove
% 1e7f
;
1909 PVector P
= new PVector(), tP
= new PVector(), pSave
= new PVector();
1910 PVector pTrans
= new PVector(val(pTransX
)*200-100, val(pTransY
)*100-50,0);
1914 float tRamp
= (lx
.tempo
.rampf() % .25f
);
1915 if (tRamp
< LastJog
) xyzJog
.set(randctr(mMax
.x
*.2f
), randctr(mMax
.y
*.2f
), randctr(mMax
.z
*.2f
));
1919 // precalculate this stuff
1920 float wvAmp
= val(pWave
), sprk
= val(pSpark
);
1922 for (int i
=0; i
<ceil(mMax
.x
)+1; i
++)
1923 yWaveNz
[i
] = wvAmp
* (noise(i
/(mMax
.x
*.3f
)-(2e3f
+NoiseMove
)/1500.f
) - .5f
) * (mMax
.y
/2.f
);
1925 for (int i
=0; i
<ceil(mMax
.y
)+1; i
++)
1926 xWaveNz
[i
] = wvAmp
* (noise(i
/(mMax
.y
*.3f
)-(1e3f
+NoiseMove
)/1500.f
) - .5f
) * (mMax
.x
/2.f
);
1929 for (Point p
: model
.points
) { nPoint
++;
1933 if (sprk
> 0) {P
.y
+= sprk
*randctr(50); P
.x
+= sprk
*randctr(50); P
.z
+= sprk
*randctr(50); }
1934 if (wvAmp
> 0) P
.y
+= interpWv(p
.x
-modmin
.x
, yWaveNz
);
1935 if (wvAmp
> 0) P
.x
+= interpWv(p
.y
-modmin
.y
, xWaveNz
);
1936 if (pJog
.b
) P
.add(xyzJog
);
1939 int cNew
, cOld
= colors
[p
.index
];
1940 { tP
.set(P
); cNew
= CalcPoint(tP
); }
1941 if (pXsym
.b
) { tP
.set(mMax
.x
-P
.x
,P
.y
,P
.z
); cNew
= blendColor(cNew
, CalcPoint(tP
), ADD
); }
1942 if (pYsym
.b
) { tP
.set(P
.x
,mMax
.y
-P
.y
,P
.z
); cNew
= blendColor(cNew
, CalcPoint(tP
), ADD
); }
1943 if (pRsym
.b
) { tP
.set(mMax
.x
-P
.x
,mMax
.y
-P
.y
,mMax
.z
-P
.z
); cNew
= blendColor(cNew
, CalcPoint(tP
), ADD
); }
1944 if (pXdup
.b
) { tP
.set((P
.x
+mMax
.x
*.5f
)%mMax
.x
,P
.y
,P
.z
); cNew
= blendColor(cNew
, CalcPoint(tP
), ADD
); }
1945 if (pGrey
.b
) { cNew
= lx
.hsb(0, 0, lx
.b(cNew
)); }
1946 colors
[p
.index
] = cNew
;
1950 //----------------------------------------------------------------------------------------------------------------------------------
1954 dTurn(int _pos0
, dVertex _v
, int _pos1
) { v
= _v
; pos0
= _pos0
; pos1
= _pos1
; }
1958 dVertex c0
, c1
, c2
, c3
, // connections on the cube
1959 opp
, same
; // opp - same strip, opp direction
1960 // same - same strut, diff strip, dir
1961 dTurn t0
, t1
, t2
, t3
;
1963 int dir
, ci
; // dir -- 1 or -1.
1964 // ci -- color index
1966 dVertex(Strip _s
, Point _p
) { s
= _s
; ci
= _p
.index
; }
1967 public Point
getPoint(int i
) { return s
.points
.get(dir
>0 ? i
: 15-i
); }
1968 public void setOpp(dVertex _opp
) { opp
= _opp
; dir
= (ci
< opp
.ci ?
1 : -1); }
1970 //----------------------------------------------------------------------------------------------------------------------------------
1971 class dPixel
{ dVertex v
; int pos
; dPixel(dVertex _v
, int _pos
) { v
=_v
; pos
=_pos
; } }
1973 public void addTurn (dVertex v0
, int pos0
, dVertex v1
, int pos1
) { dTurn t
= new dTurn(pos0
, v1
, pos1
);
1974 if (v0
.t0
== null) { v0
.t0
=t
; return; }
1975 if (v0
.t1
== null) { v0
.t1
=t
; return; }
1976 if (v0
.t2
== null) { v0
.t2
=t
; return; }
1977 if (v0
.t3
== null) { v0
.t3
=t
; return; }
1979 public float dist2 (Strip s1
, int pos1
, Strip s2
, int pos2
) { return pointDist(s1
.points
.get(pos1
), s2
.points
.get(pos2
)); }
1980 public float pd2 (Point p1
, float x
, float y
, float z
) { return dist(p1
.x
,p1
.y
,p1
.z
,x
,y
,z
); }
1981 public boolean sameSame (Strip s1
, Strip s2
) { return max(dist2(s1
, 0, s2
, 0), dist2(s1
,15, s2
,15)) < 5 ; } // same strut, same direction
1982 public boolean sameOpp (Strip s1
, Strip s2
) { return max(dist2(s1
, 0, s2
,15), dist2(s1
,15, s2
,0 )) < 5 ; } // same strut, opp direction
1983 public boolean sameBar (Strip s1
, Strip s2
) { return sameSame(s1
,s2
) || sameOpp(s1
,s2
); } // 2 strips on same strut
1986 public void addJoint (dVertex v1
, dVertex v2
) {
1987 // should probably replace parallel but further with the new one
1988 if (v1
.c0
!= null && sameBar(v2
.s
, v1
.c0
.s
)) return;
1989 if (v1
.c1
!= null && sameBar(v2
.s
, v1
.c1
.s
)) return;
1990 if (v1
.c2
!= null && sameBar(v2
.s
, v1
.c2
.s
)) return;
1991 if (v1
.c3
!= null && sameBar(v2
.s
, v1
.c3
.s
)) return;
1993 if (v1
.c0
== null) v1
.c0
= v2
;
1994 else if (v1
.c1
== null) v1
.c1
= v2
;
1995 else if (v1
.c2
== null) v1
.c2
= v2
;
1996 else if (v1
.c3
== null) v1
.c3
= v2
;
1999 public dVertex
v0(Strip s
) { return (dVertex
)s
.obj1
; }
2000 public dVertex
v1(Strip s
) { return (dVertex
)s
.obj2
; }
2002 public dPixel
getClosest(PVector p
) {
2003 dVertex v
= null; int pos
=0; float d
= 500;
2005 for (Strip s
: glucose
.model
.strips
) {
2006 float nd
= pd2(s
.points
.get(0),p
.x
,p
.y
,p
.z
); if (nd
< d
) { v
=v0(s
); d
=nd
; pos
=0; }
2007 if (nd
> 30) continue;
2008 for (int k
=0; k
<=15; k
++) {
2009 nd
= pd2(s
.points
.get(k
),p
.x
,p
.y
,p
.z
); if (nd
< d
) { v
=v0(s
); d
=nd
; pos
=k
; }
2012 return random(2) < 1 ?
new dPixel(v
,pos
) : new dPixel(v
.opp
,15-pos
);
2018 for (Strip s
: glucose
.model
.strips
) {
2019 dVertex vrtx0
= new dVertex(s
,s
.points
.get(0 )); s
.obj1
=vrtx0
;
2020 dVertex vrtx1
= new dVertex(s
,s
.points
.get(15)); s
.obj2
=vrtx1
;
2021 vrtx0
.setOpp(vrtx1
); vrtx1
.setOpp(vrtx0
);
2024 for (Strip s1
: glucose
.model
.strips
) { for (Strip s2
: glucose
.model
.strips
) {
2025 if (s1
.points
.get(0).index
< s2
.points
.get(0).index
) continue;
2027 if (sameSame(s1
,s2
)) { v0(s1
).same
= v0(s2
); v1(s1
).same
= v1(s2
);
2028 v0(s2
).same
= v0(s1
); v1(s2
).same
= v1(s1
); continue; } // parallel
2029 if (sameOpp (s1
,s2
)) { v0(s1
).same
= v1(s2
); v1(s1
).same
= v0(s2
);
2030 v0(s2
).same
= v1(s1
); v1(s2
).same
= v0(s1
); continue; } // parallel
2031 if (dist2(s1
, 0, s2
, 0) < 5) { c
++; addJoint(v1(s1
), v0(s2
)); addJoint(v1(s2
), v0(s1
)); }
2032 if (dist2(s1
, 0, s2
,15) < 5) { c
++; addJoint(v1(s1
), v1(s2
)); addJoint(v0(s2
), v0(s1
)); }
2033 if (dist2(s1
,15, s2
, 0) < 5) { c
++; addJoint(v0(s1
), v0(s2
)); addJoint(v1(s2
), v1(s1
)); }
2034 if (dist2(s1
,15, s2
,15) < 5) { c
++; addJoint(v0(s1
), v1(s2
)); addJoint(v0(s2
), v1(s1
)); }
2037 // Are they touching at all?
2038 int pos1
=0, pos2
=0; float d
= 100;
2040 while (pos1
< 15 || pos2
< 15) {
2042 if (pos1
<15) { float d2
= dist2(s1
, pos1
+1, s2
, pos2
+0); if (d2
< d
) { d
=d2
; pos1
++; } }
2043 if (pos2
<15) { float d2
= dist2(s1
, pos1
+0, s2
, pos2
+1); if (d2
< d
) { d
=d2
; pos2
++; } }
2044 if (d
> 50 || oldD
== d
) break ;
2048 addTurn(v0(s1
), pos1
, v0(s2
), pos2
); addTurn(v1(s1
), 15-pos1
, v0(s2
), pos2
);
2049 addTurn(v0(s2
), pos2
, v0(s1
), pos1
); addTurn(v1(s2
), 15-pos2
, v0(s1
), pos1
);
2055 //----------------------------------------------------------------------------------------------------------------------------------
2059 public boolean changed
= false;
2060 public int position
= 0;
2061 public ArrayList
<Integer
> graphicBuffer
;
2064 graphicBuffer
= new ArrayList
<Integer
>();
2068 return graphicBuffer
.size();
2073 class Granim
extends Graphic
2075 HashMap
<String
,Graphic
> displayList
;
2079 displayList
= new HashMap
<String
,Graphic
>();
2081 public Graphic
addGraphic(String name
, Graphic g
)
2083 while(width()< g
.position
+1)
2085 graphicBuffer
.add(lx
.hsb(0,0,0));
2088 displayList
.put(name
, g
);
2093 public Graphic
getGraphicByName(String name
)
2095 return displayList
.get(name
);
2098 public void update()
2101 for(Graphic g
: displayList
.values())
2103 if(g
instanceof Granim
)
2105 ((Granim
) g
).update();
2108 changed
= changed
|| g
.changed
;
2111 while(width()< g
.position
+ g
.width())
2113 graphicBuffer
.add(lx
.hsb(0,0,0));
2125 public void drawOne(Graphic g
)
2127 graphicBuffer
.addAll(g
.position
,g
.graphicBuffer
);
2129 public void drawAll()
2133 class GranimPattern
extends SCPattern
2135 HashMap
<String
,Graphic
> displayList
;
2137 GranimPattern(GLucose glucose
)
2140 displayList
= new HashMap
<String
,Graphic
>();
2143 public Graphic
addGraphic(String name
, Graphic g
)
2145 displayList
.put(name
,g
);
2149 public Graphic
getGraphicByName(String name
)
2151 return displayList
.get(name
);
2154 public void run(double deltaMs
)
2158 private Integer
[] gbuffer
;
2159 public void drawToPointList()
2161 for(Graphic g
: displayList
.values())
2163 if(g
instanceof Granim
)
2165 ((Granim
) g
).update();
2167 List
<Point
> drawList
= model
.points
.subList(Math
.min(g
.position
,colors
.length
-1), Math
.min(g
.position
+ g
.width(),colors
.length
-1));
2168 //println("drawlistsize "+drawList.size());
2170 gbuffer
= g
.graphicBuffer
.toArray(new Integer
[0]);
2172 for (int i
=0; i
< drawList
.size(); i
++)
2174 colors
[drawList
.get(i
).index
] = gbuffer
[i
];
2182 class RedsGraphic
extends Graphic
2189 RedsGraphic(int len
)
2195 public void drawit(int len
)
2197 for(int i
= 0; i
< len
;i
++)
2199 graphicBuffer
.add(lx
.hsb(0,255,255));
2204 class RedsGranim
extends Granim
2209 addGraphic("myreds", new RedsGraphic(10));
2214 addGraphic("myreds", new RedsGraphic(len
));
2216 public float count
= 0.0f
;
2217 public void update()
2219 Graphic g
=getGraphicByName("myreds");
2220 g
.position
= Math
.round(sin(count
)*20)+100;
2231 class RandomsGranim
extends Granim
2233 private int _len
=0 ;
2238 addGraphic("myrandoms", makeGraphic(_len
));
2240 RandomsGranim(int len
)
2244 addGraphic("myrandoms", makeGraphic(len
));
2247 public Graphic
makeGraphic(int len
)
2250 int[] colors
= new int[len
];
2251 for(int i
=0;i
<len
;i
++)
2253 colors
[i
]=(int) Math
.round(Math
.random()*80)+colorLid
;
2257 return new ColorDotsGraphic(colors
);
2259 private int count
=1;
2260 private int instanceCount
=0;
2261 public void update()
2264 if(instanceCount
<90 && count
% 20==0)
2267 Graphic h
=addGraphic("myrandoms_"+instanceCount
, makeGraphic(_len
));
2268 h
.position
= instanceCount
*(_len
+100);
2269 //println("one more " + instanceCount+" at "+h.position);
2280 class ColorDotsGraphic
extends Graphic
2282 ColorDotsGraphic(int[] colorSequence
)
2285 for (int colorVal
: colorSequence
)
2287 graphicBuffer
.add(lx
.hsb(colorVal
, 255, 255));
2292 int BLACK
= 0xff000000;
2294 class Gimbal
extends SCPattern
{
2296 private final boolean DEBUG_MANUAL_ABG
= false;
2297 private final int MAXIMUM_BEATS_PER_REVOLUTION
= 100;
2299 private boolean first_run
= true;
2300 private final Projection projection
;
2301 private final BasicParameter beatsPerRevolutionParam
= new BasicParameter("SLOW", 20.f
/MAXIMUM_BEATS_PER_REVOLUTION
);
2302 private final BasicParameter hueDeltaParam
= new BasicParameter("HUED", 60.f
/360);
2303 private final BasicParameter fadeFromCoreParam
= new BasicParameter("FADE", 1);
2304 private final BasicParameter girthParam
= new BasicParameter("GRTH", .18f
);
2305 private final BasicParameter ringExtendParam
= new BasicParameter("XTND", 1);
2306 private final BasicParameter relativeSpeedParam
= new BasicParameter("RLSP", .83f
);
2307 private final BasicParameter sizeParam
= new BasicParameter("SIZE", .9f
);
2309 private final BasicParameter aP
= new BasicParameter("a", 0);
2310 private final BasicParameter bP
= new BasicParameter("b", 0);
2311 private final BasicParameter gP
= new BasicParameter("g", 0);
2313 Gimbal(GLucose glucose
) {
2315 projection
= new Projection(model
);
2316 addParameter(beatsPerRevolutionParam
);
2317 addParameter(hueDeltaParam
);
2318 addParameter(fadeFromCoreParam
);
2319 addParameter(girthParam
);
2320 addParameter(ringExtendParam
);
2321 addParameter(relativeSpeedParam
);
2322 addParameter(sizeParam
);
2324 if (DEBUG_MANUAL_ABG
) {
2331 float a
= 0, b
= 0, g
= 0;
2333 public void run(double deltaMs
) {
2335 if (DEBUG_MANUAL_ABG
) {
2336 a
= aP
.getValuef() * (2 * PI
);
2337 b
= bP
.getValuef() * (2 * PI
);
2338 g
= gP
.getValuef() * (2 * PI
);
2340 float relativeSpeed
= relativeSpeedParam
.getValuef();
2341 float time
= millis() / 1000.f
;
2343 int beatsPerRevolution
= (int) (beatsPerRevolutionParam
.getValuef() * MAXIMUM_BEATS_PER_REVOLUTION
) + 1;
2344 float radiansPerMs
= 2 * PI
// radians / revolution
2345 / beatsPerRevolution
// beats / revolution
2346 * lx
.tempo
.bpmf() // BPM beats / min
2350 a
+= deltaMs
* radiansPerMs
* pow(relativeSpeed
, 0);
2351 b
+= deltaMs
* radiansPerMs
* pow(relativeSpeed
, 1);
2352 g
+= deltaMs
* radiansPerMs
* pow(relativeSpeed
, 2);
2358 float hue
= lx
.getBaseHuef();
2359 float hue_delta
= hueDeltaParam
.getValuef() * 360;
2361 float radius1
= model
.xMax
/ 2 * sizeParam
.getValuef();
2362 float radius2
= ((model
.xMax
+ model
.yMax
) / 2) / 2 * sizeParam
.getValuef();
2363 float radius3
= model
.yMax
/ 2 * sizeParam
.getValuef();
2364 float girth
= model
.xMax
* girthParam
.getValuef();
2365 Ring ring1
= new Ring((hue
+ hue_delta
* 0) % 360, radius1
, girth
);
2366 Ring ring2
= new Ring((hue
+ hue_delta
* 1) % 360, radius2
, girth
);
2367 Ring ring3
= new Ring((hue
+ hue_delta
* 2) % 360, radius3
, girth
);
2369 projection
.reset(model
)
2370 // Translate so the center of the car is the origin
2371 .translateCenter(model
, 0, 0, 0);
2373 for (Coord c
: projection
) {
2374 //if (first_run) println(c.x + "," + c.y + "," + c.z);
2376 rotate3d(c
, a
, 0, 0);
2377 rotate3d(c
, PI
/4, PI
/4, PI
/4);
2378 int color1
= ring1
.colorFor(c
);
2380 rotate3d(c
, 0, b
, 0);
2381 int color2
= ring2
.colorFor(c
);
2383 rotate3d(c
, 0, 0, g
);
2384 int color3
= ring3
.colorFor(c
);
2386 colors
[c
.index
] = specialBlend(color1
, color2
, color3
);
2395 float radius
, girth
;
2397 public Ring(float hue
, float radius
, float girth
) {
2399 this.radius
= radius
;
2403 public int colorFor(Coord c
) {
2404 float theta
= atan2(c
.y
, c
.x
);
2405 float nearest_circle_x
= cos(theta
) * radius
;
2406 float nearest_circle_y
= sin(theta
) * radius
;
2407 float nearest_circle_z
= 0;
2409 float distance_to_circle
2410 = sqrt(pow(nearest_circle_x
- c
.x
, 2)
2411 + pow(nearest_circle_y
- c
.y
, 2)
2412 + pow(nearest_circle_z
- c
.z
* ringExtendParam
.getValuef(), 2));
2414 float xy_distance
= sqrt(c
.x
*c
.x
+ c
.y
*c
.y
);
2415 return lx
.hsb(this.hue
, 100, (1 - distance_to_circle
/ girth
* fadeFromCoreParam
.getValuef()) * 100);
2427 class Zebra
extends SCPattern
{
2429 private final Projection projection
;
2430 SinLFO angleM
= new SinLFO(0, PI
* 2, 30000);
2433 SinLFO x, y, z, dx, dy, dz;
2438 Zebra(GLucose glucose
) {
2440 projection
= new Projection(model
);
2442 addModulator(angleM
).trigger();
2445 public int colorFor(Coord c
) {
2446 float hue
= lx
.getBaseHuef();
2452 c.x = c.x + millis() / 100.f;
2457 int stripe_count
= 12;
2458 float stripe_width
= model
.xMax
/ (float)stripe_count
;
2459 if (Math
.floor((c
.x
) / stripe_width
) % 2 == 0) {
2460 return lx
.hsb(hue
, 100, 100);
2462 return lx
.hsb((hue
+ 90) % 360, 100, 100);
2468 if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
2469 return lx.hsb(lx.getBaseHuef(), 100, 100);
2471 return lx.hsb(0, 0, 0);
2476 public int isPositiveBit(float f
) {
2477 return f
> 0 ?
1 : 0;
2480 public void run(double deltaMs
) {
2481 float a
= (millis() / 1000.f
) % (2 * PI
);
2482 float b
= (millis() / 1200.f
) % (2 * PI
);
2483 float g
= (millis() / 1600.f
) % (2 * PI
);
2485 projection
.reset(model
)
2486 // Translate so the center of the car is the origin
2487 .translateCenter(model
, 0, 0, 0);
2489 for (Coord c
: projection
) {
2490 // rotate3d(c, a, b, g);
2491 colors
[c
.index
] = colorFor(c
);
2499 boolean first_run
= true;
2500 private void log(String s
) {
2509 public void rotate3d(Coord c
, float a
/* roll */, float b
/* pitch */, float g
/* yaw */) {
2510 float cosa
= cos(a
);
2511 float cosb
= cos(b
);
2512 float cosg
= cos(g
);
2513 float sina
= sin(a
);
2514 float sinb
= sin(b
);
2515 float sing
= sin(g
);
2517 float a1
= cosa
*cosb
;
2518 float a2
= cosa
*sinb
*sing
- sina
*cosg
;
2519 float a3
= cosa
*sinb
*cosg
+ sina
*sing
;
2520 float b1
= sina
*cosb
;
2521 float b2
= sina
*sinb
*sing
+ cosa
*cosg
;
2522 float b3
= sina
*sinb
*cosg
- cosa
*sing
;
2524 float c2
= cosb
*sing
;
2525 float c3
= cosb
*cosg
;
2527 float[] cArray
= { c
.x
, c
.y
, c
.z
};
2528 c
.x
= dotProduct(new float[] {a1
, a2
, a3
}, cArray
);
2529 c
.y
= dotProduct(new float[] {b1
, b2
, b3
}, cArray
);
2530 c
.z
= dotProduct(new float[] {c1
, c2
, c3
}, cArray
);
2533 public float dotProduct(float[] a
, float[] b
) {
2535 for (int i
= 0 ; i
< a
.length
; ++i
) {
2541 public int specialBlend(int c1
, int c2
, int c3
) {
2546 // force h1 < h2 < h3
2554 float s1
= saturation(c1
);
2555 float s2
= saturation(c2
);
2556 float s3
= saturation(c3
);
2558 float b1
= brightness(c1
);
2559 float b2
= brightness(c2
);
2560 float b3
= brightness(c3
);
2561 float relative_b1
= b1
/ (b1
+ b2
+ b3
);
2562 float relative_b2
= b2
/ (b1
+ b2
+ b3
);
2563 float relative_b3
= b3
/ (b1
+ b2
+ b3
);
2566 (h1
* relative_b1
+ h2
* relative_b1
+ h3
* relative_b3
) % 360,
2567 s1
* relative_b1
+ s2
* relative_b2
+ s3
* relative_b3
,
2568 max(max(b1
, b2
), b3
)
2573 * A Projection of sin wave in 3d space.
2574 * It sort of looks like an animal swiming around in water.
2575 * Angle sliders are sort of a work in progress that allow yo to change the crazy ways it moves around.
2576 * Hue slider allows you to control how different the colors are along the wave.
2578 * This code copied heavily from Tim and Slee.
2580 class Swim
extends SCPattern
{
2583 private final Projection projection
;
2584 SawLFO rotation
= new SawLFO(0, TWO_PI
, 19000);
2585 SinLFO yPos
= new SinLFO(-25, 25, 12323);
2586 final BasicParameter xAngle
= new BasicParameter("XANG", 0.9f
);
2587 final BasicParameter yAngle
= new BasicParameter("YANG", 0.3f
);
2588 final BasicParameter zAngle
= new BasicParameter("ZANG", 0.3f
);
2590 final BasicParameter hueScale
= new BasicParameter("HUE", 0.3f
);
2592 public Swim(GLucose glucose
) {
2594 projection
= new Projection(model
);
2596 addParameter(xAngle
);
2597 addParameter(yAngle
);
2598 addParameter(zAngle
);
2599 addParameter(hueScale
);
2601 addModulator(rotation
).trigger();
2602 addModulator(yPos
).trigger();
2608 public void run(double deltaMs
) {
2611 float ramp
= (float)lx
.tempo
.ramp();
2612 if (ramp
< prevRamp
) {
2613 beat
= (beat
+ 1) % 4;
2616 float phase
= (beat
+ramp
) / 2.0f
* 2 * PI
;
2618 float denominator
= max(xAngle
.getValuef() + yAngle
.getValuef() + zAngle
.getValuef(), 1);
2620 projection
.reset(model
)
2621 // Swim around the world
2622 .rotate(rotation
.getValuef(), xAngle
.getValuef() / denominator
, yAngle
.getValuef() / denominator
, zAngle
.getValuef() / denominator
)
2623 .translateCenter(model
, 0, 50 + yPos
.getValuef(), 0);
2625 float model_height
= model
.yMax
- model
.yMin
;
2626 float model_width
= model
.xMax
- model
.xMin
;
2627 for (Coord p
: projection
) {
2628 float x_percentage
= (p
.x
- model
.xMin
)/model_width
;
2630 // Multiply by 1.4 to shrink the size of the sin wave to be less than the height of the cubes.
2631 float y_in_range
= 1.4f
* (2*p
.y
- model
.yMax
- model
.yMin
) / model_height
;
2632 float sin_x
= sin(phase
+ 2 * PI
* x_percentage
);
2634 // Color fade near the top of the sin wave
2635 float v1
= sin_x
> y_in_range ?
(100 + 100*(y_in_range
- sin_x
)) : 0;
2637 float hue_color
= (lx
.getBaseHuef() + hueScale
.getValuef() * (abs(p
.x
-model
.xMax
/2.f
)*.3f
+ abs(p
.y
-model
.yMax
/2)*.9f
+ abs(p
.z
- model
.zMax
/2.f
))) % 360;
2638 colors
[p
.index
] = lx
.hsb(hue_color
, 70, v1
);
2644 * The idea here is to do another sin wave pattern, but with less rotation and more of a breathing / heartbeat affect with spheres above / below the wave.
2647 class Balance
extends SCPattern
{
2649 final BasicParameter hueScale
= new BasicParameter("Hue", 0.4f
);
2657 private final Projection projection
;
2659 SinLFO sphere1Z
= new SinLFO(0, 0, 15323);
2660 SinLFO sphere2Z
= new SinLFO(0, 0, 8323);
2661 SinLFO rotationX
= new SinLFO(-PI
/32, PI
/32, 9000);
2662 SinLFO rotationY
= new SinLFO(-PI
/16, PI
/16, 7000);
2663 SinLFO rotationZ
= new SinLFO(-PI
/16, PI
/16, 11000);
2664 SawLFO phaseLFO
= new SawLFO(0, 2 * PI
, 5000 - 4500 * 0.5f
);
2665 final BasicParameter phaseParam
= new BasicParameter("Spd", 0.5f
);
2666 final BasicParameter crazyParam
= new BasicParameter("Crzy", 0.2f
);
2669 private final Sphere
[] spheres
;
2670 private final float centerX
, centerY
, centerZ
, modelHeight
, modelWidth
, modelDepth
;
2671 SinLFO heightMod
= new SinLFO(0.8f
, 1.9f
, 17298);
2673 public Balance(GLucose glucose
) {
2676 projection
= new Projection(model
);
2678 addParameter(hueScale
);
2679 addParameter(phaseParam
);
2680 addParameter(crazyParam
);
2682 spheres
= new Sphere
[2];
2683 centerX
= (model
.xMax
+ model
.xMin
) / 2;
2684 centerY
= (model
.yMax
+ model
.yMin
) / 2;
2685 centerZ
= (model
.zMax
+ model
.zMin
) / 2;
2686 modelHeight
= model
.yMax
- model
.yMin
;
2687 modelWidth
= model
.xMax
- model
.xMin
;
2688 modelDepth
= model
.zMax
- model
.zMin
;
2690 spheres
[0] = new Sphere();
2691 spheres
[0].x
= 1*modelWidth
/2 + model
.xMin
;
2692 spheres
[0].y
= centerY
+ 20;
2693 spheres
[0].z
= centerZ
;
2695 spheres
[1] = new Sphere();
2696 spheres
[1].x
= model
.xMin
;
2697 spheres
[1].y
= centerY
- 20;
2698 spheres
[1].z
= centerZ
;
2700 addModulator(rotationX
).trigger();
2701 addModulator(rotationY
).trigger();
2702 addModulator(rotationZ
).trigger();
2705 addModulator(sphere1Z
).trigger();
2706 addModulator(sphere2Z
).trigger();
2707 addModulator(phaseLFO
).trigger();
2709 addModulator(heightMod
).trigger();
2712 public void onParameterChanged(LXParameter parameter
) {
2713 if (parameter
== phaseParam
) {
2714 phaseLFO
.setDuration(5000 - 4500 * parameter
.getValuef());
2720 public void run(double deltaMs
) {
2723 float ramp
= (float)lx
.tempo
.ramp();
2724 if (ramp
< prevRamp
) {
2725 beat
= (beat
+ 1) % 4;
2728 float phase
= phaseLFO
.getValuef();
2730 float crazy_factor
= crazyParam
.getValuef() / 0.2f
;
2731 projection
.reset(model
)
2732 .rotate(rotationZ
.getValuef() * crazy_factor
, 0, 1, 0)
2733 .rotate(rotationX
.getValuef() * crazy_factor
, 0, 0, 1)
2734 .rotate(rotationY
.getValuef() * crazy_factor
, 0, 1, 0);
2736 for (Coord p
: projection
) {
2737 float x_percentage
= (p
.x
- model
.xMin
)/modelWidth
;
2739 float y_in_range
= heightMod
.getValuef() * (2*p
.y
- model
.yMax
- model
.yMin
) / modelHeight
;
2740 float sin_x
= sin(PI
/ 2 + phase
+ 2 * PI
* x_percentage
);
2742 // Color fade near the top of the sin wave
2743 float v1
= max(0, 100 * (1 - 4*abs(sin_x
- y_in_range
)));
2745 float hue_color
= (lx
.getBaseHuef() + hueScale
.getValuef() * (abs(p
.x
-model
.xMax
/2.f
) + abs(p
.y
-model
.yMax
/2)*.2f
+ abs(p
.z
- model
.zMax
/2.f
)*.5f
)) % 360;
2746 int c
= lx
.hsb(hue_color
, 80, v1
);
2748 // Now draw the spheres
2749 for (Sphere s
: spheres
) {
2750 float phase_x
= (s
.x
- phase
/ (2 * PI
) * modelWidth
) % modelWidth
;
2751 float x_dist
= LXUtils
.wrapdistf(p
.x
, phase_x
, modelWidth
);
2753 float sphere_z
= (s
== spheres
[0]) ?
(s
.z
+ sphere1Z
.getValuef()) : (s
.z
- sphere2Z
.getValuef());
2756 float d
= sqrt(pow(x_dist
, 2) + pow(p
.y
- s
.y
, 2) + pow(p
.z
- sphere_z
, 2));
2758 float distance_from_beat
= (beat
% 2 == 1) ?
1 - ramp
: ramp
;
2762 float r
= 40 - pow(distance_from_beat
, 0.75f
) * 20;
2764 float distance_value
= max(0, 1 - max(0, d
- r
) / 10);
2765 float beat_value
= 1.0f
;
2767 float value
= min(beat_value
, distance_value
);
2769 float sphere_color
= (lx
.getBaseHuef() - (1 - hueScale
.getValuef()) * d
/r
* 45) % 360;
2771 c
= blendColor(c
, lx
.hsb((sphere_color
+ 270) % 360, 60, min(1, value
) * 100), ADD
);
2773 colors
[p
.index
] = c
;
2777 class Cathedrals
extends SCPattern
{
2779 private final BasicParameter xpos
= new BasicParameter("XPOS", 0.5f
);
2780 private final BasicParameter wid
= new BasicParameter("WID", 0.5f
);
2781 private final BasicParameter arms
= new BasicParameter("ARMS", 0.5f
);
2782 private final BasicParameter sat
= new BasicParameter("SAT", 0.5f
);
2783 private GraphicEQ eq
;
2785 Cathedrals(GLucose glucose
) {
2793 protected void onActive() {
2795 eq
= new GraphicEQ(lx
, 16);
2796 eq
.slope
.setValue(0.7f
);
2797 eq
.range
.setValue(0.4f
);
2798 eq
.attack
.setValue(0.4f
);
2799 eq
.release
.setValue(0.4f
);
2800 addParameter(eq
.level
);
2801 addParameter(eq
.range
);
2802 addParameter(eq
.attack
);
2803 addParameter(eq
.release
);
2804 addParameter(eq
.slope
);
2809 public void run(double deltaMs
) {
2811 float bassLevel
= eq
.getAverageLevel(0, 4);
2812 float trebleLevel
= eq
.getAverageLevel(8, 6);
2814 float falloff
= 100 / (2 + 14*wid
.getValuef());
2815 float cx
= model
.xMin
+ (model
.xMax
-model
.xMin
) * xpos
.getValuef();
2816 float barm
= 12 + 60*arms
.getValuef()*max(0, 2*(bassLevel
-0.1f
));
2817 float tarm
= 12 + 60*arms
.getValuef()*max(0, 2*(trebleLevel
-0.1f
));
2822 float sf
= 100.f
/ (70 - 69.9f
*sat
.getValuef());
2824 for (Point p
: model
.points
) {
2825 float d
= MAX_FLOAT
;
2826 if (p
.y
> model
.cy
) {
2828 middle
= model
.yMax
* 3/5.f
;
2831 middle
= model
.yMax
* 1/5.f
;
2833 if (abs(p
.x
- cx
) < arm
) {
2834 d
= min(abs(p
.x
- cx
), abs(p
.y
- middle
));
2836 colors
[p
.index
] = color(
2837 (lx
.getBaseHuef() + .2f
*abs(p
.y
- model
.cy
)) % 360,
2838 min(100, sf
*dist(abs(p
.x
- cx
), p
.y
, arm
, middle
)),
2839 max(0, 120 - d
*falloff
));
2844 class MidiMusic
extends SCPattern
{
2846 private final Stack
<LXLayer
> newLayers
= new Stack
<LXLayer
>();
2848 private final Map
<Integer
, LightUp
> lightMap
= new HashMap
<Integer
, LightUp
>();
2849 private final List
<LightUp
> lights
= new ArrayList
<LightUp
>();
2850 private final BasicParameter lightSize
= new BasicParameter("SIZE", 0.5f
);
2852 private final List
<Sweep
> sweeps
= new ArrayList
<Sweep
>();
2854 private final LinearEnvelope sparkle
= new LinearEnvelope(0, 1, 500);
2855 private boolean sparkleDirection
= true;
2856 private float sparkleBright
= 100;
2858 private final BasicParameter wave
= new BasicParameter("WAVE", 0);
2860 MidiMusic(GLucose glucose
) {
2862 addParameter(lightSize
);
2864 addModulator(sparkle
).setValue(1);
2867 public void onReset() {
2868 for (LightUp light
: lights
) {
2869 light
.noteOff(null);
2873 class Sweep
extends LXLayer
{
2875 final LinearEnvelope position
= new LinearEnvelope(0, 1, 1000);
2880 addModulator(position
);
2883 public void run(double deltaMs
, int[] colors
) {
2884 if (!position
.isRunning()) {
2887 float posf
= position
.getValuef();
2888 for (Point p
: model
.points
) {
2889 colors
[p
.index
] = blendColor(colors
[p
.index
], color(
2890 (lx
.getBaseHuef() + .2f
*abs(p
.x
- model
.cx
) + .2f
*abs(p
.y
- model
.cy
)) % 360,
2892 max(0, bright
- posf
*100 - falloff
*abs(p
.y
- posf
*model
.yMax
))
2898 class LightUp
extends LXLayer
{
2900 private final LinearEnvelope brt
= new LinearEnvelope(0, 0, 0);
2901 private final Accelerator yPos
= new Accelerator(0, 0, 0);
2909 public boolean isAvailable() {
2910 return brt
.getValuef() <= 0;
2913 public void noteOn(Note note
) {
2914 xPos
= lerp(0, model
.xMax
, constrain(0.5f
+ (note
.getPitch() - 60) / 28.f
, 0, 1));
2915 yPos
.setValue(lerp(20, model
.yMax
*.72f
, note
.getVelocity() / 127.f
)).stop();
2916 brt
.setRangeFromHereTo(lerp(40, 100, note
.getVelocity() / 127.f
), 20).start();
2919 public void noteOff(Note note
) {
2920 yPos
.setVelocity(0).setAcceleration(-380).start();
2921 brt
.setRangeFromHereTo(0, 1000).start();
2924 public void run(double deltaMs
, int[] colors
) {
2925 float bVal
= brt
.getValuef();
2929 float yVal
= yPos
.getValuef();
2930 for (Point p
: model
.points
) {
2931 float falloff
= 6 - 5*lightSize
.getValuef();
2932 float b
= max(0, bVal
- falloff
*dist(p
.x
, p
.y
, xPos
, yVal
));
2934 colors
[p
.index
] = blendColor(colors
[p
.index
], lx
.hsb(
2935 (lx
.getBaseHuef() + .2f
*abs(p
.x
- model
.cx
) + .2f
*abs(p
.y
- model
.cy
)) % 360,
2944 private LightUp
getLight() {
2945 for (LightUp light
: lights
) {
2946 if (light
.isAvailable()) {
2950 LightUp newLight
= new LightUp();
2951 lights
.add(newLight
);
2952 synchronized(newLayers
) {
2953 newLayers
.push(newLight
);
2958 private Sweep
getSweep() {
2959 for (Sweep s
: sweeps
) {
2960 if (!s
.position
.isRunning()) {
2964 Sweep newSweep
= new Sweep();
2965 sweeps
.add(newSweep
);
2966 synchronized(newLayers
) {
2967 newLayers
.push(newSweep
);
2972 public synchronized boolean noteOn(Note note
) {
2973 if (note
.getChannel() == 0) {
2974 LightUp light
= getLight();
2975 lightMap
.put(note
.getPitch(), light
);
2977 } else if (note
.getChannel() == 1) {
2978 } else if (note
.getChannel() == 9) {
2979 if (note
.getVelocity() > 0) {
2980 switch (note
.getPitch()) {
2982 Sweep s
= getSweep();
2983 s
.bright
= 50 + note
.getVelocity() / 127.f
* 50;
2984 s
.falloff
= 20 - note
.getVelocity() / 127.f
* 17;
2985 s
.position
.trigger();
2988 sparkleBright
= note
.getVelocity() / 127.f
* 100;
2989 sparkleDirection
= true;
2993 sparkleBright
= note
.getVelocity() / 127.f
* 100;
2994 sparkleDirection
= false;
2998 effects
.boom
.trigger();
3001 effects
.flash
.trigger();
3009 public synchronized boolean noteOff(Note note
) {
3010 if (note
.getChannel() == 0) {
3011 LightUp light
= lightMap
.get(note
.getPitch());
3012 if (light
!= null) {
3013 light
.noteOff(note
);
3019 final float[] wval
= new float[16];
3022 public synchronized void run(double deltaMs
) {
3023 wavoff
+= deltaMs
* .001f
;
3024 for (int i
= 0; i
< wval
.length
; ++i
) {
3025 wval
[i
] = model
.cy
+ 0.2f
* model
.yMax
/2.f
* sin(wavoff
+ i
/ 1.9f
);
3027 float sparklePos
= (sparkleDirection ? sparkle
.getValuef() : (1 - sparkle
.getValuef())) * (Cube
.POINTS_PER_STRIP
)/2.f
;
3028 float maxBright
= sparkleBright
* (1 - sparkle
.getValuef());
3029 for (Strip s
: model
.strips
) {
3031 for (Point p
: s
.points
) {
3032 int wavi
= (int) constrain(p
.x
/ model
.xMax
* wval
.length
, 0, wval
.length
-1);
3033 float wavb
= max(0, wave
.getValuef()*100.f
- 8.f
*abs(p
.y
- wval
[wavi
]));
3034 colors
[p
.index
] = color(
3035 (lx
.getBaseHuef() + .2f
*abs(p
.x
- model
.cx
) + .2f
*abs(p
.y
- model
.cy
)) % 360,
3037 constrain(wavb
+ max(0, maxBright
- 40.f
*abs(sparklePos
- abs(i
- (Cube
.POINTS_PER_STRIP
-1)/2.f
))), 0, 100)
3043 if (!newLayers
.isEmpty()) {
3044 synchronized(newLayers
) {
3045 while (!newLayers
.isEmpty()) {
3046 addLayer(newLayers
.pop());
3053 class Pulley
extends SCPattern
{
3055 final int NUM_DIVISIONS
= 16;
3056 private final Accelerator
[] gravity
= new Accelerator
[NUM_DIVISIONS
];
3057 private final Click
[] delays
= new Click
[NUM_DIVISIONS
];
3059 private final Click reset
= new Click(9000);
3060 private boolean isRising
= false;
3062 private BasicParameter sz
= new BasicParameter("SIZE", 0.5f
);
3063 private BasicParameter beatAmount
= new BasicParameter("BEAT", 0);
3065 Pulley(GLucose glucose
) {
3067 for (int i
= 0; i
< NUM_DIVISIONS
; ++i
) {
3068 addModulator(gravity
[i
] = new Accelerator(0, 0, 0));
3069 addModulator(delays
[i
] = new Click(0));
3071 addModulator(reset
).start();
3073 addParameter(beatAmount
);
3078 private void trigger() {
3079 isRising
= !isRising
;
3081 for (Accelerator g
: gravity
) {
3083 g
.setSpeed(random(20, 33), 0).start();
3085 g
.setVelocity(0).setAcceleration(-420);
3086 delays
[i
].setDuration(random(0, 500)).trigger();
3092 public void run(double deltaMs
) {
3093 if (reset
.click()) {
3098 // Fucking A, had to comment this all out because of that bizarre
3099 // Processing bug where some simple loop takes an absurd amount of
3100 // time, must be some pre-processor bug
3101 // for (Accelerator g : gravity) {
3102 // if (g.getValuef() > model.yMax) {
3104 // } else if (g.getValuef() > model.yMax*.55) {
3105 // if (g.getVelocityf() > 10) {
3106 // g.setAcceleration(-16);
3108 // g.setAcceleration(0);
3114 for (Click d
: delays
) {
3121 for (Accelerator g
: gravity
) {
3122 if (g
.getValuef() < 0) {
3123 g
.setValue(-g
.getValuef());
3124 g
.setVelocity(-g
.getVelocityf() * random(0.74f
, 0.84f
));
3129 // A little silliness to test the grid API
3130 if (midiEngine
!= null && midiEngine
.getFocusedPattern() == this) {
3131 for (int i
= 0; i
< 5; ++i
) {
3132 for (int j
= 0; j
< 8; ++j
) {
3133 int gi
= (int) constrain(j
* NUM_DIVISIONS
/ 8, 0, NUM_DIVISIONS
-1);
3134 float b
= 1 - 4.f
*abs((6-i
)/6.f
- gravity
[gi
].getValuef() / model
.yMax
);
3135 midiEngine
.grid
.setState(i
, j
, (b
< 0) ?
0 : 3);
3140 float fPos
= 1 - lx
.tempo
.rampf();
3142 fPos
= .2f
+ 4 * (.2f
- fPos
);
3144 float falloff
= 100.f
/ (3 + sz
.getValuef() * 36 + fPos
* beatAmount
.getValuef()*48);
3145 for (Point p
: model
.points
) {
3146 int gi
= (int) constrain((p
.x
- model
.xMin
) * NUM_DIVISIONS
/ (model
.xMax
- model
.xMin
), 0, NUM_DIVISIONS
-1);
3147 colors
[p
.index
] = lx
.hsb(
3148 (lx
.getBaseHuef() + abs(p
.x
- model
.cx
)*.8f
+ p
.y
*.4f
) % 360,
3149 constrain(130 - p
.y
*.8f
, 0, 100),
3150 max(0, 100 - abs(p
.y
- gravity
[gi
].getValuef())*falloff
)
3156 class ViolinWave
extends SCPattern
{
3158 BasicParameter level
= new BasicParameter("LVL", 0.45f
);
3159 BasicParameter range
= new BasicParameter("RNG", 0.5f
);
3160 BasicParameter edge
= new BasicParameter("EDG", 0.5f
);
3161 BasicParameter release
= new BasicParameter("RLS", 0.5f
);
3162 BasicParameter speed
= new BasicParameter("SPD", 0.5f
);
3163 BasicParameter amp
= new BasicParameter("AMP", 0.25f
);
3164 BasicParameter period
= new BasicParameter("WAVE", 0.5f
);
3165 BasicParameter pSize
= new BasicParameter("PSIZE", 0.5f
);
3166 BasicParameter pSpeed
= new BasicParameter("PSPD", 0.5f
);
3167 BasicParameter pDensity
= new BasicParameter("PDENS", 0.25f
);
3169 LinearEnvelope dbValue
= new LinearEnvelope(0, 0, 10);
3171 ViolinWave(GLucose glucose
) {
3173 addParameter(level
);
3175 addParameter(range
);
3176 addParameter(release
);
3177 addParameter(speed
);
3179 addParameter(period
);
3180 addParameter(pSize
);
3181 addParameter(pSpeed
);
3182 addParameter(pDensity
);
3184 addModulator(dbValue
);
3187 final List
<Particle
> particles
= new ArrayList
<Particle
>();
3191 LinearEnvelope x
= new LinearEnvelope(0, 0, 0);
3192 LinearEnvelope y
= new LinearEnvelope(0, 0, 0);
3199 public Particle
trigger(boolean direction
) {
3200 float xInit
= random(model
.xMin
, model
.xMax
);
3201 float time
= 3000 - 2500*pSpeed
.getValuef();
3202 x
.setRange(xInit
, xInit
+ random(-40, 40), time
).trigger();
3203 y
.setRange(model
.cy
+ 10, direction ? model
.yMax
+ 50 : model
.yMin
- 50, time
).trigger();
3207 public boolean isActive() {
3208 return x
.isRunning() || y
.isRunning();
3211 public void run(double deltaMs
) {
3216 float pFalloff
= (30 - 27*pSize
.getValuef());
3217 for (Point p
: model
.points
) {
3218 float b
= 100 - pFalloff
* (abs(p
.x
- x
.getValuef()) + abs(p
.y
- y
.getValuef()));
3220 colors
[p
.index
] = blendColor(colors
[p
.index
], lx
.hsb(
3221 lx
.getBaseHuef(), 20, b
3228 float[] centers
= new float[30];
3230 boolean rising
= true;
3232 public void fireParticle(boolean direction
) {
3233 boolean gotOne
= false;
3234 for (Particle p
: particles
) {
3235 if (!p
.isActive()) {
3236 p
.trigger(direction
);
3240 particles
.add(new Particle().trigger(direction
));
3243 public void run(double deltaMs
) {
3244 accum
+= deltaMs
/ (1000.f
- 900.f
*speed
.getValuef());
3245 for (int i
= 0; i
< centers
.length
; ++i
) {
3246 centers
[i
] = model
.cy
+ 30*amp
.getValuef()*sin((float) (accum
+ (i
-centers
.length
/2.f
)/(1.f
+ 9.f
*period
.getValuef())));
3249 float zeroDBReference
= pow(10, (50 - 190*level
.getValuef())/20.f
);
3250 float dB
= 20*GraphicEQ
.log10(lx
.audioInput().mix
.level() / zeroDBReference
);
3251 if (dB
> dbValue
.getValuef()) {
3253 dbValue
.setRangeFromHereTo(dB
, 10).trigger();
3256 for (int j
= 0; j
< pDensity
.getValuef()*3; ++j
) {
3258 fireParticle(false);
3262 dbValue
.setRangeFromHereTo(max(dB
, -96), 50 + 1000*release
.getValuef()).trigger();
3264 float edg
= 1 + edge
.getValuef() * 40;
3265 float rng
= (78 - 64 * range
.getValuef()) / (model
.yMax
- model
.cy
);
3266 float val
= max(2, dbValue
.getValuef());
3268 for (Point p
: model
.points
) {
3269 int ci
= (int) lerp(0, centers
.length
-1, (p
.x
- model
.xMin
) / (model
.xMax
- model
.xMin
));
3270 float rFactor
= 1.0f
- 0.9f
* abs(p
.x
- model
.cx
) / (model
.xMax
- model
.cx
);
3271 colors
[p
.index
] = lx
.hsb(
3272 (lx
.getBaseHuef() + abs(p
.x
- model
.cx
)) % 360,
3273 min(100, 20 + 8*abs(p
.y
- centers
[ci
])),
3274 constrain(edg
*(val
*rFactor
- rng
* abs(p
.y
-centers
[ci
])), 0, 100)
3278 for (Particle p
: particles
) {
3284 class BouncyBalls
extends SCPattern
{
3286 static final int NUM_BALLS
= 6;
3291 TriangleLFO xPos
= new TriangleLFO(0, model
.xMax
, random(8000, 19000));
3295 addModulator(xPos
.setBasis(random(0, TWO_PI
)).start());
3296 addModulator(yPos
= new Accelerator(0, 0, 0));
3297 zPos
= lerp(model
.zMin
, model
.zMax
, (i
+2.f
) / (NUM_BALLS
+ 4.f
));
3300 public void bounce(float midiVel
) {
3301 float v
= 100 + 8*midiVel
;
3302 yPos
.setSpeed(v
, getAccel(v
, 60 / lx
.tempo
.bpmf())).start();
3305 public float getAccel(float v
, float oneBeat
) {
3306 return -2*v
/ oneBeat
;
3309 public void run(double deltaMs
) {
3310 float flrLevel
= flr
.getValuef() * model
.xMax
/2.f
;
3311 if (yPos
.getValuef() < flrLevel
) {
3312 if (yPos
.getVelocity() < -50) {
3313 yPos
.setValue(2*flrLevel
-yPos
.getValuef());
3314 float v
= -yPos
.getVelocityf() * bounce
.getValuef();
3315 yPos
.setSpeed(v
, getAccel(v
, 60 / lx
.tempo
.bpmf()));
3317 yPos
.setValue(flrLevel
).stop();
3320 float falloff
= 130.f
/ (12 + blobSize
.getValuef() * 36);
3321 float xv
= xPos
.getValuef();
3322 float yv
= yPos
.getValuef();
3324 for (Point p
: model
.points
) {
3325 float d
= sqrt((p
.x
-xv
)*(p
.x
-xv
) + (p
.y
-yv
)*(p
.y
-yv
) + .1f
*(p
.z
-zPos
)*(p
.z
-zPos
));
3326 float b
= constrain(130 - falloff
*d
, 0, 100);
3328 colors
[p
.index
] = blendColor(colors
[p
.index
], lx
.hsb(
3329 (lx
.getBaseHuef() + p
.y
*.5f
+ abs(model
.cx
- p
.x
) * .5f
) % 360,
3330 max(0, 100 - .45f
*(p
.y
- flrLevel
)),
3338 final BouncyBall
[] balls
= new BouncyBall
[NUM_BALLS
];
3340 final BasicParameter bounce
= new BasicParameter("BNC", .8f
);
3341 final BasicParameter flr
= new BasicParameter("FLR", 0);
3342 final BasicParameter blobSize
= new BasicParameter("SIZE", 0.5f
);
3344 BouncyBalls(GLucose glucose
) {
3346 for (int i
= 0; i
< balls
.length
; ++i
) {
3347 balls
[i
] = new BouncyBall(i
);
3349 addParameter(bounce
);
3351 addParameter(blobSize
);
3354 public void run(double deltaMs
) {
3355 setColors(0xff000000);
3356 for (BouncyBall b
: balls
) {
3361 public boolean noteOn(Note note
) {
3362 int pitch
= (note
.getPitch() + note
.getChannel()) % NUM_BALLS
;
3363 balls
[pitch
].bounce(note
.getVelocity());
3368 class SpaceTime
extends SCPattern
{
3370 SinLFO pos
= new SinLFO(0, 1, 3000);
3371 SinLFO rate
= new SinLFO(1000, 9000, 13000);
3372 SinLFO falloff
= new SinLFO(10, 70, 5000);
3375 BasicParameter rateParameter
= new BasicParameter("RATE", 0.5f
);
3376 BasicParameter sizeParameter
= new BasicParameter("SIZE", 0.5f
);
3379 public SpaceTime(GLucose glucose
) {
3382 addModulator(pos
).trigger();
3383 addModulator(rate
).trigger();
3384 addModulator(falloff
).trigger();
3385 pos
.modulateDurationBy(rate
);
3386 addParameter(rateParameter
);
3387 addParameter(sizeParameter
);
3390 public void onParameterChanged(LXParameter parameter
) {
3391 if (parameter
== rateParameter
) {
3392 rate
.stop().setValue(9000 - 8000*parameter
.getValuef());
3393 } else if (parameter
== sizeParameter
) {
3394 falloff
.stop().setValue(70 - 60*parameter
.getValuef());
3398 public void run(double deltaMs
) {
3399 angle
+= deltaMs
* 0.0007f
;
3400 float sVal1
= model
.strips
.size() * (0.5f
+ 0.5f
*sin(angle
));
3401 float sVal2
= model
.strips
.size() * (0.5f
+ 0.5f
*cos(angle
));
3403 float pVal
= pos
.getValuef();
3404 float fVal
= falloff
.getValuef();
3407 for (Strip strip
: model
.strips
) {
3409 for (Point p
: strip
.points
) {
3410 colors
[p
.index
] = lx
.hsb(
3411 (lx
.getBaseHuef() + 360 - p
.x
*.2f
+ p
.y
* .3f
) % 360,
3412 constrain(.4f
* min(abs(s
- sVal1
), abs(s
- sVal2
)), 20, 100),
3413 max(0, 100 - fVal
*abs(i
- pVal
*(strip
.metrics
.numPoints
- 1)))
3422 class Swarm
extends SCPattern
{
3424 SawLFO offset
= new SawLFO(0, 1, 1000);
3425 SinLFO rate
= new SinLFO(350, 1200, 63000);
3426 SinLFO falloff
= new SinLFO(15, 50, 17000);
3427 SinLFO fX
= new SinLFO(0, model
.xMax
, 19000);
3428 SinLFO fY
= new SinLFO(0, model
.yMax
, 11000);
3429 SinLFO hOffX
= new SinLFO(0, model
.xMax
, 13000);
3431 public Swarm(GLucose glucose
) {
3434 addModulator(offset
).trigger();
3435 addModulator(rate
).trigger();
3436 addModulator(falloff
).trigger();
3437 addModulator(fX
).trigger();
3438 addModulator(fY
).trigger();
3439 addModulator(hOffX
).trigger();
3440 offset
.modulateDurationBy(rate
);
3443 public float modDist(float v1
, float v2
, float mod
) {
3447 return min(v2
-v1
, v1
+mod
-v2
);
3450 return min(v1
-v2
, v2
+mod
-v1
);
3454 public void run(double deltaMs
) {
3456 for (Strip strip
: model
.strips
) {
3458 for (Point p
: strip
.points
) {
3459 float fV
= max(-1, 1 - dist(p
.x
/2.f
, p
.y
, fX
.getValuef()/2.f
, fY
.getValuef()) / 64.f
);
3460 colors
[p
.index
] = lx
.hsb(
3461 (lx
.getBaseHuef() + 0.3f
* abs(p
.x
- hOffX
.getValuef())) % 360,
3462 constrain(80 + 40 * fV
, 0, 100),
3463 constrain(100 - (30 - fV
* falloff
.getValuef()) * modDist(i
+ (s
*63)%61, offset
.getValuef() * strip
.metrics
.numPoints
, strip
.metrics
.numPoints
), 0, 100)
3472 class SwipeTransition
extends SCTransition
{
3474 final BasicParameter bleed
= new BasicParameter("WIDTH", 0.5f
);
3476 SwipeTransition(GLucose glucose
) {
3479 addParameter(bleed
);
3482 public void computeBlend(int[] c1
, int[] c2
, double progress
) {
3483 float bleedf
= 10 + bleed
.getValuef() * 200.f
;
3484 float xPos
= (float) (-bleedf
+ progress
* (model
.xMax
+ bleedf
));
3485 for (Point p
: model
.points
) {
3486 float d
= (p
.x
- xPos
) / bleedf
;
3488 colors
[p
.index
] = c2
[p
.index
];
3490 colors
[p
.index
] = c1
[p
.index
];
3492 colors
[p
.index
] = lerpColor(c2
[p
.index
], c1
[p
.index
], d
, RGB
);
3498 abstract class BlendTransition
extends SCTransition
{
3500 final int blendType
;
3502 BlendTransition(GLucose glucose
, int blendType
) {
3504 this.blendType
= blendType
;
3507 public void computeBlend(int[] c1
, int[] c2
, double progress
) {
3508 if (progress
< 0.5f
) {
3509 for (int i
= 0; i
< c1
.length
; ++i
) {
3510 colors
[i
] = lerpColor(
3512 blendColor(c1
[i
], c2
[i
], blendType
),
3513 (float) (2.f
*progress
),
3517 for (int i
= 0; i
< c1
.length
; ++i
) {
3518 colors
[i
] = lerpColor(
3520 blendColor(c1
[i
], c2
[i
], blendType
),
3521 (float) (2.f
*(1.f
- progress
)),
3528 class MultiplyTransition
extends BlendTransition
{
3529 MultiplyTransition(GLucose glucose
) {
3530 super(glucose
, MULTIPLY
);
3534 class ScreenTransition
extends BlendTransition
{
3535 ScreenTransition(GLucose glucose
) {
3536 super(glucose
, SCREEN
);
3540 class BurnTransition
extends BlendTransition
{
3541 BurnTransition(GLucose glucose
) {
3542 super(glucose
, BURN
);
3546 class DodgeTransition
extends BlendTransition
{
3547 DodgeTransition(GLucose glucose
) {
3548 super(glucose
, DODGE
);
3552 class OverlayTransition
extends BlendTransition
{
3553 OverlayTransition(GLucose glucose
) {
3554 super(glucose
, OVERLAY
);
3558 class AddTransition
extends BlendTransition
{
3559 AddTransition(GLucose glucose
) {
3560 super(glucose
, ADD
);
3564 class SubtractTransition
extends BlendTransition
{
3565 SubtractTransition(GLucose glucose
) {
3566 super(glucose
, SUBTRACT
);
3570 class SoftLightTransition
extends BlendTransition
{
3571 SoftLightTransition(GLucose glucose
) {
3572 super(glucose
, SOFT_LIGHT
);
3576 class BassPod
extends SCPattern
{
3578 private GraphicEQ eq
= null;
3580 private final BasicParameter clr
= new BasicParameter("CLR", 0.5f
);
3582 public BassPod(GLucose glucose
) {
3587 protected void onActive() {
3589 eq
= new GraphicEQ(lx
, 16);
3590 eq
.range
.setValue(0.4f
);
3591 eq
.level
.setValue(0.4f
);
3592 eq
.slope
.setValue(0.6f
);
3593 addParameter(eq
.level
);
3594 addParameter(eq
.range
);
3595 addParameter(eq
.attack
);
3596 addParameter(eq
.release
);
3597 addParameter(eq
.slope
);
3601 public void run(double deltaMs
) {
3604 float bassLevel
= eq
.getAverageLevel(0, 5);
3606 float satBase
= bassLevel
*480*clr
.getValuef();
3608 for (Point p
: model
.points
) {
3609 int avgIndex
= (int) constrain(1 + abs(p
.x
-model
.cx
)/(model
.cx
)*(eq
.numBands
-5), 0, eq
.numBands
-5);
3611 for (int i
= avgIndex
; i
< avgIndex
+ 5; ++i
) {
3612 value
+= eq
.getLevel(i
);
3616 float b
= constrain(8 * (value
*model
.yMax
- abs(p
.y
-model
.yMax
/2.f
)), 0, 100);
3617 colors
[p
.index
] = lx
.hsb(
3618 (lx
.getBaseHuef() + abs(p
.y
- model
.cy
) + abs(p
.x
- model
.cx
)) % 360,
3619 constrain(satBase
- .6f
*dist(p
.x
, p
.y
, model
.cx
, model
.cy
), 0, 100),
3627 class CubeEQ
extends SCPattern
{
3629 private GraphicEQ eq
= null;
3631 private final BasicParameter edge
= new BasicParameter("EDGE", 0.5f
);
3632 private final BasicParameter clr
= new BasicParameter("CLR", 0.5f
);
3633 private final BasicParameter blockiness
= new BasicParameter("BLK", 0.5f
);
3635 public CubeEQ(GLucose glucose
) {
3639 protected void onActive() {
3641 eq
= new GraphicEQ(lx
, 16);
3642 addParameter(eq
.level
);
3643 addParameter(eq
.range
);
3644 addParameter(eq
.attack
);
3645 addParameter(eq
.release
);
3646 addParameter(eq
.slope
);
3649 addParameter(blockiness
);
3653 public void run(double deltaMs
) {
3656 float edgeConst
= 2 + 30*edge
.getValuef();
3657 float clrConst
= 1.1f
+ clr
.getValuef();
3659 for (Point p
: model
.points
) {
3660 float avgIndex
= constrain(2 + p
.x
/ model
.xMax
* (eq
.numBands
-4), 0, eq
.numBands
-4);
3661 int avgFloor
= (int) avgIndex
;
3663 float leftVal
= eq
.getLevel(avgFloor
);
3664 float rightVal
= eq
.getLevel(avgFloor
+1);
3665 float smoothValue
= lerp(leftVal
, rightVal
, avgIndex
-avgFloor
);
3667 float chunkyValue
= (
3668 eq
.getLevel(avgFloor
/4*4) +
3669 eq
.getLevel(avgFloor
/4*4 + 1) +
3670 eq
.getLevel(avgFloor
/4*4 + 2) +
3671 eq
.getLevel(avgFloor
/4*4 + 3)
3674 float value
= lerp(smoothValue
, chunkyValue
, blockiness
.getValuef());
3676 float b
= constrain(edgeConst
* (value
*model
.yMax
- p
.y
), 0, 100);
3677 colors
[p
.index
] = lx
.hsb(
3678 (480 + lx
.getBaseHuef() - min(clrConst
*p
.y
, 120)) % 360,
3686 class BoomEffect
extends SCEffect
{
3688 final BasicParameter falloff
= new BasicParameter("WIDTH", 0.5f
);
3689 final BasicParameter speed
= new BasicParameter("SPD", 0.5f
);
3690 final BasicParameter bright
= new BasicParameter("BRT", 1.0f
);
3691 final BasicParameter sat
= new BasicParameter("SAT", 0.2f
);
3692 List
<Layer
> layers
= new ArrayList
<Layer
>();
3693 final float maxr
= sqrt(model
.xMax
*model
.xMax
+ model
.yMax
*model
.yMax
+ model
.zMax
*model
.zMax
) + 10;
3696 LinearEnvelope boom
= new LinearEnvelope(-40, 500, 1300);
3703 public void trigger() {
3704 float falloffv
= falloffv();
3705 boom
.setRange(-100 / falloffv
, maxr
+ 100/falloffv
, 4000 - speed
.getValuef() * 3300);
3709 public void apply(int[] colors
) {
3710 float brightv
= 100 * bright
.getValuef();
3711 float falloffv
= falloffv();
3712 float satv
= sat
.getValuef() * 100;
3713 float huev
= lx
.getBaseHuef();
3714 for (Point p
: model
.points
) {
3715 colors
[p
.index
] = blendColor(
3717 lx
.hsb(huev
, satv
, constrain(brightv
- falloffv
*abs(boom
.getValuef() - dist(p
.x
, 2*p
.y
, 3*p
.z
, model
.xMax
/2, model
.yMax
, model
.zMax
*1.5f
)), 0, 100)),
3723 BoomEffect(GLucose glucose
) {
3724 super(glucose
, true);
3725 addParameter(falloff
);
3726 addParameter(speed
);
3727 addParameter(bright
);
3731 public void onEnable() {
3732 for (Layer l
: layers
) {
3733 if (!l
.boom
.isRunning()) {
3738 layers
.add(new Layer());
3741 private float falloffv() {
3742 return 20 - 19 * falloff
.getValuef();
3745 public void onTrigger() {
3749 public void apply(int[] colors
) {
3750 for (Layer l
: layers
) {
3751 if (l
.boom
.isRunning()) {
3758 public class PianoKeyPattern
extends SCPattern
{
3760 final LinearEnvelope
[] cubeBrt
;
3761 final SinLFO base
[];
3762 final BasicParameter attack
= new BasicParameter("ATK", 0.1f
);
3763 final BasicParameter release
= new BasicParameter("REL", 0.5f
);
3764 final BasicParameter level
= new BasicParameter("AMB", 0.6f
);
3766 PianoKeyPattern(GLucose glucose
) {
3769 addParameter(attack
);
3770 addParameter(release
);
3771 addParameter(level
);
3772 cubeBrt
= new LinearEnvelope
[model
.cubes
.size() / 4];
3773 for (int i
= 0; i
< cubeBrt
.length
; ++i
) {
3774 addModulator(cubeBrt
[i
] = new LinearEnvelope(0, 0, 100));
3776 base
= new SinLFO
[model
.cubes
.size() / 12];
3777 for (int i
= 0; i
< base
.length
; ++i
) {
3778 addModulator(base
[i
] = new SinLFO(0, 1, 7000 + 1000*i
)).trigger();
3782 private float getAttackTime() {
3783 return 15 + attack
.getValuef()*attack
.getValuef() * 2000;
3786 private float getReleaseTime() {
3787 return 15 + release
.getValuef() * 3000;
3790 private LinearEnvelope
getEnvelope(int index
) {
3791 return cubeBrt
[index
% cubeBrt
.length
];
3794 private SinLFO
getBase(int index
) {
3795 return base
[index
% base
.length
];
3798 public boolean noteOn(Note note
) {
3799 LinearEnvelope env
= getEnvelope(note
.getPitch());
3800 env
.setEndVal(min(1, env
.getValuef() + (note
.getVelocity() / 127.f
)), getAttackTime()).start();
3804 public boolean noteOff(Note note
) {
3805 getEnvelope(note
.getPitch()).setEndVal(0, getReleaseTime()).start();
3809 public void run(double deltaMs
) {
3811 float huef
= lx
.getBaseHuef();
3812 float levelf
= level
.getValuef();
3813 for (Cube c
: model
.cubes
) {
3814 float v
= max(getBase(i
).getValuef() * levelf
/4.f
, getEnvelope(i
++).getValuef());
3816 (huef
+ 20*v
+ abs(c
.cx
-model
.xMax
/2.f
)*.3f
+ c
.cy
) % 360,
3824 class CrossSections
extends SCPattern
{
3826 final SinLFO x
= new SinLFO(0, model
.xMax
, 5000);
3827 final SinLFO y
= new SinLFO(0, model
.yMax
, 6000);
3828 final SinLFO z
= new SinLFO(0, model
.zMax
, 7000);
3830 final BasicParameter xw
= new BasicParameter("XWID", 0.3f
);
3831 final BasicParameter yw
= new BasicParameter("YWID", 0.3f
);
3832 final BasicParameter zw
= new BasicParameter("ZWID", 0.3f
);
3833 final BasicParameter xr
= new BasicParameter("XRAT", 0.7f
);
3834 final BasicParameter yr
= new BasicParameter("YRAT", 0.6f
);
3835 final BasicParameter zr
= new BasicParameter("ZRAT", 0.5f
);
3836 final BasicParameter xl
= new BasicParameter("XLEV", 1);
3837 final BasicParameter yl
= new BasicParameter("YLEV", 1);
3838 final BasicParameter zl
= new BasicParameter("ZLEV", 0.5f
);
3841 CrossSections(GLucose glucose
) {
3843 addModulator(x
).trigger();
3844 addModulator(y
).trigger();
3845 addModulator(z
).trigger();
3849 protected void addParams() {
3861 public void onParameterChanged(LXParameter p
) {
3863 x
.setDuration(10000 - 8800*p
.getValuef());
3864 } else if (p
== yr
) {
3865 y
.setDuration(10000 - 9000*p
.getValuef());
3866 } else if (p
== zr
) {
3867 z
.setDuration(10000 - 9000*p
.getValuef());
3873 protected void updateXYZVals() {
3879 public void run(double deltaMs
) {
3882 float xlv
= 100*xl
.getValuef();
3883 float ylv
= 100*yl
.getValuef();
3884 float zlv
= 100*zl
.getValuef();
3886 float xwv
= 100.f
/ (10 + 40*xw
.getValuef());
3887 float ywv
= 100.f
/ (10 + 40*yw
.getValuef());
3888 float zwv
= 100.f
/ (10 + 40*zw
.getValuef());
3890 for (Point p
: model
.points
) {
3892 c
= blendColor(c
, lx
.hsb(
3893 (lx
.getBaseHuef() + p
.x
/10 + p
.y
/3) % 360,
3894 constrain(140 - 1.1f
*abs(p
.x
- model
.xMax
/2.f
), 0, 100),
3895 max(0, xlv
- xwv
*abs(p
.x
- xv
))
3897 c
= blendColor(c
, lx
.hsb(
3898 (lx
.getBaseHuef() + 80 + p
.y
/10) % 360,
3899 constrain(140 - 2.2f
*abs(p
.y
- model
.yMax
/2.f
), 0, 100),
3900 max(0, ylv
- ywv
*abs(p
.y
- yv
))
3902 c
= blendColor(c
, lx
.hsb(
3903 (lx
.getBaseHuef() + 160 + p
.z
/ 10 + p
.y
/2) % 360,
3904 constrain(140 - 2.2f
*abs(p
.z
- model
.zMax
/2.f
), 0, 100),
3905 max(0, zlv
- zwv
*abs(p
.z
- zv
))
3907 colors
[p
.index
] = c
;
3912 class Blinders
extends SCPattern
{
3915 final TriangleLFO r
;
3917 final TriangleLFO hs
;
3919 public Blinders(GLucose glucose
) {
3922 for (int i
= 0; i
< m
.length
; ++i
) {
3923 addModulator(m
[i
] = new SinLFO(0.5f
, 120, (120000.f
/ (3+i
)))).trigger();
3925 addModulator(r
= new TriangleLFO(9000, 15000, 29000)).trigger();
3926 addModulator(s
= new SinLFO(-20, 275, 11000)).trigger();
3927 addModulator(hs
= new TriangleLFO(0.1f
, 0.5f
, 15000)).trigger();
3928 s
.modulateDurationBy(r
);
3931 public void run(double deltaMs
) {
3932 float hv
= lx
.getBaseHuef();
3934 for (Strip strip
: model
.strips
) {
3936 float mv
= m
[si
% m
.length
].getValuef();
3937 for (Point p
: strip
.points
) {
3938 colors
[p
.index
] = lx
.hsb(
3939 (hv
+ p
.z
+ p
.y
*hs
.getValuef()) % 360,
3940 min(100, abs(p
.x
- s
.getValuef())/2.f
),
3941 max(0, 100 - mv
/2.f
- mv
* abs(i
- (strip
.metrics
.length
-1)/2.f
))
3950 class Psychedelia
extends SCPattern
{
3953 SinLFO m
= new SinLFO(-0.5f
, NUM
-0.5f
, 9000);
3954 SinLFO s
= new SinLFO(-20, 147, 11000);
3955 TriangleLFO h
= new TriangleLFO(0, 240, 19000);
3956 SinLFO c
= new SinLFO(-.2f
, .8f
, 31000);
3958 Psychedelia(GLucose glucose
) {
3960 addModulator(m
).trigger();
3961 addModulator(s
).trigger();
3962 addModulator(h
).trigger();
3963 addModulator(c
).trigger();
3966 public void run(double deltaMs
) {
3967 float huev
= h
.getValuef();
3968 float cv
= c
.getValuef();
3969 float sv
= s
.getValuef();
3970 float mv
= m
.getValuef();
3972 for (Strip strip
: model
.strips
) {
3973 for (Point p
: strip
.points
) {
3974 colors
[p
.index
] = lx
.hsb(
3975 (huev
+ i
*constrain(cv
, 0, 2) + p
.z
/2.f
+ p
.x
/4.f
) % 360,
3976 min(100, abs(p
.y
-sv
)),
3977 max(0, 100 - 50*abs((i
%NUM
) - mv
))
3985 class AskewPlanes
extends SCPattern
{
3988 private final SinLFO a
;
3989 private final SinLFO b
;
3990 private final SinLFO c
;
3997 addModulator(a
= new SinLFO(-1, 1, 4000 + 1029*i
)).trigger();
3998 addModulator(b
= new SinLFO(-1, 1, 11000 - 1104*i
)).trigger();
3999 addModulator(c
= new SinLFO(-50, 50, 4000 + 1000*i
* ((i
% 2 == 0) ?
1 : -1))).trigger();
4002 public void run(double deltaMs
) {
4006 denom
= sqrt(av
*av
+ bv
*bv
);
4010 final Plane
[] planes
;
4011 final int NUM_PLANES
= 3;
4013 AskewPlanes(GLucose glucose
) {
4015 planes
= new Plane
[NUM_PLANES
];
4016 for (int i
= 0; i
< planes
.length
; ++i
) {
4017 planes
[i
] = new Plane(i
);
4021 public void run(double deltaMs
) {
4022 float huev
= lx
.getBaseHuef();
4024 // This is super fucking bizarre. But if this is a for loop, the framerate
4025 // tanks to like 30FPS, instead of 60. Call them manually and it works fine.
4026 // Doesn't make ANY sense... there must be some weird side effect going on
4027 // with the Processing internals perhaps?
4028 // for (Plane plane : planes) {
4029 // plane.run(deltaMs);
4031 planes
[0].run(deltaMs
);
4032 planes
[1].run(deltaMs
);
4033 planes
[2].run(deltaMs
);
4035 for (Point p
: model
.points
) {
4036 float d
= MAX_FLOAT
;
4037 for (Plane plane
: planes
) {
4038 if (plane
.denom
!= 0) {
4039 d
= min(d
, abs(plane
.av
*(p
.x
-model
.cx
) + plane
.bv
*(p
.y
-model
.cy
) + plane
.cv
) / plane
.denom
);
4042 colors
[p
.index
] = lx
.hsb(
4043 (huev
+ abs(p
.x
-model
.cx
)*.3f
+ p
.y
*.8f
) % 360,
4044 max(0, 100 - .8f
*abs(p
.x
- model
.cx
)),
4045 constrain(140 - 10.f
*d
, 0, 100)
4051 class ShiftingPlane
extends SCPattern
{
4053 final SinLFO a
= new SinLFO(-.2f
, .2f
, 5300);
4054 final SinLFO b
= new SinLFO(1, -1, 13300);
4055 final SinLFO c
= new SinLFO(-1.4f
, 1.4f
, 5700);
4056 final SinLFO d
= new SinLFO(-10, 10, 9500);
4058 ShiftingPlane(GLucose glucose
) {
4060 addModulator(a
).trigger();
4061 addModulator(b
).trigger();
4062 addModulator(c
).trigger();
4063 addModulator(d
).trigger();
4066 public void run(double deltaMs
) {
4067 float hv
= lx
.getBaseHuef();
4068 float av
= a
.getValuef();
4069 float bv
= b
.getValuef();
4070 float cv
= c
.getValuef();
4071 float dv
= d
.getValuef();
4072 float denom
= sqrt(av
*av
+ bv
*bv
+ cv
*cv
);
4073 for (Point p
: model
.points
) {
4074 float d
= abs(av
*(p
.x
-model
.cx
) + bv
*(p
.y
-model
.cy
) + cv
*(p
.z
-model
.cz
) + dv
) / denom
;
4075 colors
[p
.index
] = lx
.hsb(
4076 (hv
+ abs(p
.x
-model
.cx
)*.6f
+ abs(p
.y
-model
.cy
)*.9f
+ abs(p
.z
- model
.cz
)) % 360,
4077 constrain(110 - d
*6, 0, 100),
4078 constrain(130 - 7*d
, 0, 100)
4084 class Traktor
extends SCPattern
{
4086 final int FRAME_WIDTH
= 60;
4088 final BasicParameter speed
= new BasicParameter("SPD", 0.5f
);
4090 private float[] bass
= new float[FRAME_WIDTH
];
4091 private float[] treble
= new float[FRAME_WIDTH
];
4093 private int index
= 0;
4094 private GraphicEQ eq
= null;
4096 public Traktor(GLucose glucose
) {
4098 for (int i
= 0; i
< FRAME_WIDTH
; ++i
) {
4102 addParameter(speed
);
4105 public void onActive() {
4107 eq
= new GraphicEQ(lx
, 16);
4108 eq
.slope
.setValue(0.6f
);
4109 eq
.level
.setValue(0.65f
);
4110 eq
.range
.setValue(0.35f
);
4111 eq
.release
.setValue(0.4f
);
4112 addParameter(eq
.level
);
4113 addParameter(eq
.range
);
4114 addParameter(eq
.attack
);
4115 addParameter(eq
.release
);
4116 addParameter(eq
.slope
);
4122 public void run(double deltaMs
) {
4125 int stepThresh
= (int) (40 - 39*speed
.getValuef());
4127 if (counter
< stepThresh
) {
4130 counter
= counter
% stepThresh
;
4132 index
= (index
+ 1) % FRAME_WIDTH
;
4134 float rawBass
= eq
.getAverageLevel(0, 4);
4135 float rawTreble
= eq
.getAverageLevel(eq
.numBands
-7, 7);
4137 bass
[index
] = rawBass
* rawBass
* rawBass
* rawBass
;
4138 treble
[index
] = rawTreble
* rawTreble
;
4140 for (Point p
: model
.points
) {
4141 int i
= (int) constrain((model
.xMax
- p
.x
) / model
.xMax
* FRAME_WIDTH
, 0, FRAME_WIDTH
-1);
4142 int pos
= (index
+ FRAME_WIDTH
- i
) % FRAME_WIDTH
;
4144 colors
[p
.index
] = lx
.hsb(
4145 (360 + lx
.getBaseHuef() + .8f
*abs(p
.x
-model
.cx
)) % 360,
4147 constrain(9 * (bass
[pos
]*model
.cy
- abs(p
.y
- model
.cy
+ 5)), 0, 100)
4149 colors
[p
.index
] = blendColor(colors
[p
.index
], lx
.hsb(
4150 (400 + lx
.getBaseHuef() + .5f
*abs(p
.x
-model
.cx
)) % 360,
4152 constrain(5 * (treble
[pos
]*.6f
*model
.cy
- abs(p
.y
- model
.cy
)), 0, 100)
4159 class ColorFuckerEffect
extends SCEffect
{
4161 final BasicParameter level
= new BasicParameter("BRT", 1);
4162 final BasicParameter desat
= new BasicParameter("DSAT", 0);
4163 final BasicParameter hueShift
= new BasicParameter("HSHFT", 0);
4164 final BasicParameter sharp
= new BasicParameter("SHARP", 0);
4165 final BasicParameter soft
= new BasicParameter("SOFT", 0);
4166 final BasicParameter mono
= new BasicParameter("MONO", 0);
4167 final BasicParameter invert
= new BasicParameter("INVERT", 0);
4170 float[] hsb
= new float[3];
4172 ColorFuckerEffect(GLucose glucose
) {
4174 addParameter(level
);
4175 addParameter(desat
);
4176 addParameter(sharp
);
4177 addParameter(hueShift
);
4180 addParameter(invert
);
4183 public void apply(int[] colors
) {
4187 float bMod
= level
.getValuef();
4188 float sMod
= 1 - desat
.getValuef();
4189 float hMod
= hueShift
.getValuef();
4190 float fSharp
= 1/(1.0001f
-sharp
.getValuef());
4191 float fSoft
= soft
.getValuef();
4192 boolean mon
= mono
.getValuef() > 0.5f
;
4193 boolean ivt
= invert
.getValuef() > 0.5f
;
4194 if (bMod
< 1 || sMod
< 1 || hMod
> 0 || fSharp
> 0 || ivt
|| mon
|| fSoft
> 0) {
4195 for (int i
= 0; i
< colors
.length
; ++i
) {
4196 lx
.RGBtoHSB(colors
[i
], hsb
);
4198 hsb
[0] = lx
.getBaseHuef() / 360.f
;
4201 hsb
[2] = 1 - hsb
[2];
4204 hsb
[2] = hsb
[2] < .5f ?
pow(hsb
[2],fSharp
) : 1-pow(1-hsb
[2],fSharp
);
4207 if (hsb
[2] > 0.5f
) {
4208 hsb
[2] = lerp(hsb
[2], 0.5f
+ 2 * (hsb
[2]-0.5f
)*(hsb
[2]-0.5f
), fSoft
);
4210 hsb
[2] = lerp(hsb
[2], 0.5f
* sqrt(2*hsb
[2]), fSoft
);
4214 (360.f
* hsb
[0] + hMod
*360.f
) % 360,
4215 100.f
* hsb
[1] * sMod
,
4216 100.f
* hsb
[2] * bMod
4223 class QuantizeEffect
extends SCEffect
{
4225 int[] quantizedFrame
;
4227 final BasicParameter amount
= new BasicParameter("AMT", 0);
4229 QuantizeEffect(GLucose glucose
) {
4231 quantizedFrame
= new int[glucose
.lx
.total
];
4235 public void apply(int[] colors
) {
4236 float fQuant
= amount
.getValuef();
4238 float tRamp
= (lx
.tempo
.rampf() % (1.f
/pow(2,floor((1-fQuant
) * 4))));
4239 float f
= lastQuant
;
4242 for (int i
= 0; i
< colors
.length
; ++i
) {
4243 colors
[i
] = quantizedFrame
[i
];
4248 for (int i
= 0; i
< colors
.length
; ++i
) {
4249 quantizedFrame
[i
] = colors
[i
];
4254 class BlurEffect
extends SCEffect
{
4256 final LXParameter amount
= new BasicParameter("AMT", 0);
4258 final LinearEnvelope env
= new LinearEnvelope(0, 1, 100);
4260 BlurEffect(GLucose glucose
) {
4262 addParameter(amount
);
4264 frame
= new int[lx
.total
];
4265 for (int i
= 0; i
< frame
.length
; ++i
) {
4266 frame
[i
] = 0xff000000;
4270 public void onEnable() {
4271 env
.setRangeFromHereTo(1, 400).start();
4272 for (int i
= 0; i
< frame
.length
; ++i
) {
4273 frame
[i
] = 0xff000000;
4277 public void onDisable() {
4278 env
.setRangeFromHereTo(0, 1000).start();
4281 public void apply(int[] colors
) {
4282 float amt
= env
.getValuef() * amount
.getValuef();
4285 amt
= 1 - (amt
*amt
*amt
);
4286 for (int i
= 0; i
< colors
.length
; ++i
) {
4287 // frame[i] = colors[i] = blendColor(colors[i], lerpColor(#000000, frame[i], amt, RGB), SCREEN);
4288 frame
[i
] = colors
[i
] = lerpColor(colors
[i
], blendColor(colors
[i
], frame
[i
], SCREEN
), amt
, RGB
);
4294 abstract class SamPattern
extends SCPattern
{
4295 public SamPattern(GLucose glucose
) {
4301 class JazzRainbow
extends SamPattern
{
4302 public JazzRainbow(GLucose glucose
) {
4307 public void run(double deltaMs
) {
4308 // Access the core master hue via this method call
4309 float hv
= lx
.getBaseHuef();
4310 for (int i
= 0; i
< colors
.length
*5; i
=i
+27) {
4313 for (int b
= 0; b
< 70; b
++) {
4314 colors
[(i
+b
)%colors
.length
] = lx
.hsb(a
+i
%250, 100, b
*a
%100);
4323 class HelixPattern
extends SCPattern
{
4325 // Stores a line in point + vector form
4326 private class Line
{
4327 private final PVector origin
;
4328 private final PVector vector
;
4330 Line(PVector pt
, PVector v
) {
4336 public PVector
getPoint() {
4340 public PVector
getVector() {
4344 public PVector
getPointAt(final float t
) {
4345 return PVector
.add(origin
, PVector
.mult(vector
, t
));
4348 public boolean isColinear(final PVector pt
) {
4349 PVector projected
= projectPoint(pt
);
4350 return projected
.x
==pt
.x
&& projected
.y
==pt
.y
&& projected
.z
==pt
.z
;
4353 public float getTValue(final PVector pt
) {
4354 PVector subtraction
= PVector
.sub(pt
, origin
);
4355 return subtraction
.dot(vector
);
4358 public PVector
projectPoint(final PVector pt
) {
4359 return getPointAt(getTValue(pt
));
4362 public PVector
rotatePoint(final PVector p
, final float t
) {
4363 final PVector o
= origin
;
4364 final PVector v
= vector
;
4366 final float cost
= cos(t
);
4367 final float sint
= sin(t
);
4369 float x
= (o
.x
*(v
.y
*v
.y
+ v
.z
*v
.z
) - v
.x
*(o
.y
*v
.y
+ o
.z
*v
.z
- v
.x
*p
.x
- v
.y
*p
.y
- v
.z
*p
.z
))*(1 - cost
) + p
.x
*cost
+ (-o
.z
*v
.y
+ o
.y
*v
.z
- v
.z
*p
.y
+ v
.y
*p
.z
)*sint
;
4370 float y
= (o
.y
*(v
.x
*v
.x
+ v
.z
*v
.z
) - v
.y
*(o
.x
*v
.x
+ o
.z
*v
.z
- v
.x
*p
.x
- v
.y
*p
.y
- v
.z
*p
.z
))*(1 - cost
) + p
.y
*cost
+ (o
.z
*v
.x
- o
.x
*v
.z
+ v
.z
*p
.x
- v
.x
*p
.z
)*sint
;
4371 float z
= (o
.z
*(v
.x
*v
.x
+ v
.y
*v
.y
) - v
.z
*(o
.x
*v
.x
+ o
.y
*v
.y
- v
.x
*p
.x
- v
.y
*p
.y
- v
.z
*p
.z
))*(1 - cost
) + p
.z
*cost
+ (-o
.y
*v
.x
+ o
.x
*v
.y
- v
.y
*p
.x
+ v
.x
*p
.y
)*sint
;
4372 return new PVector(x
, y
, z
);
4376 private class Helix
{
4377 private final Line axis
;
4378 private final float period
; // period of coil
4379 private final float rotationPeriod
; // animation period
4380 private final float radius
; // radius of coil
4381 private final float girth
; // girth of coil
4382 private final PVector referencePoint
;
4383 private float phase
;
4384 private PVector phaseNormal
;
4386 Helix(Line axis
, float period
, float radius
, float girth
, float phase
, float rotationPeriod
) {
4388 this.period
= period
;
4389 this.radius
= radius
;
4392 this.rotationPeriod
= rotationPeriod
;
4394 // Generate a normal that will rotate to
4395 // produce the helical shape.
4396 PVector pt
= new PVector(0, 1, 0);
4397 if (this.axis
.isColinear(pt
)) {
4398 pt
= new PVector(0, 0, 1);
4399 if (this.axis
.isColinear(pt
)) {
4400 pt
= new PVector(0, 1, 1);
4404 this.referencePoint
= pt
;
4406 // The normal is calculated by the cross product of the axis
4407 // and a random point that is not colinear with it.
4408 phaseNormal
= axis
.getVector().cross(referencePoint
);
4409 phaseNormal
.normalize();
4410 phaseNormal
.mult(radius
);
4413 public Line
getAxis() {
4417 public PVector
getPhaseNormal() {
4421 public float getPhase() {
4425 public void step(double deltaMs
) {
4427 if (rotationPeriod
!= 0) {
4428 this.phase
= (phase
+ ((float)deltaMs
/ (float)rotationPeriod
) * TWO_PI
);
4432 public PVector
pointOnToroidalAxis(float t
) {
4433 PVector p
= axis
.getPointAt(t
);
4434 PVector middle
= PVector
.add(p
, phaseNormal
);
4435 return axis
.rotatePoint(middle
, (t
/ period
) * TWO_PI
+ phase
);
4438 private float myDist(PVector p1
, PVector p2
) {
4439 final float x
= p2
.x
-p1
.x
;
4440 final float y
= p2
.y
-p1
.y
;
4441 final float z
= p2
.z
-p1
.z
;
4442 return sqrt(x
*x
+ y
*y
+ z
*z
);
4445 public int colorOfPoint(final PVector p
) {
4446 final float t
= axis
.getTValue(p
);
4447 final PVector axisPoint
= axis
.getPointAt(t
);
4449 // For performance reasons, cut out points that are outside of
4450 // the tube where the toroidal coil lives.
4451 if (abs(myDist(p
, axisPoint
) - radius
) > girth
*.5f
) {
4452 return lx
.hsb(0,0,0);
4455 // Find the appropriate point for the current rotation
4457 PVector toroidPoint
= axisPoint
;
4458 toroidPoint
.add(phaseNormal
);
4459 toroidPoint
= axis
.rotatePoint(toroidPoint
, (t
/ period
) * TWO_PI
+ phase
);
4461 // The rotated point represents the middle of the girth of
4462 // the helix. Figure out if the current point is inside that
4464 float d
= myDist(p
, toroidPoint
);
4466 // Soften edges by fading brightness.
4467 float b
= constrain(100*(1 - ((d
-.5f
*girth
)/(girth
*.5f
))), 0, 100);
4468 return lx
.hsb((lx
.getBaseHuef() + (360*(phase
/ TWO_PI
)))%360, 80, b
);
4472 private class BasePairInfo
{
4477 BasePairInfo(Line line
, float colorPhase1
, float colorPhase2
) {
4479 this.colorPhase1
= colorPhase1
;
4480 this.colorPhase2
= colorPhase2
;
4484 private final Helix h1
;
4485 private final Helix h2
;
4486 private final BasePairInfo
[] basePairs
;
4488 private final BasicParameter helix1On
= new BasicParameter("H1ON", 1);
4489 private final BasicParameter helix2On
= new BasicParameter("H2ON", 1);
4490 private final BasicParameter basePairsOn
= new BasicParameter("BPON", 1);
4492 private static final float helixCoilPeriod
= 100;
4493 private static final float helixCoilRadius
= 50;
4494 private static final float helixCoilGirth
= 30;
4495 private static final float helixCoilRotationPeriod
= 5000;
4497 private static final float spokePeriod
= 40;
4498 private static final float spokeGirth
= 20;
4499 private static final float spokePhase
= 10;
4500 private static final float spokeRadius
= helixCoilRadius
- helixCoilGirth
*.5f
;
4502 private static final float tMin
= -200;
4503 private static final float tMax
= 200;
4505 public HelixPattern(GLucose glucose
) {
4508 addParameter(helix1On
);
4509 addParameter(helix2On
);
4510 addParameter(basePairsOn
);
4512 PVector origin
= new PVector(100, 50, 55);
4513 PVector axis
= new PVector(1,0,0);
4516 new Line(origin
, axis
),
4521 helixCoilRotationPeriod
);
4523 new Line(origin
, axis
),
4528 helixCoilRotationPeriod
);
4530 basePairs
= new BasePairInfo
[(int)floor((tMax
- tMin
)/spokePeriod
)];
4533 private void calculateSpokes() {
4534 float colorPhase
= PI
/6;
4535 for (float t
= tMin
+ spokePhase
; t
< tMax
; t
+= spokePeriod
) {
4536 int spokeIndex
= (int)floor((t
- tMin
)/spokePeriod
);
4537 PVector h1point
= h1
.pointOnToroidalAxis(t
);
4538 PVector spokeCenter
= h1
.getAxis().getPointAt(t
);
4539 PVector spokeVector
= PVector
.sub(h1point
, spokeCenter
);
4540 Line spokeLine
= new Line(spokeCenter
, spokeVector
);
4541 basePairs
[spokeIndex
] = new BasePairInfo(spokeLine
, colorPhase
* spokeIndex
, colorPhase
* (spokeIndex
+ 1));
4545 private int calculateSpokeColor(final PVector pt
) {
4546 // Find the closest spoke's t-value and calculate its
4547 // axis. Until everything animates in the model reference
4548 // frame, this has to be calculated at every step because
4549 // the helices rotate.
4550 Line axis
= h1
.getAxis();
4551 float t
= axis
.getTValue(pt
) + spokePhase
;
4552 int spokeIndex
= (int)floor((t
- tMin
+ spokePeriod
/2) / spokePeriod
);
4553 if (spokeIndex
< 0 || spokeIndex
>= basePairs
.length
) {
4554 return lx
.hsb(0,0,0);
4556 BasePairInfo basePair
= basePairs
[spokeIndex
];
4557 Line spokeLine
= basePair
.line
;
4558 PVector pointOnSpoke
= spokeLine
.projectPoint(pt
);
4559 float d
= PVector
.dist(pt
, pointOnSpoke
);
4560 float b
= (PVector
.dist(pointOnSpoke
, spokeLine
.getPoint()) < spokeRadius
) ?
constrain(100*(1 - ((d
-.5f
*spokeGirth
)/(spokeGirth
*.5f
))), 0, 100) : 0.f
;
4561 float phase
= spokeLine
.getTValue(pointOnSpoke
) < 0 ? basePair
.colorPhase1
: basePair
.colorPhase2
;
4562 return lx
.hsb((lx
.getBaseHuef() + (360*(phase
/ TWO_PI
)))%360, 80.f
, b
);
4565 public void run(double deltaMs
) {
4566 boolean h1on
= helix1On
.getValue() > 0.5f
;
4567 boolean h2on
= helix2On
.getValue() > 0.5f
;
4568 boolean spokesOn
= (float)basePairsOn
.getValue() > 0.5f
;
4574 for (Point p
: model
.points
) {
4575 PVector pt
= new PVector(p
.x
,p
.y
,p
.z
);
4576 int h1c
= h1
.colorOfPoint(pt
);
4577 int h2c
= h2
.colorOfPoint(pt
);
4578 int spokeColor
= calculateSpokeColor(pt
);
4581 h1c
= lx
.hsb(0,0,0);
4585 h2c
= lx
.hsb(0,0,0);
4589 spokeColor
= lx
.hsb(0,0,0);
4592 // The helices are positioned to not overlap. If that changes,
4593 // a better blending formula is probably needed.
4594 colors
[p
.index
] = blendColor(blendColor(h1c
, h2c
, ADD
), spokeColor
, ADD
);
4599 class BlankPattern
extends SCPattern
{
4600 BlankPattern(GLucose glucose
) {
4604 public void run(double deltaMs
) {
4605 setColors(0xff000000);
4609 abstract class TestPattern
extends SCPattern
{
4610 public TestPattern(GLucose glucose
) {
4616 class TestSpeakerMapping
extends TestPattern
{
4617 TestSpeakerMapping(GLucose glucose
) {
4621 public void run(double deltaMs
) {
4623 for (Speaker speaker
: model
.speakers
) {
4624 for (Strip strip
: speaker
.strips
) {
4626 for (Point p
: strip
.points
) {
4627 colors
[p
.index
] = lx
.hsb(h
% 360, 100, b
);
4637 class TestBassMapping
extends TestPattern
{
4638 TestBassMapping(GLucose glucose
) {
4642 public void run(double deltaMs
) {
4643 int[] strips
= { 2, 1, 0, 3, 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6 };
4645 for (int si
: strips
) {
4647 for (Point p
: model
.bassBox
.strips
.get(si
).points
) {
4648 colors
[p
.index
] = lx
.hsb(h
% 360, 100, b
);
4656 class TestFloorMapping
extends TestPattern
{
4657 TestFloorMapping(GLucose glucose
) {
4661 public void run(double deltaMs
) {
4662 int[] strutIndices
= {6, 5, 4, 3, 2, 1, 0, 7};
4664 for (int si
: strutIndices
) {
4666 for (Point p
: model
.bassBox
.struts
.get(si
).points
) {
4667 colors
[p
.index
] = lx
.hsb(h
% 360, 100, b
);
4672 int[] floorIndices
= {0, 1, 2, 3};
4674 for (int fi
: floorIndices
) {
4676 for (Point p
: model
.boothFloor
.strips
.get(fi
).points
) {
4677 colors
[p
.index
] = lx
.hsb(h
, 100, b
);
4685 class TestPerformancePattern
extends TestPattern
{
4687 final BasicParameter ops
= new BasicParameter("OPS", 0);
4688 final BasicParameter iter
= new BasicParameter("ITER", 0);
4690 TestPerformancePattern(GLucose glucose
) {
4696 public void run(double deltaMs
) {
4698 for (int j
= 0; j
< ops
.getValuef() * 400000; ++j
) {
4702 if (iter
.getValuef() < 0.25f
) {
4703 for (Point p
: model
.points
) {
4704 colors
[p
.index
] = lx
.hsb(
4705 (p
.x
*.1f
+ p
.y
*.1f
) % 360,
4710 } else if (iter
.getValuef() < 0.5f
) {
4711 for (int i
= 0; i
< colors
.length
; ++i
) {
4713 (90 + model
.px
[i
]*.1f
+ model
.py
[i
]*.1f
) % 360,
4718 } else if (iter
.getValuef() < 0.75f
) {
4719 for (int i
= 0; i
< colors
.length
; ++i
) {
4721 (180 + model
.p
[3*i
]*.1f
+ model
.p
[3*i
+1]*.1f
) % 360,
4727 for (int i
= 0; i
< colors
.length
; ++i
) {
4729 (270 + model
.x(i
)*.1f
+ model
.y(i
)*.1f
) % 360,
4738 class TestStripPattern
extends TestPattern
{
4740 SinLFO d
= new SinLFO(4, 40, 4000);
4742 public TestStripPattern(GLucose glucose
) {
4744 addModulator(d
).trigger();
4747 public void run(double deltaMs
) {
4748 for (Strip s
: model
.strips
) {
4749 for (Point p
: s
.points
) {
4750 colors
[p
.index
] = lx
.hsb(
4753 max(0, 100 - d
.getValuef()*dist(p
.x
, p
.y
, s
.cx
, s
.cy
))
4761 * Simplest demonstration of using the rotating master hue.
4762 * All pixels are full-on the same color.
4764 class TestHuePattern
extends TestPattern
{
4765 public TestHuePattern(GLucose glucose
) {
4769 public void run(double deltaMs
) {
4770 // Access the core master hue via this method call
4771 float hv
= lx
.getBaseHuef();
4772 for (int i
= 0; i
< colors
.length
; ++i
) {
4773 colors
[i
] = lx
.hsb(hv
, 100, 100);
4779 * Test of a wave moving across the X axis.
4781 class TestXPattern
extends TestPattern
{
4782 private final SinLFO xPos
= new SinLFO(0, model
.xMax
, 4000);
4783 public TestXPattern(GLucose glucose
) {
4785 addModulator(xPos
).trigger();
4787 public void run(double deltaMs
) {
4788 float hv
= lx
.getBaseHuef();
4789 for (Point p
: model
.points
) {
4790 // This is a common technique for modulating brightness.
4791 // You can use abs() to determine the distance between two
4792 // values. The further away this point is from an exact
4793 // point, the more we decrease its brightness
4794 float bv
= max(0, 100 - abs(p
.x
- xPos
.getValuef()));
4795 colors
[p
.index
] = lx
.hsb(hv
, 100, bv
);
4801 * Test of a wave on the Y axis.
4803 class TestYPattern
extends TestPattern
{
4804 private final SinLFO yPos
= new SinLFO(0, model
.yMax
, 4000);
4805 public TestYPattern(GLucose glucose
) {
4807 addModulator(yPos
).trigger();
4809 public void run(double deltaMs
) {
4810 float hv
= lx
.getBaseHuef();
4811 for (Point p
: model
.points
) {
4812 float bv
= max(0, 100 - abs(p
.y
- yPos
.getValuef()));
4813 colors
[p
.index
] = lx
.hsb(hv
, 100, bv
);
4819 * Test of a wave on the Z axis.
4821 class TestZPattern
extends TestPattern
{
4822 private final SinLFO zPos
= new SinLFO(0, model
.zMax
, 4000);
4823 public TestZPattern(GLucose glucose
) {
4825 addModulator(zPos
).trigger();
4827 public void run(double deltaMs
) {
4828 float hv
= lx
.getBaseHuef();
4829 for (Point p
: model
.points
) {
4830 float bv
= max(0, 100 - abs(p
.z
- zPos
.getValuef()));
4831 colors
[p
.index
] = lx
.hsb(hv
, 100, bv
);
4837 * This shows how to iterate over towers, enumerated in the model.
4839 class TestTowerPattern
extends TestPattern
{
4840 private final SawLFO towerIndex
= new SawLFO(0, model
.towers
.size(), 1000*model
.towers
.size());
4842 public TestTowerPattern(GLucose glucose
) {
4844 addModulator(towerIndex
).trigger();
4847 public void run(double deltaMs
) {
4849 for (Tower t
: model
.towers
) {
4850 for (Point p
: t
.points
) {
4851 colors
[p
.index
] = lx
.hsb(
4854 max(0, 100 - 80*LXUtils
.wrapdistf(ti
, towerIndex
.getValuef(), model
.towers
.size()))
4864 * This is a demonstration of how to use the projection library. A projection
4865 * creates a mutation of the coordinates of all the points in the model, creating
4866 * virtual x,y,z coordinates. In effect, this is like virtually rotating the entire
4867 * art car. However, since in reality the car does not move, the result is that
4868 * it appears that the object we are drawing on the car is actually moving.
4870 * Keep in mind that what we are creating a projection of is the view coordinates.
4871 * Depending on your intuition, some operations may feel backwards. For instance,
4872 * if you translate the view to the right, it will make it seem that the object
4873 * you are drawing has moved to the left. If you scale the view up 2x, objects
4874 * drawn with the same absolute values will seem to be half the size.
4876 * If this feels counterintuitive at first, don't worry. Just remember that you
4877 * are moving the pixels, not the structure. We're dealing with a finite set
4878 * of sparse, non-uniformly spaced pixels. Mutating the structure would move
4879 * things to a space where there are no pixels in 99% of the cases.
4881 class TestProjectionPattern
extends TestPattern
{
4883 private final Projection projection
;
4884 private final SawLFO angle
= new SawLFO(0, TWO_PI
, 9000);
4885 private final SinLFO yPos
= new SinLFO(-20, 40, 5000);
4887 public TestProjectionPattern(GLucose glucose
) {
4889 projection
= new Projection(model
);
4890 addModulator(angle
).trigger();
4891 addModulator(yPos
).trigger();
4894 public void run(double deltaMs
) {
4895 // For the same reasons described above, it may logically feel to you that
4896 // some of these operations are in reverse order. Again, just keep in mind that
4897 // the car itself is what's moving, not the object
4898 projection
.reset(model
)
4900 // Translate so the center of the car is the origin, offset by yPos
4901 .translateCenter(model
, 0, yPos
.getValuef(), 0)
4903 // Rotate around the origin (now the center of the car) about an X-vector
4904 .rotate(angle
.getValuef(), 1, 0, 0)
4906 // Scale up the Y axis (objects will look smaller in that access)
4909 float hv
= lx
.getBaseHuef();
4910 for (Coord c
: projection
) {
4911 float d
= sqrt(c
.x
*c
.x
+ c
.y
*c
.y
+ c
.z
*c
.z
); // distance from origin
4912 // d = abs(d-60) + max(0, abs(c.z) - 20); // life saver / ring thing
4913 d
= max(0, abs(c
.y
) - 10 + .1f
*abs(c
.z
) + .02f
*abs(c
.x
)); // plane / spear thing
4914 colors
[c
.index
] = lx
.hsb(
4915 (hv
+ .6f
*abs(c
.x
) + abs(c
.z
)) % 360,
4917 constrain(140 - 40*d
, 0, 100)
4923 class TestCubePattern
extends TestPattern
{
4925 private SawLFO index
= new SawLFO(0, Cube
.POINTS_PER_CUBE
, Cube
.POINTS_PER_CUBE
*60);
4927 TestCubePattern(GLucose glucose
) {
4929 addModulator(index
).start();
4932 public void run(double deltaMs
) {
4933 for (Cube c
: model
.cubes
) {
4935 for (Point p
: c
.points
) {
4936 colors
[p
.index
] = lx
.hsb(
4939 max(0, 100 - 80.f
*abs(i
- index
.getValuef()))
4947 class MappingTool
extends TestPattern
{
4949 private int cubeIndex
= 0;
4950 private int stripIndex
= 0;
4951 private int channelIndex
= 0;
4953 public final int MAPPING_MODE_ALL
= 0;
4954 public final int MAPPING_MODE_CHANNEL
= 1;
4955 public final int MAPPING_MODE_SINGLE_CUBE
= 2;
4956 public int mappingMode
= MAPPING_MODE_ALL
;
4958 public final int CUBE_MODE_ALL
= 0;
4959 public final int CUBE_MODE_SINGLE_STRIP
= 1;
4960 public final int CUBE_MODE_STRIP_PATTERN
= 2;
4961 public int cubeMode
= CUBE_MODE_ALL
;
4963 public boolean channelModeRed
= true;
4964 public boolean channelModeGreen
= false;
4965 public boolean channelModeBlue
= false;
4967 private final int numChannels
;
4969 private final PandaMapping
[] pandaMappings
;
4970 private PandaMapping activePanda
;
4971 private ChannelMapping activeChannel
;
4973 MappingTool(GLucose glucose
, PandaMapping
[] pandaMappings
) {
4975 this.pandaMappings
= pandaMappings
;
4976 numChannels
= pandaMappings
.length
* PandaMapping
.CHANNELS_PER_BOARD
;
4980 public int numChannels() {
4984 private void setChannel() {
4985 activePanda
= pandaMappings
[channelIndex
/ PandaMapping
.CHANNELS_PER_BOARD
];
4986 activeChannel
= activePanda
.channelList
[channelIndex
% PandaMapping
.CHANNELS_PER_BOARD
];
4989 private int indexOfCubeInChannel(Cube c
) {
4990 if (activeChannel
.mode
== ChannelMapping
.MODE_CUBES
) {
4992 for (int index
: activeChannel
.objectIndices
) {
4993 if ((index
>= 0) && (c
== model
.getCubeByRawIndex(index
))) {
5002 private void printInfo() {
5003 println("Cube:" + cubeIndex
+ " Strip:" + (stripIndex
+1));
5006 public void cube(int delta
) {
5007 int len
= model
.cubes
.size();
5008 cubeIndex
= (len
+ cubeIndex
+ delta
) % len
;
5012 public void strip(int delta
) {
5013 int len
= Cube
.STRIPS_PER_CUBE
;
5014 stripIndex
= (len
+ stripIndex
+ delta
) % len
;
5018 public void run(double deltaMs
) {
5019 int off
= 0xff000000;
5024 if (channelModeRed
) c
|= r
;
5025 if (channelModeGreen
) c
|= g
;
5026 if (channelModeBlue
) c
|= b
;
5029 for (Cube cube
: model
.cubes
) {
5030 boolean cubeOn
= false;
5031 int indexOfCubeInChannel
= indexOfCubeInChannel(cube
);
5032 switch (mappingMode
) {
5033 case MAPPING_MODE_ALL
: cubeOn
= true; break;
5034 case MAPPING_MODE_SINGLE_CUBE
: cubeOn
= (cubeIndex
== ci
); break;
5035 case MAPPING_MODE_CHANNEL
: cubeOn
= (indexOfCubeInChannel
> 0); break;
5038 if (mappingMode
== MAPPING_MODE_CHANNEL
) {
5040 switch (indexOfCubeInChannel
) {
5041 case 1: cc
= r
; break;
5042 case 2: cc
= r
|g
; break;
5043 case 3: cc
= g
; break;
5044 case 4: cc
= b
; break;
5045 case 5: cc
= r
|b
; break;
5048 } else if (cubeMode
== CUBE_MODE_STRIP_PATTERN
) {
5051 for (Strip strip
: cube
.strips
) {
5052 int faceI
= si
/ Face
.STRIPS_PER_FACE
;
5054 case 0: sc
= r
; break;
5055 case 1: sc
= g
; break;
5056 case 2: sc
= b
; break;
5057 case 3: sc
= r
|g
|b
; break;
5059 if (si
% Face
.STRIPS_PER_FACE
== 2) {
5062 setColor(strip
, sc
);
5065 } else if (cubeMode
== CUBE_MODE_SINGLE_STRIP
) {
5066 setColor(cube
, off
);
5067 setColor(cube
.strips
.get(stripIndex
), c
);
5072 setColor(cube
, off
);
5078 public void setCube(int index
) {
5079 cubeIndex
= index
% model
.cubes
.size();
5082 public void incCube() {
5083 cubeIndex
= (cubeIndex
+ 1) % model
.cubes
.size();
5086 public void decCube() {
5088 if (cubeIndex
< 0) {
5089 cubeIndex
+= model
.cubes
.size();
5093 public void setChannel(int index
) {
5094 channelIndex
= index
% numChannels
;
5098 public void incChannel() {
5099 channelIndex
= (channelIndex
+ 1) % numChannels
;
5103 public void decChannel() {
5104 channelIndex
= (channelIndex
+ numChannels
- 1) % numChannels
;
5108 public void setStrip(int index
) {
5109 stripIndex
= index
% Cube
.STRIPS_PER_CUBE
;
5112 public void incStrip() {
5113 stripIndex
= (stripIndex
+ 1) % Cube
.STRIPS_PER_CUBE
;
5116 public void decStrip() {
5117 stripIndex
= (stripIndex
+ Cube
.STRIPS_PER_CUBE
- 1) % Cube
.STRIPS_PER_CUBE
;
5120 public void keyPressed(UIMapping uiMapping
) {
5122 case UP
: if (mappingMode
== MAPPING_MODE_CHANNEL
) incChannel(); else incCube(); break;
5123 case DOWN
: if (mappingMode
== MAPPING_MODE_CHANNEL
) decChannel(); else decCube(); break;
5124 case LEFT
: decStrip(); break;
5125 case RIGHT
: incStrip(); break;
5128 case 'r': channelModeRed
= !channelModeRed
; break;
5129 case 'g': channelModeGreen
= !channelModeGreen
; break;
5130 case 'b': channelModeBlue
= !channelModeBlue
; break;
5132 uiMapping
.setChannelID(channelIndex
+1);
5133 uiMapping
.setCubeID(cubeIndex
+1);
5134 uiMapping
.setStripID(stripIndex
+1);
5140 * Not very flushed out, but kind of fun nonetheless.
5142 class TimSpheres
extends SCPattern
{
5143 private BasicParameter hueParameter
= new BasicParameter("RAD", 1.0f
);
5144 private final SawLFO lfo
= new SawLFO(0, 1, 10000);
5145 private final SinLFO sinLfo
= new SinLFO(0, 1, 4000);
5146 private final float centerX
, centerY
, centerZ
;
5154 private final Sphere
[] spheres
;
5156 public TimSpheres(GLucose glucose
) {
5158 addParameter(hueParameter
);
5159 addModulator(lfo
).trigger();
5160 addModulator(sinLfo
).trigger();
5161 centerX
= (model
.xMax
+ model
.xMin
) / 2;
5162 centerY
= (model
.yMax
+ model
.yMin
) / 2;
5163 centerZ
= (model
.zMax
+ model
.zMin
) / 2;
5165 spheres
= new Sphere
[2];
5167 spheres
[0] = new Sphere();
5168 spheres
[0].x
= model
.xMin
;
5169 spheres
[0].y
= centerY
;
5170 spheres
[0].z
= centerZ
;
5172 spheres
[0].radius
= 50;
5174 spheres
[1] = new Sphere();
5175 spheres
[1].x
= model
.xMax
;
5176 spheres
[1].y
= centerY
;
5177 spheres
[1].z
= centerZ
;
5178 spheres
[1].hue
= 0.33f
;
5179 spheres
[1].radius
= 50;
5182 public void run(double deltaMs
) {
5183 // Access the core master hue via this method call
5184 float hv
= hueParameter
.getValuef();
5185 float lfoValue
= lfo
.getValuef();
5186 float sinLfoValue
= sinLfo
.getValuef();
5188 spheres
[0].x
= model
.xMin
+ sinLfoValue
* model
.xMax
;
5189 spheres
[1].x
= model
.xMax
- sinLfoValue
* model
.xMax
;
5191 spheres
[0].radius
= 100 * hueParameter
.getValuef();
5192 spheres
[1].radius
= 100 * hueParameter
.getValuef();
5194 for (Point p
: model
.points
) {
5197 int c
= lx
.hsb(0, 0, 0);
5198 for (Sphere s
: spheres
) {
5199 float d
= sqrt(pow(p
.x
- s
.x
, 2) + pow(p
.y
- s
.y
, 2) + pow(p
.z
- s
.z
, 2));
5200 float r
= (s
.radius
); // * (sinLfoValue + 0.5));
5201 value
= max(0, 1 - max(0, d
- r
) / 10);
5203 c
= blendColor(c
, lx
.hsb(((s
.hue
+ lfoValue
) % 1) * 360, 100, min(1, value
) * 100), ADD
);
5206 colors
[p
.index
] = c
;
5218 Vector2(float x
, float y
) {
5223 public float distanceTo(float x
, float y
) {
5224 return sqrt(pow(x
- this.x
, 2) + pow(y
- this.y
, 2));
5227 public float distanceTo(Vector2 v
) {
5228 return distanceTo(v
.x
, v
.y
);
5231 public Vector2
plus(float x
, float y
) {
5232 return new Vector2(this.x
+ x
, this.y
+ y
);
5235 public Vector2
plus(Vector2 v
) {
5236 return plus(v
.x
, v
.y
);
5239 public Vector2
minus(Vector2 v
) {
5240 return plus(-1 * v
.x
, -1 * v
.y
);
5251 Vector3(float x
, float y
, float z
) {
5257 public float distanceTo(float x
, float y
, float z
) {
5258 return sqrt(pow(x
- this.x
, 2) + pow(y
- this.y
, 2) + pow(z
- this.z
, 2));
5261 public float distanceTo(Vector3 v
) {
5262 return distanceTo(v
.x
, v
.y
, v
.z
);
5265 public float distanceTo(Point p
) {
5266 return distanceTo(p
.x
, p
.y
, p
.z
);
5269 public void add(Vector3 other
, float multiplier
) {
5270 this.add(other
.x
* multiplier
, other
.y
* multiplier
, other
.z
* multiplier
);
5273 public void add(float x
, float y
, float z
) {
5279 public void divide(float factor
) {
5287 private float a
, b
, c
, d
, e
, f
, g
, h
, i
;
5289 Rotation(float yaw
, float pitch
, float roll
) {
5290 float cosYaw
= cos(yaw
);
5291 float sinYaw
= sin(yaw
);
5292 float cosPitch
= cos(pitch
);
5293 float sinPitch
= sin(pitch
);
5294 float cosRoll
= cos(roll
);
5295 float sinRoll
= sin(roll
);
5297 a
= cosYaw
* cosPitch
;
5298 b
= cosYaw
* sinPitch
* sinRoll
- sinYaw
* cosRoll
;
5299 c
= cosYaw
* sinPitch
* cosRoll
+ sinYaw
* sinRoll
;
5300 d
= sinYaw
* cosPitch
;
5301 e
= sinYaw
* sinPitch
* sinRoll
+ cosYaw
* cosRoll
;
5302 f
= sinYaw
* sinPitch
* cosRoll
- cosYaw
* sinRoll
;
5304 h
= cosPitch
* sinRoll
;
5305 i
= cosPitch
* cosRoll
;
5308 public Vector3
rotated(Vector3 v
) {
5316 public float rotatedX(Vector3 v
) {
5317 return a
* v
.x
+ b
* v
.y
+ c
* v
.z
;
5320 public float rotatedY(Vector3 v
) {
5321 return d
* v
.x
+ e
* v
.y
+ f
* v
.z
;
5324 public float rotatedZ(Vector3 v
) {
5325 return g
* v
.x
+ h
* v
.y
+ i
* v
.z
;
5330 * Very literal rain effect. Not that great as-is but some tweaking could make it nice.
5332 * - changing hue and direction of "rain" could make a nice fire effect
5333 * - knobs to change frequency and size of rain drops
5334 * - sync somehow to tempo but maybe less frequently than every beat?
5336 class TimRaindrops
extends SCPattern
{
5337 public Vector3
randomVector3() {
5339 random(model
.xMax
- model
.xMin
) + model
.xMin
,
5340 random(model
.yMax
- model
.yMin
) + model
.yMin
,
5341 random(model
.zMax
- model
.zMin
) + model
.zMin
);
5352 this.p
= new Vector3(
5353 random(model
.xMax
- model
.xMin
) + model
.xMin
,
5354 model
.yMax
+ this.radius
,
5355 random(model
.zMax
- model
.zMin
) + model
.zMin
);
5356 float velMagnitude
= 120;
5357 this.v
= new Vector3(
5361 this.hue
= random(40) + 200;
5364 // returns TRUE when this should die
5365 public boolean age(double ms
) {
5366 p
.add(v
, (float) (ms
/ 1000.0f
));
5367 return this.p
.y
< (0 - this.radius
);
5371 private float leftoverMs
= 0;
5372 private float msPerRaindrop
= 40;
5373 private List
<Raindrop
> raindrops
;
5375 public TimRaindrops(GLucose glucose
) {
5377 raindrops
= new LinkedList
<Raindrop
>();
5380 public void run(double deltaMs
) {
5381 leftoverMs
+= deltaMs
;
5382 while (leftoverMs
> msPerRaindrop
) {
5383 leftoverMs
-= msPerRaindrop
;
5384 raindrops
.add(new Raindrop());
5387 for (Point p
: model
.points
) {
5390 lx
.hsb(210, 20, (float)Math
.max(0, 1 - Math
.pow((model
.yMax
- p
.y
) / 10, 2)) * 50),
5391 lx
.hsb(220, 60, (float)Math
.max(0, 1 - Math
.pow((p
.y
- model
.yMin
) / 10, 2)) * 100),
5393 for (Raindrop raindrop
: raindrops
) {
5394 if (p
.x
>= (raindrop
.p
.x
- raindrop
.radius
) && p
.x
<= (raindrop
.p
.x
+ raindrop
.radius
) &&
5395 p
.y
>= (raindrop
.p
.y
- raindrop
.radius
) && p
.y
<= (raindrop
.p
.y
+ raindrop
.radius
)) {
5396 float d
= raindrop
.p
.distanceTo(p
) / raindrop
.radius
;
5397 // float value = (float)Math.max(0, 1 - Math.pow(Math.min(0, d - raindrop.radius) / 5, 2));
5399 c
= blendColor(c
, lx
.hsb(raindrop
.hue
, 80, (float)Math
.pow(1 - d
, 0.01f
) * 100), ADD
);
5403 colors
[p
.index
] = c
;
5406 Iterator
<Raindrop
> i
= raindrops
.iterator();
5407 while (i
.hasNext()) {
5408 Raindrop raindrop
= i
.next();
5409 boolean dead
= raindrop
.age(deltaMs
);
5418 class TimCubes
extends SCPattern
{
5419 private BasicParameter rateParameter
= new BasicParameter("RATE", 0.125f
);
5420 private BasicParameter attackParameter
= new BasicParameter("ATTK", 0.5f
);
5421 private BasicParameter decayParameter
= new BasicParameter("DECAY", 0.5f
);
5422 private BasicParameter hueParameter
= new BasicParameter("HUE", 0.5f
);
5423 private BasicParameter hueVarianceParameter
= new BasicParameter("H.V.", 0.25f
);
5424 private BasicParameter saturationParameter
= new BasicParameter("SAT", 0.5f
);
5433 c
= model
.cubes
.get(floor(random(model
.cubes
.size())));
5435 boolean infiniteAttack
= (attackParameter
.getValuef() > 0.999f
);
5436 hasPeaked
= infiniteAttack
;
5437 value
= (infiniteAttack ?
1 : 0);
5440 // returns TRUE if this should die
5441 public boolean age(double ms
) {
5443 value
= value
+ (float) (ms
/ 1000.0f
* ((attackParameter
.getValuef() + 0.01f
) * 5));
5444 if (value
>= 1.0f
) {
5450 value
= value
- (float) (ms
/ 1000.0f
* ((decayParameter
.getValuef() + 0.01f
) * 10));
5456 private float leftoverMs
= 0;
5457 private List
<CubeFlash
> flashes
;
5459 public TimCubes(GLucose glucose
) {
5461 addParameter(rateParameter
);
5462 addParameter(attackParameter
);
5463 addParameter(decayParameter
);
5464 addParameter(hueParameter
);
5465 addParameter(hueVarianceParameter
);
5466 addParameter(saturationParameter
);
5467 flashes
= new LinkedList
<CubeFlash
>();
5470 public void run(double deltaMs
) {
5471 leftoverMs
+= deltaMs
;
5472 float msPerFlash
= 1000 / ((rateParameter
.getValuef() + .01f
) * 100);
5473 while (leftoverMs
> msPerFlash
) {
5474 leftoverMs
-= msPerFlash
;
5475 flashes
.add(new CubeFlash());
5478 for (Point p
: model
.points
) {
5479 colors
[p
.index
] = 0;
5482 for (CubeFlash flash
: flashes
) {
5483 float hue
= (hueParameter
.getValuef() + (hueVarianceParameter
.getValuef() * flash
.hue
)) % 1.0f
;
5484 int c
= lx
.hsb(hue
* 360, saturationParameter
.getValuef() * 100, (flash
.value
) * 100);
5485 for (Point p
: flash
.c
.points
) {
5486 colors
[p
.index
] = c
;
5490 Iterator
<CubeFlash
> i
= flashes
.iterator();
5491 while (i
.hasNext()) {
5492 CubeFlash flash
= i
.next();
5493 boolean dead
= flash
.age(deltaMs
);
5502 * This one is the best but you need to play with all the knobs. It's synced to
5503 * the tempo, with the WSpd knob letting you pick 4 discrete multipliers for
5506 * Basically it's just 3 planes all rotating to the beat, but also rotated relative
5507 * to one another. The intersection of the planes and the cubes over time makes
5508 * for a nice abstract effect.
5510 class TimPlanes
extends SCPattern
{
5511 private BasicParameter wobbleParameter
= new BasicParameter("Wob", 0.166f
);
5512 private BasicParameter wobbleSpreadParameter
= new BasicParameter("WSpr", 0.25f
);
5513 private BasicParameter wobbleSpeedParameter
= new BasicParameter("WSpd", 0.375f
);
5514 private BasicParameter wobbleOffsetParameter
= new BasicParameter("WOff", 0);
5515 private BasicParameter derezParameter
= new BasicParameter("Drez", 0.5f
);
5516 private BasicParameter thicknessParameter
= new BasicParameter("Thick", 0.4f
);
5517 private BasicParameter ySpreadParameter
= new BasicParameter("ySpr", 0.2f
);
5518 private BasicParameter hueParameter
= new BasicParameter("Hue", 0.75f
);
5519 private BasicParameter hueSpreadParameter
= new BasicParameter("HSpr", 0.68f
);
5521 final float centerX
, centerY
, centerZ
;
5529 Plane(Vector3 center
, Rotation rotation
, float hue
) {
5530 this.center
= center
;
5531 this.rotation
= rotation
;
5536 TimPlanes(GLucose glucose
) {
5538 centerX
= (model
.xMin
+ model
.xMax
) / 2;
5539 centerY
= (model
.yMin
+ model
.yMax
) / 2;
5540 centerZ
= (model
.zMin
+ model
.zMax
) / 2;
5542 addParameter(wobbleParameter
);
5543 addParameter(wobbleSpreadParameter
);
5544 addParameter(wobbleSpeedParameter
);
5545 // addParameter(wobbleOffsetParameter);
5546 addParameter(derezParameter
);
5547 addParameter(thicknessParameter
);
5548 addParameter(ySpreadParameter
);
5549 addParameter(hueParameter
);
5550 addParameter(hueSpreadParameter
);
5555 float[] wobbleSpeeds
= { 1.0f
/8, 1.0f
/4, 1.0f
/2, 1.0f
};
5557 public void run(double deltaMs
) {
5558 float ramp
= (float)lx
.tempo
.ramp();
5559 if (ramp
< prevRamp
) {
5560 beat
= (beat
+ 1) % 32;
5564 float wobbleSpeed
= wobbleSpeeds
[floor(wobbleSpeedParameter
.getValuef() * wobbleSpeeds
.length
* 0.9999f
)];
5566 phase
= (((beat
+ ramp
) * wobbleSpeed
+ wobbleOffsetParameter
.getValuef()) % 1) * 2 * PI
;
5568 float ySpread
= ySpreadParameter
.getValuef() * 50;
5569 float wobble
= wobbleParameter
.getValuef() * PI
;
5570 float wobbleSpread
= wobbleSpreadParameter
.getValuef() * PI
;
5571 float hue
= hueParameter
.getValuef() * 360;
5572 float hueSpread
= (hueSpreadParameter
.getValuef() - 0.5f
) * 360;
5574 float saturation
= 10 + 60.0f
* pow(ramp
, 0.25f
);
5576 float derez
= derezParameter
.getValuef();
5580 new Vector3(centerX
, centerY
+ ySpread
, centerZ
),
5581 new Rotation(wobble
- wobbleSpread
, phase
, 0),
5582 (hue
+ 360 - hueSpread
) % 360),
5584 new Vector3(centerX
, centerY
, centerZ
),
5585 new Rotation(wobble
, phase
, 0),
5588 new Vector3(centerX
, centerY
- ySpread
, centerZ
),
5589 new Rotation(wobble
+ wobbleSpread
, phase
, 0),
5590 (hue
+ 360 + hueSpread
) % 360)
5593 float thickness
= (thicknessParameter
.getValuef() * 25 + 1);
5595 Vector3 normalizedPoint
= new Vector3();
5597 for (Point p
: model
.points
) {
5598 if (random(1.0f
) < derez
) {
5604 for (Plane plane
: planes
) {
5605 normalizedPoint
.x
= p
.x
- plane
.center
.x
;
5606 normalizedPoint
.y
= p
.y
- plane
.center
.y
;
5607 normalizedPoint
.z
= p
.z
- plane
.center
.z
;
5609 float v
= plane
.rotation
.rotatedY(normalizedPoint
);
5612 final int planeColor
;
5613 if (d
<= thickness
) {
5614 planeColor
= lx
.hsb(plane
.hue
, saturation
, 100);
5615 } else if (d
<= thickness
* 2) {
5616 float value
= 1 - ((d
- thickness
) / thickness
);
5617 planeColor
= lx
.hsb(plane
.hue
, saturation
, value
* 100);
5622 if (planeColor
!= 0) {
5626 c
= blendColor(c
, planeColor
, ADD
);
5631 colors
[p
.index
] = c
;
5637 * Two spinning wheels, basically XORed together, with a color palette that should
5638 * be pretty easy to switch around. Timed to the beat; also introduces "clickiness"
5639 * which makes the movement non-linear throughout a given beat, giving it a nice
5640 * dance feel. I'm not 100% sure that it's actually going to look like it's _on_
5641 * the beat, but that should be easy enough to adjust.
5643 * It's particularly nice to turn down the clickiness and turn up derez during
5644 * slow/beatless parts of the music and then revert them at the drop :) But maybe
5645 * I shouldn't be listening to so much shitty dubstep while making these...
5647 class TimPinwheels
extends SCPattern
{
5648 private BasicParameter horizSpreadParameter
= new BasicParameter("HSpr", 0.75f
);
5649 private BasicParameter vertSpreadParameter
= new BasicParameter("VSpr", 0.5f
);
5650 private BasicParameter vertOffsetParameter
= new BasicParameter("VOff", 1.0f
);
5651 private BasicParameter zSlopeParameter
= new BasicParameter("ZSlp", 0.6f
);
5652 private BasicParameter sharpnessParameter
= new BasicParameter("Shrp", 0.25f
);
5653 private BasicParameter derezParameter
= new BasicParameter("Drez", 0.25f
);
5654 private BasicParameter clickinessParameter
= new BasicParameter("Clic", 0.5f
);
5655 private BasicParameter hueParameter
= new BasicParameter("Hue", 0.667f
);
5656 private BasicParameter hueSpreadParameter
= new BasicParameter("HSpd", 0.667f
);
5659 private final int NUM_BLADES
= 12;
5668 Pinwheel(float xCenter
, float yCenter
, int numBlades
, float speed
) {
5669 this.center
= new Vector2(xCenter
, yCenter
);
5670 this.numBlades
= numBlades
;
5674 public void age(float numBeats
) {
5675 int numSteps
= numBlades
;
5677 realPhase
= (realPhase
+ numBeats
/ numSteps
) % 2.0f
;
5679 float phaseStep
= floor(realPhase
* numSteps
);
5680 float phaseRamp
= (realPhase
* numSteps
) % 1.0f
;
5681 phase
= (phaseStep
+ pow(phaseRamp
, (clickinessParameter
.getValuef() * 10) + 1)) / (numSteps
* 2);
5682 // phase = (phase + deltaMs / 1000.0 * speed) % 1.0;
5685 public boolean isOnBlade(float x
, float y
) {
5689 float normalizedAngle
= (atan2(x
, y
) / (2 * PI
) + 1 + phase
) % 1;
5690 float v
= (normalizedAngle
* 4 * numBlades
);
5691 int blade_num
= floor((v
+ 2) / 4);
5692 return (blade_num
% 2) == 0;
5696 private final List
<Pinwheel
> pinwheels
;
5697 private final float[] values
;
5699 TimPinwheels(GLucose glucose
) {
5702 addParameter(horizSpreadParameter
);
5703 // addParameter(vertSpreadParameter);
5704 addParameter(vertOffsetParameter
);
5705 addParameter(zSlopeParameter
);
5706 addParameter(sharpnessParameter
);
5707 addParameter(derezParameter
);
5708 addParameter(clickinessParameter
);
5709 addParameter(hueParameter
);
5710 addParameter(hueSpreadParameter
);
5712 pinwheels
= new ArrayList();
5713 pinwheels
.add(new Pinwheel(0, 0, NUM_BLADES
, 0.1f
));
5714 pinwheels
.add(new Pinwheel(0, 0, NUM_BLADES
, -0.1f
));
5716 this.updateHorizSpread();
5717 this.updateVertPositions();
5719 values
= new float[model
.points
.size()];
5722 public void onParameterChanged(LXParameter parameter
) {
5723 if (parameter
== horizSpreadParameter
) {
5724 updateHorizSpread();
5725 } else if (parameter
== vertSpreadParameter
|| parameter
== vertOffsetParameter
) {
5726 updateVertPositions();
5730 private void updateHorizSpread() {
5731 float xDist
= model
.xMax
- model
.xMin
;
5732 float xCenter
= (model
.xMin
+ model
.xMax
) / 2;
5734 float spread
= horizSpreadParameter
.getValuef() - 0.5f
;
5735 pinwheels
.get(0).center
.x
= xCenter
- xDist
* spread
;
5736 pinwheels
.get(1).center
.x
= xCenter
+ xDist
* spread
;
5739 private void updateVertPositions() {
5740 float yDist
= model
.yMax
- model
.yMin
;
5741 float yCenter
= model
.yMin
+ yDist
* vertOffsetParameter
.getValuef();
5743 float spread
= vertSpreadParameter
.getValuef() - 0.5f
;
5744 pinwheels
.get(0).center
.y
= yCenter
- yDist
* spread
;
5745 pinwheels
.get(1).center
.y
= yCenter
+ yDist
* spread
;
5748 private float prevRamp
= 0;
5750 public void run(double deltaMs
) {
5751 float ramp
= lx
.tempo
.rampf();
5752 float numBeats
= (1 + ramp
- prevRamp
) % 1;
5755 float hue
= hueParameter
.getValuef() * 360;
5759 float hueSpread
= (hueSpreadParameter
.getValuef() - 0.5f
) * 360;
5761 float fadeAmount
= (float) (deltaMs
/ 1000.0f
) * pow(sharpnessParameter
.getValuef() * 10, 1);
5763 for (Pinwheel pw
: pinwheels
) {
5767 float derez
= derezParameter
.getValuef();
5769 float zSlope
= (zSlopeParameter
.getValuef() - 0.5f
) * 2;
5772 for (Point p
: model
.points
) {
5776 for (Pinwheel pw
: pinwheels
) {
5777 value
+= (pw
.isOnBlade(p
.x
, p
.y
- p
.z
* zSlope
) ?
1 : 0);
5781 // colors[p.index] = lx.hsb(120, 0, 100);
5783 values
[i
] = max(0, values
[i
] - fadeAmount
);
5784 //color c = colors[p.index];
5785 //colors[p.index] = lx.hsb(max(0, lx.h(c) - 10), min(100, lx.s(c) + 10), lx.b(c) - 5 );
5788 if (random(1.0f
) >= derez
) {
5789 float v
= values
[i
];
5790 colors
[p
.index
] = lx
.hsb((360 + hue
+ pow(v
, 2) * hueSpread
) % 360, 30 + pow(1 - v
, 0.25f
) * 60, v
* 100);
5797 * This tries to figure out neighboring pixels from one cube to another to
5798 * let you have a bunch of moving points tracing all over the structure.
5799 * Adds a couple seconds of startup time to do the calculation, and in the
5800 * end just comes out looking a lot like a screensaver. Probably not worth
5801 * it but there may be useful code here.
5803 class TimTrace
extends SCPattern
{
5804 private Map
<Point
, List
<Point
>> pointToNeighbors
;
5805 private Map
<Point
, Strip
> pointToStrip
;
5806 // private final Map<Strip, List<Strip>> stripToNearbyStrips;
5813 private Strip currentStrip
;
5814 private int currentStripIndex
;
5815 private int direction
; // +1 or -1
5817 MovingPoint(Point p
) {
5818 this.setPointOnNewStrip(p
);
5822 private void setPointOnNewStrip(Point p
) {
5823 this.currentPoint
= p
;
5824 this.currentStrip
= pointToStrip
.get(p
);
5825 for (int i
= 0; i
< this.currentStrip
.points
.size(); ++i
) {
5826 if (this.currentStrip
.points
.get(i
) == p
) {
5827 this.currentStripIndex
= i
;
5831 if (this.currentStripIndex
== 0) {
5832 // we are at the beginning of the strip; go forwards
5834 } else if (this.currentStripIndex
== this.currentStrip
.points
.size()) {
5835 // we are at the end of the strip; go backwards
5836 this.direction
= -1;
5838 // we are in the middle of a strip; randomly go one way or another
5839 this.direction
= ((random(1.0f
) < 0.5f
) ?
-1 : 1);
5843 public void step() {
5844 List
<Point
> neighborsOnOtherStrips
= pointToNeighbors
.get(this.currentPoint
);
5846 Point nextPointOnCurrentStrip
= null;
5847 this.currentStripIndex
+= this.direction
;
5848 if (this.currentStripIndex
>= 0 && this.currentStripIndex
< this.currentStrip
.points
.size()) {
5849 nextPointOnCurrentStrip
= this.currentStrip
.points
.get(this.currentStripIndex
);
5852 // pick which option to take; if we can keep going on the current strip then
5853 // add that as another option
5854 int option
= floor(random(neighborsOnOtherStrips
.size() + (nextPointOnCurrentStrip
== null ?
0 : 100)));
5856 if (option
< neighborsOnOtherStrips
.size()) {
5857 this.setPointOnNewStrip(neighborsOnOtherStrips
.get(option
));
5859 this.currentPoint
= nextPointOnCurrentStrip
;
5864 List
<MovingPoint
> movingPoints
;
5866 TimTrace(GLucose glucose
) {
5871 pointToNeighbors
= this.buildPointToNeighborsMap();
5872 pointToStrip
= this.buildPointToStripMap();
5874 int numMovingPoints
= 1000;
5875 movingPoints
= new ArrayList();
5876 for (int i
= 0; i
< numMovingPoints
; ++i
) {
5877 movingPoints
.add(new MovingPoint(model
.points
.get(floor(random(model
.points
.size())))));
5882 private Map
<Strip
, List
<Strip
>> buildStripToNearbyStripsMap() {
5883 Map
<Strip
, Vector3
> stripToCenter
= new HashMap();
5884 for (Strip s
: model
.strips
) {
5885 Vector3 v
= new Vector3();
5886 for (Point p
: s
.points
) {
5887 v
.add(p
.x
, p
.y
, p
.z
);
5889 v
.divide(s
.points
.size());
5890 stripToCenter
.put(s
, v
);
5893 Map
<Strip
, List
<Strip
>> stripToNeighbors
= new HashMap();
5894 for (Strip s
: model
.strips
) {
5895 List
<Strip
> neighbors
= new ArrayList();
5896 Vector3 sCenter
= stripToCenter
.get(s
);
5897 for (Strip potentialNeighbor
: model
.strips
) {
5898 if (s
!= potentialNeighbor
) {
5899 float distance
= sCenter
.distanceTo(stripToCenter
.get(potentialNeighbor
));
5900 if (distance
< 25) {
5901 neighbors
.add(potentialNeighbor
);
5905 stripToNeighbors
.put(s
, neighbors
);
5908 return stripToNeighbors
;
5911 private Map
<Point
, List
<Point
>> buildPointToNeighborsMap() {
5912 Map
<Point
, List
<Point
>> m
= new HashMap();
5913 Map
<Strip
, List
<Strip
>> stripToNearbyStrips
= this.buildStripToNearbyStripsMap();
5915 for (Strip s
: model
.strips
) {
5916 List
<Strip
> nearbyStrips
= stripToNearbyStrips
.get(s
);
5918 for (Point p
: s
.points
) {
5919 Vector3 v
= new Vector3(p
.x
, p
.y
, p
.z
);
5921 List
<Point
> neighbors
= new ArrayList();
5923 for (Strip nearbyStrip
: nearbyStrips
) {
5924 Point closestPoint
= null;
5925 float closestPointDistance
= 100000;
5927 for (Point nsp
: nearbyStrip
.points
) {
5928 float distance
= v
.distanceTo(nsp
.x
, nsp
.y
, nsp
.z
);
5929 if (closestPoint
== null || distance
< closestPointDistance
) {
5931 closestPointDistance
= distance
;
5935 if (closestPointDistance
< 15) {
5936 neighbors
.add(closestPoint
);
5940 m
.put(p
, neighbors
);
5947 private Map
<Point
, Strip
> buildPointToStripMap() {
5948 Map
<Point
, Strip
> m
= new HashMap();
5949 for (Strip s
: model
.strips
) {
5950 for (Point p
: s
.points
) {
5957 public void run(double deltaMs
) {
5958 for (Point p
: model
.points
) {
5959 int c
= colors
[p
.index
];
5960 colors
[p
.index
] = lx
.hsb(lx
.h(c
), lx
.s(c
), lx
.b(c
) - 3);
5963 for (MovingPoint mp
: movingPoints
) {
5965 colors
[mp
.currentPoint
.index
] = blendColor(colors
[mp
.currentPoint
.index
], lx
.hsb(mp
.hue
, 10, 100), ADD
);
5969 class GlitchPlasma
extends SCPattern
{
5970 private int pos
= 0;
5971 private float satu
= 100;
5972 private float speed
= 1;
5973 private float glitch
= 0;
5974 BasicParameter saturationParameter
= new BasicParameter("SATU", 1.0f
);
5975 BasicParameter speedParameter
= new BasicParameter("SPEED", 0.1f
);
5976 BasicParameter glitchParameter
= new BasicParameter("GLITCH", 0.0f
);
5978 public GlitchPlasma(GLucose glucose
) {
5980 addParameter(saturationParameter
);
5981 addParameter(speedParameter
);
5982 addParameter(glitchParameter
);
5984 public void onParameterChanged(LXParameter parameter
) {
5985 if (parameter
== saturationParameter
) {
5986 satu
= 100*parameter
.getValuef();
5987 } else if (parameter
== speedParameter
) {
5988 speed
= 8*parameter
.getValuef();
5989 } else if (parameter
== glitchParameter
) {
5990 glitch
= parameter
.getValuef();
5994 public void run(double deltaMs
) {
5995 for (Point p
: model
.points
) {
5996 float hv
= sin(dist(p
.x
+ pos
, p
.y
, 128.0f
, 128.0f
) / 8.0f
)
5997 + sin(dist(p
.x
, p
.y
, 64.0f
, 64.0f
) / 8.0f
)
5998 + sin(dist(p
.x
, p
.y
+ pos
/ 7, 192.0f
, 64.0f
) / 7.0f
)
5999 + sin(dist(p
.x
, p
.z
+ pos
, 192.0f
, 100.0f
) / 8.0f
);
6001 colors
[p
.index
] = lx
.hsb((hv
+2)*50, satu
, bv
);
6003 if (random(1.0f
)<glitch
/20) {
6004 pos
=pos
-PApplet
.parseInt(random(10,30));
6007 if (pos
>= MAX_INT
-1) pos
=0;
6011 // This is very much a work in progress. Trying to get a flame effect.
6012 class FireEffect
extends SCPattern
{
6013 private float[][] intensity
;
6014 private float hotspot
;
6015 private float decay
= 0.3f
;
6018 BasicParameter decayParameter
= new BasicParameter("DECAY", 0.3f
);
6020 public FireEffect(GLucose glucose
) {
6022 xm
= PApplet
.parseInt(model
.xMax
);
6023 ym
= PApplet
.parseInt(model
.yMax
);
6025 intensity
= new float[xm
][ym
];
6026 addParameter(decayParameter
);
6028 public void onParameterChanged(LXParameter parameter
) {
6029 if (parameter
== decayParameter
) {
6030 decay
= parameter
.getValuef();
6033 private int flameColor(float level
) {
6034 if (level
<=0) return lx
.hsb(0,0,0);
6035 float br
=min(100,sqrt(level
)*15);
6036 return lx
.hsb(level
/1.7f
,100,br
);
6038 public void run(double deltaMs
) {
6039 for (int x
=10;x
<xm
-10;x
++) {
6040 if (x
%50>45 || x
%50<5) {
6041 intensity
[x
][ym
-1] = random(30,100);
6043 intensity
[x
][ym
-1] = random(0,50);
6046 for (int x
=1;x
<xm
-1;x
++) {
6047 for (int y
=0;y
<ym
-1;y
++) {
6048 intensity
[x
][y
] = (intensity
[x
-1][y
+1]+intensity
[x
][y
+1]+intensity
[x
+1][y
+1])/3-decay
;
6052 for (Point p
: model
.points
) {
6053 int x
= max(0,(PApplet
.parseInt(p
.x
)+PApplet
.parseInt(p
.z
))%xm
);
6054 int y
= constrain(ym
-PApplet
.parseInt(p
.y
),0,ym
-1);
6055 colors
[p
.index
] = flameColor(intensity
[x
][y
]);
6060 class StripBounce
extends SCPattern
{
6061 private final int numOsc
= 30;
6062 SinLFO
[] fX
= new SinLFO
[numOsc
]; //new SinLFO(0, model.xMax, 5000);
6063 SinLFO
[] fY
= new SinLFO
[numOsc
]; //new SinLFO(0, model.yMax, 4000);
6064 SinLFO
[] fZ
= new SinLFO
[numOsc
]; //new SinLFO(0, model.yMax, 3000);
6065 SinLFO
[] sat
= new SinLFO
[numOsc
];
6066 float[] colorOffset
= new float[numOsc
];
6068 public StripBounce(GLucose glucose
) {
6070 for (int i
=0;i
<numOsc
;i
++) {
6071 fX
[i
] = new SinLFO(0, model
.xMax
, random(2000,20000));
6072 fY
[i
] = new SinLFO(0, model
.yMax
, random(2000,20000));
6073 fZ
[i
] = new SinLFO(0, model
.zMax
, random(2000,20000));
6074 sat
[i
] = new SinLFO(60, 100, random(2000,50000));
6075 addModulator(fX
[i
]).trigger();
6076 addModulator(fY
[i
]).trigger();
6077 addModulator(fZ
[i
]).trigger();
6078 colorOffset
[i
]=random(0,256);
6082 public void run(double deltaMs
) {
6083 float[] bright
= new float[model
.points
.size()];
6084 for (Strip strip
: model
.strips
) {
6085 for (int i
=0;i
<numOsc
;i
++) {
6087 avgdist
= dist(strip
.points
.get(8).x
,strip
.points
.get(8).y
,strip
.points
.get(8).z
,fX
[i
].getValuef(),fY
[i
].getValuef(),fZ
[i
].getValuef());
6088 boolean on
= avgdist
<30;
6089 float hv
= (lx
.getBaseHuef()+colorOffset
[i
])%360;
6090 float br
= max(0,100-avgdist
*4);
6091 for (Point p
: strip
.points
) {
6092 if (on
&& br
>bright
[p
.index
]) {
6093 colors
[p
.index
] = lx
.hsb(hv
,sat
[i
].getValuef(),br
);
6094 bright
[p
.index
] = br
;
6102 class SoundRain
extends SCPattern
{
6104 private FFT fft
= null;
6105 private LinearEnvelope
[] bandVals
= null;
6106 private float[] lightVals
= null;
6107 private int avgSize
;
6108 private float gain
= 25;
6109 SawLFO pos
= new SawLFO(0, 9, 8000);
6110 SinLFO col1
= new SinLFO(0, model
.xMax
, 5000);
6111 BasicParameter gainParameter
= new BasicParameter("GAIN", 0.5f
);
6113 public SoundRain(GLucose glucose
) {
6115 addModulator(pos
).trigger();
6116 addModulator(col1
).trigger();
6117 addParameter(gainParameter
);
6120 public void onParameterChanged(LXParameter parameter
) {
6121 if (parameter
== gainParameter
) {
6122 gain
= 50*parameter
.getValuef();
6125 protected void onActive() {
6126 if (this.fft
== null) {
6127 this.fft
= new FFT(lx
.audioInput().bufferSize(), lx
.audioInput().sampleRate());
6128 this.fft
.window(FFT
.HAMMING
);
6129 this.fft
.logAverages(40, 1);
6130 this.avgSize
= this.fft
.avgSize();
6131 this.bandVals
= new LinearEnvelope
[this.avgSize
];
6132 for (int i
= 0; i
< this.bandVals
.length
; ++i
) {
6133 this.addModulator(this.bandVals
[i
] = (new LinearEnvelope(0, 0, 700+i
*4))).trigger();
6135 lightVals
= new float[avgSize
];
6139 public void run(double deltaMs
) {
6140 this.fft
.forward(this.lx
.audioInput().mix
);
6141 for (int i
= 0; i
< avgSize
; ++i
) {
6142 float value
= this.fft
.getAvg(i
);
6143 this.bandVals
[i
].setEndVal(value
,40).trigger();
6144 float lv
= min(value
*gain
,100);
6145 if (lv
>lightVals
[i
]) {
6146 lightVals
[i
]=min(lightVals
[i
]+15,lv
,100);
6148 lightVals
[i
]=max(lv
,lightVals
[i
]-5,0);
6151 for (Cube c
: model
.cubes
) {
6152 for (int j
=0; j
<c
.strips
.size(); j
++) {
6153 Strip s
= c
.strips
.get(j
);
6154 if (j
%4!=0 && j
%4!=2) {
6155 for (Point p
: s
.points
) {
6156 int seq
= PApplet
.parseInt(p
.y
*avgSize
/model
.yMax
+pos
.getValuef()+sin(p
.x
+p
.z
)*2)%avgSize
;
6157 seq
=min(abs(seq
-(avgSize
/2)),avgSize
-1);
6158 colors
[p
.index
] = lx
.hsb(200,max(0,100-abs(p
.x
-col1
.getValuef())/2),lightVals
[seq
]);
6166 class FaceSync
extends SCPattern
{
6167 SinLFO xosc
= new SinLFO(-10, 10, 3000);
6168 SinLFO zosc
= new SinLFO(-10, 10, 3000);
6169 SinLFO col1
= new SinLFO(0, model
.xMax
, 5000);
6170 SinLFO col2
= new SinLFO(0, model
.xMax
, 4000);
6172 public FaceSync(GLucose glucose
) {
6174 addModulator(xosc
).trigger();
6175 addModulator(zosc
).trigger();
6177 addModulator(col1
).trigger();
6178 addModulator(col2
).trigger();
6179 col2
.setValue(model
.xMax
);
6182 public void run(double deltaMs
) {
6184 for (Strip s
: model
.strips
) {
6186 for (Point p
: s
.points
) {
6189 dx
= p
.x
- (s
.cx
+xosc
.getValuef());
6190 dz
= p
.z
- (s
.cz
+zosc
.getValuef());
6192 dx
= p
.x
- (s
.cx
+zosc
.getValuef());
6193 dz
= p
.z
- (s
.cz
+xosc
.getValuef());
6196 float a1
=max(0,100-abs(p
.x
-col1
.getValuef()));
6197 float a2
=max(0,100-abs(p
.x
-col2
.getValuef()));
6198 float sat
= max(a1
,a2
);
6199 float h
= (359*a1
+200*a2
) / (a1
+a2
);
6200 colors
[p
.index
] = lx
.hsb(h
,sat
,100-abs(dx
*5)-abs(dz
*5));
6206 class SoundSpikes
extends SCPattern
{
6207 private FFT fft
= null;
6208 private LinearEnvelope
[] bandVals
= null;
6209 private float[] lightVals
= null;
6210 private int avgSize
;
6211 private float gain
= 25;
6212 BasicParameter gainParameter
= new BasicParameter("GAIN", 0.5f
);
6213 SawLFO pos
= new SawLFO(0, model
.xMax
, 8000);
6215 public SoundSpikes(GLucose glucose
) {
6217 addParameter(gainParameter
);
6218 addModulator(pos
).trigger();
6221 public void onParameterChanged(LXParameter parameter
) {
6222 if (parameter
== gainParameter
) {
6223 gain
= 50*parameter
.getValuef();
6226 protected void onActive() {
6227 if (this.fft
== null) {
6228 this.fft
= new FFT(lx
.audioInput().bufferSize(), lx
.audioInput().sampleRate());
6229 this.fft
.window(FFT
.HAMMING
);
6230 this.fft
.logAverages(40, 1);
6231 this.avgSize
= this.fft
.avgSize();
6232 this.bandVals
= new LinearEnvelope
[this.avgSize
];
6233 for (int i
= 0; i
< this.bandVals
.length
; ++i
) {
6234 this.addModulator(this.bandVals
[i
] = (new LinearEnvelope(0, 0, 700+i
*4))).trigger();
6236 lightVals
= new float[avgSize
];
6240 public void run(double deltaMs
) {
6241 this.fft
.forward(this.lx
.audioInput().mix
);
6242 for (int i
= 0; i
< avgSize
; ++i
) {
6243 float value
= this.fft
.getAvg(i
);
6244 this.bandVals
[i
].setEndVal(value
,40).trigger();
6245 float lv
= min(value
*gain
,model
.yMax
+10);
6246 if (lv
>lightVals
[i
]) {
6247 lightVals
[i
]=min(lightVals
[i
]+30,lv
,model
.yMax
+10);
6249 lightVals
[i
]=max(lv
,lightVals
[i
]-10,0);
6253 for (Cube c
: model
.cubes
) {
6254 for (int j
=0; j
<c
.strips
.size(); j
++) {
6255 Strip s
= c
.strips
.get(j
);
6256 if (j
%4!=0 && j
%4!=2) {
6257 for (Point p
: s
.points
) {
6258 float dis
= (abs(p
.x
-model
.xMax
/2)+pos
.getValuef())%model
.xMax
/2;
6259 int seq
= PApplet
.parseInt((dis
*avgSize
*2)/model
.xMax
);
6260 if (seq
>avgSize
) seq
=avgSize
-seq
;
6261 seq
=constrain(seq
,0,avgSize
-1);
6262 float br
=max(0, lightVals
[seq
]-p
.y
);
6263 colors
[p
.index
] = lx
.hsb((dis
*avgSize
*65)/model
.xMax
,90,br
);
6271 static public void main(String
[] passedArgs
) {
6272 String
[] appletArgs
= new String
[] { "SugarCubes" };
6273 if (passedArgs
!= null) {
6274 PApplet
.main(concat(appletArgs
, passedArgs
));
6276 PApplet
.main(appletArgs
);