0
# MIDI Input
1
2
MIDI Input handling provides comprehensive functionality for receiving and processing MIDI messages from devices. Input objects represent physical or virtual MIDI input ports, while InputChannel objects provide channel-specific message handling.
3
4
## Capabilities
5
6
### Input Port Management
7
8
Access and manage MIDI input ports.
9
10
```javascript { .api }
11
class Input extends EventEmitter {
12
/**
13
* Array of 16 InputChannel objects (channels 1-16)
14
*/
15
readonly channels: InputChannel[];
16
17
/**
18
* Input port name as reported by the system
19
*/
20
readonly name: string;
21
22
/**
23
* Unique identifier for this input port
24
*/
25
readonly id: string;
26
27
/**
28
* Connection state: "closed", "open", or "pending"
29
*/
30
readonly connection: string;
31
32
/**
33
* Port state: "connected" or "disconnected"
34
*/
35
readonly state: string;
36
37
/**
38
* Device manufacturer name (if available)
39
*/
40
readonly manufacturer: string;
41
42
/**
43
* Port type (always "input")
44
*/
45
readonly type: string;
46
47
/**
48
* Octave offset for this input (-10 to 10)
49
*/
50
readonly octaveOffset: number;
51
}
52
```
53
54
### Event Listening
55
56
Add and remove event listeners for MIDI messages.
57
58
```javascript { .api }
59
/**
60
* Add event listener for MIDI messages
61
* @param event - Event type (e.g., "noteon", "noteoff", "controlchange")
62
* @param listener - Event handler function
63
* @param options - Listener options
64
* @param options.channels - Channel filter (number, array, or "all")
65
* @param options.data1 - Filter by first data byte
66
* @param options.data2 - Filter by second data byte
67
* @returns Input instance for chaining
68
*/
69
addListener(event: string, listener: Function, options?: {
70
channels?: number | number[] | "all";
71
data1?: number | number[];
72
data2?: number | number[];
73
}): Input;
74
75
/**
76
* Add one-time event listener
77
* @param event - Event type
78
* @param listener - Event handler function
79
* @param options - Listener options
80
* @returns Input instance for chaining
81
*/
82
addOneTimeListener(event: string, listener: Function, options?: object): Input;
83
84
/**
85
* Shorthand for addListener with channel specification
86
* @param event - Event type
87
* @param channel - Channel number (1-16) or "all"
88
* @param listener - Event handler function
89
* @param options - Additional options
90
* @returns Input instance for chaining
91
*/
92
on(event: string, channel: number | "all", listener: Function, options?: object): Input;
93
94
/**
95
* Check if listener exists
96
* @param event - Event type
97
* @param listener - Event handler function
98
* @param options - Listener options to match
99
* @returns True if listener exists
100
*/
101
hasListener(event: string, listener: Function, options?: object): boolean;
102
103
/**
104
* Remove event listener
105
* @param event - Event type
106
* @param listener - Event handler function
107
* @param options - Listener options to match
108
* @returns Input instance for chaining
109
*/
110
removeListener(event: string, listener: Function, options?: object): Input;
111
```
112
113
**Usage Examples:**
114
115
```javascript
116
import { WebMidi } from "webmidi";
117
118
await WebMidi.enable();
119
const input = WebMidi.inputs[0];
120
121
// Listen for note on/off messages
122
input.addListener("noteon", (e) => {
123
console.log("Note on:", e.note.name + e.note.octave, "velocity:", e.velocity);
124
});
125
126
input.addListener("noteoff", (e) => {
127
console.log("Note off:", e.note.name + e.note.octave);
128
});
129
130
// Listen only on specific channel
131
input.addListener("controlchange", (e) => {
132
console.log("CC:", e.controller.number, "value:", e.value);
133
}, { channels: 1 });
134
135
// Listen for pitch bend on multiple channels
136
input.addListener("pitchbend", (e) => {
137
console.log("Pitch bend on channel", e.channel, "value:", e.value);
138
}, { channels: [1, 2, 3] });
139
140
// One-time listener
141
input.addOneTimeListener("programchange", (e) => {
142
console.log("Program changed to:", e.value);
143
});
144
```
145
146
### Message Forwarding
147
148
Forward MIDI messages to output ports.
149
150
```javascript { .api }
151
/**
152
* Add message forwarder to output port
153
* @param output - Output port to forward messages to
154
* @param options - Forwarding options
155
* @param options.channels - Channel filter for forwarding
156
* @param options.types - Message types to forward
157
* @returns Forwarder instance
158
*/
159
addForwarder(output: Output, options?: {
160
channels?: number | number[] | "all";
161
types?: string | string[];
162
}): Forwarder;
163
164
/**
165
* Remove message forwarder
166
* @param forwarder - Forwarder instance to remove
167
*/
168
removeForwarder(forwarder: Forwarder): void;
169
170
/**
171
* Check if forwarder exists
172
* @param forwarder - Forwarder instance to check
173
* @returns True if forwarder exists
174
*/
175
hasForwarder(forwarder: Forwarder): boolean;
176
```
177
178
**Usage Examples:**
179
180
```javascript
181
const input = WebMidi.getInputByName("My Keyboard");
182
const output = WebMidi.getOutputByName("My Synth");
183
184
// Forward all messages
185
const forwarder = input.addForwarder(output);
186
187
// Forward only note messages from channels 1-4
188
const noteForwarder = input.addForwarder(output, {
189
channels: [1, 2, 3, 4],
190
types: ["noteon", "noteoff"]
191
});
192
193
// Remove forwarder
194
input.removeForwarder(forwarder);
195
```
196
197
### InputChannel
198
199
Channel-specific input handling for targeted MIDI communication.
200
201
```javascript { .api }
202
class InputChannel extends EventEmitter {
203
/**
204
* Channel number (1-16)
205
*/
206
readonly number: number;
207
208
/**
209
* Parent Input object
210
*/
211
readonly input: Input;
212
213
/**
214
* Octave offset for this channel
215
*/
216
readonly octaveOffset: number;
217
218
/**
219
* Whether NRPN events are enabled for this channel
220
*/
221
readonly nrpnEventsEnabled: boolean;
222
}
223
```
224
225
### Channel-Specific Methods
226
227
```javascript { .api }
228
/**
229
* Get current state of a specific note
230
* @param note - Note to check (name, number, or Note object)
231
* @returns Note state object with velocity and timestamp
232
*/
233
getNoteState(note: string | number | Note): {
234
velocity: number;
235
timestamp: number;
236
rawVelocity: number;
237
} | false;
238
239
/**
240
* Get control change name by number
241
* @param number - CC number (0-127)
242
* @returns Control change name
243
*/
244
getCcNameByNumber(number: number): string;
245
246
/**
247
* Get channel mode name by number
248
* @param number - Channel mode number
249
* @returns Channel mode name
250
*/
251
getChannelModeByNumber(number: number): string;
252
253
/**
254
* Destroy the input channel (cleanup)
255
*/
256
destroy(): void;
257
```
258
259
**Usage Examples:**
260
261
```javascript
262
const input = WebMidi.inputs[0];
263
const channel1 = input.channels[0]; // Channel 1 (index 0)
264
265
// Check if a note is currently pressed
266
const noteState = channel1.getNoteState("C4");
267
if (noteState) {
268
console.log("C4 is pressed with velocity:", noteState.velocity);
269
}
270
271
// Listen to channel-specific events
272
channel1.addListener("noteon", (e) => {
273
console.log("Note on channel 1:", e.note.identifier);
274
});
275
276
// Get control change name
277
const ccName = channel1.getCcNameByNumber(64); // "sustain"
278
```
279
280
## Common MIDI Events
281
282
### Note Events
283
284
```javascript
285
// Note on event
286
input.addListener("noteon", (e) => {
287
console.log("Note:", e.note.name);
288
console.log("Octave:", e.note.octave);
289
console.log("Velocity:", e.velocity); // 0-1
290
console.log("Raw velocity:", e.rawVelocity); // 0-127
291
console.log("Channel:", e.channel); // 1-16
292
});
293
294
// Note off event
295
input.addListener("noteoff", (e) => {
296
console.log("Note off:", e.note.identifier);
297
console.log("Release velocity:", e.velocity);
298
});
299
```
300
301
### Control Change Events
302
303
```javascript
304
// Control change
305
input.addListener("controlchange", (e) => {
306
console.log("Controller:", e.controller.name);
307
console.log("Number:", e.controller.number);
308
console.log("Value:", e.value); // 0-1
309
console.log("Raw value:", e.rawValue); // 0-127
310
});
311
312
// Specific control changes
313
input.addListener("controlchange-sustain", (e) => {
314
console.log("Sustain pedal:", e.value > 0.5 ? "pressed" : "released");
315
});
316
```
317
318
### Other Common Events
319
320
```javascript
321
// Pitch bend
322
input.addListener("pitchbend", (e) => {
323
console.log("Pitch bend:", e.value); // -1 to 1
324
});
325
326
// Program change
327
input.addListener("programchange", (e) => {
328
console.log("Program:", e.value); // 1-128
329
});
330
331
// Channel aftertouch
332
input.addListener("channelaftertouch", (e) => {
333
console.log("Channel pressure:", e.value);
334
});
335
336
// Key aftertouch (polyphonic)
337
input.addListener("keyaftertouch", (e) => {
338
console.log("Key pressure:", e.note.identifier, e.value);
339
});
340
```
341
342
## Types
343
344
```javascript { .api }
345
interface NoteEvent {
346
note: Note;
347
velocity: number;
348
rawVelocity: number;
349
channel: number;
350
timestamp: number;
351
target: Input | InputChannel;
352
}
353
354
interface ControlChangeEvent {
355
controller: {
356
name: string;
357
number: number;
358
};
359
value: number;
360
rawValue: number;
361
channel: number;
362
timestamp: number;
363
target: Input | InputChannel;
364
}
365
366
interface PitchBendEvent {
367
value: number;
368
rawValue: number;
369
channel: number;
370
timestamp: number;
371
target: Input | InputChannel;
372
}
373
374
interface ListenerOptions {
375
channels?: number | number[] | "all";
376
data1?: number | number[];
377
data2?: number | number[];
378
}
379
```