/**
*
Esfera mod by spxl
*
*
* Based on Esfera.pde by David Pena
*
* v6 - Multicolour! Timewarp!
*
* Mouse:
*
* - Orientation of the object is based on mouse X,Y;
* - Click/drag to move object (smoothly) to mouse X,Y;
-
*
- To jump to mouse position, press [j];
* - Mouse Y-position used for zoom setting when [q] is pressed.
*
* Keys:
*
* - (a)gitation toggle (refers to variable "heartbeat" dependant on mouse movement);
* - (h)airs display toggle;
* - (l)ights display toggle;
* - (p)etals display toggle;
* - (s)phere display toggle;
* - (t)entacles display toggle;
* - (T)entacles noise (randomness) toggle;
* - [y]/[u]/[i] Timewarp: slowdown x4 / speedup x2 /r everse;
* - [q] Set zoom (scale) factor based on mouse Y-value;
* - (j)ump to mouse location;
* - [LEFT]/[RIGHT] or [z]..[m] to select parameter;
* - [UP]/[DOWN] or [1]..[9] to adjust period;
* - [0] or [SPACE] to toggle parameter paused;
* - [BACKSPACE] to reverse parameter direction;
* - [,][.][/][?] to set wave shape (sin, triangle, sawtooth, square);
* - [[] []] decrease/increase wave amplitude;
* - [{] [}] decrease/increase wave median value;
* - [-] [=] decrease/increase wave period;
* - [_] [+] decrease/increase all periods;
* - [F1] toggle display of current oscillator information;
* - [F2] toggle display of text petals;
* - [F3] toggle display of "binary code" on tentacles;
* - ..and maybe some I missed!
*
*/
/*
* Modifications by subpixel:
* v1:
* removal of unused global arrays;
* calculate end point of a hair as the hairLength distance from the hair base, not as a point at a fixed distance from the centre of the sphere (which causes hairs to stretch);
* reverse Ymouse reactivity so ball spins in the direction of mouse movement instead of against it;
* added start/pause functionality on mouse click event
* v2: 2008-11-09
* renamed/repurposed some identifiers
* Globals: cuantos -> NUM_HAIRS, lista[] -> HAIRS[], radio -> BASE_RADIUS,
* hairmin/max -> MIN/MAX_HAIR_LENGTH, rx/ry -> RX/RY
* class pelo -> class Hair
* dibujar() -> draw()
* new class Oscillator
* Oscillator introduced for the radius of the inner sphere, the base of the "outer sphere" (the hairs),
* and also the number of hairs displayed.
* The inner sphere is now red so you can see it
* Moving the mouse increases the "heart rate" of the inner sphere (which gradually slows down)
* Moving the mouse also increases the base radius of the outer sphere based on the speed
* v3: 2008-11-17
* Extracted class Hair and class Oscillator to separate files.
* Removed redundant FRAME variable (can use global frameCount if necessary)
* Added some keyboard controls.
* [up]/[down] control outer sphere osciallation step
* [z] toggles pause for inner sphere oscillator
* [x] toggles pause for outer sphere oscillator
* [c] toggles pause for hair count osciallator
* Added some 3D text
* Added some snaking tentacles; three new osciallators control parameters.
* v4: 2008-11-24
* MASSIVE CHANGES!
* Move references to outerOscillator.value and millis() out of Hair class
* Oscillators now based around a period instead of a phase step.
* Oscillator.tick() now requires a parameter for the number of milliseconds that have passed
* 8 "Hello" petals replaced by details of available oscillators.
* Concept of a "selected" oscillator, which can be manipulated by keyboard input:
* Selected oscillator details shown at top-left of window
* Selected oscillator hilighted a different coloured "petal" around the inner sphere
* [LEFT]/[RIGHT] to select previous/next oscillator
* [z],[x],..[m] to directly select an oscillator
* [UP]/[DOWN] to increase/decrese the oscillation period
* [1]..[9] to directly set the period to 1..9 seconds
* [0] to pause
* [SPACE] to toggle pause/unpause
* [BACKSPACE] to toggle backwards/forwards direction
* v5: 2008-12-11 Lights!
* v6: 2008-12-18 Multicolour!
* Use a specific number of point lights
* Oscillate RGB values for color of tentacles
* Update keyboard controls:
* halve/double period (for current oscillator or all oscillators)
* increase/decrease aplitude by 10%
* increase/decrease median by 10%
* key for square wave changed
* Allow object to be moved around with mouse
* Zooming
* Jump position to mouse
* Jump/move position to random lcation
* Petals/sphere/tentacles display toggle
* Tentacles noise (random variation)
* 2009-01-05 Timewarp! (warps number of milliseconds passing per frame)
*/
import processing.opengl.*;
// ------------------------------------------------------------
// Global variables
// ------------------------------------------------------------
boolean paused = false; // Opening state of the sketch. Set true to open un-paused.
boolean dispInfo = true; // Display information about current oscillator
boolean dispSphere = true; // Display the inner sphere
boolean dispHairs = true; // Display hairs
boolean dispPetals = true; // Display petals
boolean dispLights = true; // Display point lights
boolean dispTentacles = true; // Display the tentacles
boolean dispTTxt = true; // Display tentales text ("binary code")
boolean useAgitation = false; // Sphere agitation on mouse move
boolean useTNoise = true; // Tentacle noise
int numPointLights = 5; // Number of point lights to use
ArrayList oscillators = new ArrayList(); // To keep track of all oscillators
int numOsc; // Used in place of "oscillators.size()"
int clockMillis = 0; // Milliseconds since start of applet to start of current frame
int clockPrevMillis = 0; // Milliseconds since start of applet to start of previous frame
int runMillis = 0; // Milliseconds we have been running (not including when paused)
float timeWarp = 1.0f; // Factor to scale passing time by
int FRAME_RATE = 30; // Max desired frame rate (actual may be less)
int NUM_HAIRS = 800; // Number of hairs
Hair[] HAIRS; // Array/list of hairs
float flingAmount = 0; // Amount to fling hairs outwards by from mouse movement)
float BASE_RADIUS; // Radius of the sphere
float MIN_HAIR_LENGTH; // Minimum hair length
float MAX_HAIR_LENGTH; // Maximum hair length
float globalZoom;
float toZoom;
// Sphere origin
float ox;
float oy;
float oz;
// Sphere origin "target"
float tox;
float toy;
float toz;
float RX = 0; // Rotation
float RY = 0; // Rotation
float agitation;
float maxInnerPeriod; // Slowest sphere will pulsate
float minInnerPeriod; // Fastest sphere will pulsate
Oscillator innerOsc; // Oscillator for inner sphere
Oscillator outerOsc; // Oscillator for outer sphere (base of hairs)
Oscillator countOsc; // Oscillator for number of hairs to display
Oscillator tentacleCurl; // Oscillator for the tentacle curl amount
Oscillator tentacleTwist; // Oscillator for the tentacle twist amount
Oscillator tentacleScale; // Oscillator for the scaling of each tentacle. <1 grow smalled, >1 grow larger
Oscillator tentacleNoise; // Oscillator for the control of the noise function for the tentacles
Oscillator spin; // Phase speed for rotation of the petals/tentacles
Oscillator hilightOsc; // Oscillator for positioning the point lights
Oscillator tiltOsc; // Oscillator for petal tilt amount
Oscillator cRed; // Cube colour: red component
Oscillator cGreen; // Cube colour: green component
Oscillator cBlue; // Cube colour: blue component
Oscillator selectedOsc; // Allow modification of the selected oscillator
int selectedOscIndex;
PFont font;
// ------------------------------------------------------------
// Override PApplets init method
// to set the frame to undecorated=true
// ------------------------------------------------------------
void init()
{
// frame.setUndecorated(true); // This doesn't seem to work in Processing 1.0
super.init();
}
// ------------------------------------------------------------
// Main setup method
// ------------------------------------------------------------
void setup()
{
size(1200, 480, OPENGL); // Set the canvas size, and use OpenGL rendering
// set the location of the frame
frame.setLocation(0*screen.width, 0);
frameRate(FRAME_RATE);
background(0);
if (paused) noLoop(); // Opportunity to open the sketch in a paused state
// Start with the object centred
ox = tox = width / 2;
oy = toy = height / 2;
oz = toz = -width / 3;
globalZoom = toZoom = 1.0;
BASE_RADIUS = height/4; // The central sphere is half the window height (radius therefore 1/4 window height)
MIN_HAIR_LENGTH = BASE_RADIUS * 0.1; // Minimum hair length set proportionally to the sphere radius
MAX_HAIR_LENGTH = BASE_RADIUS * 0.4; // Maximum hair length ser proportionally to the sphere radius
// Set up the outer sphere hairs
HAIRS = new Hair[NUM_HAIRS]; // Initialise the array for the number of hairs
for (int i=0; i < NUM_HAIRS; i++) // For each hair...
{
float phi = random(TWO_PI); // Any angle in 360 degrees
float theta = asin(random(-1, 1));
float hairLength = random(MIN_HAIR_LENGTH, MAX_HAIR_LENGTH);
HAIRS[i] = new Hair(phi, theta, hairLength); // Create a new hair object and save it in the array
}
maxInnerPeriod = 3;
minInnerPeriod = 0.5;
float b = BASE_RADIUS;
oscillators.add(innerOsc = new Oscillator("inner", maxInnerPeriod, 0.2 * b, 0.9 * b));
oscillators.add(outerOsc = new Oscillator("outer", 4, 0.2 * b, 1.2 * b));
oscillators.add(countOsc = new Oscillator("haircount", 5, 0.5 * NUM_HAIRS, 0.5 * NUM_HAIRS));
oscillators.add(tentacleCurl = new Oscillator("curl", 26, PI/12));
oscillators.add(tentacleTwist = new Oscillator("twist", 37, PI/12, 0));
oscillators.add(tentacleScale = new Oscillator("scale", 12, 0.15, 0.9));
oscillators.add(spin = new Oscillator("spin", 128)); // Since there are 8 petals/tentacles
oscillators.add(hilightOsc = new Oscillator("hilight", 1.5, 1000, 990)); // Point light moving up and down selected oscillator text petal
oscillators.add(tiltOsc = new Oscillator("tilt", 8, PI/4, -PI/4)); // Point light moving up and down selected oscillator text petal
oscillators.add(tentacleNoise = new Oscillator("noise", 22, 20, 15));
oscillators.add(cRed = new Oscillator("cRed", 16, 127, 128, 0)); // Cube colour: red component
oscillators.add(cGreen = new Oscillator("cGreen", 12, 127, 128, 0)); // Cube colour: green component
oscillators.add(cBlue = new Oscillator("cBlue", 22, 127, 128, 0)); // Cube colour: blue component
// Start with the first oscillator selected.
selectOscillator(0);
numOsc = oscillators.size();
// Set number of "octaves" for noise function
noiseDetail(3);
// Set up the font for drawing text
font = loadFont("BroadwayBT-Regular-48.vlw");
textFont(font);
// (re)Start the clock! :o)
clockMillis = millis(); // Ignore any time passed up til now.
}
// ------------------------------------------------------------
// Main draw method
// ------------------------------------------------------------
void draw()
{
// Timing calculations
clockPrevMillis = clockMillis;
clockMillis = millis();
int millisSinceLastFrame = clockMillis - clockPrevMillis;
// frameMillis and runMillis are affected by the timeWarp...
int frameMillis = int(millisSinceLastFrame * timeWarp);
runMillis += frameMillis;
// Update the origin
float originMoveAmt = 0.2;
if (abs(timeWarp) < 1.0) originMoveAmt *= sq(timeWarp);
ox = lerp(ox, tox, originMoveAmt);
oy = lerp(oy, toy, originMoveAmt);
oz = lerp(oz, toz, originMoveAmt);
// Update the zoom factor
float zoomChangeAmt = 0.1;
if (abs(timeWarp) < 1.0) zoomChangeAmt *= sq(timeWarp);
globalZoom = lerp(globalZoom, toZoom, zoomChangeAmt);
// Update all of the oscillators
if (frameCount > 1)
for (int i = 0; i < numOsc; i++)
((Oscillator)(oscillators.get(i))).tick(frameMillis);
// Clear the display. Black background.
lights();
background(0);
// Display information about the selected oscillator
if (dispInfo)
{
fill(200, 200, 200);
textAlign(LEFT);
String message = paused ? "PAUSED" : selectedOsc.str();
text(message, 10, 48, 0);
}
// Centre the coordinate system
translate(ox, oy, oz); // Position the coordinate origin at the centre of the window
// Apply zoom factor
scale(globalZoom);
// Ease towards current mouse "position" (orientation determined by mouse position)
float rxp = ((mouseX-(width/2)) * PI / height);
float ryp = (((height/2)-mouseY) * PI / height);
float rotDist = dist(rxp, ryp, RX, RY);
float rotChangeAmt = 0.1;
if (abs(timeWarp) < 1.0) rotChangeAmt *= sq(timeWarp);
RX = lerp(RX, rxp, rotChangeAmt);
RY = lerp(RY, ryp, rotChangeAmt);
rotateY(RX);
rotateX(RY);
// The change in rotation also flings the hairs outwards
float flingChangeAmt = 0.25;
if (abs(timeWarp) < 1.0) flingChangeAmt *= sq(timeWarp);
flingAmount = lerp(flingAmount, rotDist * 40, flingChangeAmt);
// Mouse movement causes the inner sphere to be "agitated"... faster heartbeat
if (useAgitation)
{
float mouseMoveDist = dist(mouseX, mouseY, pmouseX, pmouseY);
agitation = (agitation + mouseMoveDist * 0.1) * 0.97;
innerOsc.setPeriod( minInnerPeriod + (maxInnerPeriod - minInnerPeriod) / ( 1 + agitation ) );
}
// Everything is now decided so time to draw the scene
if (dispLights) addPointLights();
if (dispSphere) drawSphere();
if (dispHairs) drawHairs(flingAmount);
if (dispPetals) drawPetals();
if (dispTentacles) drawTentacles();
}
// ------------------------------------------------------------
// Add point lights just in front of the text petals
// ------------------------------------------------------------
void addPointLights()
{
// pushMatrix();
// Falloff = 1 / (p1 + p2 * d + p3 * d^2)
lightFalloff(0.001, 0, 0.005);
for (int i = 0; i < numPointLights; i += 1)
{
pushMatrix();
rotateZ(TWO_PI * i / numPointLights + spin.phase);
rotateY(tiltOsc.value());
translate(innerOsc.value(), 0, 0);
translate(hilightOsc.value(), 0, 5);
pointLight(255, 255, 255, 0, 0, 0);
popMatrix();
}
// popMatrix();
}
// ------------------------------------------------------------
// Draw inner sphere
// ------------------------------------------------------------
void drawSphere()
{
// pushMatrix();
fill(127, 0, 0); // 50% Red...
noStroke(); // No outline...
sphere( innerOsc.value() );
// popMatrix();
}
// ------------------------------------------------------------
// Draw outer sphere hairs
// ------------------------------------------------------------
void drawHairs(float flingAmount)
{
// pushMatrix();
int displayHairs = round(countOsc.value());
float baseRadius = outerOsc.value() + flingAmount;
for (int i=0; i < displayHairs; i++) // For each hair...
{
HAIRS[i].draw( baseRadius, runMillis ); // Calculate and draw the hair
}
// popMatrix();
}
// ------------------------------------------------------------
// Draw text Petals
// ------------------------------------------------------------
void drawPetals()
{
// pushMatrix();
for (int i = 0; i < numOsc; i++)
{
pushMatrix();
// Add text information about the indexed oscillator sticking out from the edge of the sphere.
// Tilt it towards the "front" a bit so it is kind of like a flower.
float angle = TWO_PI * i / numOsc + spin.phase;
rotateZ(angle);
rotateY(tiltOsc.value());
translate(innerOsc.value(), 0, -15);
if (i == selectedOscIndex)
{
fill (220, 220, 0);
}
else
{
fill(0, 102, 153);
}
textAlign(LEFT);
String message = ((Oscillator)(oscillators.get(i))).str();
text(message, 0, 15, 0);
popMatrix();
}
// popMatrix();
}
// ------------------------------------------------------------
// Draw the tentacles
// ------------------------------------------------------------
void drawTentacles()
{
// pushMatrix();
for (int i = 0; i < numOsc; i++)
{
pushMatrix(); // Remember base matrix of the sphere so we can come back for the next tentacle
// Add a tentacle made up of a sequence of relatively sized/positioned/oriented boxes
float angle = TWO_PI * i / numOsc - spin.phase;
rotateZ(angle);
translate(outerOsc.value(), 0, 0);
int numSegments = 15;
float opacity = 255;
for (int segment = 0; segment < numSegments; segment++)
{
fill(cRed.value(), cGreen.value(), cBlue.value(), opacity);
noStroke(); // No outline...
pushMatrix();
rotateX(PI * 0.25); // Make the tentacles diagonal to the plane that their base is on
box(40);
// "Binary code" displayed on one side of the box
if (dispTTxt)
{
fill(255,255,0);
int altSeg = segment + (int)(spin.value() * 10);
rotateX(HALF_PI * (floor(2 * noise(altSeg * 7731) - 1)));
String txt = (noise(segment, i, altSeg * 10) < 0.5) ? "0" : "1";
text(txt, -20, 20, 21);
}
popMatrix();
// Move along a bit
if (useTNoise)
{
translate(tentacleScale.value() * (tentacleNoise.median + noise(segment, i, tentacleNoise.phase) * (2 * tentacleNoise.amplitude - 1)), 0, 0); // Move along a bit
}
else
{
translate(tentacleScale.value() * (tentacleNoise.median + tentacleNoise.amplitude), 0, 0);
}
rotateZ(tentacleScale.value() * tentacleCurl.value()); // Curl around a bit
rotateX(tentacleScale.value() * tentacleTwist.value()); // Twist a bit
scale(tentacleScale.value()); // Scale each segment relative to the last (may be bigger or smaller depending on oscialltor)
opacity *= 0.95; // Make each segment less opaque than the last
}
popMatrix(); // Go back to base matrix of the sphere for the next tentacle
}
// popMatrix();
}
// ------------------------------------------------------------
// Handle mouse input
// Set the origin based on mouse position when button pressed
// (including click and drag)
// ------------------------------------------------------------
void mousePressed() { originMoveToMouse(); }
void mouseDragged() { originMoveToMouse(); }
// ------------------------------------------------------------
// Handle keyboard input
// ------------------------------------------------------------
void keyPressed()
{
if (key == CODED)
{
println(keyCode);
if (keyCode == 19) { togglePaused(); } // Pause/Break key
else if (keyCode == LEFT) { selectPrevOscillator(); }
else if (keyCode == RIGHT) { selectNextOscillator(); }
else if (keyCode == UP) { setSelectedPeriod(selectedOsc.period + 0.1); }
else if (keyCode == DOWN) { setSelectedPeriod(selectedOsc.period - 0.1); }
else if (keyCode == 112) { dispInfo = !dispInfo; } // F1 toggle display of current oscillator information
else if (keyCode == 113) { dispPetals = !dispPetals; } // F2 toggle display of text petals
else if (keyCode == 114) { dispTTxt = !dispTTxt; } // F3 toggle display of "binary code" on tentacles
}
else if (key == 'y') { timeWarp *= 0.25f; }
else if (key == 'u') { timeWarp *= 2.0f; }
else if (key == 'i') { timeWarp *= -1f; }
else if (key == 's') { dispSphere = !dispSphere; }
else if (key == 'S') { useAgitation = !useAgitation; }
else if (key == 'a') { useAgitation = !useAgitation; }
else if (key == 'A') { useAgitation = false; }
else if (key == 'h') { dispHairs = !dispHairs; }
else if (key == 'p') { dispPetals = !dispPetals; }
else if (key == 'P') { dispPetals = true; }
else if (key == 't') { dispTentacles = !dispTentacles; }
else if (key == 'T') { useTNoise = !useTNoise; }
else if (key == 'l') { dispLights = !dispLights; }
else if (key == 'L') { dispLights = true; }
else if (key == ',') { selectedOsc.waveShape = 0; } // Sine
else if (key == '.') { selectedOsc.waveShape = 1; } // Triangle
else if (key == '/') { selectedOsc.waveShape = 2; } // Sawtooth
else if (key == '?') { selectedOsc.waveShape = 3; } // Square
else if (key == ' ') { selectedOsc.togglePause(); }
else if (key == '-') { selectedOsc.adjustPeriod(0.5); }
else if (key == '=') { selectedOsc.adjustPeriod(2.0); }
else if (key == BACKSPACE) { selectedOsc.reverseDirection(); }
else if (key == '_') { halveAllOscPeriods(); }
else if (key == '+') { doubleAllOscPeriods(); }
else if (key == 'z') { selectOscillator(0); }
else if (key == 'x') { selectOscillator(1); }
else if (key == 'c') { selectOscillator(2); }
else if (key == 'v') { selectOscillator(3); }
else if (key == 'b') { selectOscillator(4); }
else if (key == 'n') { selectOscillator(5); }
else if (key == 'm') { selectOscillator(6); }
else if (key == '[') { selectedOsc.amplitude *= 0.90909; }
else if (key == ']') { selectedOsc.amplitude *= 1.1; }
else if (key == '{') { selectedOsc.median *= 0.90909; }
else if (key == '}') { selectedOsc.median *= 1.1; }
else if (key == '0') { selectedOsc.togglePause(); }
else if (key == ')') { selectedOsc.pause(); }
else if (key == '1') { setSelectedPeriod(1); }
else if (key == '2') { setSelectedPeriod(2); }
else if (key == '3') { setSelectedPeriod(3); }
else if (key == '4') { setSelectedPeriod(4); }
else if (key == '5') { setSelectedPeriod(5); }
else if (key == '6') { setSelectedPeriod(6); }
else if (key == '7') { setSelectedPeriod(7); }
else if (key == '8') { setSelectedPeriod(8); }
else if (key == '9') { setSelectedPeriod(9); }
else if (key == 'j') { originJumpToMouse(); } // Jump origin to mouse location
else if (key == 'o') { originJumpTo(rnd(width), rnd(height)); } // Jump origin to random location
else if (key == 'O') { originMoveTo(rnd(width), rnd(height)); } // Move origin to random location
else if (key == 'q') { zoomTo(mouseY * 3.0 / height); }
}
// ------------------------------------------------------------
// Toggle paused state
// ------------------------------------------------------------
void togglePaused()
{
paused = !paused;
if (paused)
{
// Pause the main loop
noLoop();
}
else
{
// (Re-)start the main loop
loop();
clockMillis = millis(); // Ignore any time passed up til now.
}
}
// ------------------------------------------------------------
// Select previous oscillator
// ------------------------------------------------------------
void selectPrevOscillator()
{
selectOscillator( (selectedOscIndex - 1 + numOsc) % numOsc );
}
// ------------------------------------------------------------
// Select next oscillator
// ------------------------------------------------------------
void selectNextOscillator()
{
selectOscillator( (selectedOscIndex + 1) % numOsc );
}
// ------------------------------------------------------------
// Start move / jump to x,y coordinates based on mouse location (Z coordinate unchanged)
// ------------------------------------------------------------
void originMoveToMouse() { originMoveTo(mouseX, mouseY); }
void originJumpToMouse() { originJumpTo(mouseX, mouseY); }
// ------------------------------------------------------------
// Hard jump to x,y coordinates based on screen location (Z coordinate unchanged)
// ------------------------------------------------------------
void originJumpTo(int x, int y)
{
originMoveTo(x, y);
ox = tox;
oy = toy;
}
// ------------------------------------------------------------
// Start move to x,y coordinates based on screen location (Z coordinate unchanged)
// ------------------------------------------------------------
void originMoveTo(int x, int y)
{
int w2 = width / 2;
int h2 = height / 2;
tox = w2 + (x - w2) * 2;
toy = h2 + (y - h2) * 2;
}
// ------------------------------------------------------------
// Start global zoom (scale) to passed zoomFactor
// ------------------------------------------------------------
void zoomTo(float zoomFactor)
{
toZoom = zoomFactor;
}
// ------------------------------------------------------------
// Select the the numbered oscillator
// ------------------------------------------------------------
void selectOscillator(int i)
{
selectedOscIndex = constrain(i, 0, oscillators.size() - 1);
selectedOsc = (Oscillator)(oscillators.get(selectedOscIndex));
}
// ------------------------------------------------------------
// Set period of currently selected oscillator
// ------------------------------------------------------------
void setSelectedPeriod(float period)
{
selectedOsc.setPeriod(period);
selectedOsc.unPause();
}
// ------------------------------------------------------------
// Adjust period of selected oscillator
// ------------------------------------------------------------
void doubleSelectedOscPeriod() { selectedOsc.adjustPeriod(2.0f); }
void halveSelectedOscPeriod() { selectedOsc.adjustPeriod(0.5f); }
// ------------------------------------------------------------
// Adjust periods of all oscialltors
// ------------------------------------------------------------
void increaseAllOscPeriods() { adjustAllOscPeriods(1.1f); }
void decreaseAllOscPeriods() { adjustAllOscPeriods(0.9090909f); }
void doubleAllOscPeriods() { adjustAllOscPeriods(2.0f); }
void halveAllOscPeriods() { adjustAllOscPeriods(0.5f); }
void adjustAllOscPeriods(float factor)
{
Oscillator o;
for (int i = 0; i < numOsc; i++)
{
o = (Oscillator)(oscillators.get(i));
o.adjustPeriod(factor);
}
}
// ------------------------------------------------------------
// Return a random colour
// ------------------------------------------------------------
color rndColor()
{
return color(rnd(256), rnd(256), rnd(256));
}
// ------------------------------------------------------------
// Return a random integer from 0 to n (not including n)
// that is also not equal to x
// ------------------------------------------------------------
int rndNotX(int n, int x)
{
int val = int(random(n - 1));
return (val < x) ? val : val + 1;
}
// ------------------------------------------------------------
// Return a random integer from 0 to n (not including n)
// ------------------------------------------------------------
int rnd(int n)
{
return int(random(n));
}
// ------------------------------------------------------------
// "Wrap" a value within the limits of minValue and maxValue (inclusive).
// Similar to performing modulo arithmetic.
// ------------------------------------------------------------
int wrapConstrain(int value, int minValue, int maxValue)
{
if (value < minValue || value > maxValue)
{
int rangeSize = maxValue - minValue + 1;
for (;value < minValue; value += rangeSize);
for (;value > maxValue; value -= rangeSize);
}
return value;
}