or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants.mdindex.mdmessage-forwarding.mdmessage-processing.mdmidi-input.mdmidi-output.mdnote-processing.mdutilities.mdwebmidi-interface.md

midi-input.mddocs/

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

```