Skip to content

Instantly share code, notes, and snippets.

@danbernier
Last active December 27, 2015 23:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danbernier/2cb4d1dc4bc38ad8000f to your computer and use it in GitHub Desktop.
Save danbernier/2cb4d1dc4bc38ad8000f to your computer and use it in GitHub Desktop.
Playing with uGens, modular composition, and registers
interface UGen<T> {
T val();
}
interface Movie {
void update();
void draw(PGraphics g);
}
class MovieBag implements Movie {
Movie[] movieObjects;
MovieBag(Movie... movieObjects) {
this.movieObjects = movieObjects;
}
MovieBag(ArrayList<Movie> movieObjectList) {
this.movieObjects = movieObjectList.toArray(new Movie[0]);
}
void update() {
for (Movie m : movieObjects) {
m.update();
}
}
void draw(PGraphics g) {
for (Movie m : movieObjects) {
m.draw(g);
}
}
}
interface MovieFilter {
void filter(PGraphics g);
boolean isEnabled();
void toggleEnabled();
}
abstract class BaseMovieFilter implements MovieFilter {
boolean enabled = false;
boolean isEnabled() {
return enabled;
}
void toggleEnabled() {
enabled = !enabled;
}
}
class VertLeftMirrorFilter extends BaseMovieFilter {
void filter(PGraphics g) {
PImage left = g.get(0, 0, g.width/2, g.height);
g.scale(-1, 1);
g.image(left, -g.width, 0);
}
}
class VertRightMirrorFilter extends BaseMovieFilter {
void filter(PGraphics g) {
PImage right = g.get(g.width/2, 0, g.width/2, g.height);
g.scale(-1, 1);
g.image(right, -g.width/2, 0);
}
}
class HorizTopMirrorFilter extends BaseMovieFilter {
void filter(PGraphics g) {
PImage top = g.get(0, 0, g.width, g.height/2);
g.scale(1, -1);
g.image(top, 0, -g.height);
}
}
class HorizBottomMirrorFilter extends BaseMovieFilter {
void filter(PGraphics g) {
PImage bottom = g.get(0, g.height/2, g.width, g.height/2);
g.scale(1, -1);
g.image(bottom, 0, -g.height/2);
}
}
class VertDoubleFilter extends BaseMovieFilter {
void filter(PGraphics g) {
PImage right = g.get(g.width/2, 0, g.width/2, g.height);
g.image(right, 0, 0);
}
}
class HorizDoubleFilter extends BaseMovieFilter {
void filter(PGraphics g) {
PImage bottom = g.get(0, g.height/2, g.width, g.height/2);
g.image(bottom, 0, 0);
}
}
class PulsingCircle implements Movie {
float diam = 0;
UGen<Float> pulse;
PulsingCircle() {
pulse = new RangeMapper(new Sin(1), -1, 1, 30, 100);
}
void update() {
diam = pulse.val();
}
void draw(PGraphics g) {
g.stroke(#4395A5);
g.strokeWeight(5);
g.fill(#F7E493);
g.ellipse(300, 300, diam, diam);
}
}
class PulsingCircles implements Movie {
Osc osc;
float theta;
PulsingCircles() {
osc = new Osc(1);
}
void update() {
theta = osc.val();
}
void draw(PGraphics g) {
g.stroke(#4395A5);
g.strokeWeight(5);
g.fill(#F7E493);
for (int i = 0; i < 6; i++) {
float angle = theta + (i*(TAU/6.0));
float x = 300 + cos(angle) * 120;
float y = 300 + sin(angle) * 120;
float diam = map(sin(angle), -1, 1, 30, 120);
g.ellipse(x, y, diam, diam);
}
}
}
class BurstingBalloon implements Movie {
float x;
float y;
float rad = 0;
float maxRad;
boolean popped = false;
BurstingBalloon() {
x = random(width);
y = random(height);
maxRad = random(100, 125);
}
void update() {
if (!popped) {
if (rad < maxRad) {
float newArea = 135.0;
rad = sqrt((rad*rad) + (newArea / PI));
} else {
popped = true;
}
} else {
if (rad > 0.00001) {
rad *= 0.45;
} else {
rad = 0;
x = random(width);
y = random(height);
maxRad = random(100, 125);
popped = false;
}
}
}
void draw(PGraphics g) {
g.noStroke();
g.fill(255, map(rad, 0, maxRad, 255, 220));
g.ellipse(x, y, rad*2, rad*2);
}
}
class FallingVertLine implements Movie {
float x;
float y;
float h;
float speed;
FallingVertLine() {
setUp();
}
private void setUp() {
h = random(100, 300);
y = -h * 1.3;
speed = random(0.5, 5);
x = random(width);
int numLanes = 9;
x = map(round(random(1, numLanes)), 0, numLanes+1, 0, width-30);
speed = map(x, 0, width, 0.5, 5);
}
void update() {
y += speed;
if (y > height) {
setUp();
}
}
void draw(PGraphics g) {
g.rect(x, y, 30, h);
}
}
class WebCam implements Movie {
Capture capture;
PImage lastFrame;
int sketchWidth;
int sketchHeight;
WebCam(PApplet sketch) {
//println(Capture.list());
capture = new Capture(sketch, "name=/dev/video0,size=960x540,fps=15");
capture.start();
this.sketchWidth = sketch.width;
this.sketchHeight = sketch.height;
}
void update() {
if (capture.available()) {
capture.read();
lastFrame = capture.get(0, 0, capture.width, capture.height);
lastFrame.resize(0, sketchHeight);
int widthDifference = round(0.5 * (lastFrame.width - sketchWidth));
lastFrame = lastFrame.get(widthDifference, 0, sketchWidth, sketchHeight);
}
}
void draw(PGraphics g) {
if (lastFrame != null) {
g.image(lastFrame, 0, 0);
}
}
}
class MovieRegister {
Movie[] movies;
int index = 0;
MovieRegister(Movie... movies) {
this.movies = movies;
}
Movie current() {
return movies[index];
}
void load(int newIndex) {
if (0 <= newIndex && newIndex < movies.length) {
this.index = newIndex;
}
}
}
class MovieFilterRegister {
MovieFilter[] filters;
MovieFilterRegister(MovieFilter... movies) {
this.filters = movies;
}
void filterAllEnabled(PGraphics g) {
for (MovieFilter f : filters) {
if (f.isEnabled()) {
f.filter(g);
}
}
}
void toggleEnabled(int index) {
if (0 <= index && index < filters.length) {
filters[index].toggleEnabled();
}
}
}
class RangeMapper implements UGen<Float> {
UGen<Float> src;
float srcMin; float srcMax; float resMin; float resMax;
RangeMapper(UGen<Float> src, float srcMin, float srcMax, float resMin, float resMax) {
this.src = src;
this.srcMin = srcMin;
this.srcMax = srcMax;
this.resMin = resMin;
this.resMax = resMax;
}
Float val() {
return map(src.val(), srcMin, srcMax, resMin, resMax);
}
}
// This is the main file for the processing sketch.
// It's pretty shit-show. Sorry about that.
import processing.video.*;
MovieRegister movieRegister;
MovieFilterRegister filterRegister;
// TODO make the registers fire (movie loads, filter toggles) on the pulse.
// TODO make the filter register report on status when a key is pressed (until you have a launchpad, heh)
// TODO make a PImagePromise, so sketches can run (partially) while the images load
void setup() {
size(600, 600);
movieRegister = new MovieRegister(
new PulsingCircle(),
new PulsingCircles(),
new MovieBag(new BurstingBalloon(), new BurstingBalloon(), new BurstingBalloon(), new BurstingBalloon(), new BurstingBalloon()),
new MovieBag(new FallingVertLine(),new FallingVertLine(),new FallingVertLine(),
new FallingVertLine(),new FallingVertLine(),new FallingVertLine(),
new FallingVertLine(),new FallingVertLine(),new FallingVertLine(),
new FallingVertLine(),new FallingVertLine(),new FallingVertLine(),
new FallingVertLine(),new FallingVertLine(),new FallingVertLine(),
new FallingVertLine(),new FallingVertLine(),new FallingVertLine()),
new WebCam(this)
);
filterRegister = new MovieFilterRegister(
new VertLeftMirrorFilter(),
new VertRightMirrorFilter(),
new HorizTopMirrorFilter(),
new HorizBottomMirrorFilter(),
new VertDoubleFilter(),
new HorizDoubleFilter()
);
}
void draw() {
background(#8CBFC9);
movieRegister.current().update();
movieRegister.current().draw(g);
filterRegister.filterAllEnabled(g);
}
void keyPressed() {
String topRow = "',.pyfgcrl/=\\";
String middleRow = "aoeuidhtns-";
String bottomRow = ";qjkxbmwvz";
if (bottomRow.indexOf(key) > -1) {
movieRegister.load(bottomRow.indexOf(key));
}
if (middleRow.indexOf(key) > -1) {
filterRegister.toggleEnabled(middleRow.indexOf(key));
}
}
class Constant<T> implements UGen<T> {
T val;
Constant(T val) {
this.val = val;
}
T val() {
return val;
}
}
class Sin implements UGen<Float> {
Osc osc;
Sin(float hertz) {
osc = new Osc(hertz);
}
Float val() {
return sin(osc.val());
}
}
class Osc implements UGen<Float> {
float theta;
float millihertz; // cycles per millisecond
Osc(float hertz) {
millihertz = hertz * 0.001;
}
Float val() {
return millihertz * millis() * TAU;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment