MIDI
Read and emit MIDI with the typed message layer.A device reads MIDI when it declares a midiIn("MIDI") port and emits when it declares a
midiOut("MIDI") port. See Ports. Prefer the typed
surface below over hand-decoding status bytes.
Reading
| Call | Returns |
|---|---|
ctx.midiInCount() | Number of MIDI-in events this block. |
ctx.midiEvent(e) | A typed MidiMsg for event e (see below). |
ctx.midiInOffset(e) | Sample offset of event e within the block. |
ctx.midiInByte(e, b) | Raw status/data byte b (0..3) of event e. |
for (let e = 0; e < ctx.midiInCount(); e++) {
const m = ctx.midiEvent(e);
if (m.isNoteOn()) alloc.noteOn(m.note);
else if (m.isNoteOff()) alloc.noteOff(m.note);
}Warning
ctx.midiEvent returns the SAME MidiMsg instance every call (its fields are
overwritten). Copy out anything you need to keep, and don't hold two events at
once.
MidiMsg
| Field | Meaning |
|---|---|
kind | A MidiKind (note-on/off, CC, etc). |
channel | Channel 0..15. |
offset | Sample offset within the block. |
note | Note number (note and poly-aftertouch messages). |
velocity | Velocity (note-on; 0 for a normalized note-off). |
controller | Controller number (control change). |
value | CC value, program number, or pressure amount. |
bend | Centered pitch bend, -8192..8191 (0 = no bend). |
| Method | Returns |
|---|---|
isNoteOn() / isNoteOff() | Note-on / note-off. |
isNote() | Either note-on or note-off. |
isControlChange() / isPitchBend() | Control change / pitch bend. |
bendNorm() | Pitch bend normalized to -1..1. |
A note-on with velocity 0 reads back as a note-off (isNoteOff() is true, kind is
NoteOff), matching MIDI's running-status convention.
MidiKind
NoteOn, NoteOff, PolyAftertouch, ControlChange, ProgramChange,
ChannelPressure, PitchBend, Other.
Emitting
Each helper takes a sample offset within the block. ch defaults to 0. Out-of-range
data bytes pin to the edge (0..127) rather than wrapping. Each is a no-op if the device
declared no midiOut() port, or the per-block capacity (256 events) is exceeded.
| Call | Emits |
|---|---|
ctx.noteOn(offset, note, vel, ch?) | Note-on. vel <= 0 emits a note-off instead. |
ctx.noteOff(offset, note, ch?) | Note-off. |
ctx.cc(offset, controller, value, ch?) | Control change (controller, value are 0..127). |
ctx.pitchBend(offset, centered, ch?) | Pitch bend (centered is -8192..8191, 0 = no bend). |
ctx.programChange(offset, program, ch?) | Program change (program 0..127). |
ctx.channelPressure(offset, pressure, ch?) | Channel pressure (0..127). |
ctx.polyAftertouch(offset, note, pressure, ch?) | Polyphonic key pressure. |
ctx.noteOn(0, 60, 100); // middle C, velocity 100, at the block start
ctx.noteOff(64, 60); // release it 64 samples laterRaw emit
For messages the typed helpers don't cover, write the status byte yourself.
ctx.emitMidi(offset, status, d1, d2);status is the full status byte (0x90 | ch for note-on, 0x80 | ch for note-off,
0xB0 | ch for control change), d1/d2 the data bytes. Use 0 for unused data bytes.
Constants
PITCH_BEND_CENTER is 8192. Common controller numbers read better than literals:
CC_MOD_WHEEL, CC_BREATH, CC_FOOT, CC_PORTAMENTO_TIME, CC_VOLUME, CC_BALANCE,
CC_PAN, CC_EXPRESSION, CC_SUSTAIN, CC_PORTAMENTO, CC_SOSTENUTO, CC_SOFT_PEDAL,
CC_RESONANCE, CC_RELEASE_TIME, CC_ATTACK_TIME, CC_BRIGHTNESS, CC_ALL_SOUND_OFF,
CC_RESET_ALL_CONTROLLERS, CC_ALL_NOTES_OFF.
To sync emitted MIDI to the host timeline, read ctx.ppqPosition(), ctx.isPlaying(),
and ctx.tempo() from the device API. For
note allocation, arps, and chords, see
Harmony and sequencing and
Synth blocks.