or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdmidi-constants.mdmidi-io.mdmidi-utilities.md

midi-io.mddocs/

0

# Core MIDI I/O

1

2

Primary interfaces for MIDI input and output operations, providing cross-platform realtime MIDI functionality with support for both hardware and virtual ports.

3

4

## Capabilities

5

6

### MidiIn Class

7

8

MIDI input client interface for receiving MIDI messages with support for polling and callback-based message handling.

9

10

```python { .api }

11

class MidiIn:

12

def __init__(self, rtapi=API_UNSPECIFIED, name="RtMidi Client", queue_size_limit=1024):

13

"""

14

Create MIDI input instance.

15

16

Parameters:

17

- rtapi: API backend (API_UNSPECIFIED, API_LINUX_ALSA, API_MACOSX_CORE, etc.)

18

- name: Client name for MIDI system

19

- queue_size_limit: Internal ring buffer size for incoming MIDI events

20

21

Raises:

22

- SystemError: If RtMidi backend initialization fails

23

- TypeError: If incompatible parameter type is passed

24

"""

25

26

def get_current_api(self):

27

"""

28

Get the low-level MIDI backend API used by this instance.

29

30

Returns:

31

- int: One of the API_* constants

32

"""

33

34

def get_port_count(self):

35

"""

36

Get number of available MIDI input ports.

37

38

Returns:

39

- int: Number of available ports

40

"""

41

42

def get_port_name(self, port, encoding='auto'):

43

"""

44

Get name of MIDI input port by number.

45

46

Parameters:

47

- port: Port number (0-based)

48

- encoding: Text encoding ('auto', 'utf-8', 'latin1', 'macroman', or None)

49

50

Returns:

51

- str: Port name (if encoding specified)

52

- bytes: Port name (if encoding=None)

53

- None: If port name is empty

54

"""

55

56

def get_ports(self, encoding='auto'):

57

"""

58

Get list of available MIDI input port names.

59

60

Parameters:

61

- encoding: Text encoding for port names

62

63

Returns:

64

- list[str]: List of port names with index corresponding to port number

65

"""

66

67

def is_port_open(self):

68

"""

69

Check if a port is currently open.

70

71

Returns:

72

- bool: True if port is open (including virtual ports)

73

"""

74

75

def open_port(self, port=0, name=None):

76

"""

77

Open MIDI input port by number.

78

79

Parameters:

80

- port: Port number to open (default: 0)

81

- name: Port name (default: "RtMidi input")

82

83

Returns:

84

- MidiIn: Self for method chaining

85

86

Raises:

87

- InvalidPortError: Invalid port number

88

- InvalidUseError: Port already open

89

- TypeError: Incompatible parameter type

90

"""

91

92

def open_virtual_port(self, name=None):

93

"""

94

Open virtual MIDI input port.

95

96

Parameters:

97

- name: Virtual port name (default: "RtMidi virtual input")

98

99

Returns:

100

- MidiIn: Self for method chaining

101

102

Raises:

103

- InvalidUseError: Port already open

104

- UnsupportedOperationError: Virtual ports not supported (Windows MM)

105

- TypeError: Incompatible parameter type

106

"""

107

108

def close_port(self):

109

"""

110

Close opened MIDI input port and cancel any callbacks.

111

Safe to call repeatedly or when no port is open.

112

"""

113

114

def set_client_name(self, name):

115

"""

116

Set MIDI client name (ALSA only).

117

118

Parameters:

119

- name: Client name string

120

121

Raises:

122

- UnsupportedOperationError: API doesn't support client name changes

123

- TypeError: Incompatible parameter type

124

"""

125

126

def set_port_name(self, name):

127

"""

128

Set name of currently opened port (ALSA/JACK only).

129

130

Parameters:

131

- name: Port name string

132

133

Raises:

134

- InvalidUseError: No port currently open

135

- UnsupportedOperationError: API doesn't support port name changes

136

- TypeError: Incompatible parameter type

137

"""

138

139

def get_message(self):

140

"""

141

Poll for MIDI input message.

142

143

Returns:

144

- tuple[list[int], float]: (message_bytes, delta_time) if message available

145

- None: If no message available

146

147

Note: Non-blocking. Returns immediately if no message available.

148

"""

149

150

def ignore_types(self, sysex=True, timing=True, active_sense=True):

151

"""

152

Enable/disable filtering of MIDI event types.

153

154

Parameters:

155

- sysex: Filter System Exclusive messages (default: True)

156

- timing: Filter MIDI Clock messages (default: True)

157

- active_sense: Filter Active Sensing messages (default: True)

158

159

Note: Set to False to receive these message types.

160

"""

161

162

def set_callback(self, func, data=None):

163

"""

164

Register callback function for MIDI input.

165

166

Parameters:

167

- func: Callback function taking (message_tuple, data) arguments

168

- data: User data passed to callback (can be any Python object)

169

170

Note: Callback receives ((message_bytes, delta_time), data) arguments.

171

Replaces any previously registered callback.

172

"""

173

174

def cancel_callback(self):

175

"""

176

Remove registered callback function.

177

Safe to call when no callback is registered.

178

"""

179

180

def set_error_callback(self, func, data=None):

181

"""

182

Register error callback function.

183

184

Parameters:

185

- func: Error callback taking (error_type, error_message, data) arguments

186

- data: User data passed to callback

187

188

Note: Replaces default error handler that raises exceptions.

189

"""

190

191

def cancel_error_callback(self):

192

"""

193

Remove error callback and reinstate default error handler.

194

"""

195

196

def delete(self):

197

"""

198

Manually destroy C++ instance for immediate cleanup.

199

200

Warning: Instance must not be used after calling this method.

201

"""

202

203

@property

204

def is_deleted(self):

205

"""Check if C++ instance has been destroyed."""

206

207

def __enter__(self):

208

"""Context manager entry - returns self."""

209

210

def __exit__(self, *exc_info):

211

"""Context manager exit - closes port automatically."""

212

```

213

214

### MidiOut Class

215

216

MIDI output client interface for sending MIDI messages to hardware and virtual ports.

217

218

```python { .api }

219

class MidiOut:

220

def __init__(self, rtapi=API_UNSPECIFIED, name="RtMidi Client"):

221

"""

222

Create MIDI output instance.

223

224

Parameters:

225

- rtapi: API backend (API_UNSPECIFIED, API_LINUX_ALSA, API_MACOSX_CORE, etc.)

226

- name: Client name for MIDI system

227

228

Raises:

229

- SystemError: If RtMidi backend initialization fails

230

- TypeError: If incompatible parameter type is passed

231

"""

232

233

def get_current_api(self):

234

"""

235

Get the low-level MIDI backend API used by this instance.

236

237

Returns:

238

- int: One of the API_* constants

239

"""

240

241

def get_port_count(self):

242

"""

243

Get number of available MIDI output ports.

244

245

Returns:

246

- int: Number of available ports

247

"""

248

249

def get_port_name(self, port, encoding='auto'):

250

"""

251

Get name of MIDI output port by number.

252

253

Parameters:

254

- port: Port number (0-based)

255

- encoding: Text encoding ('auto', 'utf-8', 'latin1', 'macroman', or None)

256

257

Returns:

258

- str: Port name (if encoding specified)

259

- bytes: Port name (if encoding=None)

260

- None: If port name is empty

261

"""

262

263

def get_ports(self, encoding='auto'):

264

"""

265

Get list of available MIDI output port names.

266

267

Parameters:

268

- encoding: Text encoding for port names

269

270

Returns:

271

- list[str]: List of port names with index corresponding to port number

272

"""

273

274

def is_port_open(self):

275

"""

276

Check if a port is currently open.

277

278

Returns:

279

- bool: True if port is open (including virtual ports)

280

"""

281

282

def open_port(self, port=0, name=None):

283

"""

284

Open MIDI output port by number.

285

286

Parameters:

287

- port: Port number to open (default: 0)

288

- name: Port name (default: "RtMidi output")

289

290

Returns:

291

- MidiOut: Self for method chaining

292

293

Raises:

294

- InvalidPortError: Invalid port number

295

- InvalidUseError: Port already open

296

- TypeError: Incompatible parameter type

297

"""

298

299

def open_virtual_port(self, name=None):

300

"""

301

Open virtual MIDI output port.

302

303

Parameters:

304

- name: Virtual port name (default: "RtMidi virtual output")

305

306

Returns:

307

- MidiOut: Self for method chaining

308

309

Raises:

310

- InvalidUseError: Port already open

311

- UnsupportedOperationError: Virtual ports not supported (Windows MM)

312

- TypeError: Incompatible parameter type

313

"""

314

315

def close_port(self):

316

"""

317

Close opened MIDI output port.

318

Safe to call repeatedly or when no port is open.

319

"""

320

321

def set_client_name(self, name):

322

"""

323

Set MIDI client name (ALSA only).

324

325

Parameters:

326

- name: Client name string

327

328

Raises:

329

- UnsupportedOperationError: API doesn't support client name changes

330

- TypeError: Incompatible parameter type

331

"""

332

333

def set_port_name(self, name):

334

"""

335

Set name of currently opened port (ALSA/JACK only).

336

337

Parameters:

338

- name: Port name string

339

340

Raises:

341

- InvalidUseError: No port currently open

342

- UnsupportedOperationError: API doesn't support port name changes

343

- TypeError: Incompatible parameter type

344

"""

345

346

def send_message(self, message):

347

"""

348

Send MIDI message to output port.

349

350

Parameters:

351

- message: Iterable of integers (0-255) representing MIDI message bytes

352

353

Raises:

354

- ValueError: Empty message or invalid SysEx message format

355

356

Notes:

357

- Normal MIDI messages: 1-3 bytes

358

- SysEx messages: Must start with 0xF0 if longer than 3 bytes

359

- With some APIs (Windows MM) this function blocks until message is sent

360

"""

361

362

def set_error_callback(self, func, data=None):

363

"""

364

Register error callback function.

365

366

Parameters:

367

- func: Error callback taking (error_type, error_message, data) arguments

368

- data: User data passed to callback

369

370

Note: Replaces default error handler that raises exceptions.

371

"""

372

373

def cancel_error_callback(self):

374

"""

375

Remove error callback and reinstate default error handler.

376

"""

377

378

def delete(self):

379

"""

380

Manually destroy C++ instance for immediate cleanup.

381

382

Warning: Instance must not be used after calling this method.

383

"""

384

385

@property

386

def is_deleted(self):

387

"""Check if C++ instance has been destroyed."""

388

389

def __enter__(self):

390

"""Context manager entry - returns self."""

391

392

def __exit__(self, *exc_info):

393

"""Context manager exit - closes port automatically."""

394

```

395

396

## Usage Examples

397

398

### Basic MIDI Output

399

400

```python

401

import rtmidi

402

403

# Create and open MIDI output

404

midiout = rtmidi.MidiOut()

405

ports = midiout.get_ports()

406

407

if ports:

408

print("Available output ports:")

409

for i, port in enumerate(ports):

410

print(f" {i}: {port}")

411

412

midiout.open_port(0)

413

print(f"Opened: {ports[0]}")

414

else:

415

midiout.open_virtual_port("Python Virtual Out")

416

print("Created virtual output port")

417

418

# Send MIDI messages

419

note_on = [0x90, 60, 100] # Note On, Middle C, velocity 100

420

note_off = [0x80, 60, 0] # Note Off, Middle C

421

422

midiout.send_message(note_on)

423

time.sleep(1.0)

424

midiout.send_message(note_off)

425

426

# Clean up

427

midiout.close_port()

428

del midiout

429

```

430

431

### Callback-based MIDI Input

432

433

```python

434

import rtmidi

435

import time

436

437

def midi_callback(message_data, user_data):

438

message, delta_time = message_data

439

print(f"MIDI: {message} (dt: {delta_time:.3f}s)")

440

441

# Create and configure MIDI input

442

midiin = rtmidi.MidiIn()

443

midiin.ignore_types(sysex=False) # Enable SysEx reception

444

445

ports = midiin.get_ports()

446

if ports:

447

midiin.open_port(0)

448

else:

449

midiin.open_virtual_port("Python Virtual In")

450

451

# Set callback and wait for messages

452

midiin.set_callback(midi_callback)

453

print("Listening for MIDI messages. Press Enter to exit.")

454

input()

455

456

# Clean up

457

midiin.cancel_callback()

458

midiin.close_port()

459

del midiin

460

```

461

462

### Context Manager Usage

463

464

```python

465

import rtmidi

466

467

# Automatic resource cleanup with context manager

468

with rtmidi.MidiOut() as midiout:

469

if midiout.get_port_count() > 0:

470

midiout.open_port(0)

471

midiout.send_message([0x90, 64, 100]) # Send note

472

time.sleep(0.5)

473

midiout.send_message([0x80, 64, 0]) # Stop note

474

# Port automatically closed when exiting context

475

```