Skip to main content

Midi Fighter Classic

Sixteen arcade buttons in a 4×4 grid with an on/off LED under each. Every button is a note and every LED is a note sent back. That's the whole device, which makes it the easiest one on the table to understand completely. It's the 2010 Classic, not the 3D, so no colours and no accelerometer. There are four on the table.

What it sends​

EventMessageNotes
PressNote on, channel 3Status 0x92. Velocity is fixed per unit, 127 or 125 on ours.
ReleaseNote off, channel 3Status 0x82.
USB name"Midi Fighter Classic"

In the factory Default mode the notes are 36 to 51. Bottom-left is the lowest note and top-left is 48:

48 49 50 51
44 45 46 47
40 41 42 43
36 37 38 39

The helper numbers cells 0 to 15 in reading order, top-left first, and reports a bank if the unit is in Four Banks mode, where the top row switches banks and sends notes 0 to 3. All units should be in Default. If the top row does something odd, the unit is in Four Banks mode and the helper reports the bank.

Lighting the LEDs​

Send the button's own note back on channel 3. Velocity above 0 lights it, 0 or a note off clears it. No brightness, no colour. A held button stays lit. The device never reports LED state, so the helper keeps its own picture of which are on.

Start here​

Open starters/java/MidiFighterStarter/MidiFighterStarter.pde.

MidiFighterStarter.pde
// Midi Fighter starter: a 4x4 grid. Press a button to toggle its cell on screen and its LED.
// No Midi Fighter: keys 1234 / qwer / asdf / zxcv. Edit the lines marked "change this".
MidiFighter mf;
boolean[] lit = new boolean[16];

void setup() {
size(600, 600);
mf = new MidiFighter(this); // change this: new MidiFighter(this, "name", channel) if it isn't found
mf.connect(); // prints the MIDI devices it found; fine with no device
}

void draw() {
background(20);
for (int i = 0; i < 16; i++) { // index 0 is top-left, reading order
float x = mf.col(i) * 150, y = mf.row(i) * 150;
fill(lit[i] ? color(255, 200, 60) : (mf.pressed(i) ? 110 : 50)); // change this: colours
rect(x + 10, y + 10, 130, 130, 24); // change this: what a cell looks like
}
}

void padPressed(int i) { // the helper calls this on every press (or poll mf.justPressed(i) in draw)
lit[i] = !lit[i]; // change this: what a press does
mf.led(i, lit[i]); // light the real button to match; the device remembers it
}

The helper​

new MidiFighter(this)Connects to the first device whose name contains "Midi Fighter".
mf.pressed(i), mf.justPressed(i)Cell i, 0 to 15 in reading order. "Just" is true for one frame.
mf.bank0 to 3 when the unit is in bank mode, otherwise 0.
mf.led(i, on), mf.led(i, on, bank), mf.clear()Lights are on or off. The bank form writes into a bank you are not looking at. The device shows it when you switch.
void padPressed(int index), void padReleased(int index)Define either in your sketch and the helper calls it.

From the helpers' README​

Sixteen arcade buttons in a 4x4, one on/off LED each. Notes in grid-controllers/MIDI-FIGHTER-CLASSIC.md.

MidiFighter mf = new MidiFighter(this); // or (this, "name"), (this, "name", channel)
mf.pressed(i); mf.justPressed(i); mf.justReleased(i); // i = 0..15, 0 = top-left, reading order
mf.velocity[i]; mf.anyPressed(); mf.row(i); mf.col(i); mf.index(row, col);
mf.bank; // 0..3 in Four Banks Internal mode, else 0
mf.mode; // "default" or "internal", detected; set it to force
mf.led(i, true); mf.led(i, true, bank); mf.leds(new int[] {0, 5, 10, 15}); mf.clear();
mf.setMap(loadJSONObject("map.json")); // a layout learned in grid-explorer.html

Callbacks: padPressed(int index), padReleased(int index), bankChanged(int bank). Stand-in: keys 1234 / qwer / asdf / zxcv.

Message map: Note On / Note Off on channel 3 (default; new MidiFighter(this, "midi fighter", ch) for a unit set differently). Default mode notes, reading order:

48 49 50 51
44 45 46 47
40 41 42 43
36 37 38 39

Four Banks Internal: the top row sends notes 0..3 (bank select, 0-based here, 1-based in the DJ TechTools docs) and the other twelve send 36 + 12·bank + offset. The helper starts in default mode and switches to internal the first time it sees a note 0..3. LEDs: Note On velocity 127 on the same channel lights a button, Note Off clears it. Bank-select LEDs belong to the device. Unchanged LED states are not re-sent.

Python: MidiFighter(this, name="midi fighter", channel=3), mf.pressed(i), mf.just_pressed(i), mf.bank, mf.led(i, True, bank), mf.leds([0, 5]), mf.clear(), mf.set_map(dict); module-level note_for_index(index, mode, bank) and index_for_note(note, mode).

Try first​

  • Toggle lights, which the starter does. Then a press lights its neighbours too: Lights Out.
  • A sixteen-step sequencer. Each button a step, a playhead on the LEDs. There is a port to take apart.
  • Simon. The LEDs play a sequence, you play it back.
  • A 4×4 pixel canvas, mirrored big on screen.

More on the ideas page and the demos page. The on-device menu and how to un-brick one: MIDI-FIGHTER-CLASSIC.md.

Without the helper​

Notes 36 to 51 in, the same notes back out for the LEDs. Under sixty lines, same stand-ins. Read the three bytes, no helpers first.