The Blog

XYLOS

Just finished album art for Xylos last week. Go hear the pretty fun sounds. K THX.

Orbitor 2

A digital recreation of the Orbitor 1 pinball machine.

Orbitor 1 is a 1982 pinball machine made by Stern Electronics. A fairly rare machine that I had the amazing opportunity to play while at the Pinball Hall of Fame just outside Las Vegas. Designed by Dixie Rinehart and Art Myers, Stern Electronics only produced about 800 of these. Orbitor uses magnets, motors, and a textured playfield in an attempt to simulate movement and gravitational pull in space. The ball spins, shoots and wobbles through a pseudo anti-gravity environment, occasionally getting caught in the magnetic orbits of the “planets” (bumpers) and shooting off in unpredictable directions.

This digital version of Orbitor aims to recreate the zero gravity environment and planetary gravitational attractions via scripting in Unity 3D. The recreation will attempt to incorporate blocky, pastel vector aesthetics and a faux-2D environment into Orbitor in an attempt to visually modernize the game.

PLAYABLE:

**If the embedded player is not working or you’d like to play full-screen, please visit this link to a full-res player >>   ORBITOR 2 WEB PLAYER

**Or click here to download the stand-alone app >>   ORBITOR 2

SCREENCAPS:

Orbitor 2 : Reviving Zero Gravity Pinball

Goal: to digitally recreate Orbitor 1 with an updated aesthetic and accurate physics.

Orbitor 1 is a 1982 pinball machine made by Stern Electronics. A fairly rare machine that I had the amazing opportunity to play while at the Pinball Hall of Fame just outside Las Vegas. Designed by Dixie Rinehart and Art Myers, Stern Electronics only produced about 800 of these. Orbitor uses magnets, motors, and a 3D playfield placed under clear plexiglass in an attempt to simulate movement and gravitational pull in space. The ball spins, shoots and wobbles through a pseudo anti-gravity environment, occasionally getting caught in the magnetic orbits of the “planets” (bumpers) and shooting off in an unpredictable direction.

Clear, contoured plastic playfield has a “moon surface”-like substrate. Playfield slopes down and in towards the spinning bumpers which fling the ball away. The playfield slopes behind the flippers, allowing balls to be flipped backwards and then rescued for a forward-flipping shot. The kick-out hole always traps the ball landing in it, until released for multiball.

This digital version of Orbitor will endeavor to recreate the zero gravity environment and planetary gravitational attractions via scripting in Unity 3D. The recreation will attempt to incorporate blocky, pastel vector aesthetics and a faux-2D environment into Orbitor in an attempt to visually modernize the game.

Less for immediate output and more for the simulation of a pinball machine’s dimensions, I’m intending to set up the game in portrait layout with iPhone- compatible dimensions. Additionally, a bottom-aligned scoreboard layout will be employed.

(Visual reference: Gluddle for iOS and World of Goo for Wii)

Early visual development:

Some rudimentary space physics have been employed in the above rough draft. Key next steps are to develop the game mechanisms and goals, incorporate audio, add obstacles/landscapes/alt perspectives, and build out the remaining 3D models (thematic flippers,  spring, ramps, etc.).

Digitizing Facial Movement During Singing

1 Digitizing Facial Movement During Singing : Original Concept

A machine that uses flex sensors to detect movement and change in facial muscles/mechanics during phonation, specifically singing. Sensors can then be reverse engineered for output. Why? Because fascination with the physics of sound, the origin of the phonetic alphabet (Phoenician/Greek war tool later adapted by the Romans), and the mechanics of the voice (much facial movement/recognition research at the moment leans in the direction of expression rather than sound generation).

Found two exceptional pieces on not just the muscles of the face but the muscular and structural mechanics of speech AND two solid journal articles about digitizing facial tracking. After reading the better part of The Mechanics of the Human Voice, and being inspired by the Physiology of Phonation chapter,  we decided to develop a system of sensors to log the muscle position and contraction of singers during different pitches in an attempt to funnel the data into an audio output that translates the sound. For example, is there a particular and common muscle contraction/extension that occurs during high C? We save that, then  while a different non-singing user contracts in the same way the computer recognizes that and plays the corresponding note.

2 Digitizing Facial Movement During Singing : Prototype

We decided to use a three-part apparatus for tracking facial movements during simple singing: a barometric pressure sensor to monitor airflow, electromyography (EMGs) to monitor extrinsic facial muscles and a camera to track facial movement. While this data feeds in we will be manually recording fluctuations at different frequencies. Specially, the aim is to record changes in pressure, muscle contractions and position for each note in one octave—comparing to the face’s resting state. Ideally, data mining will be performed on at least five professional vocalists.

The barometric pressure sensor will be placed in front of the text subject, discretely mounted to a tiny stand. The EMGs will be placed (via medical adhesive) to the extrinsic muscles of the larynx involved in articulation; relevant muscles include the orbicularis oris (lips), geniohyoid (tongue and lower jaw), mylohyoid (mandible), masseter (cheek and jaw) and the hyoglossus (tongue). And finally, facial movement and geometry will be monitored using an external camera.

Luckily we found an Instructables DIY EMG guide.

3 Digitizing Facial Movement During Singing : Sensor Assembly

Pressure Sensor Diagram:

BMP085-hookup

DIY Electromyography Circuit Diagram & EMG Map: biomechanics_Circuit_v1 FaceEMG-Diagram

FaceOSC/Syphon/Processing Source Code:

FaceOSC

import codeanticode.syphon.*; import oscP5.*;
PGraphics canvas;
 SyphonClient client;
 OscP5 oscP5;
 Face face = new Face();
public void setup() {
   size(640, 480, P3D);
   println(“Available Syphon servers:”);
   println(SyphonClient.listServers());
   client = new SyphonClient(this, “FaceOSC”);
   oscP5 = new OscP5(this, 8338);
 }
public void draw() {
   background(255);
     if(client.available()) {
     canvas = client.getGraphics(canvas);
     image(canvas, 0, 0, width, height);
   }
     print(face.toString());
   }
 }
void oscEvent(OscMessage m) {
   face.parseOSC(m);
 }

+ LINK to the (ORIGINAL) Face class.

4 Digitizing Facial Movement During Singing : Geometry Troubleshooting

We ran tests on the FaceOSC/Syphon/Processing facial geometry detector and were able to mine the following data (seen in the above screen capture):

pose
 scale: 3.8911576
 position: [ 331.74725, 153.13004, 0.0 ]
 orientation: [ 0.107623726, -0.06095604, 0.085640974 ]
gesture
 mouth: 14.871553 4.777506
 eye: 2.649438 2.6013117
 eyebrow: 7.41446 7.520543
 jaw: 24.912415
 nostrils: 5.7812777

Using the on-camera feed to track geometric displacement in the face (relating to muscle movement), only the data in the “gesture” category really applies—categories with two values are recording x and y fluctuation. Fortunately, scale, position and orientation do not bias the gesture readings. Unfortunately, there is a fair bit of natural fluctuation in the readings. We’ve gathered that fluctuations of over 0.5 are actual movement while those under 0.5 are natural oscillations in the camera’s reading.

Digitizing Facial Movement During Singing : Sensor Build

We had a bit of trouble getting just the right stuff (one of our circuit chips was not available for order and the BMP085 barometric pressure sensor arrived without a breakout board) but worked on building out the EMG to -> Arduino circuitry:

EMG-circuits

As well as writing preliminary code to read the two physical sensor systems (EMG & BMP085) and print muscle contractions and changes in air pressure and temperature.  Much of the pressure print out code is taken from Jim Lindblom’s BMP085 Barometric Pressure Sensor Quickstart post on Sparkfun and much of the muscle contraction print out code is derived from Brian Kaminski’s USB Biofeedback Game Controller project guide on Instructables. We’ve refined the muscle sensors from five down to one, and with that, the muscle sensing will occupy analog pin 0 while the pressure/temperature sensor will occupy pins 4 and 5. Additionally we struggled with finding the Reference, Mid and End points of the facial muscle as well as the ideal muscle to use—as we had never worked with EMGs before.

Those issues established, build for the pressure sensor is super minimal and does not require any extensive set up before we receive the breakout board. Also, after experience with the sensitivity of camera-based facial geometry tracking and research into the size, flexion/extension, and general active proficiency of the sternocleidomastoid muscle (located in the neck) we decided to make that our single muscle to electromyographically track. The sternocleidomastoid muscle contributes quite a bit by way of posture and air flow during the singing process.

Sternocleidomastoid Muscle:

5 Digitizing Facial Movement During Singing : Interface Development

With all that established, it was time to work on building an interface that could help us to track all elements of the sensing system (pressure, electromyography, and geometry), compile these with audio frequency/pitch, display them in an easy to understand manner and then save everything to a data file for reference. We came up with a system of sliders (data is mapped to the tested highest and lowest points of each input so that sliders sitting at the top of the interface are reading at zero fluctuation and sliders which have reached the bottom are extended to their full potential). Actual number values are printed to the console and saved to a local data fie for reference. Geometry (mouth height/width, jaw protrusion) are measured in centimeters (cm), air pressure in pascals (Pa) and muscle fluctuation is to be measure by an unaltered analog reading. Additionally, the interface display and logs the frequency/pitch (using the minim library’s Fast Fourier Transform class and a popular frequency to MIDI formula).

Current monitoring interface and datafile screencap:

Testing Interface Code:

import codeanticode.syphon.*;
import processing.serial.*;
import oscP5.*;
import ddf.minim.*;
import ddf.minim.analysis.*;

PGraphics canvas;
SyphonClient client;
OscP5 oscP5;
Serial port;
Minim minim;
AudioInput in;
FFT fft;
Face face = new Face();

// Analog Inputs
int muscleFluc;
float airPressure;
int[] serialInArray = new int[2];
int serialCount = 0;
boolean firstContact = false;

// Data File
String dataFile = "/Users/mcortese_/Documents/Processing/FaceProcessing2/data/data.txt";

// Frequency Detection
String note;
int n;
float hertz;
float midi;
int noteNumber;
int sampleRate= 44100; 
float [] max= new float [sampleRate/2];
float maximum;
float frequency;

// Interface
PFont font;

public void setup() {
  size(570, 400, P3D);
  println("Available Syphon servers:");
  println(SyphonClient.listServers());
  client = new SyphonClient(this, "FaceOSC");
  oscP5 = new OscP5(this, 8338);
  println(Serial.list());
  String portName = Serial.list()[0];
  port = new Serial(this, portName, 9600);
  font = createFont("GothamHTF-Light-48.vlw", 24);
  minim = new Minim(this);
  minim.debugOn();
  in = minim.getLineIn(Minim.MONO, 4096, sampleRate);
  fft = new FFT(in.left.size(), sampleRate);
}

public void draw() {
  background(255);
  fill(0,100);
  text("MOUTH WIDTH", 25, height/2);
  text("MOUTH HEIGHT", 133, height/2);
  text("JAW", 275, height/2);
  text("MUSCLE FLUC", 357, height/2);
  text("AIR PRESSURE", 460, height/2);
  stroke(160);
  line(15,350,555,350);
  findNote();
  text (frequency-6+" hz   /   NOTE "+ note, 15, 375);
  if (client.available()) {
    canvas = client.getGraphics(canvas);
    image(canvas, 0, 0, width, height);
  }
  if (face.found > 0) {
    print(face.toString());
    println();
    saveData(dataFile, face.toString(), true);
    fill(0);    
    rect(15,map(face.mouthWidth,9,18,5, 345), 100, 10);
    rect(125,map(face.mouthHeight, 1, 10, 5, 345), 100, 10);
    rect(235,map(face.jaw, 20, 29, 5, 345), 100, 10);
    rect(345,muscleFluc, 100, 10);
    rect(455,airPressure, 100, 10);
  }
}

void oscEvent(OscMessage m) {
  face.parseOSC(m);
}

void serialEvent(Serial port) {
  int inByte = port.read();
  if (firstContact == false) {
    if (inByte == 'A') { 
      port.clear();
      firstContact = true;
      port.write('A');
    }
  } 
  else {
    serialInArray[serialCount] = inByte;
    serialCount++;
    if (serialCount > 2 ) {
      muscleFluc = serialInArray[0];
      airPressure = serialInArray[1];
      port.write('A');
      serialCount = 0;
    }
  }
}

void saveData(String fileName, String newData, boolean appendData) {
  BufferedWriter bw = null;
  try {  
    FileWriter fw = new FileWriter(fileName, appendData);
    bw = new BufferedWriter(fw);
    bw.write(newData + " " + System.getProperty("line.separator"));
  } 
  catch (IOException e) {
  } 
  finally {
    if (bw != null) {
      try { 
        bw.close();
      } 
      catch (IOException e) {
      }
    }
  }
}

class Face {
  int found;
  float poseScale;
  float mouthHeight, mouthWidth;
  float jaw;

  Face() {}

  boolean parseOSC(OscMessage m) {
    if(m.checkAddrPattern("/found")) {
        found = m.get(0).intValue();
        return true;
    }
    else if(m.checkAddrPattern("/pose/scale")) {
        poseScale = m.get(0).floatValue();
        return true;
    }
    else if(m.checkAddrPattern("/gesture/mouth/width")) {
        mouthWidth = m.get(0).floatValue();
        return true;
    }
    else if(m.checkAddrPattern("/gesture/mouth/height")) {
        mouthHeight = m.get(0).floatValue();
        return true;
    }
    else if(m.checkAddrPattern("/gesture/jaw")) {
        jaw = m.get(0).floatValue();
        return true;
    }
    return false;
  }

  String toString() {
    return "found: " + found + "\n"
           + "scale: " + poseScale + "\n"
           + "mouth: " + mouthWidth + " " + mouthHeight + "\n"
           + "jaw: " + jaw + "\n"
           + "muscle: " + muscleFluc + "\n"
           + "pressure: " + airPressure + "\n"
           + "frequency: " + frequency + "\n"
           + "note: " + note + "\n";
  }

}
/*
---------------------------
FREQUENCY ANALYZER COMMENTS
FAST FOURIER TRANSFORM CLASS / FRQ TO MIDI / VIA MINIM LIBRARY
---------------------------
Analyses amplitude between 0 and 22050 hertz.
Corresponds each index in [f] to a frequency and amplitude value.
Finds peak volume via max(max). Compares.
If value is equal to amplitude of peak, get index, corresponding to freq.
Uses frequency to MIDI formula: 69+12x(logxlog(freq/440Hz). Casts product as a int.
And finally, casts n to a note based on division of 12 tones/semitones.
---------------------------
*/

void findNote() {
  fft.forward(in.left);
  for (int f=0;f<sampleRate/2;f++) {
    max[f]=fft.getFreq(float(f));
  }
  maximum=max(max); 
  for (int i=0; i<max.length; i++) {
    if (max[i] == maximum) {
      frequency= i;
    }
  }

  midi= 69+12*(log((frequency-6)/440));
  n= int (midi);

if (n%12==9){
    note = ("a");
  }
  if (n%12==10){
    note = ("a#");
  } 
  if (n%12==11){
    note = ("b");
  }
  if (n%12==0){
    note = ("c");
  } 
  if (n%12==1){
    note = ("c#");
  } 
  if (n%12==2){
    note = ("d");
  }
  if (n%12==3){
    note = ("d#");
  }
  if (n%12==4){
    note = ("e");
  }
  if (n%12==5){
    note = ("f");
  }
  if (n%12==6){
    note = ("f#");
  } 
  if (n%12==7){
    note = ("g");
  } 
  if (n%12==8){
    note = ("g#");
  }
}

void stop(){
  in.close();
  minim.stop();
  super.stop();
}

6 Digitizing Facial Movement During Singing : Data Collection and Reverse Engineering

While building the interface we had to keep in mind that we would soon be reverse engineering our findings into a “singing machine” and that our code should begin to reflect that. Our solution to solved two late-game issues: what is the form and application of this singing machine and what does it look like? Our testing interface of sliders became the perfect jumping off point to a visual interface that resembling a soundboard. Once we have reviewed enough data to know which configurations of mouth height/width, jaw protrusion, sternocleidomastoid fluctuation and air pressure produce each of the twelve tones and semitones in an octave we can program Ableton to output those notes upon a non-singing user’s input. The user can then view their biomechanical data through a familiar sound-generating interface: a soundboard.

Aesthetic direction for final interface:

For the next three weeks: official data recording/review, reversing the system/sending data to Ableton and finally refined the aesthetics of the interface.

Toxiclibs and Fractals

For this week’s round of pre-final experiments, I played mostly with toxiclibs and attempted the fractal tree with springs exercise (allowing the tree to stand up straight using toxiclibs gravity function as a negative value). Besides this, I’ve pinpoint that my final involve a physical analog input, toxiclibs, springs, and fractals so I’ve been playing with all of those in hopes to reach a higher level of comfort with all.

Also, I’m currently struggling with:
We’ve established that we can know location points of self generating fractal sketches through arraylists, but how much can we do with them? If one were to create a system in which, on demand, an analog input controls the scale, quantity, geometrical structure and recursion data of a fractal and then draws each set at a random place on the screen, how would one go about locating all on-screen points, regardless of which fractal group they are part of? (To either connect them or employ some kind of collision detection).

Live Audio Visualizer With Key/Mouse Triggers

Round 1 live music visualizer development.

Original goal was to create an abstract, 3D aquarium aesthetic with a selection of organisms that would react to both drum triggers (via piezo sensors) and MIDI input. It has morphed into an interactive cell (in the biological respect). The sketch uses a mixture of toxiclibs geometric mesh, oscillating sine waves and bunch of ribosome-ish particles (the 2D circles located inside the 3D mesh nucleus shape). Each element can be altered in force and structure by key commands (w,l,a,s,g,h,-,=). The key commands are designed to create as much visual change (while remaining aesthetically unified) with one single switch in order to maintain a visualizer dynamic enough to last a full set length.

Key switches are currently slow because they are running off of simultaneous keyboard/mouse hover (performed by one user) and are not currently emulating the actual speed of the intended drum/MIDI inputs. KEYS: g/h = shrink/grow sine wave weight, a/s = crank or drop the ribosomal attraction level, l/r = smooth/recompute subdivisions of cell membrane, -/= = faux-zoom in/out, w = wireframe on/off switch.

Next natural step is to sync to the intended audio sources, tweak the glitchy areas and add a few more triggers that will appear as isolated elements (not modifiers).

Source code can be found HERE.

HEY! WATCHOUT! LISTEN!

Practice play with particle systems & PVectors: control your own Navi.

Essentially, it’s a watercolor painting of Navi from Ocarina of Time that can be controlled by the arrow keys ( ^ = forward, > = tilt right, < = tilt left) whilst of a particle system of fairy dust trails behind her. If she hits a wall she bounces off.

The JS won’t work (PImages not loading) but regardless the sketch can be found HERE and the code HERE.
& If—for whatever reason—you want to run this precisely as you see here, the PImage PNGs can found HERE (navi) and HERE (particle).

Trollin’ for Biomechanics topics

TOPIC: A machine that uses flex sensors to detect movement and change in facial muscles/mechanics, output TBD. [Considering elements of sensory swapping].

Why? Because I’m absolutely fascinated by the physics of sound, the origin of the phonetic alphabet (Phoenician/Greek war tool later adapted by the Romans), and the mechanics of singing.

RESEARCH PROGRESS :

Found two exceptional pieces on not just the muscles of the face but the muscular and structural mechanics of speech AND two solid journal articles about digitizing facial tracking. I’m not sure exactly what I can do with the data from examining facial muscle movement during speech but I feel like this subject potentially has a LOT of depth and the opportunity to combine with subject three. After reading the better part of The Mechanics of the Human Voice, and being inspired by the Physiology of Phonation chapter, I’m now considering developing a system of sensors (most likely flex sensors and a camera, and/or something that can track vocal cord movement) to log the muscle position of singers during different styles and pitches in an attempt to funnel the data into an audio output that translates the sound. For example, is there a particular and common muscle contraction/extension that occurs during high C? The computer sees that contraction and plays the note.

[Continued research on sensory swapping] Read a few chapters of David Eagleman’s Incognito: The Secret Lives of the Brain. The book is both wonderful and misleading. Toting itself as an enlightening journey through the brain, it eventually reveals its true agenda:an argumentative piece angled to sway common folk into reconsidering their opinions on criminal law and sentencing. Regardless, the Testimony of the Senses chapter does an incredible job of describing how little data (by comparison to what’s out there) our sensory sensors actually pull in and underlining the fact that it really just is data by referencing the effect of sensory innovations on people like Mike May (a man who lost his sight at age 3, regained it, and could not reconcile the meaning of visual data for a fairly long time) and Eric Weihenmayer (a blind extreme rock climber who uses a sonar sensor connected to a grid on his tongue to “see” mountains during unassisted climbs).

HIGH SPEED FISH CHASE

Back to video input! I’m really digging the idea of creating videos that interact with on-screen ecosystems, tinkering with the idea of applying it to music video. But for now, I’m just using the built-in iSight cam to interact with a few elements. For the oscillation week I turned the color-chasing circle into directionally pointed rectangles then added an sine of moving bokeh. The waves have their own color attraction: they displace by 50 pixels when in contact with a certain shade of green. Unfortunately, this double color track slowed down the sketch IMMENSELY. Help?

Rectangle creatures eating my eye:

Experimenting with having both the waves and rects fearful of the green:

With the blocks’ ability to turn themselves around I figured why not fish? So I turned the blocks into fish and swapped around the attractor/detractor color preferences. Also, removed the waves’ detractor for this one, the double color track mixed with PImage was slowing the LIFE out of my sketch.

Fun fact: the fish hate wine.

FIRST SKETCH CODE:  VideoAttractor2

Joint Color Tracker

A cluster of circle that are attracted to an on-screen color, in this case, red (calibration to color via my lipstick because it was the easiest thing to smear on my face contrast to my green-ish surroundings). The idea was to track acceleration and drag in the elbow joint’s extension.

If a color is left on screen for enough time to feel nature, the circles cluster around the color. If the color then moves the circles follow, sensitive to physical properties (friction, bounds of the screen, acceleration of the motion). I used this to abstractly track the movement of my elbow, concept diagram below.

import processing.video.*;

Mover[] movers = new Mover[150];
Attractor a;
Capture cam;
color trackColor;

void setup() {
  size(600, 400);
  smooth();
  for (int i = 0; i < movers.length; i++) {
    movers[i] = new Mover(random(0.1, 2), random(width), random(height));
  }
  a = new Attractor();
  String[] cameras = Capture.list();
  for (int i = 0; i < cameras.length; i++) {
  }
  cam = new Capture(this,cameras[0]);
  cam.start();
  trackColor = color(90,25,40);
}

void draw() {
  background(255,0);
  a.display();
  for (int i = 0; i < movers.length; i++) {
    PVector force = a.attract(movers[i]);
    movers[i].applyForce(force);
    movers[i].boundaries();
    movers[i].update();
    movers[i].display();
  }
}

class Attractor {
  float mass;
  float G;
  PVector location;

  Attractor() {
    location = new PVector(width/2,height/2);
    mass = 20;
    G = 2;
  }

  PVector attract(Mover m) {
    PVector force = PVector.sub(location,m.location);
    float d = force.mag();
    d = constrain(d,5.0,25.0);
    force.normalize();
    float strength = (G * mass * m.mass) / (d * d);
    force.mult(strength);
    return force;
  }

  void display() {
  if (cam.available() == true) {
    cam.read();
  }
  cam.loadPixels();
  image(cam,0,0);
  float worldRecord = 500;
  int closestX = 0;
  int closestY = 0;
  for (int x = 0; x < cam.width; x ++ ) {
    for (int y = 0; y < cam.height; y ++ ) {
      int loc = x + y*cam.width;
      color currentColor = cam.pixels[loc];
      float r1 = red(currentColor);
      float g1 = green(currentColor);
      float b1 = blue(currentColor);
      float r2 = red(trackColor);
      float g2 = green(trackColor);
      float b2 = blue(trackColor);
      float d = dist(r1,g1,b1,r2,g2,b2);
      if (d < worldRecord) {
        worldRecord = d;
        location.x = x;
        location.y = y;
      }
    }
  }
  if (worldRecord < 50) {
    fill(90,25,40,150);
    strokeWeight(1.0);
    stroke(0);
    ellipse(location.x,location.y,mass*2,mass*2);
  }
  }

}

class Mover {

  PVector location;
  PVector velocity;
  PVector acceleration;
  float mass;

  Mover(float m, float x, float y) {
    mass = m;
    location = new PVector(random(width), random(height));
    velocity = new PVector(1.5, 0);
    acceleration = new PVector(0, 0);
  }

  void applyForce(PVector force) {
    PVector f = PVector.div(force, mass);
    acceleration.add(f);
  }

  void update() {
    velocity.add(acceleration);
    location.add(velocity);
    acceleration.mult(0);
  }

  void display() {
    stroke(255);
    strokeWeight(0);
    fill(255,50);
    ellipse(location.x, location.y, mass*10, mass*10);
  }

    void boundaries() {
    float d = 50;
    PVector force = new PVector(0, 0);
    if (location.x < d) {
      force.x = 1;
    }
    else if (location.x > width -d) {
      force.x = -1;
    }
    if (location.y < d) {
      force.y = 1;
    }
    else if (location.y > height-d) {
      force.y = -1;
    }
    force.normalize();
    force.mult(0.1);
    applyForce(force);
  }
}

http://itp.nyu.edu/~mc4562/noc/colourfollow/VideoAttractor.pde

WP Like Button Plugin by Free WordPress Templates