Stefan Goodchild

Novation Launchpad Life (in Processing)

Using RWMidi library I quickly converted the Game of Life example that comes with Processing to work with the Novation Launchpad.

import rwmidi.*;

MidiInput input;
MidiOutput output;

int sx, sy;
float density = 0.5;
int[][][] world;
int note;

void setup()
{
  size(8, 8, P2D);
  frameRate(5);
  sx = width;
  sy = height;
  world = new int[sx][sy][2]; 

  input = RWMidi.getInputDevices()[2].createInput(this);
  output = RWMidi.getOutputDevices()[2].createOutput();

  // Set random cells to 'on'
  for (int i = 0; i < sx * sy * density; i++) {
    world[(int)random(sx)][(int)random(sy)][1] = 1;
  }
} 

void draw()
{
  background(0); 

  // Drawing and update cycle
  for (int x = 0; x < sx; x=x+1) {
    for (int y = 0; y < sy; y=y+1) {
      note = y * 16 + x;
      //if (world[x][y][1] == 1)
      if ((world[x][y][1] == 1) || (world[x][y][1] == 0 &amp;&amp; world[x][y][0] == 1))
      {
        world[x][y][0] = 1;
        set(x, y, #FFFFFF);
        output.sendNoteOn(0, note, 127);
      } else {
        output.sendNoteOn(0, note, 0);
      }
      if (world[x][y][1] == -1)
      {
        world[x][y][0] = 0;
      }
      world[x][y][1] = 0;
    }
  }
  // Birth and death cycle
  for (int x = 0; x < sx; x=x+1) {
    for (int y = 0; y < sy; y=y+1) {
      int count = neighbors(x, y);
      if (count == 3 &amp;&amp; world[x][y][0] == 0)
      {
        world[x][y][1] = 1;
      }
      if ((count < 2 || count > 3) &amp;&amp; world[x][y][0] == 1)
     {
        world[x][y][1] = -1;
      }
    }
  }
} 

void noteOnReceived(Note note) {
  println("note on " + note.getPitch() + ":"  + note.getVelocity());
  if (note.getVelocity() > 0) {
    int nx = note.getPitch() % 16;
    int ny = (note.getPitch() - nx) / 16;
    output.sendNoteOn(0, note.getPitch(), 100);
    println(nx);
    println(ny);
    world[nx][ny][1] = 1;
  }
}

// Count the number of adjacent cells 'on'
int neighbors(int x, int y)
{
  return world[(x + 1) % sx][y][0] +
         world[x][(y + 1) % sy][0] +
         world[(x + sx - 1) % sx][y][0] +
         world[x][(y + sy - 1) % sy][0] +
         world[(x + 1) % sx][(y + 1) % sy][0] +
         world[(x + sx - 1) % sx][(y + 1) % sy][0] +
         world[(x + sx - 1) % sx][(y + sy - 1) % sy][0] +
         world[(x + 1) % sx][(y + sy - 1) % sy][0];
}

Novation Launchpad – Note number to XY Coordinates and back again.

First thing I did with my new Launchpad? Nope, I didn’t hook it up to Live and jam. I hooked it up, fired up Processing and worked out how to light up the pads and recieve the notes so I could hack it to do anything I wanted to.

One thing I noticed straight off the bat is the note numbers are not incremental. Each row starts 16 higher than the last - I assume to allow for the same firmware to work in a 16 x 16 layout model - and there is a very simple way that reminds me of the technique of bitshifting I used back in the bad old days of DVD authoring to convert from one to the other.

// To go from XY to the note number
noteNumber = y * 16 + x;

// To go from the note number to the XY
x = noteNumber % 16;
y = (noteNumber - x) / 16;

Hopefully that will save someone ten minutes of head scratching.