From e037f60f518373c3bb952f79a2ae66950e55a52f Mon Sep 17 00:00:00 2001 From: Mark Slee Date: Mon, 24 Feb 2014 22:06:07 -0800 Subject: [PATCH] Lots of code cleanup, removed Panda code, all grizzly, cleaning up mapping --- TestPatterns.pde | 31 +- _DebugUI.pde | 283 -- _Grizzly.pde | 12 +- _Internals.pde | 90 +- _Mappings.pde | 522 +-- _PandaDriver.pde | 438 --- _UIImplementation.pde | 27 +- build-tmp/source/SugarCubes.java | 6279 ------------------------------ code/HeronLX.jar | Bin 131634 -> 131690 bytes 9 files changed, 190 insertions(+), 7492 deletions(-) delete mode 100644 _DebugUI.pde delete mode 100644 _PandaDriver.pde delete mode 100644 build-tmp/source/SugarCubes.java diff --git a/TestPatterns.pde b/TestPatterns.pde index 6a662f2..80754a6 100644 --- a/TestPatterns.pde +++ b/TestPatterns.pde @@ -314,15 +314,11 @@ class MappingTool extends TestPattern { public boolean channelModeBlue = false; private final int numChannels; - - private final PandaMapping[] pandaMappings; - private PandaMapping activePanda; - private ChannelMapping activeChannel; - - MappingTool(GLucose glucose, PandaMapping[] pandaMappings) { + + MappingTool(GLucose glucose) { super(glucose); - this.pandaMappings = pandaMappings; - numChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD; + // TODO(mcslee): port channels to grizzly + numChannels = 0; setChannel(); } @@ -331,21 +327,12 @@ class MappingTool extends TestPattern { } private void setChannel() { - activePanda = pandaMappings[channelIndex / PandaMapping.CHANNELS_PER_BOARD]; - activeChannel = activePanda.channelList[channelIndex % PandaMapping.CHANNELS_PER_BOARD]; + // TODO(mcslee): port to grizzly } private int indexOfCubeInChannel(Cube c) { - if (activeChannel.mode == ChannelMapping.MODE_CUBES) { - int i = 1; - for (int index : activeChannel.objectIndices) { - if ((index >= 0) && (c == model.getCubeByRawIndex(index))) { - return i; - } - ++i; - } - } - return 0; + // TODO(mcslee): port to grizzly + return -1; } private void printInfo() { @@ -440,7 +427,9 @@ class MappingTool extends TestPattern { } public void setChannel(int index) { - channelIndex = index % numChannels; + if (numChannels > 0) { + channelIndex = index % numChannels; + } setChannel(); } diff --git a/_DebugUI.pde b/_DebugUI.pde deleted file mode 100644 index a36f688..0000000 --- a/_DebugUI.pde +++ /dev/null @@ -1,283 +0,0 @@ -/** - * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND - * - * //\\ //\\ //\\ //\\ - * ///\\\ ///\\\ ///\\\ ///\\\ - * \\\/// \\\/// \\\/// \\\/// - * \\// \\// \\// \\// - * - * EXPERTS ONLY!! EXPERTS ONLY!! - * - * Overlay UI that indicates pattern control, etc. This will be moved - * into the Processing library once it is stabilized and need not be - * regularly modified. - */ - -class DebugUI { - - final ChannelMapping[] channelList; - final int debugX = 5; - final int debugY = 5; - final int debugXSpacing = 28; - final int debugYSpacing = 21; - final int[][] debugState; - final int[] indexState; - - final int CUBE_STATE_UNUSED = 0; - final int CUBE_STATE_USED = 1; - final int CUBE_STATE_DUPLICATED = 2; - - final int DEBUG_STATE_ANIM = 0; - final int DEBUG_STATE_WHITE = 1; - final int DEBUG_STATE_OFF = 2; - final int DEBUG_STATE_UNUSED = 3; - - DebugUI(PandaMapping[] pandaMappings) { - int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD; - debugState = new int[totalChannels+1][ChannelMapping.CUBES_PER_CHANNEL+1]; - indexState = new int[glucose.model.cubes.size()+1]; - - channelList = new ChannelMapping[totalChannels]; - int channelIndex = 0; - for (PandaMapping pm : pandaMappings) { - for (ChannelMapping channel : pm.channelList) { - channelList[channelIndex++] = channel; - } - } - for (int i = 0; i < debugState.length; ++i) { - for (int j = 0; j < debugState[i].length; ++j) { - debugState[i][j] = DEBUG_STATE_ANIM; - } - } - - for (int rawIndex = 0; rawIndex < glucose.model.cubes.size()+1; ++rawIndex) { - indexState[rawIndex] = CUBE_STATE_UNUSED; - } - for (ChannelMapping channel : channelList) { - for (int rawCubeIndex : channel.objectIndices) { - if (rawCubeIndex > 0) - ++indexState[rawCubeIndex]; - } - } - } - - void draw() { - noStroke(); - int xBase = debugX; - int yPos = debugY; - - textSize(10); - - fill(#000000); - rect(0, 0, debugX + 5*debugXSpacing, height); - - int channelNum = 0; - for (ChannelMapping channel : channelList) { - int xPos = xBase; - drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]); - xPos += debugXSpacing; - - switch (channel.mode) { - case ChannelMapping.MODE_CUBES: - int stateIndex = 0; - boolean first = true; - for (int rawCubeIndex : channel.objectIndices) { - if (rawCubeIndex < 0) { - break; - } - if (first) { - first = false; - } else { - stroke(#999999); - line(xPos - 12, yPos + 8, xPos, yPos + 8); - } - drawNumBox(xPos, yPos, rawCubeIndex, debugState[channelNum][stateIndex+1], indexState[rawCubeIndex]); - ++stateIndex; - xPos += debugXSpacing; - } - break; - case ChannelMapping.MODE_BASS: - drawNumBox(xPos, yPos, "B", debugState[channelNum][1]); - break; - case ChannelMapping.MODE_SPEAKER: - drawNumBox(xPos, yPos, "S" + channel.objectIndices[0], debugState[channelNum][1]); - break; - case ChannelMapping.MODE_STRUTS_AND_FLOOR: - drawNumBox(xPos, yPos, "F", debugState[channelNum][1]); - break; - case ChannelMapping.MODE_NULL: - break; - default: - throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode); - } - - yPos += debugYSpacing; - ++channelNum; - } - drawNumBox(xBase, yPos, "A", debugState[channelNum][0]); - yPos += debugYSpacing * 2; - - noFill(); - fill(#CCCCCC); - text("Unused Cubes", xBase, yPos + 12); - yPos += debugYSpacing; - - int xIndex = 0; - for (int rawIndex = 1; rawIndex <= glucose.model.cubes.size(); ++rawIndex) { - if (indexState[rawIndex] == CUBE_STATE_UNUSED) { - drawNumBox(xBase + (xIndex * debugXSpacing), yPos, rawIndex, DEBUG_STATE_UNUSED); - ++xIndex; - if (xIndex > 4) { - xIndex = 0; - yPos += debugYSpacing + 2; - } - } - } - } - - - void drawNumBox(int xPos, int yPos, int label, int state) { - drawNumBox(xPos, yPos, "" + label, state); - } - - void drawNumBox(int xPos, int yPos, String label, int state) { - drawNumBox(xPos, yPos, "" + label, state, CUBE_STATE_USED); - } - - void drawNumBox(int xPos, int yPos, int label, int state, int cubeState) { - drawNumBox(xPos, yPos, "" + label, state, cubeState); - } - - void drawNumBox(int xPos, int yPos, String label, int state, int cubeState) { - noFill(); - color textColor = #cccccc; - switch (state) { - case DEBUG_STATE_ANIM: - noStroke(); - fill(#880000); - rect(xPos, yPos, 16, 8); - fill(#000088); - rect(xPos, yPos+8, 16, 8); - noFill(); - stroke(textColor); - break; - case DEBUG_STATE_WHITE: - stroke(textColor); - fill(#e9e9e9); - textColor = #333333; - break; - case DEBUG_STATE_OFF: - stroke(textColor); - break; - case DEBUG_STATE_UNUSED: - stroke(textColor); - fill(#880000); - break; - } - - if (cubeState >= CUBE_STATE_DUPLICATED) { - stroke(textColor = #FF0000); - } - - rect(xPos, yPos, 16, 16); - noStroke(); - fill(textColor); - text(label, xPos + 2, yPos + 12); - } - - void maskColors(color[] colors) { - color white = #FFFFFF; - color off = #000000; - int channelIndex = 0; - int state; - for (ChannelMapping channel : channelList) { - switch (channel.mode) { - case ChannelMapping.MODE_CUBES: - int cubeIndex = 1; - for (int rawCubeIndex : channel.objectIndices) { - if (rawCubeIndex >= 0) { - state = debugState[channelIndex][cubeIndex]; - if (state != DEBUG_STATE_ANIM) { - color debugColor = (state == DEBUG_STATE_WHITE) ? white : off; - Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex); - for (LXPoint p : cube.points) { - colors[p.index] = debugColor; - } - } - } - ++cubeIndex; - } - break; - - case ChannelMapping.MODE_BASS: - state = debugState[channelIndex][1]; - if (state != DEBUG_STATE_ANIM) { - color debugColor = (state == DEBUG_STATE_WHITE) ? white : off; - for (Strip s : glucose.model.bassBox.boxStrips) { - for (LXPoint p : s.points) { - colors[p.index] = debugColor; - } - } - } - break; - - case ChannelMapping.MODE_STRUTS_AND_FLOOR: - state = debugState[channelIndex][1]; - if (state != DEBUG_STATE_ANIM) { - color debugColor = (state == DEBUG_STATE_WHITE) ? white : off; - for (LXPoint p : glucose.model.boothFloor.points) { - colors[p.index] = debugColor; - } - for (Strip s : glucose.model.bassBox.struts) { - for (LXPoint p : s.points) { - colors[p.index] = debugColor; - } - } - } - break; - - case ChannelMapping.MODE_SPEAKER: - state = debugState[channelIndex][1]; - if (state != DEBUG_STATE_ANIM) { - color debugColor = (state == DEBUG_STATE_WHITE) ? white : off; - for (LXPoint p : glucose.model.speakers.get(channel.objectIndices[0]).points) { - colors[p.index] = debugColor; - } - } - break; - - case ChannelMapping.MODE_NULL: - break; - - default: - throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode); - } - ++channelIndex; - } - } - - boolean mousePressed() { - int dx = (mouseX - debugX) / debugXSpacing; - int dy = (mouseY - debugY) / debugYSpacing; - if ((dy < 0) || (dy >= debugState.length)) { - return false; - } - if ((dx < 0) || (dx >= debugState[dy].length)) { - return false; - } - int newState = debugState[dy][dx] = (debugState[dy][dx] + 1) % 3; - if (dy == debugState.length-1) { - for (int[] states : debugState) { - for (int i = 0; i < states.length; ++i) { - states[i] = newState; - } - } - } else if (dx == 0) { - for (int i = 0; i < debugState[dy].length; ++i) { - debugState[dy][i] = newState; - } - } - return true; - } -} - diff --git a/_Grizzly.pde b/_Grizzly.pde index cc7dec8..f376fab 100644 --- a/_Grizzly.pde +++ b/_Grizzly.pde @@ -15,18 +15,23 @@ GrizzlyOutput[] buildGrizzlies() throws SocketException, UnknownHostException { return new GrizzlyOutput[] { - new GrizzlyOutput(lx, "192.168.88.100", 1, 2, 3, 4, 5, 6, 7, 8), - new GrizzlyOutput(lx, "192.168.88.101", 9, 10, 11, 12, 13, 14, 15, 16), + new GrizzlyOutput(lx, "192.168.88.100", 6, 5, 6, 7, 7, 8, 1, 2, 4, 3, 11, 10, 9, 9, 12, 13), + new GrizzlyOutput(lx, "192.168.88.101", 25, 23, 24, 43, 45, 44, 1, 1, 1, 1, 1, 41, 42, 21, 20, 22), + new GrizzlyOutput(lx, "192.168.88.104", 26, 28, 27, 19, 18, 17, 1, 1, 18, 19, 15, 16, 14, 29, 30, 31), + new GrizzlyOutput(lx, "192.168.88.105", 1, 1, 1, 39, 38, 40, 34, 35, 33, 32, 37, 37, 1, 1, 1, 1), }; } class GrizzlyOutput extends LXDatagramOutput { + public final String ipAddress; + private int frameNumber = 0; GrizzlyOutput(LX lx, String ipAddress, int ... cubeIndices) throws UnknownHostException, SocketException { super(lx); - int channelNum = 1; + this.ipAddress = ipAddress; + int channelNum = 0; for (int rawCubeIndex : cubeIndices) { if (rawCubeIndex > 0) { Cube cube = model.getCubeByRawIndex(rawCubeIndex); @@ -34,6 +39,7 @@ class GrizzlyOutput extends LXDatagramOutput { } ++channelNum; } + this.enabled.setValue(false); } protected void beforeSend(int[] colors) { diff --git a/_Internals.pde b/_Internals.pde index 0100c05..7eb5f93 100644 --- a/_Internals.pde +++ b/_Internals.pde @@ -49,15 +49,13 @@ Model model; LXPattern[] patterns; Effects effects; MappingTool mappingTool; -PandaDriver[] pandaBoards; +GrizzlyOutput[] grizzlies; PresetManager presetManager; MidiEngine midiEngine; // Display configuration mode boolean mappingMode = false; boolean debugMode = false; -DebugUI debugUI; -boolean uiOn = true; boolean simulationOn = true; boolean diagnosticsOn = false; LXPattern restoreToPattern = null; @@ -153,54 +151,58 @@ void setup() { logTime("Setup MIDI devices"); // Build output driver + grizzlies = new GrizzlyOutput[]{}; try { - GrizzlyOutput[] grizzlies = buildGrizzlies(); + grizzlies = buildGrizzlies(); for (LXOutput output : grizzlies) { lx.addOutput(output); } } catch (Exception x) { x.printStackTrace(); } + logTime("Built Grizzly Outputs"); + + // Mapping tools + mappingTool = new MappingTool(glucose); - PandaMapping[] pandaMappings = buildPandaList(); - pandaBoards = new PandaDriver[pandaMappings.length]; - int pbi = 0; - for (PandaMapping pm : pandaMappings) { - pandaBoards[pbi++] = new PandaDriver(pm.ip, glucose.model, pm); - } - mappingTool = new MappingTool(glucose, pandaMappings); - logTime("Built PandaDriver"); - // Build overlay UI - debugUI = new DebugUI(pandaMappings); - UIContext[] contexts = new UIContext[] { + UILayer[] layers = new UILayer[] { + // Camera layer + new UICameraLayer(lx.ui) + .setCenter(TRAILER_WIDTH/2., glucose.model.yMax/2, TRAILER_DEPTH/2.) + .setRadius(290).addComponent(new UICubesLayer()), + + // Left controls uiPatternA = new UIPatternDeck(lx.ui, lx.engine.getDeck(GLucose.LEFT_DECK), "PATTERN A", 4, 4, 140, 324), new UIBlendMode(4, 332, 140, 86), new UIEffects(4, 422, 140, 144), new UITempo(4, 570, 140, 50), uiSpeed = new UISpeed(4, 624, 140, 50), + // Right controls new UIPatternDeck(lx.ui, lx.engine.getDeck(GLucose.RIGHT_DECK), "PATTERN B", width-144, 4, 140, 324), uiMidi = new UIMidi(midiEngine, width-144, 332, 140, 158), - new UIOutput(width-144, 494, 140, 106), + new UIOutput(grizzlies, width-144, 494, 140, 106), + // Crossfader uiCrossfader = new UICrossfader(width/2-90, height-90, 180, 86), + // Overlays uiDebugText = new UIDebugText(148, height-138, width-304, 44), uiMapping = new UIMapping(mappingTool, 4, 4, 140, 324) }; - uiMapping.setVisible(false); - lx.ui.addLayer(new UICameraLayer(lx.ui).setCenter(TRAILER_WIDTH/2., glucose.model.yMax/2, TRAILER_DEPTH/2.).setRadius(290).addComponent(new UICubesLayer())); - for (UIContext context : contexts) { - lx.ui.addLayer(context); + uiMapping.setVisible(false); + for (UILayer layer : layers) { + lx.ui.addLayer(layer); } - logTime("Built overlay UI"); + logTime("Built UI"); // Load logo image logo = loadImage("data/logo.png"); + logTime("Loaded logo image"); println("Total setup: " + (millis() - startMillis) + "ms"); - println("Hit the 'p' key to toggle Panda Board output"); + println("Hit the 'o' key to toggle live output"); } /** @@ -213,11 +215,7 @@ void draw() { background(40); // Send colors - color[] sendColors = glucose.getColors(); - if (debugMode) { - debugUI.maskColors(sendColors); - } - + color[] sendColors = glucose.getColors(); long gammaStart = System.nanoTime(); // Gamma correction here. Apply a cubic to the brightness // for better representation of dynamic range @@ -228,23 +226,15 @@ void draw() { } long gammaNanos = System.nanoTime() - gammaStart; - long sendStart = System.nanoTime(); - for (PandaDriver p : pandaBoards) { - p.send(sendColors); - } - long sendNanos = System.nanoTime() - sendStart; - + // Always draw FPS meter drawFPS(); - if (debugMode) { - debugUI.draw(); - } // TODO(mcslee): fix long drawNanos = System.nanoTime() - drawStart; long simulationNanos = 0, uiNanos = 0; if (diagnosticsOn) { - drawDiagnostics(drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos); + drawDiagnostics(drawNanos, simulationNanos, uiNanos, gammaNanos); } } @@ -257,9 +247,6 @@ class UICubesLayer extends UICameraComponent { } else if (displayMode == "B") { simulationColors = lx.engine.getDeck(GLucose.RIGHT_DECK).getColors(); } - if (debugMode) { - debugUI.maskColors(simulationColors); - } long simulationStart = System.nanoTime(); if (simulationOn) { @@ -275,7 +262,7 @@ class UICubesLayer extends UICameraComponent { } } -void drawDiagnostics(long drawNanos, long simulationNanos, long uiNanos, long gammaNanos, long sendNanos) { +void drawDiagnostics(long drawNanos, long simulationNanos, long uiNanos, long gammaNanos) { float ws = 4 / 1000000.; int thirtyfps = 1000000000 / 30; int sixtyfps = 1000000000 / 60; @@ -288,7 +275,7 @@ void drawDiagnostics(long drawNanos, long simulationNanos, long uiNanos, long ga noStroke(); int xp = x; float hv = 0; - for (long val : new long[] {lx.timer.drawNanos, simulationNanos, uiNanos, gammaNanos, sendNanos }) { + for (long val : new long[] {lx.timer.drawNanos, simulationNanos, uiNanos, gammaNanos, lx.timer.outputNanos }) { fill(lx.hsb(hv % 360, 100, 80)); rect(xp, y, val * ws, h-1); hv += 140; @@ -579,9 +566,10 @@ void keyPressed() { lx.engine.setThreaded(!lx.engine.isThreaded()); } break; + case 'o': case 'p': - for (PandaDriver p : pandaBoards) { - p.toggle(); + for (LXOutput output : grizzlies) { + output.enabled.toggle(); } break; case 'q': @@ -594,20 +582,6 @@ void keyPressed() { simulationOn = !simulationOn; } break; - case 'u': - if (!midiEngine.isQwertyEnabled()) { - uiOn = !uiOn; - } - break; - } -} - -/** - * Top-level mouse event handling - */ -void mousePressed() { - if (debugMode) { - debugUI.mousePressed(); } } diff --git a/_Mappings.pde b/_Mappings.pde index 5bcdb73..bb5c438 100644 --- a/_Mappings.pde +++ b/_Mappings.pde @@ -13,9 +13,6 @@ * when physical changes or tuning is being done to the structure. */ -final int MaxCubeHeight = 6; -final int NumBackTowers = 16; - public Model buildModel() { // Shorthand helpers for specifying wiring more quickly @@ -23,11 +20,11 @@ public Model buildModel() { final Cube.Wiring WFR = Cube.Wiring.FRONT_RIGHT; final Cube.Wiring WRL = Cube.Wiring.REAR_LEFT; final Cube.Wiring WRR = Cube.Wiring.REAR_RIGHT; - + // Utility value if you need the height of a cube shorthand final float CH = Cube.EDGE_HEIGHT; final float CW = Cube.EDGE_WIDTH ; - + // Positions for the bass box final float BBY = BassBox.EDGE_HEIGHT + BoothFloor.PLEXI_WIDTH; final float BBX = 56; @@ -52,161 +49,125 @@ public Model buildModel() { // We can do better than this. The raw object index should be obvious from the code-- looking through the // rendered simulation and counting through cubes in mapping mode is grossly inefficient. - TowerMapping[] towerCubes = new TowerMapping[] {}; - // Single cubes can be constructed directly here if you need them Cube[] singleCubes = new Cube[] { // new Cube(15, int( Cube.EDGE_HEIGHT), 39, 0, 10, 0, WRL), // Back left channel behind speaker - //new Cube(x, y, z, rx, ry, rz, wiring), - //new Cube(0,0,0,0,225,0, WRR), + // new Cube(x, y, z, rx, ry, rz, wiring), + // new Cube(0,0,0,0,225,0, WRR), }; // The bass box! - // BassBox bassBox = BassBox.unlitBassBox(BBX, 0, BBZ); // frame exists, no lights - BassBox bassBox = BassBox.noBassBox(); // no bass box at all - // BassBox bassBox = new BassBox(BBX, 0, BBZ); // bass box with lights - + BassBox bassBox = BassBox.noBassBox(); // no bass box at all + // The speakers! List speakers = Arrays.asList(new Speaker[] { - // Each speaker parameter is x, y, z, rotation, the left speaker comes first - // new Speaker(TRAILER_WIDTH - Speaker.EDGE_WIDTH + 8, 6, 3, -15) - }); - - - //////////////////////////////////////////////////////////////////////// - // dan's proposed lattice - ArrayList scubes = new ArrayList(); - //if (NumBackTowers != 25) exit(); - // for (int i=0; i dcubes = new ArrayList(); - // for (int i=1; i<6; i++) { - // if (i>1) dcubes.add(new Cube(-6+CW*4/3*i , 0, 0, 0, 0, 0, WRR)); - // dcubes.add(new Cube(-6+CW*4/3*i+CW*2/3., CH*.5, 0, 0, 0, 0, WRR)); - // } - -float[] pos = new float[3]; -pos[0] = 50; -pos[2] = 100; -scubes.add(new StaggeredTower(//tower 1 - pos[0], // x - 0 , // y - pos[2], // z - 0, 4, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - - -pos[0] += 25; -pos[2] -= 10; -scubes.add(new StaggeredTower(// tower 2 - pos[0], // x - 15 , // y - pos[2], // z - 0, 4, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += 25; -pos[2] += -12.5; -scubes.add(new StaggeredTower(//tower 3 - pos[0], // x - 0 , // y - pos[2], // z - 0, 5, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += -32.75; -pos[2] += -13; -scubes.add(new StaggeredTower(//tower 4 - pos[0], // x - 0, // y - pos[2], // z - 0, 6, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += 26; -pos[2] += -16; -scubes.add(new StaggeredTower(//tower 5 - pos[0], // x - 15 , // y - pos[2], // z - 0, 6, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += 26; -pos[2] += -4.5; -scubes.add(new StaggeredTower(//tower 6 - pos[0], // x - 0 , // y - pos[2], // z - 0, 6, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += -56.5; -pos[2] += -6.5; -scubes.add(new StaggeredTower(// tower 7 - pos[0], // x - 15 , // y - pos[2], // z - 0, 4, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += 26; -pos[2] += -16.5; -scubes.add(new StaggeredTower(//tower 8 - pos[0], // x - 0 , // y - pos[2], // z - 0, 5, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -pos[0] += 27; -pos[2] += -4.5; -scubes.add(new StaggeredTower(//tower 9 - pos[0], // x - 15 , // y - pos[2], // z - 0, 5, new Cube.Wiring[] { WRR, WRR, WRR, WRR, WRR, WRR}) ); - -// //TOWERS ON DANCE FLOOR -// scubes.add(new StaggeredTower(//tower 10 -// 83.75+39+43-124.5, // x -// 0, // y -// -47.5-43, // z -// 45, 4, new Cube.Wiring[]{ WRR, WRR, WRR, WRR}) ); -// scubes.add(new StaggeredTower(//tower 11 -// 83.75, // x -// 0, // y -// -47.5, // z -// 45, 4, new Cube.Wiring[]{ WRR, WRR, WRR, WRR}) ); -// scubes.add(new StaggeredTower(//tower 12 -// 83.75+39, // x -// 0, // y -// -47.5, // z -// 45, 4, new Cube.Wiring[]{ WRR, WRR, WRR, WRR}) ); -// scubes.add(new StaggeredTower(//tower 13 -// 83.75+39+43, // x -// 0, // y -// -47.5-43, // z -// 45, 4, new Cube.Wiring[]{ WRR, WRR, WRR, WRR}) ); - -// scubes.add(new StaggeredTower(// Single cube on top of tower 4 -// 42, // x -// 112 , // y -// 72, // z -// -10, 1, new Cube.Wiring[]{ WRL}) ); - - - + // Each speaker parameter is x, y, z, rotation, the left speaker comes first + // new Speaker(TRAILER_WIDTH - Speaker.EDGE_WIDTH + 8, 6, 3, -15) + } + ); + + List scubes = new ArrayList(); + + float[] pos = new float[3]; + pos[0] = 50; + pos[2] = 100; + scubes.add(new StaggeredTower(//tower 1 + pos[0], // x + 0, // y + pos[2], // z + 0, 4, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + pos[0] += 25; + pos[2] -= 10; + scubes.add(new StaggeredTower(// tower 2 + pos[0], // x + 15, // y + pos[2], // z + 0, 4, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += 25; + pos[2] += -12.5; + scubes.add(new StaggeredTower(//tower 3 + pos[0], // x + 0, // y + pos[2], // z + 0, 5, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += -32.75; + pos[2] += -13; + scubes.add(new StaggeredTower(//tower 4 + pos[0], // x + 0, // y + pos[2], // z + 0, 6, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += 26; + pos[2] += -16; + scubes.add(new StaggeredTower(//tower 5 + pos[0], // x + 15, // y + pos[2], // z + 0, 6, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += 26; + pos[2] += -4.5; + scubes.add(new StaggeredTower(//tower 6 + pos[0], // x + 0, // y + pos[2], // z + 0, 6, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += -56.5; + pos[2] += -6.5; + scubes.add(new StaggeredTower(// tower 7 + pos[0], // x + 15, // y + pos[2], // z + 0, 4, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += 26; + pos[2] += -16.5; + scubes.add(new StaggeredTower(//tower 8 + pos[0], // x + 0, // y + pos[2], // z + 0, 5, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); + + pos[0] += 27; + pos[2] += -4.5; + scubes.add(new StaggeredTower(//tower 9 + pos[0], // x + 15, // y + pos[2], // z + 0, 5, new Cube.Wiring[] { + WRR, WRR, WRR, WRR, WRR, WRR + } + )); ////////////////////////////////////////////////////////////////////// @@ -214,33 +175,17 @@ scubes.add(new StaggeredTower(//tower 9 ////////////////////////////////////////////////////////////////////// // These guts just convert the shorthand mappings into usable objects - ArrayList towerList = new ArrayList(); - ArrayList tower; + List towerList = new ArrayList(); + List tower; Cube[] cubes = new Cube[200]; int cubeIndex = 1; - float px, pz, ny; - for (TowerMapping tm : towerCubes) { - px = tm.x; - ny = tm.y; - pz = tm.z; - tower = new ArrayList(); - for (CubeMapping cm : tm.cubeMappings) { - tower.add(cubes[cubeIndex++] = new Cube(px = px + cm.dx, ny, pz = pz + cm.dz, 0, cm.ry, 0, cm.wiring)); - ny += Cube.EDGE_HEIGHT; - } - towerList.add(new Tower(tower)); - } - for (Cube cube : singleCubes) { cubes[cubeIndex++] = cube; } - for (Cube cube : dcubes) { - cubes[cubeIndex++] = cube; - } for (StaggeredTower st : scubes) { tower = new ArrayList(); - for (int i=0; i < st.n; i++) { + for (int i = 0; i < st.n; i++) { Cube.Wiring w = (i < st.wiring.length) ? st.wiring[i] : WRR; tower.add(cubes[cubeIndex++] = new Cube(st.x, st.y + CH* 4/3.*i, st.z, 0, st.r, 0, w)); } @@ -250,239 +195,22 @@ scubes.add(new StaggeredTower(//tower 9 return new Model(towerList, cubes, bassBox, speakers); } -/** - * This function maps the panda boards. We have an array of them, each has - * an IP address and a list of channels. - */ -public PandaMapping[] buildPandaList() { - final int LEFT_SPEAKER = 0; - final int RIGHT_SPEAKER = 1; - - // 8 channels map to: 3, 4, 7, 8, 13, 14, 15, 16. - return new PandaMapping[] { - new PandaMapping( - "192.168.88.100", new ChannelMapping[] { // G1 - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 6}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 5}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 6}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 7}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 7}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 8}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 2}), - - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 4}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 3}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 11}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 10}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 9}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 9}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 12}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 13}), - }), - - new PandaMapping( - "192.168.88.101", new ChannelMapping[] { //G4 - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 25}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 23}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 24}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 43}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 45}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 44}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 41}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 42}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 21}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 20}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 22}), - }), - - new PandaMapping( - "192.168.88.104", new ChannelMapping[] { // G3 - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 26}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 28}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 27}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 19}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 18}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 17}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 18}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 19}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 15}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 16}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 14}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 29}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 30}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 31}), - }), - - new PandaMapping( - "192.168.88.105", new ChannelMapping[] { // G2 - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 39}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 38}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 40}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 34}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 35}), - - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 33}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 32}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 37}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 37}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - new ChannelMapping(ChannelMapping.MODE_CUBES, new int[] { 1}), - }), - }; -} - -class TowerMapping { - public final float x, y, z; - public final CubeMapping[] cubeMappings; - - TowerMapping(float x, float y, float z, CubeMapping[] cubeMappings) { - this.x = x; - this.y = y; - this.z = z; - this.cubeMappings = cubeMappings; - } -} - -class CubeMapping { - public final float dx, dz, ry; - public final Cube.Wiring wiring; - - CubeMapping(float dx, float dz, Cube.Wiring wiring) { - this(dx, dz, 0., wiring); - } - CubeMapping(float dx, float dz, float ry) { - this(dz, dz, ry, Cube.Wiring.FRONT_LEFT); - } - - CubeMapping(float dx, float dz, float ry, Cube.Wiring wiring) { - this.dx = dx; - this.dz = dz; - this.ry = ry; - this.wiring = wiring; - } -} - class StaggeredTower { public final float x, y, z, r; public final int n; public final Cube.Wiring[] wiring; - StaggeredTower(float _x, float _y, float _z, float _r, int _n) { this(_x, _y, _z, _r, _n, new Cube.Wiring[]{}); } - StaggeredTower(float _x, float _y, float _z, float _r, int _n, Cube.Wiring[] _wiring) { x=_x; y=_y; z=_z; r=_r; n=_n; wiring=_wiring;} -} - -/** - * Each panda board has an IP address and a fixed number of channels. The channels - * each have a fixed number of pixels on them. Whether or not that many physical - * pixels are connected to the channel, we still send it that much data. - */ -class PandaMapping { - - // How many channels are on the panda board - public final static int CHANNELS_PER_BOARD = 16; - - // How many total pixels on the whole board - public final static int PIXELS_PER_BOARD = ChannelMapping.PIXELS_PER_CHANNEL * CHANNELS_PER_BOARD; - - final String ip; - final ChannelMapping[] channelList = new ChannelMapping[CHANNELS_PER_BOARD]; - - PandaMapping(String ip, ChannelMapping[] rawChannelList) { - this.ip = ip; - - // Ensure our array is the right length and has all valid items in it - for (int i = 0; i < channelList.length; ++i) { - channelList[i] = (i < rawChannelList.length) ? rawChannelList[i] : new ChannelMapping(); - if (channelList[i] == null) { - channelList[i] = new ChannelMapping(); - } + StaggeredTower(float _x, float _y, float _z, float _r, int _n) { + this(_x, _y, _z, _r, _n, new Cube.Wiring[] { } + ); } -} - -/** - * Each channel on a pandaboard can be mapped in a number of modes. The typical is - * to a series of connected cubes, but we also have special mappings for the bass box, - * the speaker enclosures, and the DJ booth floor. - * - * This class is just the mapping meta-data. It sanitizes the input to make sure - * that the cubes and objects being referenced actually exist in the model. - * - * The logic for how to encode the pixels is contained in the PandaDriver. - */ -class ChannelMapping { - - // How many cubes per channel xc_PB is configured for - public final static int CUBES_PER_CHANNEL = 1; - - // How many total pixels on each channel - public final static int PIXELS_PER_CHANNEL = Cube.POINTS_PER_CUBE * CUBES_PER_CHANNEL; - - public static final int MODE_NULL = 0; - public static final int MODE_CUBES = 1; - public static final int MODE_BASS = 2; - public static final int MODE_SPEAKER = 3; - public static final int MODE_STRUTS_AND_FLOOR = 4; - public static final int MODE_INVALID = 5; - - public static final int NO_OBJECT = -1; - - final int mode; - final int[] objectIndices = new int[CUBES_PER_CHANNEL]; - - ChannelMapping() { - this(MODE_NULL); - } - - ChannelMapping(int mode) { - this(mode, new int[]{}); - } - - ChannelMapping(int mode, int rawObjectIndex) { - this(mode, new int[]{ rawObjectIndex }); - } - - ChannelMapping(int mode, int[] rawObjectIndices) { - if (mode < 0 || mode >= MODE_INVALID) { - throw new RuntimeException("Invalid channel mapping mode: " + mode); - } - if (mode == MODE_SPEAKER) { - if (rawObjectIndices.length != 1) { - throw new RuntimeException("Speaker channel mapping mode must specify one speaker index"); - } - int speakerIndex = rawObjectIndices[0]; - if (speakerIndex < 0 || speakerIndex >= glucose.model.speakers.size()) { - throw new RuntimeException("Invalid speaker channel mapping: " + speakerIndex); - } - } else if ((mode == MODE_STRUTS_AND_FLOOR) || (mode == MODE_BASS) || (mode == MODE_NULL)) { - if (rawObjectIndices.length > 0) { - throw new RuntimeException("Bass/floor/null mappings cannot specify object indices"); - } - } else if (mode == MODE_CUBES) { - for (int rawCubeIndex : rawObjectIndices) { - if (glucose.model.getCubeByRawIndex(rawCubeIndex) == null) { - throw new RuntimeException("Non-existing cube specified in cube mapping: " + rawCubeIndex); - } - } - } - - this.mode = mode; - for (int i = 0; i < objectIndices.length; ++i) { - objectIndices[i] = (i < rawObjectIndices.length) ? rawObjectIndices[i] : NO_OBJECT; - } + StaggeredTower(float _x, float _y, float _z, float _r, int _n, Cube.Wiring[] _wiring) { + x=_x; + y=_y; + z=_z; + r=_r; + n=_n; + wiring=_wiring; } } + diff --git a/_PandaDriver.pde b/_PandaDriver.pde deleted file mode 100644 index 26ac3d7..0000000 --- a/_PandaDriver.pde +++ /dev/null @@ -1,438 +0,0 @@ -import netP5.*; -import oscP5.*; - - -/** - * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND - * - * //\\ //\\ //\\ //\\ - * ///\\\ ///\\\ ///\\\ ///\\\ - * \\\/// \\\/// \\\/// \\\/// - * \\// \\// \\// \\// - * - * EXPERTS ONLY!! EXPERTS ONLY!! - * - * This class implements the output function to the Panda Boards. It - * will be moved into GLucose once stabilized. - */ -public static class PandaDriver { - - interface Listener { - public void onToggle(boolean enabled); - } - - private Listener listener = null; - - // IP address - public final String ip; - - public PandaMapping pm; - - private final static int PORT = 779; - - private final DatagramSocket socket; - - // Address to send to - private final NetAddress address; - - // Whether board output is enabled - private boolean enabled = false; - - // Frame count for Grizzlies - private int frameNum = 1; - - // OSC message - private final OscMessage message; - - // List of point indices that get sent to this board - private final int[] points; - - // Packet data - private final byte[] packet = new byte[4*280]; // magic number, our UDP packet size - - private static final int NO_POINT = -1; - - private Model _model; - - //////////////////////////////////////////////////////////////// - // - // READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!! - // READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!! - // READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!! - // - // The mappings below indicate the physical order of strips - // connected to a pandaboard channel. The strip numbers are a - // reflection of how the model is built. - // - // For ANYTHING in the model which is a rectangular prism, - // which means Cubes, the BassBox, and each Speaker, the - // strips are numbered incrementally by face. The first - // face is always the FRONT, which you are looking at. - // The next face is the RIGHT, then the BACK, then the LEFT. - // - // For every face, the strips are ordered numerically moving - // clockwise from the the TOP LEFT. - // - // So, for a cube: - // - // Strip 0: front face, top strip, left to right - // Strip 1: front face, right strip, top to bottom - // Strip 2: front face, bottom strip, right to left - // Strip 3: front face, left strip, bottom to top - // - // Strip 4: right face, top strip, left to right - // ... and so on - // Strip 14: left face, bottom strip, right to left - // Strip 15: left face, left strip, bottom to top - // - //////////////////////////////////////////////////////////////// - - private final static int FORWARD = -1; - private final static int BACKWARD = -2; - - /** - * These constant arrays indicate the order in which the strips of a cube - * are wired. There are four different options, depending on which bottom - * corner of the cube the data wire comes in. - */ - private final static int[][] CUBE_STRIP_ORDERINGS = new int[][] { -// { 2, 1, 0, 3, 13, 12, 15, 14, 4, 7, 6, 5, 11, 10, 9, 8 }, // FRONT_LEFT -// { 6, 5, 4, 7, 1, 0, 3, 2, 8, 11, 10, 9, 15, 14, 13, 12 }, // FRONT_RIGHT -// { 14, 13, 12, 15, 9, 8, 11, 10, 0, 3, 2, 1, 7, 6, 5, 4 }, // REAR_LEFT -// { 10, 9, 8, 11, 5, 4, 7, 6, 12, 15, 14, 13, 3, 2, 1, 0 }, // REAR_RIGHT - - - { 2, 1, 0, 3, 13, 12, 15, 14, 4, 7, 6, 5, 11, 10, 9, 8 }, // FRONT_LEFT - { 6, 5, 4, 7, 1, 0, 3, 2, 8, 11, 10, 9, 15, 14, 13, 12 }, // FRONT_RIGHT - { 14, 13, 12, 15, 9, 8, 11, 10, 0, 3, 2, 1, 7, 6, 5, 4 }, // REAR_LEFT - { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 }, // REAR_RIGHT - - }; - - private final static int[][] BASS_STRIP_ORDERING = { - // front face, counterclockwise from bottom front left - {2, BACKWARD /* if this strip has extra pixels, you can add them here */ /*, 4 */ }, - {1, BACKWARD /* if this strip is short some pixels, substract them here */ /*, -3 */ }, - {0, BACKWARD }, - {3, BACKWARD }, - - // left face, counterclockwise from bottom front left - {13, BACKWARD }, - {12, BACKWARD }, - {15, BACKWARD }, - {14, BACKWARD }, - - // back face, counterclockwise from bottom rear left - {9, BACKWARD }, - {8, BACKWARD }, - {11, BACKWARD }, - {10, BACKWARD }, - - // right face, counterclockwise from bottom rear right - {5, BACKWARD }, - {4, BACKWARD }, - {7, BACKWARD }, - {6, BACKWARD }, - }; - - private final static int[][] STRUT_STRIP_ORDERING = { - {6, BACKWARD}, - {5, FORWARD}, - {4, BACKWARD}, - {3, FORWARD}, - {2, BACKWARD}, - {1, FORWARD}, - {0, BACKWARD}, - {7, FORWARD}, - }; - - private final static int[][] FLOOR_STRIP_ORDERING = { - {0, FORWARD}, - {1, FORWARD}, - {2, FORWARD}, - {3, BACKWARD}, - }; - - // The speakers are currently configured to be wired the same - // as cubes with Wiring.FRONT_LEFT. If this needs to be changed, - // remove this null assignment and change the below to have mappings - // for the LEFT and RIGHT speaker - private final static int[][][] SPEAKER_STRIP_ORDERING = { - // Left speaker - { - // Front face, counter-clockwise from bottom left - {2, BACKWARD }, - {1, BACKWARD }, - {0, BACKWARD }, - {3, BACKWARD }, - }, - // Right speaker - { - // Front face, counter-clockwise from bottom left - {2, BACKWARD }, - {1, BACKWARD }, - {0, BACKWARD }, - {3, BACKWARD }, - } - }; - - public PandaDriver(String ip) { - this.ip = ip; - - // Initialize our OSC output stuff - address = new NetAddress(ip, 779); - message = new OscMessage("/shady/pointbuffer"); - - try { - socket = new DatagramSocket(); - } catch (Exception x) { - throw new RuntimeException(x); - } - - // Build the array of points, initialize all to nothing - points = new int[PandaMapping.PIXELS_PER_BOARD]; - for (int i = 0; i < points.length; ++i) { - points[i] = NO_POINT; - } - } - - public PandaDriver(String ip, Model model, PandaMapping _pm) { - this(ip); - pm = _pm; - _model = model; - // Ok, we are initialized, time to build the array if points in order to - // send out. We start at the head of our point buffer, and work our way - // down. This is the order in which points will be sent down the wire. - int ci = -1; - - // Iterate through all our channelq s - for (ChannelMapping channel : pm.channelList) { - ++ci; - int pi = ci * ChannelMapping.PIXELS_PER_CHANNEL; - - switch (channel.mode) { - - case ChannelMapping.MODE_CUBES: - // We have a list of cubes per channel - for (int rawCubeIndex : channel.objectIndices) { - if (rawCubeIndex < 0) { - // No cube here, skip ahead in the buffer - pi += Cube.POINTS_PER_CUBE; - } else { - // The cube exists, check which way it is wired to - // figure out the order of strips. - Cube cube = model.getCubeByRawIndex(rawCubeIndex); - int stripOrderIndex = 0; - switch (cube.wiring) { - case FRONT_LEFT: stripOrderIndex = 0; break; - case FRONT_RIGHT: stripOrderIndex = 1; break; - case REAR_LEFT: stripOrderIndex = 2; break; - case REAR_RIGHT: stripOrderIndex = 3; break; - } - - // TODO(mcslee): clean up, ordering always consistent now - stripOrderIndex = 2; - - // Iterate through all the strips on the cube and add the points - for (int stripIndex : CUBE_STRIP_ORDERINGS[stripOrderIndex]) { - // We go backwards here... in the model strips go clockwise, but - // the physical wires are run counter-clockwise - pi = mapStrip(cube.strips.get(stripIndex), BACKWARD, points, pi); - } - } - } - break; - - case ChannelMapping.MODE_BASS: - for (int[] config : BASS_STRIP_ORDERING) { - pi = mapStrip(model.bassBox.strips.get(config[0]), config[1], points, pi); - if (config.length >= 3) pi += config[2]; - } - break; - - case ChannelMapping.MODE_STRUTS_AND_FLOOR: - for (int[] config : STRUT_STRIP_ORDERING) { - pi = mapStrip(model.bassBox.struts.get(config[0]), config[1], points, pi); - if (config.length >= 3) pi += config[2]; - } - for (int[] config : FLOOR_STRIP_ORDERING) { - pi = mapStrip(model.boothFloor.strips.get(config[0]), config[1], points, pi); - if (config.length >= 3) pi += config[2]; - } - break; - - case ChannelMapping.MODE_SPEAKER: - int [][] speakerStripOrdering; - if (SPEAKER_STRIP_ORDERING == null) { - // Copy the cube strip ordering - int[] frontLeftCubeWiring = CUBE_STRIP_ORDERINGS[0]; - speakerStripOrdering = new int[frontLeftCubeWiring.length][]; - for (int i = 0; i < frontLeftCubeWiring.length; ++i) { - speakerStripOrdering[i] = new int[] { frontLeftCubeWiring[0], BACKWARD }; - } - } else { - speakerStripOrdering = SPEAKER_STRIP_ORDERING[channel.objectIndices[0]]; - } - for (int[] config : speakerStripOrdering) { - Speaker speaker = model.speakers.get(channel.objectIndices[0]); - pi = mapStrip(speaker.strips.get(config[0]), config[1], points, pi); - if (config.length >= 3) pi += config[2]; - } - break; - - case ChannelMapping.MODE_NULL: - // No problem, nothing on this channel! - break; - - default: - throw new RuntimeException("Invalid/unhandled channel mapping mode: " + channel.mode); - } - - } - } - - private int mapStrip(Strip s, int direction, int[] points, int pi) { - return mapStrip(s, direction, points, pi, s.points.size()); - } - - private int mapStrip(Strip s, int direction, int[] points, int pi, int len) { - if (direction == FORWARD) { - int i = 0; - for (LXPoint p : s.points) { - points[pi++] = p.index; - if (++i >= len) { - break; - } - } - } else if (direction == BACKWARD) { - for (int i = len-1; i >= 0; --i) { - points[pi++] = s.points.get(i).index; - } - } else { - throw new RuntimeException("Unidentified strip mapping direction: " + direction); - } - return pi; - } - - public PandaDriver setListener(Listener listener) { - this.listener = listener; - return this; - } - - public void setEnabled(boolean enabled) { - if (this.enabled != enabled) { - this.enabled = enabled; - println("PandaBoard/" + ip + ": " + (enabled ? "ON" : "OFF")); - if (listener != null) { - listener.onToggle(enabled); - } - } - } - - public boolean isEnabled() { - return this.enabled; - } - - public void disable() { - setEnabled(false); - } - - public void enable() { - setEnabled(true); - } - - public void toggle() { - setEnabled(!enabled); - } - - private final int[] GRIZZLY_STRIP_ORDERING = new int[] { 9, 8, 11, 5, 4, 7, 6, 10, 14, 2, 1, 0, 3, 13, 12, 15 }; - - public final void send(int[] colors) { - if (!enabled) { - return; - } - frameNum++; - int len = 0; - int packetNum = 0; - for (ChannelMapping channel : pm.channelList) { - for (int rawCubeIndex : channel.objectIndices) { - if (rawCubeIndex > 0) { - Cube cube = _model.getCubeByRawIndex(rawCubeIndex); - - // TODO(mcslee): clean this up, precompute paths - for (int stripIndex : GRIZZLY_STRIP_ORDERING) { - Strip strip = cube.strips.get(stripIndex); - int stripLen = ((stripIndex == 9) || (stripIndex == 16)) ? 15 : 16; - for (int i = stripLen-1; i >= 0; --i) { - int c = colors[strip.points.get(i).index]; - byte r = (byte) ((c >> 16) & 0xFF); - byte g = (byte) ((c >> 8) & 0xFF); - byte b = (byte) ((c) & 0xFF); - packet[len++] = (byte) 0; // alpha channel, unused but makes for 4-byte alignment - packet[len++] = (byte) r; - packet[len++] = (byte) g; - packet[len++] = (byte) b; - } - } - -// for (LXPoint p : cube.points) { -// int c = (p.index < 0) ? 0 : colors[p.index]; -// byte r = (byte) ((c >> 16) & 0xFF); -// byte g = (byte) ((c >> 8) & 0xFF); -// byte b = (byte) ((c) & 0xFF); -// packet[len++] = (byte) 0; // alpha channel, unused but makes for 4-byte alignment -// packet[len++] = (byte) r; -// packet[len++] = (byte) g; -// packet[len++] = (byte) b; -// } - } - } - // println("Packet number: " + packetNum); - sendPacket(frameNum, packetNum++); - len = 0; - } - // for (int index : points) { - // int c = (index < 0) ? 0 : colors[index]; - // byte r = (byte) ((c >> 16) & 0xFF); - // byte g = (byte) ((c >> 8) & 0xFF); - // byte b = (byte) ((c) & 0xFF); - // packet[len++] = 0; // alpha channel, unused but makes for 4-byte alignment - // packet[len++] = r; - // packet[len++] = g; - // packet[len++] = b; - - // // Flush once packet is full buffer size - // if (len >= packet.length) { - // sendPacket(packetNum++); - // len = 0; - // } - // } - - // // Flush any remaining data - // if (len > 0) { - // sendPacket(packetNum++); - // } - } - - - private void sendPacket(int frameNum, int packetNum) { - // println("Sending frame #" + frameNum + ", channel # " + packetNum); - message.clearArguments(); - message.add(frameNum); - message.add(0xDEADBEEF); - message.add(packetNum); - message.add(0xFEEDBEEF); - message.add(packet.length); - message.add(packet); - message.add(0xBEFFFFEB); - - try { - // OscP5.flush(message, address); // new DatagramSocket every time, no thanks - byte[] bytes = message.getBytes(); - DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address.inetaddress(), PORT); - socket.send(packet); - } catch (Exception x) { - x.printStackTrace(); - } - } -} diff --git a/_UIImplementation.pde b/_UIImplementation.pde index 9fbc876..32c654e 100644 --- a/_UIImplementation.pde +++ b/_UIImplementation.pde @@ -163,17 +163,17 @@ class UIEffects extends UIWindow { } class UIOutput extends UIWindow { - public UIOutput(float x, float y, float w, float h) { + public UIOutput(GrizzlyOutput[] grizzlies, float x, float y, float w, float h) { super(lx.ui, "OUTPUT", x, y, w, h); float yp = UIWindow.TITLE_LABEL_HEIGHT; final UIScrollList outputs = new UIScrollList(1, UIWindow.TITLE_LABEL_HEIGHT, w-2, 80); List items = new ArrayList(); - for (final PandaDriver panda : pandaBoards) { - items.add(new PandaScrollItem(panda)); - panda.setListener(new PandaDriver.Listener() { - public void onToggle(boolean active) { + for (GrizzlyOutput grizzly : grizzlies) { + items.add(new GrizzlyScrollItem(grizzly)); + grizzly.enabled.addListener(new LXParameterListener() { + public void onParameterChanged(LXParameter parameter) { outputs.redraw(); } }); @@ -181,22 +181,23 @@ class UIOutput extends UIWindow { outputs.setItems(items).addToContainer(this); } - class PandaScrollItem extends UIScrollList.AbstractItem { - final PandaDriver panda; - PandaScrollItem(PandaDriver panda) { - this.panda = panda; + class GrizzlyScrollItem extends UIScrollList.AbstractItem { + final GrizzlyOutput output; + + GrizzlyScrollItem(GrizzlyOutput output) { + this.output = output; } public String getLabel() { - return panda.ip; + return output.ipAddress; } public boolean isSelected() { - return panda.isEnabled(); + return output.enabled.isOn(); } public void onMousePressed() { - panda.toggle(); + output.enabled.setOn(!isSelected()); } } } @@ -272,7 +273,7 @@ class UIMapping extends UIWindow { protected void onValueChange(int value) { mappingTool.setChannel(value-1); } - }).setRange(1, mappingTool.numChannels()).addToContainer(this); + }).setRange(0, mappingTool.numChannels()).addToContainer(this); yp += 24; new UILabel(4, yp+8, w-10, 20).setLabel("CUBE ID").addToContainer(this); diff --git a/build-tmp/source/SugarCubes.java b/build-tmp/source/SugarCubes.java deleted file mode 100644 index edd72f4..0000000 --- a/build-tmp/source/SugarCubes.java +++ /dev/null @@ -1,6279 +0,0 @@ -import processing.core.*; -import processing.data.*; -import processing.event.*; -import processing.opengl.*; - -import netP5.*; -import oscP5.*; -import processing.serial.*; -import java.util.LinkedHashMap; -import toxi.geom.Vec3D; -import toxi.geom.Matrix4x4; - -import heronarts.lx.font.*; -import heronarts.lx.transition.*; -import glucose.transform.*; -import netP5.*; -import heronarts.lx.pattern.*; -import glucose.pattern.*; -import heronarts.lx.model.*; -import toxi.geom.mesh2d.*; -import heronarts.lx.client.*; -import glucose.*; -import toxi.util.datatypes.*; -import toxi.math.waves.*; -import heronarts.lx.kinet.*; -import oscP5.*; -import toxi.geom.*; -import toxi.util.events.*; -import heronarts.lx.modulator.*; -import rwmidi.*; -import glucose.transition.*; -import glucose.effect.*; -import glucose.model.*; -import toxi.math.conversion.*; -import heronarts.lx.effect.*; -import heronarts.lx.control.*; -import glucose.control.*; -import toxi.math.noise.*; -import toxi.util.*; -import heronarts.lx.*; -import toxi.math.*; -import heronarts.lx.audio.*; - -import java.util.HashMap; -import java.util.ArrayList; -import java.io.File; -import java.io.BufferedReader; -import java.io.PrintWriter; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.IOException; - -public class SugarCubes extends PApplet { - -/** - * +-+-+-+-+-+ +-+-+-+-+-+ - * / /| |\ \ - * / / + + \ \ - * +-+-+-+-+-+ | +-+-+-+-+ | +-+-+-+-+-+ - * | | + / \ + | | - * + THE + / / \ \ + CUBES + - * | |/ +-+-+-+-+-+-+-+ \| | - * +-+-+-+-+-+ | | +-+-+-+-+-+ - * + + - * | SUGAR | - * + + - * | | - * +-+-+-+-+-+-+-+ - * - * Welcome to the Sugar Cubes! This Processing sketch is a fun place to build - * animations, effects, and interactions for the platform. Most of the icky - * code guts are embedded in the GLucose library extension. If you're an - * artist, you shouldn't need to worry about any of that. - * - * Below, you will find definitions of the Patterns, Effects, and Interactions. - * If you're an artist, create a new tab in the Processing environment with - * your name. Implement your classes there, and add them to the list below. - */ - -public LXPattern[] patterns(GLucose glucose) { - return new LXPattern[] { - - - // Slee - new Cathedrals(glucose), - new MidiMusic(glucose), - new Pulley(glucose), - new Swarm(glucose), - new ViolinWave(glucose), - new BouncyBalls(glucose), - new SpaceTime(glucose), - new ShiftingPlane(glucose), - new AskewPlanes(glucose), - new Blinders(glucose), - new CrossSections(glucose), - new Psychedelia(glucose), - - new Traktor(glucose).setEligible(false), - new BassPod(glucose).setEligible(false), - new CubeEQ(glucose).setEligible(false), - new PianoKeyPattern(glucose).setEligible(false), - - // DanH - new Noise(glucose), - new Play (glucose), - new Pong (glucose), - new Worms(glucose), - - // Alex G - new SineSphere(glucose), -// new CubeCurl(glucose), - - // Shaheen - new HelixPattern(glucose).setEligible(false), - - // Toby - new GlitchPlasma(glucose), - new FireEffect(glucose).setEligible(false), - new StripBounce(glucose), - new SoundRain(glucose).setEligible(false), - new SoundSpikes(glucose).setEligible(false), - new FaceSync(glucose), - - // Jack - new Swim(glucose), - new Balance(glucose), - - // Tim - new TimPlanes(glucose), - new TimPinwheels(glucose), - new TimRaindrops(glucose), - new TimCubes(glucose), - // new TimTrace(glucose), - new TimSpheres(glucose), - - // Ben - // new Sandbox(glucose), - new TowerParams(glucose), - new DriveableCrossSections(glucose), - new GranimTestPattern2(glucose), - - //JR - new Gimbal(glucose), - - // Sam - new JazzRainbow(glucose), - - // Arjun - new TelevisionStatic(glucose), - new AbstractPainting(glucose), - new Spirality(glucose), - - // Basic test patterns for reference, not art - new TestCubePattern(glucose), - new TestTowerPattern(glucose), - new TestProjectionPattern(glucose), - new TestStripPattern(glucose), - new TestBassMapping(glucose), - new TestFloorMapping(glucose), - new TestSpeakerMapping(glucose), - new TestPerformancePattern(glucose), - // new TestHuePattern(glucose), - // new TestXPattern(glucose), - // new TestYPattern(glucose), - // new TestZPattern(glucose), - - }; -} - -public LXTransition[] transitions(GLucose glucose) { - return new LXTransition[] { - new DissolveTransition(lx), - new AddTransition(glucose), - new MultiplyTransition(glucose), - new OverlayTransition(glucose), - new DodgeTransition(glucose), - new SwipeTransition(glucose), - new FadeTransition(lx), -// new SubtractTransition(glucose), // similar to multiply - dh -// new BurnTransition(glucose), // similar to multiply - dh -// new ScreenTransition(glucose), // same as add -dh -// new SoftLightTransition(glucose), // same as overlay -dh - }; -} - -// Handles to globally triggerable effects -class Effects { - FlashEffect flash = new FlashEffect(lx); - BoomEffect boom = new BoomEffect(glucose); - BlurEffect blur = new BlurEffect(glucose); - QuantizeEffect quantize = new QuantizeEffect(glucose); - ColorFuckerEffect colorFucker = new ColorFuckerEffect(glucose); - - Effects() { - blur.enable(); - quantize.enable(); - colorFucker.enable(); - } -} - -class SineSphere extends SCPattern { - private SinLFO yrot = new SinLFO(0, TWO_PI, 2000); - public final Projection sinespin; - float modelrad = sqrt((model.xMax)*(model.xMax) + (model.yMax)*(model.yMax) + (model.zMax)*(model.zMax)); - Pick Sshape; - - class Sphery { - float f1xcenter, f1ycenter, f1zcenter, f2xcenter , f2ycenter, f2zcenter; //second three are for an ellipse with two foci - private SinLFO vibration; - private SinLFO surface; - private SinLFO vx; - private SinLFO xbounce; - public SinLFO ybounce; - private SinLFO zbounce; - float vibration_min, vibration_max, vperiod; - public BasicParameter widthparameter; - public BasicParameter huespread; - public BasicParameter bouncerate; - public BasicParameter bounceamp; - - - - public Sphery(float f1xcenter, float f1ycenter, float f1zcenter, float vibration_min, float vibration_max, float vperiod) - { - this.f1xcenter = f1xcenter; - this.f1ycenter = f1ycenter; - this.f1zcenter = f1zcenter; - this.vibration_min = vibration_min; - this.vibration_max = vibration_max; - this.vperiod = vperiod; - addParameter(bounceamp = new BasicParameter("Amp", .5f)); - addParameter(bouncerate = new BasicParameter("Rate", .5f)); //ybounce.modulateDurationBy(bouncerate); - addParameter(widthparameter = new BasicParameter("Width", .1f)); - addParameter(huespread = new BasicParameter("Hue", .2f)); - - addModulator( vx = new SinLFO(-4000, 10000, 100000)).trigger() ; - //addModulator(xbounce = new SinLFO(model.xMax/3, 2*model.yMax/3, 2000)).trigger(); - addModulator(ybounce= new SinLFO(model.yMax/3, 2*model.yMax/3, 240000.f/lx.tempo.bpm())).trigger(); //ybounce.modulateDurationBy - - //addModulator(bounceamp); //ybounce.setMagnitude(bouncerate); - addModulator( vibration = new SinLFO(vibration_min , vibration_max, 240000.f/lx.tempo.bpm())).trigger(); //vibration.modulateDurationBy(vx); - - } - public Sphery(float f1xcenter, float f1ycenter, float f1zcenter, float f2xcenter, float f2ycenter, float f2zcenter, - float vibration_min, float vibration_max, float vperiod) - { - this.f1xcenter = f1xcenter; - this.f1ycenter = f1ycenter; - this.f1zcenter = f1zcenter; - this.f2xcenter = f2xcenter; - this.f2ycenter = f2ycenter; - this.f2zcenter = f2zcenter; - this.vibration_min = vibration_min; - this.vibration_max = vibration_max; - this.vperiod = vperiod; - //addModulator(xbounce = new SinLFO(model.xMax/3, 2*model.yMax/3, 2000)).trigger(); - addModulator(ybounce).trigger(); - addModulator( vibration = new SinLFO(vibration_min , vibration_max, lx.tempo.rampf())).trigger(); //vibration.modulateDurationBy(vx); - addParameter(widthparameter = new BasicParameter("Width", .1f)); - addParameter(huespread = new BasicParameter("Hue", .2f)); - -} - - - - - -public float distfromcirclecenter(float px, float py, float pz, float f1x, float f1y, float f1z) -{ - return dist(px, py, pz, f1x, f1y, f1z); - } - //void updatespherey(deltaMs, ) - public int spheryvalue (float px, float py, float pz , float f1xc, float f1yc, float f1zc) - { -//switch(sShpape.cur() ) {} - return lx.hsb(constrain(huespread.getValuef()*5*px, 0, 360) , dist(px, py, pz, f1xc, f1yc, f1zc) , - max(0, 100 - 100*widthparameter.getValuef()*abs(dist(px, py, pz, f1xcenter, ybounce.getValuef(), f1zcenter) - - vibration.getValuef() ) ) ); - } - public int ellipsevalue(float px, float py, float pz , float f1xc, float f1yc, float f1zc, float f2xc, float f2yc, float f2zc) - { -//switch(sShpape.cur() ) {} - return lx.hsb(huespread.getValuef()*5*px, dist(model.xMax-px, model.yMax-py, model.zMax-pz, f1xc, f1yc, f1zc) , - max(0, 100 - 100*widthparameter.getValuef() * - abs( (dist(px, py, pz, f1xc, ybounce.getValuef(), f1zc) + - (dist(px, py , pz, f2xc, ybounce.getValuef(), f2zc) ) )/2 - - 1.2f*vibration.getValuef() ) ) ) ; - } - -public void run(double deltaMs) { - float vv = vibration.getValuef(); - float ybv = ybounce.getValuef(); - - } - -} - - -final Sphery[] spherys; - SineSphere(GLucose glucose) - { - super(glucose); - sinespin = new Projection(model); - addModulator(yrot).trigger(); - //Sshape = addPick("Shape", , 1); - spherys = new Sphery[] { - new Sphery(model.xMax/4, model.yMax/2, model.zMax/2, modelrad/16, modelrad/8, 3000), - new Sphery(.75f*model.xMax, model.yMax/2, model.zMax/2, modelrad/20, modelrad/10, 2000), - new Sphery(model.xMax/2, model.yMax/2, model.zMax/2, modelrad/4, modelrad/8, 2300), - }; - - } - -// public void onParameterChanged(LXParameter parameter) -// { - - -// for (Sphery s : spherys) { -// if (s == null) continue; -// double bampv = s.bounceamp.getValue(); -// double brv = s.bouncerate.getValue(); -// double tempobounce = lx.tempo.bpm(); -// if (parameter == s.bounceamp) -// { -// s.ybounce.setRange(bampv*model.yMax/3 , bampv*2*model.yMax/3, brv); -// } -// else if ( parameter == s.bouncerate ) -// { -// s.ybounce.setDuration(120000./tempobounce); -// } -// } -// } - - public void run( double deltaMs) { - float t = lx.tempo.rampf(); - float bpm = lx.tempo.bpmf(); - //spherys[1].run(deltaMs); - //spherys[2].run(deltaMs); - //spherys[3].run(deltaMs);] - sinespin.reset(model) - - // Translate so the center of the car is the origin, offset by yPos - .translateCenter(model, 0, 0, 0) - - // Rotate around the origin (now the center of the car) about an X-vector - .rotate(yrot.getValuef(), 0, 1, 0); - - - - for (Point p: model.points){ - int c = 0; - c = blendColor(c, spherys[1].spheryvalue(p.x, p.y, p.z, .75f*model.xMax, model.yMax/2, model.zMax/2), ADD); - c = blendColor(c, spherys[0].spheryvalue(p.x, p.y, p.z, model.xMax/4, model.yMax/4, model.zMax/2), ADD); - c = blendColor(c, spherys[2].spheryvalue(p.x, p.y, p.z, model.xMax/2, model.yMax/2, model.zMax/2),ADD); - - colors[p.index] = lx.hsb(lx.h(c), lx.s(c), lx.b(c)); - - } - - - - } - int spheremode = 0; - - // void keyPressed() { - // spheremode++; - // } - - // color CalcPoint(PVector Px) - // { - // // if (spheremode == 0 ) - //{ - - //} - // else if (spheremode == 1) - // { - - // color c = 0; - // 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); - // return c; - // } - // return lx.hsb(0,0,0); - // // else if(spheremode ==2) - // { color c = 0; - // return lx.hsb(CalcCone( (xyz by = new xyz(0,spherys[2].ybounce.getValuef(),0) ), Px, mid) ); - - // } - - - // } - - } - -class CubeCurl extends SCPattern{ -float CH, CW, diag; -ArrayList cubeorigin = new ArrayList(); -ArrayList centerlist = new ArrayList(); -private SinLFO curl = new SinLFO(0, Cube.EDGE_HEIGHT, 5000 ); - -private SinLFO bg = new SinLFO(180, 220, 3000); - -CubeCurl(GLucose glucose){ -super(glucose); -addModulator(curl).trigger(); -addModulator(bg).trigger(); - this.CH = Cube.EDGE_HEIGHT; - this.CW = Cube.EDGE_WIDTH; - this.diag = sqrt(CW*CW + CW*CW); - - -ArrayList centerlistrelative = new ArrayList(); -for (int i = 0; i < model.cubes.size(); i++){ - Cube a = model.cubes.get(i); - cubeorigin.add(new PVector(a.x, a.y, a.z)); - centerlist.add(centerofcube(i)); - -} - -} -//there is definitely a better way of doing this! -public PVector centerofcube(int i) { -Cube c = model.cubes.get(i); - -println(" cube #: " + i + " c.x " + c.x + " c.y " + c.y + " c.z " + c.z ); -PVector cubeangle = new PVector(c.rx, c.ry, c.rz); -//println("raw x" + cubeangle.x + "raw y" + cubeangle.y + "raw z" + cubeangle.z); -PVector cubecenter = new PVector(c.x + CW/2, c.y + CH/2, c.z + CW/2); -println("cubecenter unrotated: " + cubecenter.x + " " +cubecenter.y + " " +cubecenter.z ); -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); - // nCos*(y-o.y) - nSin*(z-o.z) + o.y -cubecenter = PVector.add(cubecenter, centerrot); -println( " cubecenter.x " + cubecenter.x + " cubecenter.y " + cubecenter.y + " cubecenter.z " + cubecenter.z + " "); - - -return cubecenter; -} - - -public void run(double deltaMs){ -for (int i =0; i < model.cubes.size(); i++) { -Cube c = model.cubes.get(i); -float cfloor = c.y; - -// if (i%3 == 0){ - -// for (Point p : c.points ){ -// // colors[p.index]=color(0,0,0); -// //float dif = (p.y - c.y); -// //colors[p.index] = color( bg.getValuef() , 80 , dif < curl.getValuef() ? 80 : 0, ADD); -// } -// } - -// else if (i%3 == 1) { - -// for (Point p: c.points){ -// colors[p.index]=color(0,0,0); -// float dif = (p.y - c.y); -// // colors[p.index] = -// // color(bg.getValuef(), -// // map(curl.getValuef(), 0, Cube.EDGE_HEIGHT, 20, 100), -// // 100 - 10*abs(dif - curl.getValuef()), ADD ); -// } -// } -// else if (i%3 == 2){ - // centerlist[i].sub(cubeorigin(i); - for (Point p: c.points) { - PVector pv = new PVector(p.x, p.y, p.z); - colors[p.index] =color( constrain(4* pv.dist(centerlist.get(i)), 0, 360) , 50, 100 ); - // colors[p.index] =color(constrain(centerlist[i].x, 0, 360), constrain(centerlist[i].y, 0, 100), ); - - - } - - - //} - - } - } - } - - class HueTestHSB extends SCPattern{ - BasicParameter HueT = new BasicParameter("Hue", .5f); - BasicParameter SatT = new BasicParameter("Sat", .5f); - BasicParameter BriT = new BasicParameter("Bright", .5f); - -HueTestHSB(GLucose glucose) { - super(glucose); - addParameter(HueT); - addParameter(SatT); - addParameter(BriT); -} - public void run(double deltaMs){ - - for (Point p : model.points) { - int c = 0; - c = blendColor(c, lx.hsb(360*HueT.getValuef(), 100*SatT.getValuef(), 100*BriT.getValuef()), ADD); - colors[p.index]= c; - } - int now= millis(); - if (now % 1000 <= 20) - { - println("Hue: " + 360*HueT.getValuef() + "Sat: " + 100*SatT.getValuef() + "Bright: " + 100*BriT.getValuef()); - } - } - - } - -class TelevisionStatic extends SCPattern { - BasicParameter brightParameter = new BasicParameter("BRIGHT", 1.0f); - BasicParameter saturationParameter = new BasicParameter("SAT", 1.0f); - BasicParameter hueParameter = new BasicParameter("HUE", 1.0f); - SinLFO direction = new SinLFO(0, 10, 3000); - - public TelevisionStatic(GLucose glucose) { - super(glucose); - addModulator(direction).trigger(); - addParameter(brightParameter); - addParameter(saturationParameter); - addParameter(hueParameter); - } - - public void run(double deltaMs) { - boolean d = direction.getValuef() > 5.0f; - for (Point p : model.points) { - colors[p.index] = lx.hsb((lx.getBaseHuef() + random(hueParameter.getValuef() * 360))%360, random(saturationParameter.getValuef() * 100), random(brightParameter.getValuef() * 100)); - } - } -} - -class AbstractPainting extends SCPattern { - - PImage img; - - SinLFO colorMod = new SinLFO(0, 360, 5000); - SinLFO brightMod = new SinLFO(0, model.zMax, 2000); - - public AbstractPainting(GLucose glucose) { - super(glucose); - addModulator(colorMod).trigger(); - addModulator(brightMod).trigger(); - - img = loadImage("abstract.jpg"); - img.loadPixels(); - } - - public void run(double deltaMs) { - for (Point p : model.points) { - int c = img.get((int)((p.x / model.xMax) * img.width), img.height - (int)((p.y / model.yMax) * img.height)); - colors[p.index] = lx.hsb(hue(c) + colorMod.getValuef()%360, saturation(c), brightness(c) - ((p.z - brightMod.getValuef())/p.z)); - } - } -} - -class Spirality extends SCPattern { - final BasicParameter r = new BasicParameter("RADIUS", 0.5f); - - float angle = 0; - float rad = 0; - int direction = 1; - - Spirality(GLucose glucose) { - super(glucose); - addParameter(r); - for (Point p : model.points) { - colors[p.index] = lx.hsb(0, 0, 0); - } - } - - public void run(double deltaMs) { - angle += deltaMs * 0.007f; - rad += deltaMs * .025f * direction; - float x = model.xMax / 2 + cos(angle) * rad; - float y = model.yMax / 2 + sin(angle) * rad; - for (Point p : model.points) { - float b = dist(x,y,p.x,p.y); - if (b < 90) { - colors[p.index] = blendColor( - colors[p.index], - lx.hsb(lx.getBaseHuef() + 25, 10, map(b, 0, 10, 100, 0)), - ADD); - } else { - colors[p.index] = blendColor( - colors[p.index], - lx.hsb(25, 10, map(b, 0, 10, 0, 15)), - SUBTRACT); - } - } - if (rad > model.xMax / 2 || rad <= .001f) { - direction *= -1; - } - } -} - - - - -/** - * This is a reusable equalizer class that lets you get averaged - * bands with dB scaling and smoothing. - */ -public static class GraphicEQ { - - private final LX lx; - - public final BasicParameter level = new BasicParameter("LVL", 0.5f); - public final BasicParameter range = new BasicParameter("RNGE", 0.5f); - public final BasicParameter slope = new BasicParameter("SLOP", 0.5f); - public final BasicParameter attack = new BasicParameter("ATK", 0.5f); - public final BasicParameter release = new BasicParameter("REL", 0.5f); - - private final FFT fft; - private final int numBands; - - private final LinearEnvelope[] bandVals; - - public final static int DEFAULT_NUM_BANDS = 16; - - public GraphicEQ(LX lx) { - this(lx, DEFAULT_NUM_BANDS); - } - - /** - * Note that the number of bands is a suggestion. Due to the FFT implementation - * the actual number may be slightly different. - */ - public GraphicEQ(LX lx, int num) { - this.lx = lx; - fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate()); - fft.window(FFT.HAMMING); - fft.logAverages(50, num/8); - numBands = this.fft.avgSize(); - bandVals = new LinearEnvelope[numBands]; - for (int i = 0; i < bandVals.length; ++i) { - (bandVals[i] = new LinearEnvelope(0, 0, 500)).trigger(); - } - } - - static final float logTen = log(10); - public static float log10(float val) { - return log(val) / logTen; - } - - public float getLevel(int band) { - return bandVals[band].getValuef(); - } - - public float getAverageLevel(int minBand, int numBands) { - float avg = 0; - for (int i = minBand; i < minBand + numBands; ++i) { - avg += bandVals[i].getValuef(); - } - avg /= numBands; - return avg; - } - - public void run(double deltaMs) { - fft.forward(lx.audioInput().mix); - float zeroDBReference = pow(10, 100*(1-level.getValuef())/20.f); - float decibelRange = 12 + range.getValuef() * 60; - float decibelSlope = slope.getValuef() * 60.f / numBands; - for (int i = 0; i < numBands; ++i) { - float raw = fft.getAvg(i); - float decibels = 20*log10(raw / zeroDBReference); - float positiveDecibels = decibels + decibelRange; - positiveDecibels += i*decibelSlope; - float value = constrain(positiveDecibels / decibelRange, 0, 1); - - if (value > bandVals[i].getValuef()) { - bandVals[i].setRangeFromHereTo(value, attack.getValuef() * 20).trigger(); - } - } - for (LinearEnvelope band : bandVals) { - band.run(deltaMs); - if (!band.isRunning() && band.getValuef() > 0) { - band.setRangeFromHereTo(0, release.getValuef() * 1600).trigger(); - } - } - } -} - - -class TowerParams extends SCPattern -{ - BasicParameter hueoff = new BasicParameter("Hueoff", 0.0f); - BasicParameter hueSpan = new BasicParameter("HueRange", 0.0f); - BasicParameter t1 = new BasicParameter("T1", 0.0f); - BasicParameter t2 = new BasicParameter("T2", 0.0f); - BasicParameter t3 = new BasicParameter("T3", 0.0f); - BasicParameter t4 = new BasicParameter("T4", 0.0f); - BasicParameter t5 = new BasicParameter("T5", 0.0f); - BasicParameter t6 = new BasicParameter("T6", 0.0f); - BasicParameter t7 = new BasicParameter("T7", 0.0f); - BasicParameter t8 = new BasicParameter("T8", 0.0f); - BasicParameter t9 = new BasicParameter("T9", 0.0f); - BasicParameter t10 = new BasicParameter("T10", 0.0f); - BasicParameter t11 = new BasicParameter("T11", 0.0f); - BasicParameter t12 = new BasicParameter("T12", 0.0f); - BasicParameter t13 = new BasicParameter("T13", 0.0f); - BasicParameter t14 = new BasicParameter("T14", 0.0f); - BasicParameter t15 = new BasicParameter("T15", 0.0f); - BasicParameter t16 = new BasicParameter("T16", 0.0f); - - ArrayList towerParams; - int towerSize; - int colorSpan; - TowerParams(GLucose glucose) { - super(glucose); - - towerParams = new ArrayList(); - addParameter(hueoff); - addParameter(hueSpan); - towerParams.add(t1); - towerParams.add(t2); - towerParams.add(t3); - towerParams.add(t4); - towerParams.add(t5); - towerParams.add(t6); - towerParams.add(t7); - towerParams.add(t8); - towerParams.add(t9); - towerParams.add(t10); - towerParams.add(t11); - towerParams.add(t12); - towerParams.add(t13); - towerParams.add(t14); - towerParams.add(t15); - towerParams.add(t16); - for(BasicParameter p : towerParams) - { - addParameter(p); - } - towerSize = model.towers.size(); - colorSpan = 255 / towerSize; - } - - public void run(double deltaMs) - { - clearALL(); - Tower t; - for(int i=0; i0.5f; - } - - public void updateXYZVals() - { - if(interactive()) - { - xv = xd.getValuef()*200; - yv = yd.getValuef()*115; - zv = zd.getValuef()*100; - }else{ - super.updateXYZVals(); - copyValuesToKnobs(); - } - } - -} -//---------------------------------------------------------------------------------------------------------------------------------- -public class Pong extends DPat { - SinLFO x,y,z,dx,dy,dz; - float cRad; BasicParameter pSize; - Pick pChoose; - PVector v = new PVector(), vMir = new PVector(); - - Pong(GLucose glucose) { - super(glucose); - cRad = mMax.x/10; - addModulator(dx = new SinLFO(6000, 500, 30000 )).trigger(); - addModulator(dy = new SinLFO(3000, 500, 22472 )).trigger(); - addModulator(dz = new SinLFO(1000, 500, 18420 )).trigger(); - addModulator(x = new SinLFO(cRad, mMax.x - cRad, 0)).trigger(); x.modulateDurationBy(dx); - addModulator(y = new SinLFO(cRad, mMax.y - cRad, 0)).trigger(); y.modulateDurationBy(dy); - addModulator(z = new SinLFO(cRad, mMax.z - cRad, 0)).trigger(); z.modulateDurationBy(dz); - pSize = addParam ("Size" , 0.4f ); - pChoose = addPick ("Animiation" , 2, 2, new String[] {"Pong", "Ball", "Cone"} ); - } - - public void StartRun(double deltaMs) { cRad = mMax.x*val(pSize)/6; } - public int CalcPoint(PVector p) { - v.set(x.getValuef(), y.getValuef(), z.getValuef()); - v.z=0;p.z=0;// ignore z dimension - switch(pChoose.Cur()) { - case 0: vMir.set(mMax); vMir.sub(p); - return lx.hsb(lxh(),100,c1c(1 - min(v.dist(p), v.dist(vMir))*.5f/cRad)); // balls - case 1: return lx.hsb(lxh(),100,c1c(1 - v.dist(p)*.5f/cRad)); // ball - case 2: vMir.set(mMax.x/2,0,mMax.z/2); - return lx.hsb(lxh(),100,c1c(1 - calcCone(p,v,vMir) * max(.02f,.45f-val(pSize)))); // spot - } - return lx.hsb(0,0,0); - } -} -//---------------------------------------------------------------------------------------------------------------------------------- -public class NDat { - float xz, yz, zz, hue, speed, angle, den; - float xoff,yoff,zoff; - float sinAngle, cosAngle; - boolean isActive; - NDat () { isActive=false; } - public boolean Active() { return isActive; } - public void set (float _hue, float _xz, float _yz, float _zz, float _den, float _speed, float _angle) { - isActive = true; - hue=_hue; xz=_xz; yz=_yz; zz =_zz; den=_den; speed=_speed; angle=_angle; - xoff = random(100e3f); yoff = random(100e3f); zoff = random(100e3f); - } -} - -public class Noise extends DPat -{ - int CurAnim, iSymm; - int XSym=1,YSym=2,RadSym=3; - float zTime , zTheta=0, zSin, zCos, rtime, ttime; - BasicParameter pSpeed , pDensity, pSharp; - Pick pChoose, pSymm; - int _ND = 4; - NDat N[] = new NDat[_ND]; - - Noise(GLucose glucose) { - super(glucose); - pSpeed = addParam("Fast" , .55f); - pDensity = addParam("Dens" , .5f); - pSharp = addParam("Shrp" , 0); - pSymm = addPick("Symmetry" , 0, 3, new String[] {"None", "X", "Y", "Radial"} ); - pChoose = addPick("Animation", 6, 7, new String[] {"Drip", "Cloud", "Rain", "Fire", "Machine", "Spark","VWave", "Wave"} ); - for (int i=0; i<_ND; i++) N[i] = new NDat(); - } - - public void onActive() { zTime = random(500); zTheta=0; rtime = 0; ttime = 0; } - - public void StartRun(double deltaMs) { - zTime += deltaMs*(val(pSpeed)-.5f)*.002f ; - zTheta += deltaMs*(spin()-.5f)*.01f ; - rtime += deltaMs; - iSymm = pSymm.Cur(); - zSin = sin(zTheta); - zCos = cos(zTheta); - - if (pChoose.Cur() != CurAnim) { - CurAnim = pChoose.Cur(); ttime = rtime; - pSpin .reset(); zTheta = 0; - pDensity .reset(); pSpeed .reset(); - for (int i=0; i<_ND; i++) { N[i].isActive = false; } - - switch(CurAnim) { - // hue xz yz zz den mph angle - case 0: N[0].set(0 ,75 ,75 ,150,45 ,3 ,0 ); pSharp.setValue(1 ); break; // drip - case 1: N[0].set(0 ,100,100,200,45 ,3 ,180); pSharp.setValue(0 ); break; // clouds - case 2: N[0].set(0 ,2 ,400,2 ,20 ,3 ,0 ); pSharp.setValue(.5f); break; // rain - case 3: N[0].set(40 ,100,100,200,10 ,1 ,180); - N[1].set(0 ,100,100,200,10 ,5 ,180); pSharp.setValue(0 ); break; // fire 1 - case 4: N[0].set(0 ,40 ,40 ,40 ,15 ,2.5f,180); - N[1].set(20 ,40 ,40 ,40 ,15 ,4 ,0 ); - N[2].set(40 ,40 ,40 ,40 ,15 ,2 ,90 ); - N[3].set(60 ,40 ,40 ,40 ,15 ,3 ,-90); pSharp.setValue(.5f); break; // machine - case 5: N[0].set(0 ,400,100,2 ,15 ,3 ,90 ); - N[1].set(20 ,400,100,2 ,15 ,2.5f,0 ); - N[2].set(40 ,100,100,2 ,15 ,2 ,180); - N[3].set(60 ,100,100,2 ,15 ,1.5f,270); pSharp.setValue(.5f); break; // spark - } - } - - for (int i=0; i<_ND; i++) if (N[i].Active()) { - N[i].sinAngle = sin(radians(N[i].angle)); - N[i].cosAngle = cos(radians(N[i].angle)); - } - } - - public int CalcPoint(PVector p) { - int c = 0; - rotateZ(p, mCtr, zSin, zCos); - - if (CurAnim == 6 || CurAnim == 7) { - setNorm(p); - return lx.hsb(lxh(),100, 100 * ( - constrain(1-50*(1-val(pDensity))*abs(p.y-sin(zTime*10 + p.x*(300))*.5f - .5f),0,1) + - (CurAnim == 7 ? constrain(1-50*(1-val(pDensity))*abs(p.x-sin(zTime*10 + p.y*(300))*.5f - .5f),0,1) : 0)) - ); - } - - if (iSymm == XSym && p.x > mMax.x/2) p.x = mMax.x-p.x; - if (iSymm == YSym && p.y > mMax.y/2) p.y = mMax.y-p.y; - - for (int i=0;i<_ND; i++) if (N[i].Active()) { - NDat n = N[i]; - float zx = zTime * n.speed * n.sinAngle, - zy = zTime * n.speed * n.cosAngle; - - float b = (iSymm==RadSym ? noise(zTime*n.speed+n.xoff-p.dist(mCtr)/n.xz) - : noise(p.x/n.xz+zx+n.xoff,p.y/n.yz+zy+n.yoff,p.z/n.zz+n.zoff)) - *1.8f; - - b += n.den/100 -.4f + val(pDensity) -1; - c = blendColor(c,lx.hsb(lxh()+n.hue,100,c1c(b)),ADD); - } - return c; - } -} -//---------------------------------------------------------------------------------------------------------------------------------- -public class Play extends DPat -{ - public class rAngle { - float prvA, dstA, c; - float prvR, dstR, r; - float _cos, _sin, x, y; - public float fixAngle (float a, float b) { return a abs(a+2*PI-b) ? a : a+2*PI) : - (abs(a-b) > abs(a-2*PI-b) ? a : a-2*PI) ; } - public float getX(float r) { return mCtr.x + _cos*r; } - public float getY(float r) { return mCtr.y + _sin*r; } - public void move() { c = interp(t,prvA,dstA); - r = interp(t,prvR,dstR); - _cos = cos(c); _sin = sin(c); - x = getX(r); y = getY(r); } - public void set() { prvA = dstA; dstA = random(2*PI); prvA = fixAngle(prvA, dstA); - prvR = dstR; dstR = random(mCtr.y); } - } - - BasicParameter pAmp, pRadius, pBounce; - Pick pTimePattern, pTempoMult, pShape; - - ArrayList waves = new ArrayList(10); - - int nBeats = 0; - float t,amp,rad,bnc,zTheta=0; - - rAngle a1 = new rAngle(), a2 = new rAngle(), - a3 = new rAngle(), a4 = new rAngle(); - PVector cPrev = new PVector(), cRand = new PVector(), - cMid = new PVector(), V = new PVector(), - theta = new PVector(), tSin = new PVector(), - tCos = new PVector(), cMidNorm = new PVector(), - Pn = new PVector(); - float LastBeat=3, LastMeasure=3; - int curRandTempo = 1, curRandTPat = 1; - - Play(GLucose glucose) { - super(glucose); - pRadius = addParam("Rad" , .1f ); - pBounce = addParam("Bnc" , .2f ); - pAmp = addParam("Amp" , .2f ); - pTempoMult = addPick ("TMult" , 5 , 5 , new String[] {"1x", "2x", "4x", "8x", "16x", "Rand" } ); - pTimePattern= addPick ("TPat" , 7 , 7 , new String[] {"Bounce", "Sin", "Roll", "Quant", "Accel", "Deccel", "Slide", "Rand"} ); - pShape = addPick ("Shape" , 7 , 15 , new String[] {"Line", "Tap", "V", "RandV", - "Pyramid", "Wings", "W2", "Clock", - "Triangle", "Quad", "Sphere", "Cone", - "Noise", "Wave", "?", "?"} ); - } - - public class rWave { - float v0, a0, x0, t,damp,a; - boolean bDone=false; - final float len=8; - rWave(float _x0, float _a0, float _v0, float _damp) { x0=_x0*len; a0=_a0; v0=_v0; t=0; damp = _damp; } - public void move(double deltaMs) { - t += deltaMs*.001f; - if (t>4) bDone=true; - } - public float val(float _x) { - _x*=len; - float dist = t*v0 - abs(_x-x0); - if (dist<0) { a=1; return 0; } - a = a0*exp(-dist*damp) * exp(-abs(_x-x0)/(.2f*len)); // * max(0,1-t/dur) - return -a*sin(dist); - } - } - - public void onReset() { zTheta=0; super.onReset(); } - public void onActive() { - zTheta=0; - while (lx.tempo.bpm() > 40) lx.tempo.setBpm(lx.tempo.bpm()/2); - } - - int KeyPressed = -1; - public boolean noteOn(Note note) { - int row = note.getPitch(), col = note.getChannel(); - if (row == 57) {KeyPressed = col; return true; } - return super.noteOn(note); - } - - public void StartRun(double deltaMs) { - t = lx.tempo.rampf(); - amp = pAmp .getValuef(); - rad = pRadius .getValuef(); - bnc = pBounce .getValuef(); - zTheta += deltaMs*(val(pSpin)-.5f)*.01f; - - theta .set(val(pRotX)*PI*2, val(pRotY)*PI*2, val(pRotZ)*PI*2 + zTheta); - tSin .set(sin(theta.x), sin(theta.y), sin(theta.z)); - tCos .set(cos(theta.x), cos(theta.y), cos(theta.z)); - - if (t 6 ? 2+PApplet.parseInt(random(5)) : PApplet.parseInt(random(7)); } - } LastMeasure = t; - - int nTempo = pTempoMult .Cur(); if (nTempo == 5) nTempo = curRandTempo; - int nTPat = pTimePattern.Cur(); if (nTPat == 7) nTPat = curRandTPat ; - - switch (nTempo) { - case 0: t = t; break; - case 1: t = (t*2.f )%1.f; break; - case 2: t = (t*4.f )%1.f; break; - case 3: t = (t*8.f )%1.f; break; - case 4: t = (t*16.f)%1.f; break; - } - - int i=0; while (i< waves.size()) { - rWave w = waves.get(i); - w.move(deltaMs); if (w.bDone) waves.remove(i); else i++; - } - - if ((t-1) { - waves.add(new rWave( - KeyPressed>-1 ? map(KeyPressed,0,7,0,1) : random(1), // location - bnc*10, // bounciness - 7, // velocity - 2*(1-amp))); // dampiness - KeyPressed=-1; - if (waves.size() > 5) waves.remove(0); - } - - if (t .5f?1:0)); // cone - - case 12: return lx.hsb(lxh() + noise(Pn.x,Pn.y,Pn.z + (NoiseMove+50000)/1000.f)*200, - 85,c1c(Pn.y < noise(Pn.x + NoiseMove/2000.f,Pn.z)*(1+amp)-amp/2.f-.1f ? 1 : 0)); // noise - - case 13: - case 14: float y=0; for (rWave w : waves) y += .5f*w.val(Pn.x); // wave - V.set(Pn.x, .7f+y, Pn.z); - break; - - default: return lx.hsb(0,0,0); - } - - return lx.hsb(lxh(), 100, c1c(1 - V.dist(Pn)/rad)); - } -} -//---------------------------------------------------------------------------------------------------------------------------------- -boolean dDebug = false; -class dCursor { - dVertex vCur, vNext, vDest; - float destSpeed; - int posStop, pos,posNext; // 0 - 65535 - int clr; - - dCursor() {} - - public boolean isDone () { return pos==posStop; } - public boolean atDest () { return vCur.s==vDest.s || - xyDist(vCur.getPoint(0), vDest.getPoint(0)) < 12 || - xyDist(vCur.getPoint(0), vDest.getPoint(15))< 12;} - public void setCur (dVertex _v, int _p) { p2=null; vCur=_v; pos=_p; pickNext(); } - public void setCur (dPixel _p) { setCur(_p.v, _p.pos); } - public void setNext (dVertex _v, int _p, int _s) { vNext = _v; posNext = _p<<12; posStop = _s<<12; } - public void setDest (dVertex _v, float _speed) { vDest = _v; destSpeed = _speed; } - public void onDone () { setCur(vNext, posNext); pickNext(); } - - float minDist; - int nTurns; - boolean bRandEval; - - public void evaluate(dVertex v, int p, int s) { - if (v == null) return; ++nTurns; - if (bRandEval) { - if (random(nTurns) < 1) setNext(v,p,s); return; } - else { - float d = xyDist(v.getPoint(15), vDest.getPoint(0)); - if (d < minDist) { minDist=d; setNext(v,p,s); } - if (d == minDist && random(2)<1) { minDist=d; setNext(v,p,s); } - } - } - - public void evalTurn(dTurn t) { - if (t == null || t.pos0<<12 <= pos) return; - evaluate(t.v , t.pos1, t.pos0); - evaluate(t.v.opp, 16-t.pos1, t.pos0); - } - - public void pickNext() { - bRandEval = random(.05f+destSpeed) < .05f; minDist=500; nTurns=0; - evaluate(vCur.c0, 0, 16); evaluate(vCur.c1, 0, 16); - evaluate(vCur.c2, 0, 16); evaluate(vCur.c3, 0, 16); - evalTurn(vCur.t0); evalTurn(vCur.t1); - evalTurn(vCur.t2); evalTurn(vCur.t3); - } - - Point p1, p2; int i2; - - public int draw(int nAmount, SCPattern pat) { - int nFrom = (pos ) >> 12; - int nMv = min(nAmount, posStop-pos); - int nTo = min(15,(pos+nMv) >> 12); - dVertex v = vCur; - - if (dDebug) { p1 = v.getPoint(nFrom); float d = (p2 == null ? 0 : pointDist(p1,p2)); if (d>5) { println("too wide! quitting: " + d); exit(); }} - for (int i = nFrom; i <= nTo; i++) { pat.getColors()[v.ci + v.dir*i ] = clr; } - if (v.same != null) for (int i = nFrom; i <= nTo; i++) { pat.getColors()[v.same.ci + v.same.dir*i] = clr; } - - if (dDebug) { p2 = v.getPoint(nTo); i2 = nTo; } - - pos += nMv; return nAmount - nMv; - } -} - -//---------------------------------------------------------------------------------------------------------------------------------- -class Worms extends SCPattern { - float StripsPerSec = 10; - float TrailTime = 3000; - int numCursors = 50; - ArrayList cur = new ArrayList(30); - - private GraphicEQ eq = null; - - private BasicParameter pBeat = new BasicParameter("BEAT", 0); - private BasicParameter pSpeed = new BasicParameter("FAST", .2f); - private BasicParameter pBlur = new BasicParameter("BLUR", .3f); - private BasicParameter pWorms = new BasicParameter("WRMS", .3f); - private BasicParameter pConfusion = new BasicParameter("CONF", .1f); - private BasicParameter pEQ = new BasicParameter("EQ" , 0); - private BasicParameter pSpawn = new BasicParameter("DIR" , 0); - private BasicParameter pColor = new BasicParameter("CLR" , .1f); - - float zMidLat = 82.f; - float nConfusion; - private final Click moveChase = new Click(1000); - - PVector middle; - public int AnimNum() { return floor(pSpawn.getValuef()*(4-.01f)); } - public float randX() { return random(model.xMax-model.xMin)+model.xMin; } - public float randY() { return random(model.yMax-model.yMin)+model.yMin; } - public PVector randEdge() { - return random(2) < 1 ? new PVector(random(2)<1 ? model.xMin:model.xMax, randY(), zMidLat) : - new PVector(randX(), random(2)<1 ? model.yMin:model.yMax, zMidLat) ; - } - - Worms(GLucose glucose) { - super(glucose); - addModulator(moveChase).start(); - addParameter(pBeat); addParameter(pSpeed); - addParameter(pBlur); addParameter(pWorms); - addParameter(pEQ); addParameter(pConfusion); - addParameter(pSpawn); addParameter(pColor); - - middle = new PVector(1.5f*model.cx, 1.5f*model.cy, 71); - if (lattice == null) lattice = new dLattice(); - for (int i=0; i 100) return; - if (moveChase.click()) setNewDest(); - - float fBass=0, fTreble=0; - if (pEQ.getValuef()>0) { // EQ - eq.run(deltaMs); - fBass = eq.getAverageLevel(0, 4); - fTreble = eq.getAverageLevel(eq.numBands-7, 7); - } - - if (pBlur.getValuef() < 1) { // trails - for (int i=0,s=model.points.size(); i0) colors[i] = lx.hsb(lx.h(c), lx.s(c), constrain((float)(b-100*deltaMs/(pBlur.getValuef()*TrailTime)),0,100)); - } - } - - int nWorms = floor(pWorms.getValuef() * numCursors * - map(pEQ.getValuef(),0,1,1,constrain(2*fTreble,0,1))); - - for (int i=0; i 0) { - nLeft = c.draw(nLeft,this); if (!c.isDone()) continue; - c.onDone(); if (c.atDest()) reset(c); - } - } - } - - - public void onActive() { if (eq == null) { - eq = new GraphicEQ(lx, 16); eq.slope.setValue(0.6f); - eq.level.setValue(0.65f); eq.range.setValue(0.35f); - eq.release.setValue(0.4f); - }} -} -//---------------------------------------------------------------------------------------------------------------------------------- -class GenericController { - GenericController(){} - public void RotateKnob(int type, int num, float val){ - LXParameter p = null; - if(type==0) { - p = glucose.patternKnobs.get(num); - if(p!=null) { p.setValue(val); } - } - if(type==1) { - p = glucose.transitionKnobs.get(num); - if(p!=null) { p.setValue(val); } - } - if(type==2) { - p = glucose.effectKnobs.get(num); - if(p!=null) { p.setValue(val); } - } - } -} - -class MidiController extends GenericController { - MidiController() { - super(); - } -} -//PApplet xparent; // be sure to set - - - -OscP5 listener; -// Setup OSC -//listener = new OscP5(this,7022); - -//boolean[] noteState = new boolean[16]; -// -//void controllerChangeReceived(rwmidi.Controller cc) { -// if (debugMode) { -// println("CC: " + cc.toString()); -// } -// if(cc.getCC()==1){ -// for(int i=0; i<16; i++){ -// if(noteState[i] && i<8) { LXParameter p = glucose.patternKnobs.get(i); p.setValue(cc.getValue()/127.0); } -// else if(noteState[i] && i<12) { LXParameter p = glucose.transitionKnobs.get(i-8); p.setValue(cc.getValue()/127.0); } -// else if(noteState[i] && i<16) { LXParameter p = glucose.effectKnobs.get(i-12); p.setValue(cc.getValue()/127.0); } -// } -// } -//} -// -//void noteOnReceived(Note note) { -// if (debugMode) { -// println("Note On: " + note.toString()); -// } -// int pitch = note.getPitch(); -// if(pitch>=36 && pitch <36+16){ -// noteState[pitch-36]=true; -// } -//} -// -//void noteOffReceived(Note note) { -// if (debugMode) { -// println("Note Off: " + note.toString()); -// } -// int pitch = note.getPitch(); -// if(pitch>=36 && pitch <36+16){ -// noteState[pitch-36]=false; -// } -//} -// -//void oscEvent(OscMessage theOscMessage) { -// println(theOscMessage); -// LXPattern currentPattern = lx.getPattern(); -// if (currentPattern instanceof OSCPattern) { -// ((OSCPattern)currentPattern).oscEvent(theOscMessage); -// } -//} -// - - -class ObjectMuckerEffect extends SCEffect { - ObjectMuckerEffect(GLucose glucose) { - super(glucose); - } - public void apply(int[] colors){ - /*for(Strip s: model.strips){ - for(int i=0; i0; i--){ - frames[i] = frames[i-1]; - } - frames[0] = new int[model.points.size()]; - - for(int i=0; i> 16) & 0xFF); - g += ((frames[j][i] >> 8) & 0xFF); - b += ((frames[j][i] >> 0) & 0xFF); - } - r/=blendfactor; - g/=blendfactor; - b/=blendfactor; - colorMode(ARGB); - colors[i] = (0xFF << 24) | (r << 16) | (g << 8) | b; - colorMode(HSB); - } - - } - } -} - - - - - - - -abstract class OSCPattern extends SCPattern { - public OSCPattern(GLucose glucose){super(glucose);} - public abstract void oscEvent(OscMessage msg); -} - -class Ball { - public int lastSeen; - public float x,y; - public Ball(){ - x=y=lastSeen=0; - } -} - -class OSC_Balls extends OSCPattern { - Ball[] balls; - public OSC_Balls(GLucose glucose){ - super(glucose); - balls = new Ball[20]; - for(int i=0; i x-4 && p.y < y+4 && p.y > y-4) { colors[p.index] = 0xffFF0000; } - } - } - } - } -} - - - - -/*class ScreenScrape extends SCPattern { - PImage pret; - ScreenShot ss; - public ScreenScrape(GLucose glucose) { - super(glucose); - System.loadLibrary("ScreenShot"); - pret = new PImage(8, 128, ARGB); - ss = new ScreenShot(); - } - void run(double deltaMs){ - int x=(1366/2)+516; - int y=768-516; - int w=8; - int h=128; - pret.pixels = ss.getScreenShotJNI2(x, y, w, h); - //for(int i=0; i= b && a <= c; } -public boolean btwn (double a,double b,double c) { return a >= b && a <= c; } -public float interp (float a, float b, float c) { return (1-a)*b + a*c; } -public float randctr (float a) { return random(a) - a*.5f; } -public float min (float a, float b, float c, float d) { return min(min(a,b),min(c,d)); } -public float pointDist(Point p1, Point p2) { return dist(p1.x,p1.y,p1.z,p2.x,p2.y,p2.z); } -public float xyDist (Point p1, Point p2) { return dist(p1.x,p1.y,p2.x,p2.y); } -public float distToSeg(float x, float y, float x1, float y1, float x2, float y2) { - float A = x - x1, B = y - y1, C = x2 - x1, D = y2 - y1; - float dot = A * C + B * D, len_sq = C * C + D * D; - float xx, yy,param = dot / len_sq; - - if (param < 0 || (x1 == x2 && y1 == y2)) { xx = x1; yy = y1; } - else if (param > 1) { xx = x2; yy = y2; } - else { xx = x1 + param * C; - yy = y1 + param * D; } - float dx = x - xx, dy = y - yy; - return sqrt(dx * dx + dy * dy); -} - -public class Pick { - int NumPicks, Default , - CurRow , CurCol , - StartRow, EndRow ; - String tag , Desc[] ; - - Pick (String label, int _Def, int _Num, int nStart, String d[]) { - NumPicks = _Num; Default = _Def; - StartRow = nStart; EndRow = StartRow + floor((NumPicks-1) / NumApcCols); - tag = label; Desc = d; - reset(); - } - - public int Cur() { return (CurRow-StartRow)*NumApcCols + CurCol; } - public String CurDesc() { return Desc[Cur()]; } - public void reset() { CurCol = Default % NumApcCols; CurRow = StartRow + Default / NumApcCols; } - - public boolean set(int r, int c) { - if (!btwn(r,StartRow,EndRow) || !btwn(c,0,NumApcCols-1) || - !btwn((r-StartRow)*NumApcCols + c,0,NumPicks-1)) return false; - CurRow=r; CurCol=c; return true; - } -} - -public class DBool { - boolean def, b; - String tag; - int row, col; - public void reset() { b = def; } - public boolean set (int r, int c, boolean val) { if (r != row || c != col) return false; b = val; return true; } - DBool(String _tag, boolean _def, int _row, int _col) { - def = _def; b = _def; tag = _tag; row = _row; col = _col; - } -} -//---------------------------------------------------------------------------------------------------------------------------------- -public class DPat extends SCPattern -{ - ArrayList picks = new ArrayList (); - ArrayList bools = new ArrayList (); - - PVector mMax, mCtr, mHalf; - - MidiOutput APCOut; - int nMaxRow = 53; - float LastJog = -1; - float[] xWaveNz, yWaveNz; - int nPoint , nPoints; - PVector xyzJog = new PVector(), modmin; - - float NoiseMove = random(10000); - BasicParameter pSpark, pWave, pRotX, pRotY, pRotZ, pSpin, pTransX, pTransY; - DBool pXsym, pYsym, pRsym, pXdup, pXtrip, pJog, pGrey; - - public float lxh () { return lx.getBaseHuef(); } - public int c1c (float a) { return round(100*constrain(a,0,1)); } - public float interpWv(float i, float[] vals) { return interp(i-floor(i), vals[floor(i)], vals[ceil(i)]); } - public void setNorm (PVector vec) { vec.set(vec.x/mMax.x, vec.y/mMax.y, vec.z/mMax.z); } - public void setRand (PVector vec) { vec.set(random(mMax.x), random(mMax.y), random(mMax.z)); } - public void setVec (PVector vec, Point p) { vec.set(p.x, p.y, p.z); } - 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)); } - public void StartRun(double deltaMs) { } - public float val (BasicParameter p) { return p.getValuef(); } - public int CalcPoint(PVector p) { return lx.hsb(0,0,0); } - public int blend3(int c1, int c2, int c3) { return blendColor(c1,blendColor(c2,c3,ADD),ADD); } - - 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); } - 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 ); } - 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 ); } - - public BasicParameter addParam(String label, double value) { BasicParameter p = new BasicParameter(label, value); addParameter(p); return p; } - - PVector vT1 = new PVector(), vT2 = new PVector(); - public float calcCone (PVector v1, PVector v2, PVector c) { vT1.set(v1); vT2.set(v2); vT1.sub(c); vT2.sub(c); - return degrees(PVector.angleBetween(vT1,vT2)); } - - public Pick addPick(String name, int def, int _max, String[] desc) { - Pick P = new Pick(name, def, _max+1, nMaxRow, desc); - nMaxRow = P.EndRow + 1; - picks.add(P); - return P; - } - - public boolean noteOff(Note note) { - int row = note.getPitch(), col = note.getChannel(); - for (int i=0; i= 0.55f) { - return raw - 0.05f; - } - return 0.5f; - } - - public void setAPCOutput(MidiOutput output) { - APCOut = output; - } - - public void updateLights() { if (APCOut == null) return; - for (int i = 0; i < NumApcRows; ++i) - for (int j = 0; j < 8; ++j) APCOut.sendNoteOn(j, 53+i, 0); - for (int i=0; i 100) return; - - if (this == midiEngine.getFocusedDeck().getActivePattern()) { - String Text1="", Text2=""; - for (int i=0; i 0) { - for (int i=0; i 0) {P.y += sprk*randctr(50); P.x += sprk*randctr(50); P.z += sprk*randctr(50); } - if (wvAmp > 0) P.y += interpWv(p.x-modmin.x, yWaveNz); - if (wvAmp > 0) P.x += interpWv(p.y-modmin.y, xWaveNz); - if (pJog.b) P.add(xyzJog); - - - int cNew, cOld = colors[p.index]; - { tP.set(P); cNew = CalcPoint(tP); } - if (pXsym.b) { tP.set(mMax.x-P.x,P.y,P.z); cNew = blendColor(cNew, CalcPoint(tP), ADD); } - if (pYsym.b) { tP.set(P.x,mMax.y-P.y,P.z); cNew = blendColor(cNew, CalcPoint(tP), ADD); } - if (pRsym.b) { tP.set(mMax.x-P.x,mMax.y-P.y,mMax.z-P.z); cNew = blendColor(cNew, CalcPoint(tP), ADD); } - if (pXdup.b) { tP.set((P.x+mMax.x*.5f)%mMax.x,P.y,P.z); cNew = blendColor(cNew, CalcPoint(tP), ADD); } - if (pGrey.b) { cNew = lx.hsb(0, 0, lx.b(cNew)); } - colors[p.index] = cNew; - } - } -} -//---------------------------------------------------------------------------------------------------------------------------------- -class dTurn { - dVertex v; - int pos0, pos1; - dTurn(int _pos0, dVertex _v, int _pos1) { v = _v; pos0 = _pos0; pos1 = _pos1; } -} - -class dVertex { - dVertex c0, c1, c2, c3, // connections on the cube - opp, same; // opp - same strip, opp direction - // same - same strut, diff strip, dir - dTurn t0, t1, t2, t3; - Strip s; - int dir, ci; // dir -- 1 or -1. - // ci -- color index - - dVertex(Strip _s, Point _p) { s = _s; ci = _p.index; } - public Point getPoint(int i) { return s.points.get(dir>0 ? i : 15-i); } - public void setOpp(dVertex _opp) { opp = _opp; dir = (ci < opp.ci ? 1 : -1); } -} -//---------------------------------------------------------------------------------------------------------------------------------- -class dPixel { dVertex v; int pos; dPixel(dVertex _v, int _pos) { v=_v; pos=_pos; } } -class dLattice { - public void addTurn (dVertex v0, int pos0, dVertex v1, int pos1) { dTurn t = new dTurn(pos0, v1, pos1); - if (v0.t0 == null) { v0.t0=t; return; } - if (v0.t1 == null) { v0.t1=t; return; } - if (v0.t2 == null) { v0.t2=t; return; } - if (v0.t3 == null) { v0.t3=t; return; } - } - public float dist2 (Strip s1, int pos1, Strip s2, int pos2) { return pointDist(s1.points.get(pos1), s2.points.get(pos2)); } - public float pd2 (Point p1, float x, float y, float z) { return dist(p1.x,p1.y,p1.z,x,y,z); } - public boolean sameSame (Strip s1, Strip s2) { return max(dist2(s1, 0, s2, 0), dist2(s1,15, s2,15)) < 5 ; } // same strut, same direction - public boolean sameOpp (Strip s1, Strip s2) { return max(dist2(s1, 0, s2,15), dist2(s1,15, s2,0 )) < 5 ; } // same strut, opp direction - public boolean sameBar (Strip s1, Strip s2) { return sameSame(s1,s2) || sameOpp(s1,s2); } // 2 strips on same strut - - - public void addJoint (dVertex v1, dVertex v2) { - // should probably replace parallel but further with the new one - if (v1.c0 != null && sameBar(v2.s, v1.c0.s)) return; - if (v1.c1 != null && sameBar(v2.s, v1.c1.s)) return; - if (v1.c2 != null && sameBar(v2.s, v1.c2.s)) return; - if (v1.c3 != null && sameBar(v2.s, v1.c3.s)) return; - - if (v1.c0 == null) v1.c0 = v2; - else if (v1.c1 == null) v1.c1 = v2; - else if (v1.c2 == null) v1.c2 = v2; - else if (v1.c3 == null) v1.c3 = v2; - } - - public dVertex v0(Strip s) { return (dVertex)s.obj1; } - public dVertex v1(Strip s) { return (dVertex)s.obj2; } - - public dPixel getClosest(PVector p) { - dVertex v = null; int pos=0; float d = 500; - - for (Strip s : glucose.model.strips) { - float nd = pd2(s.points.get(0),p.x,p.y,p.z); if (nd < d) { v=v0(s); d=nd; pos=0; } - if (nd > 30) continue; - for (int k=0; k<=15; k++) { - nd = pd2(s.points.get(k),p.x,p.y,p.z); if (nd < d) { v =v0(s); d=nd; pos=k; } - } - } - return random(2) < 1 ? new dPixel(v,pos) : new dPixel(v.opp,15-pos); - } - - dLattice() { - lattice=this; - - for (Strip s : glucose.model.strips) { - dVertex vrtx0 = new dVertex(s,s.points.get(0 )); s.obj1=vrtx0; - dVertex vrtx1 = new dVertex(s,s.points.get(15)); s.obj2=vrtx1; - vrtx0.setOpp(vrtx1); vrtx1.setOpp(vrtx0); - } - - for (Strip s1 : glucose.model.strips) { for (Strip s2 : glucose.model.strips) { - if (s1.points.get(0).index < s2.points.get(0).index) continue; - int c=0; - if (sameSame(s1,s2)) { v0(s1).same = v0(s2); v1(s1).same = v1(s2); - v0(s2).same = v0(s1); v1(s2).same = v1(s1); continue; } // parallel - if (sameOpp (s1,s2)) { v0(s1).same = v1(s2); v1(s1).same = v0(s2); - v0(s2).same = v1(s1); v1(s2).same = v0(s1); continue; } // parallel - if (dist2(s1, 0, s2, 0) < 5) { c++; addJoint(v1(s1), v0(s2)); addJoint(v1(s2), v0(s1)); } - if (dist2(s1, 0, s2,15) < 5) { c++; addJoint(v1(s1), v1(s2)); addJoint(v0(s2), v0(s1)); } - if (dist2(s1,15, s2, 0) < 5) { c++; addJoint(v0(s1), v0(s2)); addJoint(v1(s2), v1(s1)); } - if (dist2(s1,15, s2,15) < 5) { c++; addJoint(v0(s1), v1(s2)); addJoint(v0(s2), v1(s1)); } - if (c>0) continue; - - // Are they touching at all? - int pos1=0, pos2=0; float d = 100; - - while (pos1 < 15 || pos2 < 15) { - float oldD = d; - if (pos1<15) { float d2 = dist2(s1, pos1+1, s2, pos2+0); if (d2 < d) { d=d2; pos1++; } } - if (pos2<15) { float d2 = dist2(s1, pos1+0, s2, pos2+1); if (d2 < d) { d=d2; pos2++; } } - if (d > 50 || oldD == d) break ; - } - - if (d>5) continue; - addTurn(v0(s1), pos1, v0(s2), pos2); addTurn(v1(s1), 15-pos1, v0(s2), pos2); - addTurn(v0(s2), pos2, v0(s1), pos1); addTurn(v1(s2), 15-pos2, v0(s1), pos1); - }} - } -} - -dLattice lattice; -//---------------------------------------------------------------------------------------------------------------------------------- - -class Graphic -{ - public boolean changed = false; - public int position = 0; - public ArrayList graphicBuffer; - Graphic() - { - graphicBuffer = new ArrayList(); - } - public int width() - { - return graphicBuffer.size(); - } - - -}; -class Granim extends Graphic -{ - HashMap displayList; - - Granim() - { - displayList = new HashMap(); - } - public Graphic addGraphic(String name, Graphic g) - { - while(width()< g.position+1) - { - graphicBuffer.add(lx.hsb(0,0,0)); - } - drawAll(); - displayList.put(name , g); - changed =true; - return g; - } - - public Graphic getGraphicByName(String name) - { - return displayList.get(name); - } - - public void update() - { - - for(Graphic g : displayList.values()) - { - if(g instanceof Granim) - { - ((Granim) g).update(); - - } - changed = changed || g.changed; - if(changed) - { - while(width()< g.position + g.width()) - { - graphicBuffer.add(lx.hsb(0,0,0)); - } - if(g.changed) - { - drawOne(g); - g.changed =false; - } - } - } - changed = false; - - } - public void drawOne(Graphic g) - { - graphicBuffer.addAll(g.position,g.graphicBuffer); - } - public void drawAll() - { - } -}; -class GranimPattern extends SCPattern -{ - HashMap displayList; - - GranimPattern(GLucose glucose) - { - super(glucose); - displayList = new HashMap(); - } - - public Graphic addGraphic(String name, Graphic g) - { - displayList.put(name,g); - return g; - } - - public Graphic getGraphicByName(String name) - { - return displayList.get(name); - } - - public void run(double deltaMs) - { - drawToPointList(); - } - private Integer[] gbuffer; - public void drawToPointList() - { - for(Graphic g : displayList.values()) - { - if(g instanceof Granim) - { - ((Granim) g).update(); - } - List drawList = model.points.subList(Math.min(g.position,colors.length-1), Math.min(g.position + g.width(),colors.length-1)); - //println("drawlistsize "+drawList.size()); - - gbuffer = g.graphicBuffer.toArray(new Integer[0]); - - for (int i=0; i < drawList.size(); i++) - { - colors[drawList.get(i).index] = gbuffer[i]; - } - g.changed = false; - } - } - -}; - -class RedsGraphic extends Graphic -{ - RedsGraphic() - { - super(); - drawit(10); - } - RedsGraphic(int len) - { - super(); - drawit(len); - - } - public void drawit(int len) - { - for(int i = 0; i < len ;i++) - { - graphicBuffer.add(lx.hsb(0,255,255)); - } - } -}; - -class RedsGranim extends Granim -{ - RedsGranim() - { - super(); - addGraphic("myreds", new RedsGraphic(10)); - } - RedsGranim(int len) - { - super(); - addGraphic("myreds", new RedsGraphic(len)); - } - public float count = 0.0f; - public void update() - { - Graphic g=getGraphicByName("myreds"); - g.position = Math.round(sin(count)*20)+100; - count+= 0.1f; - if(count>Math.PI*2) - { - count=0; - } - super.update(); - } - -}; - -class RandomsGranim extends Granim -{ - private int _len =0 ; - RandomsGranim() - { - super(); - _len =100; - addGraphic("myrandoms", makeGraphic(_len)); - } - RandomsGranim(int len) - { - super(); - _len=len; - addGraphic("myrandoms", makeGraphic(len)); - } - int colorLid=0; - public Graphic makeGraphic(int len) - { - - int[] colors= new int[len]; - for(int i =0;i 0 ? 1 : 0; - } - - public void run(double deltaMs) { - float a = (millis() / 1000.f) % (2 * PI); - float b = (millis() / 1200.f) % (2 * PI); - float g = (millis() / 1600.f) % (2 * PI); - - projection.reset(model) - // Translate so the center of the car is the origin - .translateCenter(model, 0, 0, 0); - - for (Coord c : projection) { -// rotate3d(c, a, b, g); - colors[c.index] = colorFor(c); - } - - first_run = false; - } - - - // Utility! - boolean first_run = true; - private void log(String s) { - if (first_run) { - println(s); - } - } - - -} - -public void rotate3d(Coord c, float a /* roll */, float b /* pitch */, float g /* yaw */) { - float cosa = cos(a); - float cosb = cos(b); - float cosg = cos(g); - float sina = sin(a); - float sinb = sin(b); - float sing = sin(g); - - float a1 = cosa*cosb; - float a2 = cosa*sinb*sing - sina*cosg; - float a3 = cosa*sinb*cosg + sina*sing; - float b1 = sina*cosb; - float b2 = sina*sinb*sing + cosa*cosg; - float b3 = sina*sinb*cosg - cosa*sing; - float c1 = -sinb; - float c2 = cosb*sing; - float c3 = cosb*cosg; - - float[] cArray = { c.x, c.y, c.z }; - c.x = dotProduct(new float[] {a1, a2, a3}, cArray); - c.y = dotProduct(new float[] {b1, b2, b3}, cArray); - c.z = dotProduct(new float[] {c1, c2, c3}, cArray); -} - -public float dotProduct(float[] a, float[] b) { - float ret = 0; - for (int i = 0 ; i < a.length; ++i) { - ret += a[i] * b[i]; - } - return ret; -} - -public int specialBlend(int c1, int c2, int c3) { - float h1 = hue(c1); - float h2 = hue(c2); - float h3 = hue(c3); - - // force h1 < h2 < h3 - while (h2 < h1) { - h2 += 360; - } - while (h3 < h2) { - h3 += 360; - } - - float s1 = saturation(c1); - float s2 = saturation(c2); - float s3 = saturation(c3); - - float b1 = brightness(c1); - float b2 = brightness(c2); - float b3 = brightness(c3); - float relative_b1 = b1 / (b1 + b2 + b3); - float relative_b2 = b2 / (b1 + b2 + b3); - float relative_b3 = b3 / (b1 + b2 + b3); - - return lx.hsb( - (h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360, - s1 * relative_b1 + s2 * relative_b2 + s3 * relative_b3, - max(max(b1, b2), b3) - ); -} - -/** - * A Projection of sin wave in 3d space. - * It sort of looks like an animal swiming around in water. - * Angle sliders are sort of a work in progress that allow yo to change the crazy ways it moves around. - * Hue slider allows you to control how different the colors are along the wave. - * - * This code copied heavily from Tim and Slee. - */ -class Swim extends SCPattern { - - // Projection stuff - private final Projection projection; - SawLFO rotation = new SawLFO(0, TWO_PI, 19000); - SinLFO yPos = new SinLFO(-25, 25, 12323); - final BasicParameter xAngle = new BasicParameter("XANG", 0.9f); - final BasicParameter yAngle = new BasicParameter("YANG", 0.3f); - final BasicParameter zAngle = new BasicParameter("ZANG", 0.3f); - - final BasicParameter hueScale = new BasicParameter("HUE", 0.3f); - - public Swim(GLucose glucose) { - super(glucose); - projection = new Projection(model); - - addParameter(xAngle); - addParameter(yAngle); - addParameter(zAngle); - addParameter(hueScale); - - addModulator(rotation).trigger(); - addModulator(yPos).trigger(); - } - - - int beat = 0; - float prevRamp = 0; - public void run(double deltaMs) { - - // Sync to the beat - float ramp = (float)lx.tempo.ramp(); - if (ramp < prevRamp) { - beat = (beat + 1) % 4; - } - prevRamp = ramp; - float phase = (beat+ramp) / 2.0f * 2 * PI; - - float denominator = max(xAngle.getValuef() + yAngle.getValuef() + zAngle.getValuef(), 1); - - projection.reset(model) - // Swim around the world - .rotate(rotation.getValuef(), xAngle.getValuef() / denominator, yAngle.getValuef() / denominator, zAngle.getValuef() / denominator) - .translateCenter(model, 0, 50 + yPos.getValuef(), 0); - - float model_height = model.yMax - model.yMin; - float model_width = model.xMax - model.xMin; - for (Coord p : projection) { - float x_percentage = (p.x - model.xMin)/model_width; - - // Multiply by 1.4 to shrink the size of the sin wave to be less than the height of the cubes. - float y_in_range = 1.4f * (2*p.y - model.yMax - model.yMin) / model_height; - float sin_x = sin(phase + 2 * PI * x_percentage); - - // Color fade near the top of the sin wave - float v1 = sin_x > y_in_range ? (100 + 100*(y_in_range - sin_x)) : 0; - - 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; - colors[p.index] = lx.hsb(hue_color, 70, v1); - } - } -} - -/** - * 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. - * This is not done. - */ -class Balance extends SCPattern { - - final BasicParameter hueScale = new BasicParameter("Hue", 0.4f); - - class Sphere { - float x, y, z; - } - - - // Projection stuff - private final Projection projection; - - SinLFO sphere1Z = new SinLFO(0, 0, 15323); - SinLFO sphere2Z = new SinLFO(0, 0, 8323); - SinLFO rotationX = new SinLFO(-PI/32, PI/32, 9000); - SinLFO rotationY = new SinLFO(-PI/16, PI/16, 7000); - SinLFO rotationZ = new SinLFO(-PI/16, PI/16, 11000); - SawLFO phaseLFO = new SawLFO(0, 2 * PI, 5000 - 4500 * 0.5f); - final BasicParameter phaseParam = new BasicParameter("Spd", 0.5f); - final BasicParameter crazyParam = new BasicParameter("Crzy", 0.2f); - - - private final Sphere[] spheres; - private final float centerX, centerY, centerZ, modelHeight, modelWidth, modelDepth; - SinLFO heightMod = new SinLFO(0.8f, 1.9f, 17298); - - public Balance(GLucose glucose) { - super(glucose); - - projection = new Projection(model); - - addParameter(hueScale); - addParameter(phaseParam); - addParameter(crazyParam); - - spheres = new Sphere[2]; - centerX = (model.xMax + model.xMin) / 2; - centerY = (model.yMax + model.yMin) / 2; - centerZ = (model.zMax + model.zMin) / 2; - modelHeight = model.yMax - model.yMin; - modelWidth = model.xMax - model.xMin; - modelDepth = model.zMax - model.zMin; - - spheres[0] = new Sphere(); - spheres[0].x = 1*modelWidth/2 + model.xMin; - spheres[0].y = centerY + 20; - spheres[0].z = centerZ; - - spheres[1] = new Sphere(); - spheres[1].x = model.xMin; - spheres[1].y = centerY - 20; - spheres[1].z = centerZ; - - addModulator(rotationX).trigger(); - addModulator(rotationY).trigger(); - addModulator(rotationZ).trigger(); - - - addModulator(sphere1Z).trigger(); - addModulator(sphere2Z).trigger(); - addModulator(phaseLFO).trigger(); - - addModulator(heightMod).trigger(); - } - - public void onParameterChanged(LXParameter parameter) { - if (parameter == phaseParam) { - phaseLFO.setDuration(5000 - 4500 * parameter.getValuef()); - } - } - - int beat = 0; - float prevRamp = 0; - public void run(double deltaMs) { - - // Sync to the beat - float ramp = (float)lx.tempo.ramp(); - if (ramp < prevRamp) { - beat = (beat + 1) % 4; - } - prevRamp = ramp; - float phase = phaseLFO.getValuef(); - - float crazy_factor = crazyParam.getValuef() / 0.2f; - projection.reset(model) - .rotate(rotationZ.getValuef() * crazy_factor, 0, 1, 0) - .rotate(rotationX.getValuef() * crazy_factor, 0, 0, 1) - .rotate(rotationY.getValuef() * crazy_factor, 0, 1, 0); - - for (Coord p : projection) { - float x_percentage = (p.x - model.xMin)/modelWidth; - - float y_in_range = heightMod.getValuef() * (2*p.y - model.yMax - model.yMin) / modelHeight; - float sin_x = sin(PI / 2 + phase + 2 * PI * x_percentage); - - // Color fade near the top of the sin wave - float v1 = max(0, 100 * (1 - 4*abs(sin_x - y_in_range))); - - 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; - int c = lx.hsb(hue_color, 80, v1); - - // Now draw the spheres - for (Sphere s : spheres) { - float phase_x = (s.x - phase / (2 * PI) * modelWidth) % modelWidth; - float x_dist = LXUtils.wrapdistf(p.x, phase_x, modelWidth); - - float sphere_z = (s == spheres[0]) ? (s.z + sphere1Z.getValuef()) : (s.z - sphere2Z.getValuef()); - - - float d = sqrt(pow(x_dist, 2) + pow(p.y - s.y, 2) + pow(p.z - sphere_z, 2)); - - float distance_from_beat = (beat % 2 == 1) ? 1 - ramp : ramp; - - min(ramp, 1-ramp); - - float r = 40 - pow(distance_from_beat, 0.75f) * 20; - - float distance_value = max(0, 1 - max(0, d - r) / 10); - float beat_value = 1.0f; - - float value = min(beat_value, distance_value); - - float sphere_color = (lx.getBaseHuef() - (1 - hueScale.getValuef()) * d/r * 45) % 360; - - c = blendColor(c, lx.hsb((sphere_color + 270) % 360, 60, min(1, value) * 100), ADD); - } - colors[p.index] = c; - } - } -} -class Cathedrals extends SCPattern { - - private final BasicParameter xpos = new BasicParameter("XPOS", 0.5f); - private final BasicParameter wid = new BasicParameter("WID", 0.5f); - private final BasicParameter arms = new BasicParameter("ARMS", 0.5f); - private final BasicParameter sat = new BasicParameter("SAT", 0.5f); - private GraphicEQ eq; - - Cathedrals(GLucose glucose) { - super(glucose); - addParameter(xpos); - addParameter(wid); - addParameter(arms); - addParameter(sat); - } - - protected void onActive() { - if (eq == null) { - eq = new GraphicEQ(lx, 16); - eq.slope.setValue(0.7f); - eq.range.setValue(0.4f); - eq.attack.setValue(0.4f); - eq.release.setValue(0.4f); - addParameter(eq.level); - addParameter(eq.range); - addParameter(eq.attack); - addParameter(eq.release); - addParameter(eq.slope); - } - } - - - public void run(double deltaMs) { - eq.run(deltaMs); - float bassLevel = eq.getAverageLevel(0, 4); - float trebleLevel = eq.getAverageLevel(8, 6); - - float falloff = 100 / (2 + 14*wid.getValuef()); - float cx = model.xMin + (model.xMax-model.xMin) * xpos.getValuef(); - float barm = 12 + 60*arms.getValuef()*max(0, 2*(bassLevel-0.1f)); - float tarm = 12 + 60*arms.getValuef()*max(0, 2*(trebleLevel-0.1f)); - - float arm = 0; - float middle = 0; - - float sf = 100.f / (70 - 69.9f*sat.getValuef()); - - for (Point p : model.points) { - float d = MAX_FLOAT; - if (p.y > model.cy) { - arm = tarm; - middle = model.yMax * 3/5.f; - } else { - arm = barm; - middle = model.yMax * 1/5.f; - } - if (abs(p.x - cx) < arm) { - d = min(abs(p.x - cx), abs(p.y - middle)); - } - colors[p.index] = color( - (lx.getBaseHuef() + .2f*abs(p.y - model.cy)) % 360, - min(100, sf*dist(abs(p.x - cx), p.y, arm, middle)), - max(0, 120 - d*falloff)); - } - } -} - -class MidiMusic extends SCPattern { - - private final Stack newLayers = new Stack(); - - private final Map lightMap = new HashMap(); - private final List lights = new ArrayList(); - private final BasicParameter lightSize = new BasicParameter("SIZE", 0.5f); - - private final List sweeps = new ArrayList(); - - private final LinearEnvelope sparkle = new LinearEnvelope(0, 1, 500); - private boolean sparkleDirection = true; - private float sparkleBright = 100; - - private final BasicParameter wave = new BasicParameter("WAVE", 0); - - MidiMusic(GLucose glucose) { - super(glucose); - addParameter(lightSize); - addParameter(wave); - addModulator(sparkle).setValue(1); - } - - public void onReset() { - for (LightUp light : lights) { - light.noteOff(null); - } - } - - class Sweep extends LXLayer { - - final LinearEnvelope position = new LinearEnvelope(0, 1, 1000); - float bright = 100; - float falloff = 10; - - Sweep() { - addModulator(position); - } - - public void run(double deltaMs, int[] colors) { - if (!position.isRunning()) { - return; - } - float posf = position.getValuef(); - for (Point p : model.points) { - colors[p.index] = blendColor(colors[p.index], color( - (lx.getBaseHuef() + .2f*abs(p.x - model.cx) + .2f*abs(p.y - model.cy)) % 360, - 100, - max(0, bright - posf*100 - falloff*abs(p.y - posf*model.yMax)) - ), ADD); - } - } - } - - class LightUp extends LXLayer { - - private final LinearEnvelope brt = new LinearEnvelope(0, 0, 0); - private final Accelerator yPos = new Accelerator(0, 0, 0); - private float xPos; - - LightUp() { - addModulator(brt); - addModulator(yPos); - } - - public boolean isAvailable() { - return brt.getValuef() <= 0; - } - - public void noteOn(Note note) { - xPos = lerp(0, model.xMax, constrain(0.5f + (note.getPitch() - 60) / 28.f, 0, 1)); - yPos.setValue(lerp(20, model.yMax*.72f, note.getVelocity() / 127.f)).stop(); - brt.setRangeFromHereTo(lerp(40, 100, note.getVelocity() / 127.f), 20).start(); - } - - public void noteOff(Note note) { - yPos.setVelocity(0).setAcceleration(-380).start(); - brt.setRangeFromHereTo(0, 1000).start(); - } - - public void run(double deltaMs, int[] colors) { - float bVal = brt.getValuef(); - if (bVal <= 0) { - return; - } - float yVal = yPos.getValuef(); - for (Point p : model.points) { - float falloff = 6 - 5*lightSize.getValuef(); - float b = max(0, bVal - falloff*dist(p.x, p.y, xPos, yVal)); - if (b > 0) { - colors[p.index] = blendColor(colors[p.index], lx.hsb( - (lx.getBaseHuef() + .2f*abs(p.x - model.cx) + .2f*abs(p.y - model.cy)) % 360, - 100, - b - ), ADD); - } - } - } - } - - private LightUp getLight() { - for (LightUp light : lights) { - if (light.isAvailable()) { - return light; - } - } - LightUp newLight = new LightUp(); - lights.add(newLight); - synchronized(newLayers) { - newLayers.push(newLight); - } - return newLight; - } - - private Sweep getSweep() { - for (Sweep s : sweeps) { - if (!s.position.isRunning()) { - return s; - } - } - Sweep newSweep = new Sweep(); - sweeps.add(newSweep); - synchronized(newLayers) { - newLayers.push(newSweep); - } - return newSweep; - } - - public synchronized boolean noteOn(Note note) { - if (note.getChannel() == 0) { - LightUp light = getLight(); - lightMap.put(note.getPitch(), light); - light.noteOn(note); - } else if (note.getChannel() == 1) { - } else if (note.getChannel() == 9) { - if (note.getVelocity() > 0) { - switch (note.getPitch()) { - case 36: - Sweep s = getSweep(); - s.bright = 50 + note.getVelocity() / 127.f * 50; - s.falloff = 20 - note.getVelocity() / 127.f * 17; - s.position.trigger(); - break; - case 37: - sparkleBright = note.getVelocity() / 127.f * 100; - sparkleDirection = true; - sparkle.trigger(); - break; - case 38: - sparkleBright = note.getVelocity() / 127.f * 100; - sparkleDirection = false; - sparkle.trigger(); - break; - case 39: - effects.boom.trigger(); - break; - case 40: - effects.flash.trigger(); - break; - } - } - } - return true; - } - - public synchronized boolean noteOff(Note note) { - if (note.getChannel() == 0) { - LightUp light = lightMap.get(note.getPitch()); - if (light != null) { - light.noteOff(note); - } - } - return true; - } - - final float[] wval = new float[16]; - float wavoff = 0; - - public synchronized void run(double deltaMs) { - wavoff += deltaMs * .001f; - for (int i = 0; i < wval.length; ++i) { - wval[i] = model.cy + 0.2f * model.yMax/2.f * sin(wavoff + i / 1.9f); - } - float sparklePos = (sparkleDirection ? sparkle.getValuef() : (1 - sparkle.getValuef())) * (Cube.POINTS_PER_STRIP)/2.f; - float maxBright = sparkleBright * (1 - sparkle.getValuef()); - for (Strip s : model.strips) { - int i = 0; - for (Point p : s.points) { - int wavi = (int) constrain(p.x / model.xMax * wval.length, 0, wval.length-1); - float wavb = max(0, wave.getValuef()*100.f - 8.f*abs(p.y - wval[wavi])); - colors[p.index] = color( - (lx.getBaseHuef() + .2f*abs(p.x - model.cx) + .2f*abs(p.y - model.cy)) % 360, - 100, - constrain(wavb + max(0, maxBright - 40.f*abs(sparklePos - abs(i - (Cube.POINTS_PER_STRIP-1)/2.f))), 0, 100) - ); - ++i; - } - } - - if (!newLayers.isEmpty()) { - synchronized(newLayers) { - while (!newLayers.isEmpty()) { - addLayer(newLayers.pop()); - } - } - } - } -} - -class Pulley extends SCPattern { - - final int NUM_DIVISIONS = 16; - private final Accelerator[] gravity = new Accelerator[NUM_DIVISIONS]; - private final Click[] delays = new Click[NUM_DIVISIONS]; - - private final Click reset = new Click(9000); - private boolean isRising = false; - - private BasicParameter sz = new BasicParameter("SIZE", 0.5f); - private BasicParameter beatAmount = new BasicParameter("BEAT", 0); - - Pulley(GLucose glucose) { - super(glucose); - for (int i = 0; i < NUM_DIVISIONS; ++i) { - addModulator(gravity[i] = new Accelerator(0, 0, 0)); - addModulator(delays[i] = new Click(0)); - } - addModulator(reset).start(); - addParameter(sz); - addParameter(beatAmount); - trigger(); - - } - - private void trigger() { - isRising = !isRising; - int i = 0; - for (Accelerator g : gravity) { - if (isRising) { - g.setSpeed(random(20, 33), 0).start(); - } else { - g.setVelocity(0).setAcceleration(-420); - delays[i].setDuration(random(0, 500)).trigger(); - } - ++i; - } - } - - public void run(double deltaMs) { - if (reset.click()) { - trigger(); - } - - if (isRising) { - // Fucking A, had to comment this all out because of that bizarre - // Processing bug where some simple loop takes an absurd amount of - // time, must be some pre-processor bug -// for (Accelerator g : gravity) { -// if (g.getValuef() > model.yMax) { -// g.stop(); -// } else if (g.getValuef() > model.yMax*.55) { -// if (g.getVelocityf() > 10) { -// g.setAcceleration(-16); -// } else { -// g.setAcceleration(0); -// } -// } -// } - } else { - int j = 0; - for (Click d : delays) { - if (d.click()) { - gravity[j].start(); - d.stop(); - } - ++j; - } - for (Accelerator g : gravity) { - if (g.getValuef() < 0) { - g.setValue(-g.getValuef()); - g.setVelocity(-g.getVelocityf() * random(0.74f, 0.84f)); - } - } - } - - // A little silliness to test the grid API - if (midiEngine != null && midiEngine.getFocusedPattern() == this) { - for (int i = 0; i < 5; ++i) { - for (int j = 0; j < 8; ++j) { - int gi = (int) constrain(j * NUM_DIVISIONS / 8, 0, NUM_DIVISIONS-1); - float b = 1 - 4.f*abs((6-i)/6.f - gravity[gi].getValuef() / model.yMax); - midiEngine.grid.setState(i, j, (b < 0) ? 0 : 3); - } - } - } - - float fPos = 1 - lx.tempo.rampf(); - if (fPos < .2f) { - fPos = .2f + 4 * (.2f - fPos); - } - float falloff = 100.f / (3 + sz.getValuef() * 36 + fPos * beatAmount.getValuef()*48); - for (Point p : model.points) { - int gi = (int) constrain((p.x - model.xMin) * NUM_DIVISIONS / (model.xMax - model.xMin), 0, NUM_DIVISIONS-1); - colors[p.index] = lx.hsb( - (lx.getBaseHuef() + abs(p.x - model.cx)*.8f + p.y*.4f) % 360, - constrain(130 - p.y*.8f, 0, 100), - max(0, 100 - abs(p.y - gravity[gi].getValuef())*falloff) - ); - } - } -} - -class ViolinWave extends SCPattern { - - BasicParameter level = new BasicParameter("LVL", 0.45f); - BasicParameter range = new BasicParameter("RNG", 0.5f); - BasicParameter edge = new BasicParameter("EDG", 0.5f); - BasicParameter release = new BasicParameter("RLS", 0.5f); - BasicParameter speed = new BasicParameter("SPD", 0.5f); - BasicParameter amp = new BasicParameter("AMP", 0.25f); - BasicParameter period = new BasicParameter("WAVE", 0.5f); - BasicParameter pSize = new BasicParameter("PSIZE", 0.5f); - BasicParameter pSpeed = new BasicParameter("PSPD", 0.5f); - BasicParameter pDensity = new BasicParameter("PDENS", 0.25f); - - LinearEnvelope dbValue = new LinearEnvelope(0, 0, 10); - - ViolinWave(GLucose glucose) { - super(glucose); - addParameter(level); - addParameter(edge); - addParameter(range); - addParameter(release); - addParameter(speed); - addParameter(amp); - addParameter(period); - addParameter(pSize); - addParameter(pSpeed); - addParameter(pDensity); - - addModulator(dbValue); - } - - final List particles = new ArrayList(); - - class Particle { - - LinearEnvelope x = new LinearEnvelope(0, 0, 0); - LinearEnvelope y = new LinearEnvelope(0, 0, 0); - - Particle() { - addModulator(x); - addModulator(y); - } - - public Particle trigger(boolean direction) { - float xInit = random(model.xMin, model.xMax); - float time = 3000 - 2500*pSpeed.getValuef(); - x.setRange(xInit, xInit + random(-40, 40), time).trigger(); - y.setRange(model.cy + 10, direction ? model.yMax + 50 : model.yMin - 50, time).trigger(); - return this; - } - - public boolean isActive() { - return x.isRunning() || y.isRunning(); - } - - public void run(double deltaMs) { - if (!isActive()) { - return; - } - - float pFalloff = (30 - 27*pSize.getValuef()); - for (Point p : model.points) { - float b = 100 - pFalloff * (abs(p.x - x.getValuef()) + abs(p.y - y.getValuef())); - if (b > 0) { - colors[p.index] = blendColor(colors[p.index], lx.hsb( - lx.getBaseHuef(), 20, b - ), ADD); - } - } - } - } - - float[] centers = new float[30]; - double accum = 0; - boolean rising = true; - - public void fireParticle(boolean direction) { - boolean gotOne = false; - for (Particle p : particles) { - if (!p.isActive()) { - p.trigger(direction); - return; - } - } - particles.add(new Particle().trigger(direction)); - } - - public void run(double deltaMs) { - accum += deltaMs / (1000.f - 900.f*speed.getValuef()); - for (int i = 0; i < centers.length; ++i) { - centers[i] = model.cy + 30*amp.getValuef()*sin((float) (accum + (i-centers.length/2.f)/(1.f + 9.f*period.getValuef()))); - } - - float zeroDBReference = pow(10, (50 - 190*level.getValuef())/20.f); - float dB = 20*GraphicEQ.log10(lx.audioInput().mix.level() / zeroDBReference); - if (dB > dbValue.getValuef()) { - rising = true; - dbValue.setRangeFromHereTo(dB, 10).trigger(); - } else { - if (rising) { - for (int j = 0; j < pDensity.getValuef()*3; ++j) { - fireParticle(true); - fireParticle(false); - } - } - rising = false; - dbValue.setRangeFromHereTo(max(dB, -96), 50 + 1000*release.getValuef()).trigger(); - } - float edg = 1 + edge.getValuef() * 40; - float rng = (78 - 64 * range.getValuef()) / (model.yMax - model.cy); - float val = max(2, dbValue.getValuef()); - - for (Point p : model.points) { - int ci = (int) lerp(0, centers.length-1, (p.x - model.xMin) / (model.xMax - model.xMin)); - float rFactor = 1.0f - 0.9f * abs(p.x - model.cx) / (model.xMax - model.cx); - colors[p.index] = lx.hsb( - (lx.getBaseHuef() + abs(p.x - model.cx)) % 360, - min(100, 20 + 8*abs(p.y - centers[ci])), - constrain(edg*(val*rFactor - rng * abs(p.y-centers[ci])), 0, 100) - ); - } - - for (Particle p : particles) { - p.run(deltaMs); - } - } -} - -class BouncyBalls extends SCPattern { - - static final int NUM_BALLS = 6; - - class BouncyBall { - - Accelerator yPos; - TriangleLFO xPos = new TriangleLFO(0, model.xMax, random(8000, 19000)); - float zPos; - - BouncyBall(int i) { - addModulator(xPos.setBasis(random(0, TWO_PI)).start()); - addModulator(yPos = new Accelerator(0, 0, 0)); - zPos = lerp(model.zMin, model.zMax, (i+2.f) / (NUM_BALLS + 4.f)); - } - - public void bounce(float midiVel) { - float v = 100 + 8*midiVel; - yPos.setSpeed(v, getAccel(v, 60 / lx.tempo.bpmf())).start(); - } - - public float getAccel(float v, float oneBeat) { - return -2*v / oneBeat; - } - - public void run(double deltaMs) { - float flrLevel = flr.getValuef() * model.xMax/2.f; - if (yPos.getValuef() < flrLevel) { - if (yPos.getVelocity() < -50) { - yPos.setValue(2*flrLevel-yPos.getValuef()); - float v = -yPos.getVelocityf() * bounce.getValuef(); - yPos.setSpeed(v, getAccel(v, 60 / lx.tempo.bpmf())); - } else { - yPos.setValue(flrLevel).stop(); - } - } - float falloff = 130.f / (12 + blobSize.getValuef() * 36); - float xv = xPos.getValuef(); - float yv = yPos.getValuef(); - - for (Point p : model.points) { - float d = sqrt((p.x-xv)*(p.x-xv) + (p.y-yv)*(p.y-yv) + .1f*(p.z-zPos)*(p.z-zPos)); - float b = constrain(130 - falloff*d, 0, 100); - if (b > 0) { - colors[p.index] = blendColor(colors[p.index], lx.hsb( - (lx.getBaseHuef() + p.y*.5f + abs(model.cx - p.x) * .5f) % 360, - max(0, 100 - .45f*(p.y - flrLevel)), - b - ), ADD); - } - } - } - } - - final BouncyBall[] balls = new BouncyBall[NUM_BALLS]; - - final BasicParameter bounce = new BasicParameter("BNC", .8f); - final BasicParameter flr = new BasicParameter("FLR", 0); - final BasicParameter blobSize = new BasicParameter("SIZE", 0.5f); - - BouncyBalls(GLucose glucose) { - super(glucose); - for (int i = 0; i < balls.length; ++i) { - balls[i] = new BouncyBall(i); - } - addParameter(bounce); - addParameter(flr); - addParameter(blobSize); - } - - public void run(double deltaMs) { - setColors(0xff000000); - for (BouncyBall b : balls) { - b.run(deltaMs); - } - } - - public boolean noteOn(Note note) { - int pitch = (note.getPitch() + note.getChannel()) % NUM_BALLS; - balls[pitch].bounce(note.getVelocity()); - return true; - } -} - -class SpaceTime extends SCPattern { - - SinLFO pos = new SinLFO(0, 1, 3000); - SinLFO rate = new SinLFO(1000, 9000, 13000); - SinLFO falloff = new SinLFO(10, 70, 5000); - float angle = 0; - - BasicParameter rateParameter = new BasicParameter("RATE", 0.5f); - BasicParameter sizeParameter = new BasicParameter("SIZE", 0.5f); - - - public SpaceTime(GLucose glucose) { - super(glucose); - - addModulator(pos).trigger(); - addModulator(rate).trigger(); - addModulator(falloff).trigger(); - pos.modulateDurationBy(rate); - addParameter(rateParameter); - addParameter(sizeParameter); - } - - public void onParameterChanged(LXParameter parameter) { - if (parameter == rateParameter) { - rate.stop().setValue(9000 - 8000*parameter.getValuef()); - } else if (parameter == sizeParameter) { - falloff.stop().setValue(70 - 60*parameter.getValuef()); - } - } - - public void run(double deltaMs) { - angle += deltaMs * 0.0007f; - float sVal1 = model.strips.size() * (0.5f + 0.5f*sin(angle)); - float sVal2 = model.strips.size() * (0.5f + 0.5f*cos(angle)); - - float pVal = pos.getValuef(); - float fVal = falloff.getValuef(); - - int s = 0; - for (Strip strip : model.strips) { - int i = 0; - for (Point p : strip.points) { - colors[p.index] = lx.hsb( - (lx.getBaseHuef() + 360 - p.x*.2f + p.y * .3f) % 360, - constrain(.4f * min(abs(s - sVal1), abs(s - sVal2)), 20, 100), - max(0, 100 - fVal*abs(i - pVal*(strip.metrics.numPoints - 1))) - ); - ++i; - } - ++s; - } - } -} - -class Swarm extends SCPattern { - - SawLFO offset = new SawLFO(0, 1, 1000); - SinLFO rate = new SinLFO(350, 1200, 63000); - SinLFO falloff = new SinLFO(15, 50, 17000); - SinLFO fX = new SinLFO(0, model.xMax, 19000); - SinLFO fY = new SinLFO(0, model.yMax, 11000); - SinLFO hOffX = new SinLFO(0, model.xMax, 13000); - - public Swarm(GLucose glucose) { - super(glucose); - - addModulator(offset).trigger(); - addModulator(rate).trigger(); - addModulator(falloff).trigger(); - addModulator(fX).trigger(); - addModulator(fY).trigger(); - addModulator(hOffX).trigger(); - offset.modulateDurationBy(rate); - } - - public float modDist(float v1, float v2, float mod) { - v1 = v1 % mod; - v2 = v2 % mod; - if (v2 > v1) { - return min(v2-v1, v1+mod-v2); - } - else { - return min(v1-v2, v2+mod-v1); - } - } - - public void run(double deltaMs) { - float s = 0; - for (Strip strip : model.strips ) { - int i = 0; - for (Point p : strip.points) { - float fV = max(-1, 1 - dist(p.x/2.f, p.y, fX.getValuef()/2.f, fY.getValuef()) / 64.f); - colors[p.index] = lx.hsb( - (lx.getBaseHuef() + 0.3f * abs(p.x - hOffX.getValuef())) % 360, - constrain(80 + 40 * fV, 0, 100), - constrain(100 - (30 - fV * falloff.getValuef()) * modDist(i + (s*63)%61, offset.getValuef() * strip.metrics.numPoints, strip.metrics.numPoints), 0, 100) - ); - ++i; - } - ++s; - } - } -} - -class SwipeTransition extends SCTransition { - - final BasicParameter bleed = new BasicParameter("WIDTH", 0.5f); - - SwipeTransition(GLucose glucose) { - super(glucose); - setDuration(5000); - addParameter(bleed); - } - - public void computeBlend(int[] c1, int[] c2, double progress) { - float bleedf = 10 + bleed.getValuef() * 200.f; - float xPos = (float) (-bleedf + progress * (model.xMax + bleedf)); - for (Point p : model.points) { - float d = (p.x - xPos) / bleedf; - if (d < 0) { - colors[p.index] = c2[p.index]; - } else if (d > 1) { - colors[p.index] = c1[p.index]; - } else { - colors[p.index] = lerpColor(c2[p.index], c1[p.index], d, RGB); - } - } - } -} - -abstract class BlendTransition extends SCTransition { - - final int blendType; - - BlendTransition(GLucose glucose, int blendType) { - super(glucose); - this.blendType = blendType; - } - - public void computeBlend(int[] c1, int[] c2, double progress) { - if (progress < 0.5f) { - for (int i = 0; i < c1.length; ++i) { - colors[i] = lerpColor( - c1[i], - blendColor(c1[i], c2[i], blendType), - (float) (2.f*progress), - RGB); - } - } else { - for (int i = 0; i < c1.length; ++i) { - colors[i] = lerpColor( - c2[i], - blendColor(c1[i], c2[i], blendType), - (float) (2.f*(1.f - progress)), - RGB); - } - } - } -} - -class MultiplyTransition extends BlendTransition { - MultiplyTransition(GLucose glucose) { - super(glucose, MULTIPLY); - } -} - -class ScreenTransition extends BlendTransition { - ScreenTransition(GLucose glucose) { - super(glucose, SCREEN); - } -} - -class BurnTransition extends BlendTransition { - BurnTransition(GLucose glucose) { - super(glucose, BURN); - } -} - -class DodgeTransition extends BlendTransition { - DodgeTransition(GLucose glucose) { - super(glucose, DODGE); - } -} - -class OverlayTransition extends BlendTransition { - OverlayTransition(GLucose glucose) { - super(glucose, OVERLAY); - } -} - -class AddTransition extends BlendTransition { - AddTransition(GLucose glucose) { - super(glucose, ADD); - } -} - -class SubtractTransition extends BlendTransition { - SubtractTransition(GLucose glucose) { - super(glucose, SUBTRACT); - } -} - -class SoftLightTransition extends BlendTransition { - SoftLightTransition(GLucose glucose) { - super(glucose, SOFT_LIGHT); - } -} - -class BassPod extends SCPattern { - - private GraphicEQ eq = null; - - private final BasicParameter clr = new BasicParameter("CLR", 0.5f); - - public BassPod(GLucose glucose) { - super(glucose); - addParameter(clr); - } - - protected void onActive() { - if (eq == null) { - eq = new GraphicEQ(lx, 16); - eq.range.setValue(0.4f); - eq.level.setValue(0.4f); - eq.slope.setValue(0.6f); - addParameter(eq.level); - addParameter(eq.range); - addParameter(eq.attack); - addParameter(eq.release); - addParameter(eq.slope); - } - } - - public void run(double deltaMs) { - eq.run(deltaMs); - - float bassLevel = eq.getAverageLevel(0, 5); - - float satBase = bassLevel*480*clr.getValuef(); - - for (Point p : model.points) { - int avgIndex = (int) constrain(1 + abs(p.x-model.cx)/(model.cx)*(eq.numBands-5), 0, eq.numBands-5); - float value = 0; - for (int i = avgIndex; i < avgIndex + 5; ++i) { - value += eq.getLevel(i); - } - value /= 5.f; - - float b = constrain(8 * (value*model.yMax - abs(p.y-model.yMax/2.f)), 0, 100); - colors[p.index] = lx.hsb( - (lx.getBaseHuef() + abs(p.y - model.cy) + abs(p.x - model.cx)) % 360, - constrain(satBase - .6f*dist(p.x, p.y, model.cx, model.cy), 0, 100), - b - ); - } - } -} - - -class CubeEQ extends SCPattern { - - private GraphicEQ eq = null; - - private final BasicParameter edge = new BasicParameter("EDGE", 0.5f); - private final BasicParameter clr = new BasicParameter("CLR", 0.5f); - private final BasicParameter blockiness = new BasicParameter("BLK", 0.5f); - - public CubeEQ(GLucose glucose) { - super(glucose); - } - - protected void onActive() { - if (eq == null) { - eq = new GraphicEQ(lx, 16); - addParameter(eq.level); - addParameter(eq.range); - addParameter(eq.attack); - addParameter(eq.release); - addParameter(eq.slope); - addParameter(edge); - addParameter(clr); - addParameter(blockiness); - } - } - - public void run(double deltaMs) { - eq.run(deltaMs); - - float edgeConst = 2 + 30*edge.getValuef(); - float clrConst = 1.1f + clr.getValuef(); - - for (Point p : model.points) { - float avgIndex = constrain(2 + p.x / model.xMax * (eq.numBands-4), 0, eq.numBands-4); - int avgFloor = (int) avgIndex; - - float leftVal = eq.getLevel(avgFloor); - float rightVal = eq.getLevel(avgFloor+1); - float smoothValue = lerp(leftVal, rightVal, avgIndex-avgFloor); - - float chunkyValue = ( - eq.getLevel(avgFloor/4*4) + - eq.getLevel(avgFloor/4*4 + 1) + - eq.getLevel(avgFloor/4*4 + 2) + - eq.getLevel(avgFloor/4*4 + 3) - ) / 4.f; - - float value = lerp(smoothValue, chunkyValue, blockiness.getValuef()); - - float b = constrain(edgeConst * (value*model.yMax - p.y), 0, 100); - colors[p.index] = lx.hsb( - (480 + lx.getBaseHuef() - min(clrConst*p.y, 120)) % 360, - 100, - b - ); - } - } -} - -class BoomEffect extends SCEffect { - - final BasicParameter falloff = new BasicParameter("WIDTH", 0.5f); - final BasicParameter speed = new BasicParameter("SPD", 0.5f); - final BasicParameter bright = new BasicParameter("BRT", 1.0f); - final BasicParameter sat = new BasicParameter("SAT", 0.2f); - List layers = new ArrayList(); - final float maxr = sqrt(model.xMax*model.xMax + model.yMax*model.yMax + model.zMax*model.zMax) + 10; - - class Layer { - LinearEnvelope boom = new LinearEnvelope(-40, 500, 1300); - - Layer() { - addModulator(boom); - trigger(); - } - - public void trigger() { - float falloffv = falloffv(); - boom.setRange(-100 / falloffv, maxr + 100/falloffv, 4000 - speed.getValuef() * 3300); - boom.trigger(); - } - - public void apply(int[] colors) { - float brightv = 100 * bright.getValuef(); - float falloffv = falloffv(); - float satv = sat.getValuef() * 100; - float huev = lx.getBaseHuef(); - for (Point p : model.points) { - colors[p.index] = blendColor( - colors[p.index], - 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)), - ADD); - } - } - } - - BoomEffect(GLucose glucose) { - super(glucose, true); - addParameter(falloff); - addParameter(speed); - addParameter(bright); - addParameter(sat); - } - - public void onEnable() { - for (Layer l : layers) { - if (!l.boom.isRunning()) { - l.trigger(); - return; - } - } - layers.add(new Layer()); - } - - private float falloffv() { - return 20 - 19 * falloff.getValuef(); - } - - public void onTrigger() { - onEnable(); - } - - public void apply(int[] colors) { - for (Layer l : layers) { - if (l.boom.isRunning()) { - l.apply(colors); - } - } - } -} - -public class PianoKeyPattern extends SCPattern { - - final LinearEnvelope[] cubeBrt; - final SinLFO base[]; - final BasicParameter attack = new BasicParameter("ATK", 0.1f); - final BasicParameter release = new BasicParameter("REL", 0.5f); - final BasicParameter level = new BasicParameter("AMB", 0.6f); - - PianoKeyPattern(GLucose glucose) { - super(glucose); - - addParameter(attack); - addParameter(release); - addParameter(level); - cubeBrt = new LinearEnvelope[model.cubes.size() / 4]; - for (int i = 0; i < cubeBrt.length; ++i) { - addModulator(cubeBrt[i] = new LinearEnvelope(0, 0, 100)); - } - base = new SinLFO[model.cubes.size() / 12]; - for (int i = 0; i < base.length; ++i) { - addModulator(base[i] = new SinLFO(0, 1, 7000 + 1000*i)).trigger(); - } - } - - private float getAttackTime() { - return 15 + attack.getValuef()*attack.getValuef() * 2000; - } - - private float getReleaseTime() { - return 15 + release.getValuef() * 3000; - } - - private LinearEnvelope getEnvelope(int index) { - return cubeBrt[index % cubeBrt.length]; - } - - private SinLFO getBase(int index) { - return base[index % base.length]; - } - - public boolean noteOn(Note note) { - LinearEnvelope env = getEnvelope(note.getPitch()); - env.setEndVal(min(1, env.getValuef() + (note.getVelocity() / 127.f)), getAttackTime()).start(); - return true; - } - - public boolean noteOff(Note note) { - getEnvelope(note.getPitch()).setEndVal(0, getReleaseTime()).start(); - return true; - } - - public void run(double deltaMs) { - int i = 0; - float huef = lx.getBaseHuef(); - float levelf = level.getValuef(); - for (Cube c : model.cubes) { - float v = max(getBase(i).getValuef() * levelf/4.f, getEnvelope(i++).getValuef()); - setColor(c, lx.hsb( - (huef + 20*v + abs(c.cx-model.xMax/2.f)*.3f + c.cy) % 360, - min(100, 120*v), - 100*v - )); - } - } -} - -class CrossSections extends SCPattern { - - final SinLFO x = new SinLFO(0, model.xMax, 5000); - final SinLFO y = new SinLFO(0, model.yMax, 6000); - final SinLFO z = new SinLFO(0, model.zMax, 7000); - - final BasicParameter xw = new BasicParameter("XWID", 0.3f); - final BasicParameter yw = new BasicParameter("YWID", 0.3f); - final BasicParameter zw = new BasicParameter("ZWID", 0.3f); - final BasicParameter xr = new BasicParameter("XRAT", 0.7f); - final BasicParameter yr = new BasicParameter("YRAT", 0.6f); - final BasicParameter zr = new BasicParameter("ZRAT", 0.5f); - final BasicParameter xl = new BasicParameter("XLEV", 1); - final BasicParameter yl = new BasicParameter("YLEV", 1); - final BasicParameter zl = new BasicParameter("ZLEV", 0.5f); - - - CrossSections(GLucose glucose) { - super(glucose); - addModulator(x).trigger(); - addModulator(y).trigger(); - addModulator(z).trigger(); - addParams(); - } - - protected void addParams() { - addParameter(xr); - addParameter(yr); - addParameter(zr); - addParameter(xw); - addParameter(xl); - addParameter(yl); - addParameter(zl); - addParameter(yw); - addParameter(zw); - } - - public void onParameterChanged(LXParameter p) { - if (p == xr) { - x.setDuration(10000 - 8800*p.getValuef()); - } else if (p == yr) { - y.setDuration(10000 - 9000*p.getValuef()); - } else if (p == zr) { - z.setDuration(10000 - 9000*p.getValuef()); - } - } - - float xv, yv, zv; - - protected void updateXYZVals() { - xv = x.getValuef(); - yv = y.getValuef(); - zv = z.getValuef(); - } - - public void run(double deltaMs) { - updateXYZVals(); - - float xlv = 100*xl.getValuef(); - float ylv = 100*yl.getValuef(); - float zlv = 100*zl.getValuef(); - - float xwv = 100.f / (10 + 40*xw.getValuef()); - float ywv = 100.f / (10 + 40*yw.getValuef()); - float zwv = 100.f / (10 + 40*zw.getValuef()); - - for (Point p : model.points) { - int c = 0; - c = blendColor(c, lx.hsb( - (lx.getBaseHuef() + p.x/10 + p.y/3) % 360, - constrain(140 - 1.1f*abs(p.x - model.xMax/2.f), 0, 100), - max(0, xlv - xwv*abs(p.x - xv)) - ), ADD); - c = blendColor(c, lx.hsb( - (lx.getBaseHuef() + 80 + p.y/10) % 360, - constrain(140 - 2.2f*abs(p.y - model.yMax/2.f), 0, 100), - max(0, ylv - ywv*abs(p.y - yv)) - ), ADD); - c = blendColor(c, lx.hsb( - (lx.getBaseHuef() + 160 + p.z / 10 + p.y/2) % 360, - constrain(140 - 2.2f*abs(p.z - model.zMax/2.f), 0, 100), - max(0, zlv - zwv*abs(p.z - zv)) - ), ADD); - colors[p.index] = c; - } - } -} - -class Blinders extends SCPattern { - - final SinLFO[] m; - final TriangleLFO r; - final SinLFO s; - final TriangleLFO hs; - - public Blinders(GLucose glucose) { - super(glucose); - m = new SinLFO[12]; - for (int i = 0; i < m.length; ++i) { - addModulator(m[i] = new SinLFO(0.5f, 120, (120000.f / (3+i)))).trigger(); - } - addModulator(r = new TriangleLFO(9000, 15000, 29000)).trigger(); - addModulator(s = new SinLFO(-20, 275, 11000)).trigger(); - addModulator(hs = new TriangleLFO(0.1f, 0.5f, 15000)).trigger(); - s.modulateDurationBy(r); - } - - public void run(double deltaMs) { - float hv = lx.getBaseHuef(); - int si = 0; - for (Strip strip : model.strips) { - int i = 0; - float mv = m[si % m.length].getValuef(); - for (Point p : strip.points) { - colors[p.index] = lx.hsb( - (hv + p.z + p.y*hs.getValuef()) % 360, - min(100, abs(p.x - s.getValuef())/2.f), - max(0, 100 - mv/2.f - mv * abs(i - (strip.metrics.length-1)/2.f)) - ); - ++i; - } - ++si; - } - } -} - -class Psychedelia extends SCPattern { - - final int NUM = 3; - SinLFO m = new SinLFO(-0.5f, NUM-0.5f, 9000); - SinLFO s = new SinLFO(-20, 147, 11000); - TriangleLFO h = new TriangleLFO(0, 240, 19000); - SinLFO c = new SinLFO(-.2f, .8f, 31000); - - Psychedelia(GLucose glucose) { - super(glucose); - addModulator(m).trigger(); - addModulator(s).trigger(); - addModulator(h).trigger(); - addModulator(c).trigger(); - } - - public void run(double deltaMs) { - float huev = h.getValuef(); - float cv = c.getValuef(); - float sv = s.getValuef(); - float mv = m.getValuef(); - int i = 0; - for (Strip strip : model.strips) { - for (Point p : strip.points) { - colors[p.index] = lx.hsb( - (huev + i*constrain(cv, 0, 2) + p.z/2.f + p.x/4.f) % 360, - min(100, abs(p.y-sv)), - max(0, 100 - 50*abs((i%NUM) - mv)) - ); - } - ++i; - } - } -} - -class AskewPlanes extends SCPattern { - - class Plane { - private final SinLFO a; - private final SinLFO b; - private final SinLFO c; - float av = 1; - float bv = 1; - float cv = 1; - float denom = 0.1f; - - Plane(int i) { - addModulator(a = new SinLFO(-1, 1, 4000 + 1029*i)).trigger(); - addModulator(b = new SinLFO(-1, 1, 11000 - 1104*i)).trigger(); - addModulator(c = new SinLFO(-50, 50, 4000 + 1000*i * ((i % 2 == 0) ? 1 : -1))).trigger(); - } - - public void run(double deltaMs) { - av = a.getValuef(); - bv = b.getValuef(); - cv = c.getValuef(); - denom = sqrt(av*av + bv*bv); - } - } - - final Plane[] planes; - final int NUM_PLANES = 3; - - AskewPlanes(GLucose glucose) { - super(glucose); - planes = new Plane[NUM_PLANES]; - for (int i = 0; i < planes.length; ++i) { - planes[i] = new Plane(i); - } - } - - public void run(double deltaMs) { - float huev = lx.getBaseHuef(); - - // This is super fucking bizarre. But if this is a for loop, the framerate - // tanks to like 30FPS, instead of 60. Call them manually and it works fine. - // Doesn't make ANY sense... there must be some weird side effect going on - // with the Processing internals perhaps? -// for (Plane plane : planes) { -// plane.run(deltaMs); -// } - planes[0].run(deltaMs); - planes[1].run(deltaMs); - planes[2].run(deltaMs); - - for (Point p : model.points) { - float d = MAX_FLOAT; - for (Plane plane : planes) { - if (plane.denom != 0) { - d = min(d, abs(plane.av*(p.x-model.cx) + plane.bv*(p.y-model.cy) + plane.cv) / plane.denom); - } - } - colors[p.index] = lx.hsb( - (huev + abs(p.x-model.cx)*.3f + p.y*.8f) % 360, - max(0, 100 - .8f*abs(p.x - model.cx)), - constrain(140 - 10.f*d, 0, 100) - ); - } - } -} - -class ShiftingPlane extends SCPattern { - - final SinLFO a = new SinLFO(-.2f, .2f, 5300); - final SinLFO b = new SinLFO(1, -1, 13300); - final SinLFO c = new SinLFO(-1.4f, 1.4f, 5700); - final SinLFO d = new SinLFO(-10, 10, 9500); - - ShiftingPlane(GLucose glucose) { - super(glucose); - addModulator(a).trigger(); - addModulator(b).trigger(); - addModulator(c).trigger(); - addModulator(d).trigger(); - } - - public void run(double deltaMs) { - float hv = lx.getBaseHuef(); - float av = a.getValuef(); - float bv = b.getValuef(); - float cv = c.getValuef(); - float dv = d.getValuef(); - float denom = sqrt(av*av + bv*bv + cv*cv); - for (Point p : model.points) { - float d = abs(av*(p.x-model.cx) + bv*(p.y-model.cy) + cv*(p.z-model.cz) + dv) / denom; - colors[p.index] = lx.hsb( - (hv + abs(p.x-model.cx)*.6f + abs(p.y-model.cy)*.9f + abs(p.z - model.cz)) % 360, - constrain(110 - d*6, 0, 100), - constrain(130 - 7*d, 0, 100) - ); - } - } -} - -class Traktor extends SCPattern { - - final int FRAME_WIDTH = 60; - - final BasicParameter speed = new BasicParameter("SPD", 0.5f); - - private float[] bass = new float[FRAME_WIDTH]; - private float[] treble = new float[FRAME_WIDTH]; - - private int index = 0; - private GraphicEQ eq = null; - - public Traktor(GLucose glucose) { - super(glucose); - for (int i = 0; i < FRAME_WIDTH; ++i) { - bass[i] = 0; - treble[i] = 0; - } - addParameter(speed); - } - - public void onActive() { - if (eq == null) { - eq = new GraphicEQ(lx, 16); - eq.slope.setValue(0.6f); - eq.level.setValue(0.65f); - eq.range.setValue(0.35f); - eq.release.setValue(0.4f); - addParameter(eq.level); - addParameter(eq.range); - addParameter(eq.attack); - addParameter(eq.release); - addParameter(eq.slope); - } - } - - int counter = 0; - - public void run(double deltaMs) { - eq.run(deltaMs); - - int stepThresh = (int) (40 - 39*speed.getValuef()); - counter += deltaMs; - if (counter < stepThresh) { - return; - } - counter = counter % stepThresh; - - index = (index + 1) % FRAME_WIDTH; - - float rawBass = eq.getAverageLevel(0, 4); - float rawTreble = eq.getAverageLevel(eq.numBands-7, 7); - - bass[index] = rawBass * rawBass * rawBass * rawBass; - treble[index] = rawTreble * rawTreble; - - for (Point p : model.points) { - int i = (int) constrain((model.xMax - p.x) / model.xMax * FRAME_WIDTH, 0, FRAME_WIDTH-1); - int pos = (index + FRAME_WIDTH - i) % FRAME_WIDTH; - - colors[p.index] = lx.hsb( - (360 + lx.getBaseHuef() + .8f*abs(p.x-model.cx)) % 360, - 100, - constrain(9 * (bass[pos]*model.cy - abs(p.y - model.cy + 5)), 0, 100) - ); - colors[p.index] = blendColor(colors[p.index], lx.hsb( - (400 + lx.getBaseHuef() + .5f*abs(p.x-model.cx)) % 360, - 60, - constrain(5 * (treble[pos]*.6f*model.cy - abs(p.y - model.cy)), 0, 100) - - ), ADD); - } - } -} - -class ColorFuckerEffect extends SCEffect { - - final BasicParameter level = new BasicParameter("BRT", 1); - final BasicParameter desat = new BasicParameter("DSAT", 0); - final BasicParameter hueShift = new BasicParameter("HSHFT", 0); - final BasicParameter sharp = new BasicParameter("SHARP", 0); - final BasicParameter soft = new BasicParameter("SOFT", 0); - final BasicParameter mono = new BasicParameter("MONO", 0); - final BasicParameter invert = new BasicParameter("INVERT", 0); - - - float[] hsb = new float[3]; - - ColorFuckerEffect(GLucose glucose) { - super(glucose); - addParameter(level); - addParameter(desat); - addParameter(sharp); - addParameter(hueShift); - addParameter(soft); - addParameter(mono); - addParameter(invert); - } - - public void apply(int[] colors) { - if (!enabled) { - return; - } - float bMod = level.getValuef(); - float sMod = 1 - desat.getValuef(); - float hMod = hueShift.getValuef(); - float fSharp = 1/(1.0001f-sharp.getValuef()); - float fSoft = soft.getValuef(); - boolean mon = mono.getValuef() > 0.5f; - boolean ivt = invert.getValuef() > 0.5f; - if (bMod < 1 || sMod < 1 || hMod > 0 || fSharp > 0 || ivt || mon || fSoft > 0) { - for (int i = 0; i < colors.length; ++i) { - lx.RGBtoHSB(colors[i], hsb); - if (mon) { - hsb[0] = lx.getBaseHuef() / 360.f; - } - if (ivt) { - hsb[2] = 1 - hsb[2]; - } - if (fSharp > 0) { - hsb[2] = hsb[2] < .5f ? pow(hsb[2],fSharp) : 1-pow(1-hsb[2],fSharp); - } - if (fSoft > 0) { - if (hsb[2] > 0.5f) { - hsb[2] = lerp(hsb[2], 0.5f + 2 * (hsb[2]-0.5f)*(hsb[2]-0.5f), fSoft); - } else { - hsb[2] = lerp(hsb[2], 0.5f * sqrt(2*hsb[2]), fSoft); - } - } - colors[i] = lx.hsb( - (360.f * hsb[0] + hMod*360.f) % 360, - 100.f * hsb[1] * sMod, - 100.f * hsb[2] * bMod - ); - } - } - } -} - -class QuantizeEffect extends SCEffect { - - int[] quantizedFrame; - float lastQuant; - final BasicParameter amount = new BasicParameter("AMT", 0); - - QuantizeEffect(GLucose glucose) { - super(glucose); - quantizedFrame = new int[glucose.lx.total]; - lastQuant = 0; - } - - public void apply(int[] colors) { - float fQuant = amount.getValuef(); - if (fQuant > 0) { - float tRamp = (lx.tempo.rampf() % (1.f/pow(2,floor((1-fQuant) * 4)))); - float f = lastQuant; - lastQuant = tRamp; - if (tRamp > f) { - for (int i = 0; i < colors.length; ++i) { - colors[i] = quantizedFrame[i]; - } - return; - } - } - for (int i = 0; i < colors.length; ++i) { - quantizedFrame[i] = colors[i]; - } - } -} - -class BlurEffect extends SCEffect { - - final LXParameter amount = new BasicParameter("AMT", 0); - final int[] frame; - final LinearEnvelope env = new LinearEnvelope(0, 1, 100); - - BlurEffect(GLucose glucose) { - super(glucose); - addParameter(amount); - addModulator(env); - frame = new int[lx.total]; - for (int i = 0; i < frame.length; ++i) { - frame[i] = 0xff000000; - } - } - - public void onEnable() { - env.setRangeFromHereTo(1, 400).start(); - for (int i = 0; i < frame.length; ++i) { - frame[i] = 0xff000000; - } - } - - public void onDisable() { - env.setRangeFromHereTo(0, 1000).start(); - } - - public void apply(int[] colors) { - float amt = env.getValuef() * amount.getValuef(); - if (amt > 0) { - amt = (1 - amt); - amt = 1 - (amt*amt*amt); - for (int i = 0; i < colors.length; ++i) { - // frame[i] = colors[i] = blendColor(colors[i], lerpColor(#000000, frame[i], amt, RGB), SCREEN); - frame[i] = colors[i] = lerpColor(colors[i], blendColor(colors[i], frame[i], SCREEN), amt, RGB); - } - } - - } -} -abstract class SamPattern extends SCPattern { - public SamPattern(GLucose glucose) { - super(glucose); - setEligible(false); - } -} - -class JazzRainbow extends SamPattern { - public JazzRainbow(GLucose glucose) { - super(glucose); - } - - - public void run(double deltaMs) { - // Access the core master hue via this method call - float hv = lx.getBaseHuef(); - for (int i = 0; i < colors.length*5; i=i+27) { - float a = hv%250; - if (i%2 == 0) { - for (int b = 0; b < 70; b++) { - colors[(i+b)%colors.length] = lx.hsb(a+i%250, 100, b*a%100); - } - } - } - } -} - - - -class HelixPattern extends SCPattern { - - // Stores a line in point + vector form - private class Line { - private final PVector origin; - private final PVector vector; - - Line(PVector pt, PVector v) { - origin = pt; - vector = v.get(); - vector.normalize(); - } - - public PVector getPoint() { - return origin; - } - - public PVector getVector() { - return vector; - } - - public PVector getPointAt(final float t) { - return PVector.add(origin, PVector.mult(vector, t)); - } - - public boolean isColinear(final PVector pt) { - PVector projected = projectPoint(pt); - return projected.x==pt.x && projected.y==pt.y && projected.z==pt.z; - } - - public float getTValue(final PVector pt) { - PVector subtraction = PVector.sub(pt, origin); - return subtraction.dot(vector); - } - - public PVector projectPoint(final PVector pt) { - return getPointAt(getTValue(pt)); - } - - public PVector rotatePoint(final PVector p, final float t) { - final PVector o = origin; - final PVector v = vector; - - final float cost = cos(t); - final float sint = sin(t); - - 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; - 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; - 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; - return new PVector(x, y, z); - } - } - - private class Helix { - private final Line axis; - private final float period; // period of coil - private final float rotationPeriod; // animation period - private final float radius; // radius of coil - private final float girth; // girth of coil - private final PVector referencePoint; - private float phase; - private PVector phaseNormal; - - Helix(Line axis, float period, float radius, float girth, float phase, float rotationPeriod) { - this.axis = axis; - this.period = period; - this.radius = radius; - this.girth = girth; - this.phase = phase; - this.rotationPeriod = rotationPeriod; - - // Generate a normal that will rotate to - // produce the helical shape. - PVector pt = new PVector(0, 1, 0); - if (this.axis.isColinear(pt)) { - pt = new PVector(0, 0, 1); - if (this.axis.isColinear(pt)) { - pt = new PVector(0, 1, 1); - } - } - - this.referencePoint = pt; - - // The normal is calculated by the cross product of the axis - // and a random point that is not colinear with it. - phaseNormal = axis.getVector().cross(referencePoint); - phaseNormal.normalize(); - phaseNormal.mult(radius); - } - - public Line getAxis() { - return axis; - } - - public PVector getPhaseNormal() { - return phaseNormal; - } - - public float getPhase() { - return phase; - } - - public void step(double deltaMs) { - // Rotate - if (rotationPeriod != 0) { - this.phase = (phase + ((float)deltaMs / (float)rotationPeriod) * TWO_PI); - } - } - - public PVector pointOnToroidalAxis(float t) { - PVector p = axis.getPointAt(t); - PVector middle = PVector.add(p, phaseNormal); - return axis.rotatePoint(middle, (t / period) * TWO_PI + phase); - } - - private float myDist(PVector p1, PVector p2) { - final float x = p2.x-p1.x; - final float y = p2.y-p1.y; - final float z = p2.z-p1.z; - return sqrt(x*x + y*y + z*z); - } - - public int colorOfPoint(final PVector p) { - final float t = axis.getTValue(p); - final PVector axisPoint = axis.getPointAt(t); - - // For performance reasons, cut out points that are outside of - // the tube where the toroidal coil lives. - if (abs(myDist(p, axisPoint) - radius) > girth*.5f) { - return lx.hsb(0,0,0); - } - - // Find the appropriate point for the current rotation - // of the helix. - PVector toroidPoint = axisPoint; - toroidPoint.add(phaseNormal); - toroidPoint = axis.rotatePoint(toroidPoint, (t / period) * TWO_PI + phase); - - // The rotated point represents the middle of the girth of - // the helix. Figure out if the current point is inside that - // region. - float d = myDist(p, toroidPoint); - - // Soften edges by fading brightness. - float b = constrain(100*(1 - ((d-.5f*girth)/(girth*.5f))), 0, 100); - return lx.hsb((lx.getBaseHuef() + (360*(phase / TWO_PI)))%360, 80, b); - } - } - - private class BasePairInfo { - Line line; - float colorPhase1; - float colorPhase2; - - BasePairInfo(Line line, float colorPhase1, float colorPhase2) { - this.line = line; - this.colorPhase1 = colorPhase1; - this.colorPhase2 = colorPhase2; - } - } - - private final Helix h1; - private final Helix h2; - private final BasePairInfo[] basePairs; - - private final BasicParameter helix1On = new BasicParameter("H1ON", 1); - private final BasicParameter helix2On = new BasicParameter("H2ON", 1); - private final BasicParameter basePairsOn = new BasicParameter("BPON", 1); - - private static final float helixCoilPeriod = 100; - private static final float helixCoilRadius = 50; - private static final float helixCoilGirth = 30; - private static final float helixCoilRotationPeriod = 5000; - - private static final float spokePeriod = 40; - private static final float spokeGirth = 20; - private static final float spokePhase = 10; - private static final float spokeRadius = helixCoilRadius - helixCoilGirth*.5f; - - private static final float tMin = -200; - private static final float tMax = 200; - - public HelixPattern(GLucose glucose) { - super(glucose); - - addParameter(helix1On); - addParameter(helix2On); - addParameter(basePairsOn); - - PVector origin = new PVector(100, 50, 55); - PVector axis = new PVector(1,0,0); - - h1 = new Helix( - new Line(origin, axis), - helixCoilPeriod, - helixCoilRadius, - helixCoilGirth, - 0, - helixCoilRotationPeriod); - h2 = new Helix( - new Line(origin, axis), - helixCoilPeriod, - helixCoilRadius, - helixCoilGirth, - PI, - helixCoilRotationPeriod); - - basePairs = new BasePairInfo[(int)floor((tMax - tMin)/spokePeriod)]; - } - - private void calculateSpokes() { - float colorPhase = PI/6; - for (float t = tMin + spokePhase; t < tMax; t += spokePeriod) { - int spokeIndex = (int)floor((t - tMin)/spokePeriod); - PVector h1point = h1.pointOnToroidalAxis(t); - PVector spokeCenter = h1.getAxis().getPointAt(t); - PVector spokeVector = PVector.sub(h1point, spokeCenter); - Line spokeLine = new Line(spokeCenter, spokeVector); - basePairs[spokeIndex] = new BasePairInfo(spokeLine, colorPhase * spokeIndex, colorPhase * (spokeIndex + 1)); - } - } - - private int calculateSpokeColor(final PVector pt) { - // Find the closest spoke's t-value and calculate its - // axis. Until everything animates in the model reference - // frame, this has to be calculated at every step because - // the helices rotate. - Line axis = h1.getAxis(); - float t = axis.getTValue(pt) + spokePhase; - int spokeIndex = (int)floor((t - tMin + spokePeriod/2) / spokePeriod); - if (spokeIndex < 0 || spokeIndex >= basePairs.length) { - return lx.hsb(0,0,0); - } - BasePairInfo basePair = basePairs[spokeIndex]; - Line spokeLine = basePair.line; - PVector pointOnSpoke = spokeLine.projectPoint(pt); - float d = PVector.dist(pt, pointOnSpoke); - float b = (PVector.dist(pointOnSpoke, spokeLine.getPoint()) < spokeRadius) ? constrain(100*(1 - ((d-.5f*spokeGirth)/(spokeGirth*.5f))), 0, 100) : 0.f; - float phase = spokeLine.getTValue(pointOnSpoke) < 0 ? basePair.colorPhase1 : basePair.colorPhase2; - return lx.hsb((lx.getBaseHuef() + (360*(phase / TWO_PI)))%360, 80.f, b); - } - - public void run(double deltaMs) { - boolean h1on = helix1On.getValue() > 0.5f; - boolean h2on = helix2On.getValue() > 0.5f; - boolean spokesOn = (float)basePairsOn.getValue() > 0.5f; - - h1.step(deltaMs); - h2.step(deltaMs); - calculateSpokes(); - - for (Point p : model.points) { - PVector pt = new PVector(p.x,p.y,p.z); - int h1c = h1.colorOfPoint(pt); - int h2c = h2.colorOfPoint(pt); - int spokeColor = calculateSpokeColor(pt); - - if (!h1on) { - h1c = lx.hsb(0,0,0); - } - - if (!h2on) { - h2c = lx.hsb(0,0,0); - } - - if (!spokesOn) { - spokeColor = lx.hsb(0,0,0); - } - - // The helices are positioned to not overlap. If that changes, - // a better blending formula is probably needed. - colors[p.index] = blendColor(blendColor(h1c, h2c, ADD), spokeColor, ADD); - } - } -} - -class BlankPattern extends SCPattern { - BlankPattern(GLucose glucose) { - super(glucose); - } - - public void run(double deltaMs) { - setColors(0xff000000); - } -} - -abstract class TestPattern extends SCPattern { - public TestPattern(GLucose glucose) { - super(glucose); - setEligible(false); - } -} - -class TestSpeakerMapping extends TestPattern { - TestSpeakerMapping(GLucose glucose) { - super(glucose); - } - - public void run(double deltaMs) { - int h = 0; - for (Speaker speaker : model.speakers) { - for (Strip strip : speaker.strips) { - float b = 100; - for (Point p : strip.points) { - colors[p.index] = lx.hsb(h % 360, 100, b); - b = max(0, b - 10); - } - h += 70; - } - } - } - -} - -class TestBassMapping extends TestPattern { - TestBassMapping(GLucose glucose) { - super(glucose); - } - - public void run(double deltaMs) { - int[] strips = { 2, 1, 0, 3, 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6 }; - int h = 0; - for (int si : strips) { - float b = 100; - for (Point p : model.bassBox.strips.get(si).points) { - colors[p.index] = lx.hsb(h % 360, 100, b); - b = max(0, b - 10); - } - h += 70; - } - } -} - -class TestFloorMapping extends TestPattern { - TestFloorMapping(GLucose glucose) { - super(glucose); - } - - public void run(double deltaMs) { - int[] strutIndices = {6, 5, 4, 3, 2, 1, 0, 7}; - int h = 0; - for (int si : strutIndices) { - float b = 100; - for (Point p : model.bassBox.struts.get(si).points) { - colors[p.index] = lx.hsb(h % 360, 100, b); - b = max(0, b - 10); - } - h += 50; - } - int[] floorIndices = {0, 1, 2, 3}; - h = 0; - for (int fi : floorIndices) { - float b = 100; - for (Point p : model.boothFloor.strips.get(fi).points) { - colors[p.index] = lx.hsb(h, 100, b); - b = max(0, b - 3); - } - h += 90; - } - } -} - -class TestPerformancePattern extends TestPattern { - - final BasicParameter ops = new BasicParameter("OPS", 0); - final BasicParameter iter = new BasicParameter("ITER", 0); - - TestPerformancePattern(GLucose glucose) { - super(glucose); - addParameter(ops); - addParameter(iter); - } - - public void run(double deltaMs) { - float x = 1; - for (int j = 0; j < ops.getValuef() * 400000; ++j) { - x *= random(0, 1); - } - - if (iter.getValuef() < 0.25f) { - for (Point p : model.points) { - colors[p.index] = lx.hsb( - (p.x*.1f + p.y*.1f) % 360, - 100, - 100 - ); - } - } else if (iter.getValuef() < 0.5f) { - for (int i = 0; i < colors.length; ++i) { - colors[i] = lx.hsb( - (90 + model.px[i]*.1f + model.py[i]*.1f) % 360, - 100, - 100 - ); - } - } else if (iter.getValuef() < 0.75f) { - for (int i = 0; i < colors.length; ++i) { - colors[i] = lx.hsb( - (180 + model.p[3*i]*.1f + model.p[3*i+1]*.1f) % 360, - 100, - 100 - ); - } - } else { - for (int i = 0; i < colors.length; ++i) { - colors[i] = lx.hsb( - (270 + model.x(i)*.1f + model.y(i)*.1f) % 360, - 100, - 100 - ); - } - } - } -} - -class TestStripPattern extends TestPattern { - - SinLFO d = new SinLFO(4, 40, 4000); - - public TestStripPattern(GLucose glucose) { - super(glucose); - addModulator(d).trigger(); - } - - public void run(double deltaMs) { - for (Strip s : model.strips) { - for (Point p : s.points) { - colors[p.index] = lx.hsb( - lx.getBaseHuef(), - 100, - max(0, 100 - d.getValuef()*dist(p.x, p.y, s.cx, s.cy)) - ); - } - } - } -} - -/** - * Simplest demonstration of using the rotating master hue. - * All pixels are full-on the same color. - */ -class TestHuePattern extends TestPattern { - public TestHuePattern(GLucose glucose) { - super(glucose); - } - - public void run(double deltaMs) { - // Access the core master hue via this method call - float hv = lx.getBaseHuef(); - for (int i = 0; i < colors.length; ++i) { - colors[i] = lx.hsb(hv, 100, 100); - } - } -} - -/** - * Test of a wave moving across the X axis. - */ -class TestXPattern extends TestPattern { - private final SinLFO xPos = new SinLFO(0, model.xMax, 4000); - public TestXPattern(GLucose glucose) { - super(glucose); - addModulator(xPos).trigger(); - } - public void run(double deltaMs) { - float hv = lx.getBaseHuef(); - for (Point p : model.points) { - // This is a common technique for modulating brightness. - // You can use abs() to determine the distance between two - // values. The further away this point is from an exact - // point, the more we decrease its brightness - float bv = max(0, 100 - abs(p.x - xPos.getValuef())); - colors[p.index] = lx.hsb(hv, 100, bv); - } - } -} - -/** - * Test of a wave on the Y axis. - */ -class TestYPattern extends TestPattern { - private final SinLFO yPos = new SinLFO(0, model.yMax, 4000); - public TestYPattern(GLucose glucose) { - super(glucose); - addModulator(yPos).trigger(); - } - public void run(double deltaMs) { - float hv = lx.getBaseHuef(); - for (Point p : model.points) { - float bv = max(0, 100 - abs(p.y - yPos.getValuef())); - colors[p.index] = lx.hsb(hv, 100, bv); - } - } -} - -/** - * Test of a wave on the Z axis. - */ -class TestZPattern extends TestPattern { - private final SinLFO zPos = new SinLFO(0, model.zMax, 4000); - public TestZPattern(GLucose glucose) { - super(glucose); - addModulator(zPos).trigger(); - } - public void run(double deltaMs) { - float hv = lx.getBaseHuef(); - for (Point p : model.points) { - float bv = max(0, 100 - abs(p.z - zPos.getValuef())); - colors[p.index] = lx.hsb(hv, 100, bv); - } - } -} - -/** - * This shows how to iterate over towers, enumerated in the model. - */ -class TestTowerPattern extends TestPattern { - private final SawLFO towerIndex = new SawLFO(0, model.towers.size(), 1000*model.towers.size()); - - public TestTowerPattern(GLucose glucose) { - super(glucose); - addModulator(towerIndex).trigger(); - } - - public void run(double deltaMs) { - int ti = 0; - for (Tower t : model.towers) { - for (Point p : t.points) { - colors[p.index] = lx.hsb( - lx.getBaseHuef(), - 100, - max(0, 100 - 80*LXUtils.wrapdistf(ti, towerIndex.getValuef(), model.towers.size())) - ); - } - ++ti; - } - } - -} - -/** - * This is a demonstration of how to use the projection library. A projection - * creates a mutation of the coordinates of all the points in the model, creating - * virtual x,y,z coordinates. In effect, this is like virtually rotating the entire - * art car. However, since in reality the car does not move, the result is that - * it appears that the object we are drawing on the car is actually moving. - * - * Keep in mind that what we are creating a projection of is the view coordinates. - * Depending on your intuition, some operations may feel backwards. For instance, - * if you translate the view to the right, it will make it seem that the object - * you are drawing has moved to the left. If you scale the view up 2x, objects - * drawn with the same absolute values will seem to be half the size. - * - * If this feels counterintuitive at first, don't worry. Just remember that you - * are moving the pixels, not the structure. We're dealing with a finite set - * of sparse, non-uniformly spaced pixels. Mutating the structure would move - * things to a space where there are no pixels in 99% of the cases. - */ -class TestProjectionPattern extends TestPattern { - - private final Projection projection; - private final SawLFO angle = new SawLFO(0, TWO_PI, 9000); - private final SinLFO yPos = new SinLFO(-20, 40, 5000); - - public TestProjectionPattern(GLucose glucose) { - super(glucose); - projection = new Projection(model); - addModulator(angle).trigger(); - addModulator(yPos).trigger(); - } - - public void run(double deltaMs) { - // For the same reasons described above, it may logically feel to you that - // some of these operations are in reverse order. Again, just keep in mind that - // the car itself is what's moving, not the object - projection.reset(model) - - // Translate so the center of the car is the origin, offset by yPos - .translateCenter(model, 0, yPos.getValuef(), 0) - - // Rotate around the origin (now the center of the car) about an X-vector - .rotate(angle.getValuef(), 1, 0, 0) - - // Scale up the Y axis (objects will look smaller in that access) - .scale(1, 1.5f, 1); - - float hv = lx.getBaseHuef(); - for (Coord c : projection) { - float d = sqrt(c.x*c.x + c.y*c.y + c.z*c.z); // distance from origin - // d = abs(d-60) + max(0, abs(c.z) - 20); // life saver / ring thing - d = max(0, abs(c.y) - 10 + .1f*abs(c.z) + .02f*abs(c.x)); // plane / spear thing - colors[c.index] = lx.hsb( - (hv + .6f*abs(c.x) + abs(c.z)) % 360, - 100, - constrain(140 - 40*d, 0, 100) - ); - } - } -} - -class TestCubePattern extends TestPattern { - - private SawLFO index = new SawLFO(0, Cube.POINTS_PER_CUBE, Cube.POINTS_PER_CUBE*60); - - TestCubePattern(GLucose glucose) { - super(glucose); - addModulator(index).start(); - } - - public void run(double deltaMs) { - for (Cube c : model.cubes) { - int i = 0; - for (Point p : c.points) { - colors[p.index] = lx.hsb( - lx.getBaseHuef(), - 100, - max(0, 100 - 80.f*abs(i - index.getValuef())) - ); - ++i; - } - } - } -} - -class MappingTool extends TestPattern { - - private int cubeIndex = 0; - private int stripIndex = 0; - private int channelIndex = 0; - - public final int MAPPING_MODE_ALL = 0; - public final int MAPPING_MODE_CHANNEL = 1; - public final int MAPPING_MODE_SINGLE_CUBE = 2; - public int mappingMode = MAPPING_MODE_ALL; - - public final int CUBE_MODE_ALL = 0; - public final int CUBE_MODE_SINGLE_STRIP = 1; - public final int CUBE_MODE_STRIP_PATTERN = 2; - public int cubeMode = CUBE_MODE_ALL; - - public boolean channelModeRed = true; - public boolean channelModeGreen = false; - public boolean channelModeBlue = false; - - private final int numChannels; - - private final PandaMapping[] pandaMappings; - private PandaMapping activePanda; - private ChannelMapping activeChannel; - - MappingTool(GLucose glucose, PandaMapping[] pandaMappings) { - super(glucose); - this.pandaMappings = pandaMappings; - numChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD; - setChannel(); - } - - public int numChannels() { - return numChannels; - } - - private void setChannel() { - activePanda = pandaMappings[channelIndex / PandaMapping.CHANNELS_PER_BOARD]; - activeChannel = activePanda.channelList[channelIndex % PandaMapping.CHANNELS_PER_BOARD]; - } - - private int indexOfCubeInChannel(Cube c) { - if (activeChannel.mode == ChannelMapping.MODE_CUBES) { - int i = 1; - for (int index : activeChannel.objectIndices) { - if ((index >= 0) && (c == model.getCubeByRawIndex(index))) { - return i; - } - ++i; - } - } - return 0; - } - - private void printInfo() { - println("Cube:" + cubeIndex + " Strip:" + (stripIndex+1)); - } - - public void cube(int delta) { - int len = model.cubes.size(); - cubeIndex = (len + cubeIndex + delta) % len; - printInfo(); - } - - public void strip(int delta) { - int len = Cube.STRIPS_PER_CUBE; - stripIndex = (len + stripIndex + delta) % len; - printInfo(); - } - - public void run(double deltaMs) { - int off = 0xff000000; - int c = off; - int r = 0xffFF0000; - int g = 0xff00FF00; - int b = 0xff0000FF; - if (channelModeRed) c |= r; - if (channelModeGreen) c |= g; - if (channelModeBlue) c |= b; - - int ci = 0; - for (Cube cube : model.cubes) { - boolean cubeOn = false; - int indexOfCubeInChannel = indexOfCubeInChannel(cube); - switch (mappingMode) { - case MAPPING_MODE_ALL: cubeOn = true; break; - case MAPPING_MODE_SINGLE_CUBE: cubeOn = (cubeIndex == ci); break; - case MAPPING_MODE_CHANNEL: cubeOn = (indexOfCubeInChannel > 0); break; - } - if (cubeOn) { - if (mappingMode == MAPPING_MODE_CHANNEL) { - int cc = off; - switch (indexOfCubeInChannel) { - case 1: cc = r; break; - case 2: cc = r|g; break; - case 3: cc = g; break; - case 4: cc = b; break; - case 5: cc = r|b; break; - } - setColor(cube, cc); - } else if (cubeMode == CUBE_MODE_STRIP_PATTERN) { - int si = 0; - int sc = off; - for (Strip strip : cube.strips) { - int faceI = si / Face.STRIPS_PER_FACE; - switch (faceI) { - case 0: sc = r; break; - case 1: sc = g; break; - case 2: sc = b; break; - case 3: sc = r|g|b; break; - } - if (si % Face.STRIPS_PER_FACE == 2) { - sc = r|g; - } - setColor(strip, sc); - ++si; - } - } else if (cubeMode == CUBE_MODE_SINGLE_STRIP) { - setColor(cube, off); - setColor(cube.strips.get(stripIndex), c); - } else { - setColor(cube, c); - } - } else { - setColor(cube, off); - } - ++ci; - } - } - - public void setCube(int index) { - cubeIndex = index % model.cubes.size(); - } - - public void incCube() { - cubeIndex = (cubeIndex + 1) % model.cubes.size(); - } - - public void decCube() { - --cubeIndex; - if (cubeIndex < 0) { - cubeIndex += model.cubes.size(); - } - } - - public void setChannel(int index) { - channelIndex = index % numChannels; - setChannel(); - } - - public void incChannel() { - channelIndex = (channelIndex + 1) % numChannels; - setChannel(); - } - - public void decChannel() { - channelIndex = (channelIndex + numChannels - 1) % numChannels; - setChannel(); - } - - public void setStrip(int index) { - stripIndex = index % Cube.STRIPS_PER_CUBE; - } - - public void incStrip() { - stripIndex = (stripIndex + 1) % Cube.STRIPS_PER_CUBE; - } - - public void decStrip() { - stripIndex = (stripIndex + Cube.STRIPS_PER_CUBE - 1) % Cube.STRIPS_PER_CUBE; - } - - public void keyPressed(UIMapping uiMapping) { - switch (keyCode) { - case UP: if (mappingMode == MAPPING_MODE_CHANNEL) incChannel(); else incCube(); break; - case DOWN: if (mappingMode == MAPPING_MODE_CHANNEL) decChannel(); else decCube(); break; - case LEFT: decStrip(); break; - case RIGHT: incStrip(); break; - } - switch (key) { - case 'r': channelModeRed = !channelModeRed; break; - case 'g': channelModeGreen = !channelModeGreen; break; - case 'b': channelModeBlue = !channelModeBlue; break; - } - uiMapping.setChannelID(channelIndex+1); - uiMapping.setCubeID(cubeIndex+1); - uiMapping.setStripID(stripIndex+1); - uiMapping.redraw(); - } - -} -/** - * Not very flushed out, but kind of fun nonetheless. - */ -class TimSpheres extends SCPattern { - private BasicParameter hueParameter = new BasicParameter("RAD", 1.0f); - private final SawLFO lfo = new SawLFO(0, 1, 10000); - private final SinLFO sinLfo = new SinLFO(0, 1, 4000); - private final float centerX, centerY, centerZ; - - class Sphere { - float x, y, z; - float radius; - float hue; - } - - private final Sphere[] spheres; - - public TimSpheres(GLucose glucose) { - super(glucose); - addParameter(hueParameter); - addModulator(lfo).trigger(); - addModulator(sinLfo).trigger(); - centerX = (model.xMax + model.xMin) / 2; - centerY = (model.yMax + model.yMin) / 2; - centerZ = (model.zMax + model.zMin) / 2; - - spheres = new Sphere[2]; - - spheres[0] = new Sphere(); - spheres[0].x = model.xMin; - spheres[0].y = centerY; - spheres[0].z = centerZ; - spheres[0].hue = 0; - spheres[0].radius = 50; - - spheres[1] = new Sphere(); - spheres[1].x = model.xMax; - spheres[1].y = centerY; - spheres[1].z = centerZ; - spheres[1].hue = 0.33f; - spheres[1].radius = 50; - } - - public void run(double deltaMs) { - // Access the core master hue via this method call - float hv = hueParameter.getValuef(); - float lfoValue = lfo.getValuef(); - float sinLfoValue = sinLfo.getValuef(); - - spheres[0].x = model.xMin + sinLfoValue * model.xMax; - spheres[1].x = model.xMax - sinLfoValue * model.xMax; - - spheres[0].radius = 100 * hueParameter.getValuef(); - spheres[1].radius = 100 * hueParameter.getValuef(); - - for (Point p : model.points) { - float value = 0; - - int c = lx.hsb(0, 0, 0); - for (Sphere s : spheres) { - float d = sqrt(pow(p.x - s.x, 2) + pow(p.y - s.y, 2) + pow(p.z - s.z, 2)); - float r = (s.radius); // * (sinLfoValue + 0.5)); - value = max(0, 1 - max(0, d - r) / 10); - - c = blendColor(c, lx.hsb(((s.hue + lfoValue) % 1) * 360, 100, min(1, value) * 100), ADD); - } - - colors[p.index] = c; - } - } -} - -class Vector2 { - float x, y; - - Vector2() { - this(0, 0); - } - - Vector2(float x, float y) { - this.x = x; - this.y = y; - } - - public float distanceTo(float x, float y) { - return sqrt(pow(x - this.x, 2) + pow(y - this.y, 2)); - } - - public float distanceTo(Vector2 v) { - return distanceTo(v.x, v.y); - } - - public Vector2 plus(float x, float y) { - return new Vector2(this.x + x, this.y + y); - } - - public Vector2 plus(Vector2 v) { - return plus(v.x, v.y); - } - - public Vector2 minus(Vector2 v) { - return plus(-1 * v.x, -1 * v.y); - } -} - -class Vector3 { - float x, y, z; - - Vector3() { - this(0, 0, 0); - } - - Vector3(float x, float y, float z) { - this.x = x; - this.y = y; - this.z = z; - } - - public float distanceTo(float x, float y, float z) { - return sqrt(pow(x - this.x, 2) + pow(y - this.y, 2) + pow(z - this.z, 2)); - } - - public float distanceTo(Vector3 v) { - return distanceTo(v.x, v.y, v.z); - } - - public float distanceTo(Point p) { - return distanceTo(p.x, p.y, p.z); - } - - public void add(Vector3 other, float multiplier) { - this.add(other.x * multiplier, other.y * multiplier, other.z * multiplier); - } - - public void add(float x, float y, float z) { - this.x += x; - this.y += y; - this.z += z; - } - - public void divide(float factor) { - this.x /= factor; - this.y /= factor; - this.z /= factor; - } -} - -class Rotation { - private float a, b, c, d, e, f, g, h, i; - - Rotation(float yaw, float pitch, float roll) { - float cosYaw = cos(yaw); - float sinYaw = sin(yaw); - float cosPitch = cos(pitch); - float sinPitch = sin(pitch); - float cosRoll = cos(roll); - float sinRoll = sin(roll); - - a = cosYaw * cosPitch; - b = cosYaw * sinPitch * sinRoll - sinYaw * cosRoll; - c = cosYaw * sinPitch * cosRoll + sinYaw * sinRoll; - d = sinYaw * cosPitch; - e = sinYaw * sinPitch * sinRoll + cosYaw * cosRoll; - f = sinYaw * sinPitch * cosRoll - cosYaw * sinRoll; - g = -1 * sinPitch; - h = cosPitch * sinRoll; - i = cosPitch * cosRoll; - } - - public Vector3 rotated(Vector3 v) { - return new Vector3( - rotatedX(v), - rotatedY(v), - rotatedZ(v)); - - } - - public float rotatedX(Vector3 v) { - return a * v.x + b * v.y + c * v.z; - } - - public float rotatedY(Vector3 v) { - return d * v.x + e * v.y + f * v.z; - } - - public float rotatedZ(Vector3 v) { - return g * v.x + h * v.y + i * v.z; - } -} - -/** - * Very literal rain effect. Not that great as-is but some tweaking could make it nice. - * A couple ideas: - * - changing hue and direction of "rain" could make a nice fire effect - * - knobs to change frequency and size of rain drops - * - sync somehow to tempo but maybe less frequently than every beat? - */ -class TimRaindrops extends SCPattern { - public Vector3 randomVector3() { - return new Vector3( - random(model.xMax - model.xMin) + model.xMin, - random(model.yMax - model.yMin) + model.yMin, - random(model.zMax - model.zMin) + model.zMin); - } - - class Raindrop { - Vector3 p; - Vector3 v; - float radius; - float hue; - - Raindrop() { - this.radius = 30; - this.p = new Vector3( - random(model.xMax - model.xMin) + model.xMin, - model.yMax + this.radius, - random(model.zMax - model.zMin) + model.zMin); - float velMagnitude = 120; - this.v = new Vector3( - 0, - -3 * model.yMax, - 0); - this.hue = random(40) + 200; - } - - // returns TRUE when this should die - public boolean age(double ms) { - p.add(v, (float) (ms / 1000.0f)); - return this.p.y < (0 - this.radius); - } - } - - private float leftoverMs = 0; - private float msPerRaindrop = 40; - private List raindrops; - - public TimRaindrops(GLucose glucose) { - super(glucose); - raindrops = new LinkedList(); - } - - public void run(double deltaMs) { - leftoverMs += deltaMs; - while (leftoverMs > msPerRaindrop) { - leftoverMs -= msPerRaindrop; - raindrops.add(new Raindrop()); - } - - for (Point p : model.points) { - int c = - blendColor( - lx.hsb(210, 20, (float)Math.max(0, 1 - Math.pow((model.yMax - p.y) / 10, 2)) * 50), - lx.hsb(220, 60, (float)Math.max(0, 1 - Math.pow((p.y - model.yMin) / 10, 2)) * 100), - ADD); - for (Raindrop raindrop : raindrops) { - if (p.x >= (raindrop.p.x - raindrop.radius) && p.x <= (raindrop.p.x + raindrop.radius) && - p.y >= (raindrop.p.y - raindrop.radius) && p.y <= (raindrop.p.y + raindrop.radius)) { - float d = raindrop.p.distanceTo(p) / raindrop.radius; - // float value = (float)Math.max(0, 1 - Math.pow(Math.min(0, d - raindrop.radius) / 5, 2)); - if (d < 1) { - c = blendColor(c, lx.hsb(raindrop.hue, 80, (float)Math.pow(1 - d, 0.01f) * 100), ADD); - } - } - } - colors[p.index] = c; - } - - Iterator i = raindrops.iterator(); - while (i.hasNext()) { - Raindrop raindrop = i.next(); - boolean dead = raindrop.age(deltaMs); - if (dead) { - i.remove(); - } - } - } -} - - -class TimCubes extends SCPattern { - private BasicParameter rateParameter = new BasicParameter("RATE", 0.125f); - private BasicParameter attackParameter = new BasicParameter("ATTK", 0.5f); - private BasicParameter decayParameter = new BasicParameter("DECAY", 0.5f); - private BasicParameter hueParameter = new BasicParameter("HUE", 0.5f); - private BasicParameter hueVarianceParameter = new BasicParameter("H.V.", 0.25f); - private BasicParameter saturationParameter = new BasicParameter("SAT", 0.5f); - - class CubeFlash { - Cube c; - float value; - float hue; - boolean hasPeaked; - - CubeFlash() { - c = model.cubes.get(floor(random(model.cubes.size()))); - hue = random(1); - boolean infiniteAttack = (attackParameter.getValuef() > 0.999f); - hasPeaked = infiniteAttack; - value = (infiniteAttack ? 1 : 0); - } - - // returns TRUE if this should die - public boolean age(double ms) { - if (!hasPeaked) { - value = value + (float) (ms / 1000.0f * ((attackParameter.getValuef() + 0.01f) * 5)); - if (value >= 1.0f) { - value = 1.0f; - hasPeaked = true; - } - return false; - } else { - value = value - (float) (ms / 1000.0f * ((decayParameter.getValuef() + 0.01f) * 10)); - return value <= 0; - } - } - } - - private float leftoverMs = 0; - private List flashes; - - public TimCubes(GLucose glucose) { - super(glucose); - addParameter(rateParameter); - addParameter(attackParameter); - addParameter(decayParameter); - addParameter(hueParameter); - addParameter(hueVarianceParameter); - addParameter(saturationParameter); - flashes = new LinkedList(); - } - - public void run(double deltaMs) { - leftoverMs += deltaMs; - float msPerFlash = 1000 / ((rateParameter.getValuef() + .01f) * 100); - while (leftoverMs > msPerFlash) { - leftoverMs -= msPerFlash; - flashes.add(new CubeFlash()); - } - - for (Point p : model.points) { - colors[p.index] = 0; - } - - for (CubeFlash flash : flashes) { - float hue = (hueParameter.getValuef() + (hueVarianceParameter.getValuef() * flash.hue)) % 1.0f; - int c = lx.hsb(hue * 360, saturationParameter.getValuef() * 100, (flash.value) * 100); - for (Point p : flash.c.points) { - colors[p.index] = c; - } - } - - Iterator i = flashes.iterator(); - while (i.hasNext()) { - CubeFlash flash = i.next(); - boolean dead = flash.age(deltaMs); - if (dead) { - i.remove(); - } - } - } -} - -/** - * This one is the best but you need to play with all the knobs. It's synced to - * the tempo, with the WSpd knob letting you pick 4 discrete multipliers for - * the tempo. - * - * Basically it's just 3 planes all rotating to the beat, but also rotated relative - * to one another. The intersection of the planes and the cubes over time makes - * for a nice abstract effect. - */ -class TimPlanes extends SCPattern { - private BasicParameter wobbleParameter = new BasicParameter("Wob", 0.166f); - private BasicParameter wobbleSpreadParameter = new BasicParameter("WSpr", 0.25f); - private BasicParameter wobbleSpeedParameter = new BasicParameter("WSpd", 0.375f); - private BasicParameter wobbleOffsetParameter = new BasicParameter("WOff", 0); - private BasicParameter derezParameter = new BasicParameter("Drez", 0.5f); - private BasicParameter thicknessParameter = new BasicParameter("Thick", 0.4f); - private BasicParameter ySpreadParameter = new BasicParameter("ySpr", 0.2f); - private BasicParameter hueParameter = new BasicParameter("Hue", 0.75f); - private BasicParameter hueSpreadParameter = new BasicParameter("HSpr", 0.68f); - - final float centerX, centerY, centerZ; - float phase; - - class Plane { - Vector3 center; - Rotation rotation; - float hue; - - Plane(Vector3 center, Rotation rotation, float hue) { - this.center = center; - this.rotation = rotation; - this.hue = hue; - } - } - - TimPlanes(GLucose glucose) { - super(glucose); - centerX = (model.xMin + model.xMax) / 2; - centerY = (model.yMin + model.yMax) / 2; - centerZ = (model.zMin + model.zMax) / 2; - phase = 0; - addParameter(wobbleParameter); - addParameter(wobbleSpreadParameter); - addParameter(wobbleSpeedParameter); -// addParameter(wobbleOffsetParameter); - addParameter(derezParameter); - addParameter(thicknessParameter); - addParameter(ySpreadParameter); - addParameter(hueParameter); - addParameter(hueSpreadParameter); - } - - int beat = 0; - float prevRamp = 0; - float[] wobbleSpeeds = { 1.0f/8, 1.0f/4, 1.0f/2, 1.0f }; - - public void run(double deltaMs) { - float ramp = (float)lx.tempo.ramp(); - if (ramp < prevRamp) { - beat = (beat + 1) % 32; - } - prevRamp = ramp; - - float wobbleSpeed = wobbleSpeeds[floor(wobbleSpeedParameter.getValuef() * wobbleSpeeds.length * 0.9999f)]; - - phase = (((beat + ramp) * wobbleSpeed + wobbleOffsetParameter.getValuef()) % 1) * 2 * PI; - - float ySpread = ySpreadParameter.getValuef() * 50; - float wobble = wobbleParameter.getValuef() * PI; - float wobbleSpread = wobbleSpreadParameter.getValuef() * PI; - float hue = hueParameter.getValuef() * 360; - float hueSpread = (hueSpreadParameter.getValuef() - 0.5f) * 360; - - float saturation = 10 + 60.0f * pow(ramp, 0.25f); - - float derez = derezParameter.getValuef(); - - Plane[] planes = { - new Plane( - new Vector3(centerX, centerY + ySpread, centerZ), - new Rotation(wobble - wobbleSpread, phase, 0), - (hue + 360 - hueSpread) % 360), - new Plane( - new Vector3(centerX, centerY, centerZ), - new Rotation(wobble, phase, 0), - hue), - new Plane( - new Vector3(centerX, centerY - ySpread, centerZ), - new Rotation(wobble + wobbleSpread, phase, 0), - (hue + 360 + hueSpread) % 360) - }; - - float thickness = (thicknessParameter.getValuef() * 25 + 1); - - Vector3 normalizedPoint = new Vector3(); - - for (Point p : model.points) { - if (random(1.0f) < derez) { - continue; - } - - int c = 0; - - for (Plane plane : planes) { - normalizedPoint.x = p.x - plane.center.x; - normalizedPoint.y = p.y - plane.center.y; - normalizedPoint.z = p.z - plane.center.z; - - float v = plane.rotation.rotatedY(normalizedPoint); - float d = abs(v); - - final int planeColor; - if (d <= thickness) { - planeColor = lx.hsb(plane.hue, saturation, 100); - } else if (d <= thickness * 2) { - float value = 1 - ((d - thickness) / thickness); - planeColor = lx.hsb(plane.hue, saturation, value * 100); - } else { - planeColor = 0; - } - - if (planeColor != 0) { - if (c == 0) { - c = planeColor; - } else { - c = blendColor(c, planeColor, ADD); - } - } - } - - colors[p.index] = c; - } - } -} - -/** - * Two spinning wheels, basically XORed together, with a color palette that should - * be pretty easy to switch around. Timed to the beat; also introduces "clickiness" - * which makes the movement non-linear throughout a given beat, giving it a nice - * dance feel. I'm not 100% sure that it's actually going to look like it's _on_ - * the beat, but that should be easy enough to adjust. - * - * It's particularly nice to turn down the clickiness and turn up derez during - * slow/beatless parts of the music and then revert them at the drop :) But maybe - * I shouldn't be listening to so much shitty dubstep while making these... - */ -class TimPinwheels extends SCPattern { - private BasicParameter horizSpreadParameter = new BasicParameter("HSpr", 0.75f); - private BasicParameter vertSpreadParameter = new BasicParameter("VSpr", 0.5f); - private BasicParameter vertOffsetParameter = new BasicParameter("VOff", 1.0f); - private BasicParameter zSlopeParameter = new BasicParameter("ZSlp", 0.6f); - private BasicParameter sharpnessParameter = new BasicParameter("Shrp", 0.25f); - private BasicParameter derezParameter = new BasicParameter("Drez", 0.25f); - private BasicParameter clickinessParameter = new BasicParameter("Clic", 0.5f); - private BasicParameter hueParameter = new BasicParameter("Hue", 0.667f); - private BasicParameter hueSpreadParameter = new BasicParameter("HSpd", 0.667f); - - float phase = 0; - private final int NUM_BLADES = 12; - - class Pinwheel { - Vector2 center; - int numBlades; - float realPhase; - float phase; - float speed; - - Pinwheel(float xCenter, float yCenter, int numBlades, float speed) { - this.center = new Vector2(xCenter, yCenter); - this.numBlades = numBlades; - this.speed = speed; - } - - public void age(float numBeats) { - int numSteps = numBlades; - - realPhase = (realPhase + numBeats / numSteps) % 2.0f; - - float phaseStep = floor(realPhase * numSteps); - float phaseRamp = (realPhase * numSteps) % 1.0f; - phase = (phaseStep + pow(phaseRamp, (clickinessParameter.getValuef() * 10) + 1)) / (numSteps * 2); -// phase = (phase + deltaMs / 1000.0 * speed) % 1.0; - } - - public boolean isOnBlade(float x, float y) { - x = x - center.x; - y = y - center.y; - - float normalizedAngle = (atan2(x, y) / (2 * PI) + 1 + phase) % 1; - float v = (normalizedAngle * 4 * numBlades); - int blade_num = floor((v + 2) / 4); - return (blade_num % 2) == 0; - } - } - - private final List pinwheels; - private final float[] values; - - TimPinwheels(GLucose glucose) { - super(glucose); - - addParameter(horizSpreadParameter); -// addParameter(vertSpreadParameter); - addParameter(vertOffsetParameter); - addParameter(zSlopeParameter); - addParameter(sharpnessParameter); - addParameter(derezParameter); - addParameter(clickinessParameter); - addParameter(hueParameter); - addParameter(hueSpreadParameter); - - pinwheels = new ArrayList(); - pinwheels.add(new Pinwheel(0, 0, NUM_BLADES, 0.1f)); - pinwheels.add(new Pinwheel(0, 0, NUM_BLADES, -0.1f)); - - this.updateHorizSpread(); - this.updateVertPositions(); - - values = new float[model.points.size()]; - } - - public void onParameterChanged(LXParameter parameter) { - if (parameter == horizSpreadParameter) { - updateHorizSpread(); - } else if (parameter == vertSpreadParameter || parameter == vertOffsetParameter) { - updateVertPositions(); - } - } - - private void updateHorizSpread() { - float xDist = model.xMax - model.xMin; - float xCenter = (model.xMin + model.xMax) / 2; - - float spread = horizSpreadParameter.getValuef() - 0.5f; - pinwheels.get(0).center.x = xCenter - xDist * spread; - pinwheels.get(1).center.x = xCenter + xDist * spread; - } - - private void updateVertPositions() { - float yDist = model.yMax - model.yMin; - float yCenter = model.yMin + yDist * vertOffsetParameter.getValuef(); - - float spread = vertSpreadParameter.getValuef() - 0.5f; - pinwheels.get(0).center.y = yCenter - yDist * spread; - pinwheels.get(1).center.y = yCenter + yDist * spread; - } - - private float prevRamp = 0; - - public void run(double deltaMs) { - float ramp = lx.tempo.rampf(); - float numBeats = (1 + ramp - prevRamp) % 1; - prevRamp = ramp; - - float hue = hueParameter.getValuef() * 360; - // 0 -> -180 - // 0.5 -> 0 - // 1 -> 180 - float hueSpread = (hueSpreadParameter.getValuef() - 0.5f) * 360; - - float fadeAmount = (float) (deltaMs / 1000.0f) * pow(sharpnessParameter.getValuef() * 10, 1); - - for (Pinwheel pw : pinwheels) { - pw.age(numBeats); - } - - float derez = derezParameter.getValuef(); - - float zSlope = (zSlopeParameter.getValuef() - 0.5f) * 2; - - int i = -1; - for (Point p : model.points) { - ++i; - - int value = 0; - for (Pinwheel pw : pinwheels) { - value += (pw.isOnBlade(p.x, p.y - p.z * zSlope) ? 1 : 0); - } - if (value == 1) { - values[i] = 1; -// colors[p.index] = lx.hsb(120, 0, 100); - } else { - values[i] = max(0, values[i] - fadeAmount); - //color c = colors[p.index]; - //colors[p.index] = lx.hsb(max(0, lx.h(c) - 10), min(100, lx.s(c) + 10), lx.b(c) - 5 ); - } - - if (random(1.0f) >= derez) { - float v = values[i]; - colors[p.index] = lx.hsb((360 + hue + pow(v, 2) * hueSpread) % 360, 30 + pow(1 - v, 0.25f) * 60, v * 100); - } - } - } -} - -/** - * This tries to figure out neighboring pixels from one cube to another to - * let you have a bunch of moving points tracing all over the structure. - * Adds a couple seconds of startup time to do the calculation, and in the - * end just comes out looking a lot like a screensaver. Probably not worth - * it but there may be useful code here. - */ -class TimTrace extends SCPattern { - private Map> pointToNeighbors; - private Map pointToStrip; - // private final Map> stripToNearbyStrips; - - int extraMs; - - class MovingPoint { - Point currentPoint; - float hue; - private Strip currentStrip; - private int currentStripIndex; - private int direction; // +1 or -1 - - MovingPoint(Point p) { - this.setPointOnNewStrip(p); - hue = random(360); - } - - private void setPointOnNewStrip(Point p) { - this.currentPoint = p; - this.currentStrip = pointToStrip.get(p); - for (int i = 0; i < this.currentStrip.points.size(); ++i) { - if (this.currentStrip.points.get(i) == p) { - this.currentStripIndex = i; - break; - } - } - if (this.currentStripIndex == 0) { - // we are at the beginning of the strip; go forwards - this.direction = 1; - } else if (this.currentStripIndex == this.currentStrip.points.size()) { - // we are at the end of the strip; go backwards - this.direction = -1; - } else { - // we are in the middle of a strip; randomly go one way or another - this.direction = ((random(1.0f) < 0.5f) ? -1 : 1); - } - } - - public void step() { - List neighborsOnOtherStrips = pointToNeighbors.get(this.currentPoint); - - Point nextPointOnCurrentStrip = null; - this.currentStripIndex += this.direction; - if (this.currentStripIndex >= 0 && this.currentStripIndex < this.currentStrip.points.size()) { - nextPointOnCurrentStrip = this.currentStrip.points.get(this.currentStripIndex); - } - - // pick which option to take; if we can keep going on the current strip then - // add that as another option - int option = floor(random(neighborsOnOtherStrips.size() + (nextPointOnCurrentStrip == null ? 0 : 100))); - - if (option < neighborsOnOtherStrips.size()) { - this.setPointOnNewStrip(neighborsOnOtherStrips.get(option)); - } else { - this.currentPoint = nextPointOnCurrentStrip; - } - } - } - - List movingPoints; - - TimTrace(GLucose glucose) { - super(glucose); - - extraMs = 0; - - pointToNeighbors = this.buildPointToNeighborsMap(); - pointToStrip = this.buildPointToStripMap(); - - int numMovingPoints = 1000; - movingPoints = new ArrayList(); - for (int i = 0; i < numMovingPoints; ++i) { - movingPoints.add(new MovingPoint(model.points.get(floor(random(model.points.size()))))); - } - - } - - private Map> buildStripToNearbyStripsMap() { - Map stripToCenter = new HashMap(); - for (Strip s : model.strips) { - Vector3 v = new Vector3(); - for (Point p : s.points) { - v.add(p.x, p.y, p.z); - } - v.divide(s.points.size()); - stripToCenter.put(s, v); - } - - Map> stripToNeighbors = new HashMap(); - for (Strip s : model.strips) { - List neighbors = new ArrayList(); - Vector3 sCenter = stripToCenter.get(s); - for (Strip potentialNeighbor : model.strips) { - if (s != potentialNeighbor) { - float distance = sCenter.distanceTo(stripToCenter.get(potentialNeighbor)); - if (distance < 25) { - neighbors.add(potentialNeighbor); - } - } - } - stripToNeighbors.put(s, neighbors); - } - - return stripToNeighbors; - } - - private Map> buildPointToNeighborsMap() { - Map> m = new HashMap(); - Map> stripToNearbyStrips = this.buildStripToNearbyStripsMap(); - - for (Strip s : model.strips) { - List nearbyStrips = stripToNearbyStrips.get(s); - - for (Point p : s.points) { - Vector3 v = new Vector3(p.x, p.y, p.z); - - List neighbors = new ArrayList(); - - for (Strip nearbyStrip : nearbyStrips) { - Point closestPoint = null; - float closestPointDistance = 100000; - - for (Point nsp : nearbyStrip.points) { - float distance = v.distanceTo(nsp.x, nsp.y, nsp.z); - if (closestPoint == null || distance < closestPointDistance) { - closestPoint = nsp; - closestPointDistance = distance; - } - } - - if (closestPointDistance < 15) { - neighbors.add(closestPoint); - } - } - - m.put(p, neighbors); - } - } - - return m; - } - - private Map buildPointToStripMap() { - Map m = new HashMap(); - for (Strip s : model.strips) { - for (Point p : s.points) { - m.put(p, s); - } - } - return m; - } - - public void run(double deltaMs) { - for (Point p : model.points) { - int c = colors[p.index]; - colors[p.index] = lx.hsb(lx.h(c), lx.s(c), lx.b(c) - 3); - } - - for (MovingPoint mp : movingPoints) { - mp.step(); - colors[mp.currentPoint.index] = blendColor(colors[mp.currentPoint.index], lx.hsb(mp.hue, 10, 100), ADD); - } - } -} -class GlitchPlasma extends SCPattern { - private int pos = 0; - private float satu = 100; - private float speed = 1; - private float glitch = 0; - BasicParameter saturationParameter = new BasicParameter("SATU", 1.0f); - BasicParameter speedParameter = new BasicParameter("SPEED", 0.1f); - BasicParameter glitchParameter = new BasicParameter("GLITCH", 0.0f); - - public GlitchPlasma(GLucose glucose) { - super(glucose); - addParameter(saturationParameter); - addParameter(speedParameter); - addParameter(glitchParameter); - } - public void onParameterChanged(LXParameter parameter) { - if (parameter == saturationParameter) { - satu = 100*parameter.getValuef(); - } else if (parameter == speedParameter) { - speed = 8*parameter.getValuef(); - } else if (parameter == glitchParameter) { - glitch = parameter.getValuef(); - } - } - - public void run(double deltaMs) { - for (Point p : model.points) { - float hv = sin(dist(p.x + pos, p.y, 128.0f, 128.0f) / 8.0f) - + sin(dist(p.x, p.y, 64.0f, 64.0f) / 8.0f) - + sin(dist(p.x, p.y + pos / 7, 192.0f, 64.0f) / 7.0f) - + sin(dist(p.x, p.z + pos, 192.0f, 100.0f) / 8.0f); - float bv = 100; - colors[p.index] = lx.hsb((hv+2)*50, satu, bv); - } - if (random(1.0f)= MAX_INT-1) pos=0; - } -} - -// This is very much a work in progress. Trying to get a flame effect. -class FireEffect extends SCPattern { - private float[][] intensity; - private float hotspot; - private float decay = 0.3f; - private int xm; - private int ym; - BasicParameter decayParameter = new BasicParameter("DECAY", 0.3f); - - public FireEffect(GLucose glucose) { - super(glucose); - xm = PApplet.parseInt(model.xMax); - ym = PApplet.parseInt(model.yMax); - - intensity = new float[xm][ym]; - addParameter(decayParameter); - } - public void onParameterChanged(LXParameter parameter) { - if (parameter == decayParameter) { - decay = parameter.getValuef(); - } - } - private int flameColor(float level) { - if (level<=0) return lx.hsb(0,0,0); - float br=min(100,sqrt(level)*15); - return lx.hsb(level/1.7f,100,br); - } - public void run(double deltaMs) { - for (int x=10;x45 || x%50<5) { - intensity[x][ym-1] = random(30,100); - } else { - intensity[x][ym-1] = random(0,50); - } - } - for (int x=1;xbright[p.index]) { - colors[p.index] = lx.hsb(hv,sat[i].getValuef(),br); - bright[p.index] = br; - } - } - } - } - } -} - -class SoundRain extends SCPattern { - - private FFT fft = null; - private LinearEnvelope[] bandVals = null; - private float[] lightVals = null; - private int avgSize; - private float gain = 25; - SawLFO pos = new SawLFO(0, 9, 8000); - SinLFO col1 = new SinLFO(0, model.xMax, 5000); - BasicParameter gainParameter = new BasicParameter("GAIN", 0.5f); - - public SoundRain(GLucose glucose) { - super(glucose); - addModulator(pos).trigger(); - addModulator(col1).trigger(); - addParameter(gainParameter); - } - - public void onParameterChanged(LXParameter parameter) { - if (parameter == gainParameter) { - gain = 50*parameter.getValuef(); - } - } - protected void onActive() { - if (this.fft == null) { - this.fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate()); - this.fft.window(FFT.HAMMING); - this.fft.logAverages(40, 1); - this.avgSize = this.fft.avgSize(); - this.bandVals = new LinearEnvelope[this.avgSize]; - for (int i = 0; i < this.bandVals.length; ++i) { - this.addModulator(this.bandVals[i] = (new LinearEnvelope(0, 0, 700+i*4))).trigger(); - } - lightVals = new float[avgSize]; - } - } - - public void run(double deltaMs) { - this.fft.forward(this.lx.audioInput().mix); - for (int i = 0; i < avgSize; ++i) { - float value = this.fft.getAvg(i); - this.bandVals[i].setEndVal(value,40).trigger(); - float lv = min(value*gain,100); - if (lv>lightVals[i]) { - lightVals[i]=min(lightVals[i]+15,lv,100); - } else { - lightVals[i]=max(lv,lightVals[i]-5,0); - } - } - for (Cube c : model.cubes) { - for (int j=0; jlightVals[i]) { - lightVals[i]=min(lightVals[i]+30,lv,model.yMax+10); - } else { - lightVals[i]=max(lv,lightVals[i]-10,0); - } - } - int i = 0; - for (Cube c : model.cubes) { - for (int j=0; javgSize) seq=avgSize-seq; - seq=constrain(seq,0,avgSize-1); - float br=max(0, lightVals[seq]-p.y); - colors[p.index] = lx.hsb((dis*avgSize*65)/model.xMax,90,br); - } - } - } - } - } -} - - static public void main(String[] passedArgs) { - String[] appletArgs = new String[] { "SugarCubes" }; - if (passedArgs != null) { - PApplet.main(concat(appletArgs, passedArgs)); - } else { - PApplet.main(appletArgs); - } - } -} diff --git a/code/HeronLX.jar b/code/HeronLX.jar index 4e0447cf95d58c97af7f1f9a9571a639a872b65c..82e1dd9b09afc1c908a78c6eacb60e609904c79c 100755 GIT binary patch delta 5545 zcmZWs30%$D7k}ryw%1;-QmCj%ixiEb$W}B+LXs9sW2D6}*;12+30cCEYh=rA5)z)# z5Hcibp{7WsP1+YFMfJbS>&-m>KA&IbchC8r?>YD0bIk&*sS}aySYc z&f}zm%4Xb*q=R;GL+Y-2j!o0(ZLSL?;m_?YLBQK0&!vyX)qRr#l5P`91iW|tHax0J(TJoreJur}*!Lx) z?{15=(RB`)Gbi@gvb@&uS$92A$SbQSpDiMc*Hk8raj7_OGWj#_t9GAeTTa+&h+ekh z)!W~<)}9>qWAnYH-171$&e11xxZ@T1=iIf@4q5NF{$csZ9e*w>`zqV5QRckdM@gu2 zK{vbMR@8N!(q+1%JpJ2?-l}Z=kft<0Ri`KQyt7=DTjcANx^HVYyB@!&W7OAJ=(yIg zavm@Dk!>V@QP3m>y^a-uyNCbNZd5T>3w>WW$S>8PeO1Bw?RKHt?Yd(JZJFD(@t(nE z$A~-nN8`DsdX+MM)ep@Btid0YliSH*`=ivYH_Qs}bd9^SGv%PmDQgt$^W@ULXA9S7^^7cznWMpvG*9Gi_t>^~fx#9vi;sFP;et0Ya~ez? zZG%d5?A4RrWSxpB2ZP^!p<7e3(b?Y-A%h`n#u@iK?Tr z7mXO#puBd^>Ws~eS2j)Mtmo$jP^{86CuxC>cp1_j8TJG$1v;=oZs*UMoBUboV1%yv(hU9CSS z{pA|XC*fU-I*+(`pUBmmwJX!%H^<5#!?ZZpMzgH1`_FthQ53LNBY$(3k+0_OZi)M< z!)tR})dpI(0*5rF)FfX|f2(g=Q_UP5D-%cH01c*0p97krvt@`QQswU0D_94c!D zJ&}W8{iaIAKrg2N-Gyiyp8~SrDn&JuuqNXX(M^kH>1|R54(G2DzQkV(mG!S4{S^iZqKNe{l;V$t z0qyl7*>Gs5n(hd=N`qY925(4^-=e{bG(1sx46I;#G3`(DgoT)MoQ&|HvH%$d<1ew= zS5Osgh!t;X;a;F!SyUef59oZa9E2`Pa~{Dh8p-DvJfkMlA~$c+N^X9Kw}AiEdLzWxO`k#TPh3`Mywz(g|8$YBG!9GFa$n{pV^ zDHkIPa==uKr1V%hos4(n;)8)D1y$uTka8Z(AWDxsa3u0T9=H&R^+Qod9*iObgM1do zFP|};&4-yp-?uKeuw`f4LkMlQH)l(=U4m{$%{{9e5L| zU%~uC#WKBu%}-Ft_yQ~0y56pY1q82D#qd62nOub%0@n9ev3V@6W_ew#X7RZ-;7jbw zYgpVzHL&=bTLm(G4|9i+-o6?FgRJm*RFUCutndwQ;O|^?>w95EsUAvx55^RE;i3Q7 zjkueg!)S{E7?$Uv*VIuYzZQm(xE8gzLzp!P54H|LIkljOLTh0JrKouDa;Y zT(=WN*TE!0@_>*ud?M>0{P0O1tsY42WKCL|9rjMckC~LWZ4a7K4|c?ROFj0!@r8_a z(Y1QEjQLo}^Wi}JR2YYX>Oq+xZ5psLn+GU`2V+oF1Jmv!S~WQkR&aHYq8tpO_~B%K zV~*yxx8k@z;rQlK@wX^2{Ln@iPN1L_1QI7x3RS#acqS45BHXFY;f$1mZqb%Nl~9y6{zebX`S&Iq z-p_!T2cg_17(tnuWW5LL<4NtukEIloml0#KXa-|4G52QdpKi>Qca8CfY+&6k6N{=T zv*0TMt36|t!}=Uq4rdpx0qHF}ZH8>xK#Tlzlt-t`KpnZYupRJe!8=%MB{A#L)iESH zP+?`xUx8QVh|0J1^B2l*VI5kd6}t!7O5D}af>zL^wH@o*U#ExXxE((uq~@7nFTu;B z)2*OOCVLk%;UCe~Z7>As<0}eU)&|Nnj~4hIeYT6j3LE)6Ym~8_q*<65$;u$gg28|s;Oo0k#;blxizbWzKg?DW%!Y%)Sf~(1|z?AR$S5T*u6!p#P=XAninB1 zAr`&q48HawF1v)!AfWU$vqF7KamF>cWsH}~nCC3Pn-h|RkC?=ErbMZRDnG&?V);TW z%UmTERpi|!UfGv^U!J97dLE{iuAsSY48N~~9mQ)Mn8edvqEta09iT(#l{>NJlE;56 zDQ{TdHN;ZCKw?owS3AXlp)fNz9?z!&Kho#rs29Wcbh3-Wuuqs|>k_8ivIHM&vYjMw zB(eB-GmE!3F6sfxYhrO&$}DcaxJV@ndaC=mi8|i?8Mqwnq!!fOm*GRZz=AGl7bdyo zFCkI;ciGhDclRB_&gK7?{nC{TZ}k~WXvuBJ8tjpYSJ(`%u=K~p0j>MYI_LGzIMTdT z%=7wcP(@2u;hgt<6qjxCvzy2o`}g4!DZNWKkWDu@kZeP{@j12(2BZ-TdKTX{@PDtd z9FD2ftbalI-R$nh@4*aD!YG3P-46o|G^dBHv^O!?go{mkdte9&d6{TOM2fZgk)VPu zRf_welbqkZL>wp^Kl)Mu3%7|KUTgy;Nrb6iFjq>n*mOA>H`u5z;?7P?N;}1-bUY%# zONn-EtXPY$&-6oP@fB-f-@jTp)V~+^(ZH|b&*Y2mLUG zMjmP{t6hcDt5g2A8gs7`zESbBxSBXdybpIM_p6Ag3{k%bZ?@z{AWTrYuY!wNhX3t7 zsxFP@8Q;vMC8h+J!|5T>X`xBLHKiGNf&IuI@cKJoib+ywo_;KWYN0E@r5`{1;~V$C TrxJ?*>2SF^a$BX&EI&lA0J(3Y8WN@hC|lLo*X)oo3N66^5DAkYBk*_Gv6L zm8Id?8RM@kC1p#JNNJ&>MGO7!x%X*$Gd`c^y!-v0^F8OD-@W&Ddo}B{j;+&@$tOwG zbOb?55ZuLN*$|1FnC!9%|IZzO|JM$p|BHrzgg6$Q(Ch_E@n_KIUq3`s1dg1y6qjw( z=%GouG>N5HkfI~bk?1Ic$+D-QDQ@E9G|32r3nb2Hs57y02X#^~1k^SEhr1n!lE7x7X>~Wbt^l}q}eeNy1bh|GI z!cp;}%re_iZxEw{dQW5aP@h0%yY#$CG2%NpN&h;K4&)PLcRtTO0Im)#$CCI zOeg7@K8xRz@5b!D_6~39ovu8YvNkC^b=D zF(Ni8(0^%>XP?!P?q6?rvrM0;`{$|@&kx)|s_Clc6|Z$@y3Pb&^=Bvg7|OB?iyg;x z>MSuD_vD(o*LM?b^*V*`)i10Y9{DhR*up!hBhQR*ug^;>O^toq)@XR~tJ!&0YjsU0 z@3Rgv`Qen!jWsb8xG_TKipM!?$t?Rm6fwae)|d2H5+xvv!uTTYf8pSka1^O;^> zrh1(!t96wXEjUp!-{Xuyqsh{(E4#E~Uyd?c)TDo{mt~u5#hs`T>Ei|)%suzu*KTrdYh3nq`=C^s^6VyIY@Yj`A6O>3Ko2$^NXT!z-g_ z$7e1G%DA@e?sB~<)5Hb#^G+_0XxwV<_p?*}>O|T4OMjW0$0qqNPg>}9rXsPZeAz;a z;*Nt0Zg`({cOG={;A@9si`gf<3pDqb5cht}8t$Woud6B7fa@4zy*iQBLr?ZwoS7~SEw``StU40H$->)NU z*&=kQ6LE2hH|lHAoN8bjKCAH}uIy#6ji(%%UVqF$~OWMX}aZ$5$`_T{E4 zgrG1P>IS!w0e3J&U1B^2?jz7JhQ6i{7~si)4o|RSnQgt{IV-BSFLzORjt6^2MNNcS zrax;6XfkBJ9OM#K<}$lU*P3XV8-blVSf(zq3Iv&=W;*CF!Il8X;5#4gCNLT@Wj4F%RyJ*kmh`p_NIL5;)FVv@|=>H5u#$`Cq!lQD)R9)gu`+NgN(K(V!H^39ES{~r_g1F=XULMHOJkB4^ z2Mcl~4+bJQ351fn&%3;t-s?{dA& zyS%<;r5$sR`~P^4*PDNj>-N9T$Km&38pbQ`!*sN|#hec<=6F^yOhvq_7=qExdcg6F z2Ry%|g!@k~;dSgS;rZ%H_&j_bay~_AD;~lu)bS|g{Yg^Vl2Wec{D}LRpi>(R$tY^^tCl1L;W@l^wXYOoQ$5FyA{Ns@v3{hg2CUFeyA~{@HUfy{664fO@B!&i3M@n-Mal@$B?VJr z^%7(Qa1uFjvPD+($`&UT1P7H#+*9ZN?X|q$mUUFbON)aUT3|%dij*SZGe25vq$vo^ zdV*l1BC=9j>0ifNd=*6s`f%`F9av)BmM(==Yu=bCD_a;LIdX zWeS|-DP$C$oU!#%im~KlW=8hgMK|U}y5<~JW>7v3{n;yG>1!H)-3P}*$OK>LO~$q< ziy!xw^yxzypG(*4aFzH@KhpRbJlT^U45f{?*ARqZ zDlJ(}8d~|Yb9_U?2QJ{*zIemWjzk2d;mR4d(FYnA4w|gjnDRN&CZBiH_6SaHqhL%# zH>gKGc?AY+njX!g?JQ^w*JOgwPo<8gND|*k*W3LzzM<++#BT)$`?vGCd$m*W=V%UQ ztpE+u8BOoDksZn>@8)mjf1Ez~Li(TvsK~di;0Rivl}eaP0*09pf7%3=A-nJRCB@WrH_gyr#r0|;y5f&ZYoI22h z>3FByy$;c9e`})W$~xLo)pO+}aqa>y*36>VhzrKl=>`3aQt3lyW)IOLUF?TLQqo1! zEj+Bs=%!jr@EVZnCb5u^BdVlMYMg{$E~?MU8V}Hwah0}RwdI#nk4junpoR(@J<~&g z{;X%t_Gv