- Arduino reads sensors, maps hits to MIDI note numbers, sends serial data or uses MIDI over USB.
- Raspberry Pi runs a Java app with MidiBus that listens to the MIDI input, applies velocity scaling and humanizing, and forwards to the output synth.
Arduino sketch (conceptual):
// Sends simple serial messages like "N60:100 " meaning Note 60 velocity 100 // Implementation depends on your sensor thresholding code
Java/Processing MidiBus receiver snippet:
import themidibus.*; MidiBus myBus; void setup() { MidiBus.list(); myBus = new MidiBus(this, "Arduino MIDI Input", "Your MIDI Output"); } void noteOn(int channel, int pitch, int velocity) { // Add slight randomization to velocity for human feel int v = constrain(velocity + (int)random(-8, 8), 1, 127); myBus.sendNoteOn(channel, pitch, v); }
Notes:
- If Arduino sends serial, use a serial-to-MIDI bridge (Hairless MIDI <-> Serial, or ArduinoUSB MIDI libraries).
- Calibrate sensor thresholds and use short dead-time to avoid double triggers.
Tutorial 3 — Visual-MIDI Instrument (Processing visuals linked to MIDI)
Goal: Build an instrument where visuals and sound are tightly coupled; MIDI messages both control visuals and are generated from user actions on-screen.
Features:
- On-screen pads that send notes.
- Visual feedback (pulsing circles) for incoming notes.
- CC-controlled visual effects (color, blur).
Key structure:
- GUI grid of pads with hit detection.
- MidiBus for sending/receiving.
- Visual objects storing lifetime and parameters driven by MIDI velocity/CC.
Example: pad grid send/receive (Processing):
import themidibus.*; ArrayList<Pad> pads; MidiBus myBus; void setup() { size(800, 600); MidiBus.list(); myBus = new MidiBus(this, -1, "Your MIDI Output"); pads = new ArrayList<Pad>(); int cols = 8, rows = 4; for (int y=0; y<rows; y++) { for (int x=0; x<cols; x++) { int pitch = 36 + x + y*cols; // map to MIDI note numbers pads.add(new Pad(20 + x*90, 20 + y*130, 80, 110, pitch)); } } } void draw() { background(0); for (Pad p : pads) { p.update(); p.display(); } } void mousePressed() { for (Pad p : pads) { if (p.contains(mouseX, mouseY)) { int vel = (int)map(mouseY, 0, height, 127, 30); myBus.sendNoteOn(0, p.pitch, vel); p.trigger(vel); } } } class Pad { int x,y,w,h,pitch; float life=0; Pad(int x,int y,int w,int h,int pitch) { this.x=x;this.y=y;this.w=w;this.h=h;this.pitch=pitch; } boolean contains(int mx,int my) { return mx>=x && mx<=x+w && my>=y && my<=y+h; } void trigger(int velocity) { life = velocity/127.0; } void update() { life = max(0, life - 0.02); } void display() { noStroke(); fill(255, 150*life, 50*life); rect(x,y,w,h,8); } }
Performance and reliability tips
- Minimize unnecessary object allocation in real-time paths (reuse arrays/objects).
- Batch or throttle frequent CC messages—only send when value change > threshold (e.g., >2).
- Use appropriate MIDI buffer sizes and prioritize threads if integrating with audio processing.
- Test on target hardware; latency varies by OS, drivers, and USB devices.
- For wireless setups, favor local processing; MIDI over Bluetooth/Network adds latency.
Advanced topics & extensions
- SysEx: Load custom instrument patches into hardware synths.
- MIDI mapping layers: allow user remapping of controllers to functions.
- MPE (MIDI Polyphonic Expression): MidiBus doesn’t natively implement MPE specifics, but you can send per-note channels/aftertouch messages manually.
- Network MIDI: route MIDI across machines using RTP-MIDI, rtpMIDI, or virtual MIDI ports.
- OSC bridging: convert OSC to MIDI for mobile/tablet interfaces.
Troubleshooting common issues
- No MIDI devices listed: verify drivers, cable connections, and that the device is not exclusively opened by another app.
- Stuck notes: ensure noteOff messages are sent and handle program exit by sending All Notes Off (CC 123).
- High CPU: profile rendering and MIDI callback code; throttle event rates.
- Mismatched channels: confirm channel numbering (MidiBus often uses 0-based channels).
Project ideas to explore
- Granular sampler controlled by touch gestures sending MIDI CCs for grain size/density.
- Multi-user jam station: multiple controllers mapped to different visual layers.
- Adaptive generative accompanist: algorithmic MIDI generator that listens and harmonizes in real time.
- Educational piano with visual feedback and step-by-step lessons.
Final notes
MidiBus provides a straightforward, low-friction route into MIDI programming with Java and Processing. By combining simple MIDI message handling with sensors, visuals, and careful performance practices, you can build expressive, interactive instruments suitable for installation, performance, or learning environments.
If you want, I can: convert any of the Processing examples into plain Java + Swing, add MIDI-to-Audio routing examples, or craft a step-by-step guide for connecting an Arduino drum pad to a software synth.
Leave a Reply