or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

midi-utilities.mddocs/

0

# MIDI Utilities

1

2

Helper functions for MIDI port management, API selection, and interactive port opening with support for environment-based configuration. Available through the `rtmidi.midiutil` module.

3

4

## Capabilities

5

6

### Environment-based API Selection

7

8

Determine which MIDI API backend to use based on environment variables and system capabilities.

9

10

```python { .api }

11

def get_api_from_environment(api=rtmidi.API_UNSPECIFIED):

12

"""

13

Get RtMidi API from environment variable or return specified API.

14

15

Parameters:

16

- api: Default API to use if environment doesn't specify one

17

18

Returns:

19

- int: One of the rtmidi.API_* constants

20

21

Environment:

22

- RTMIDI_API: Set to API name (LINUX_ALSA, UNIX_JACK, MACOSX_CORE,

23

WINDOWS_MM, RTMIDI_DUMMY) to specify backend

24

25

Note: If RTMIDI_API is unset or invalid, returns the api parameter value.

26

"""

27

```

28

29

### Port Listing Functions

30

31

List available MIDI input and output ports on the system.

32

33

```python { .api }

34

def list_available_ports(ports=None, midiio=None):

35

"""

36

Print list of MIDI ports to console.

37

38

Parameters:

39

- ports: List of port names (if None, gets from midiio instance)

40

- midiio: MidiIn or MidiOut instance to query ports from

41

42

Output: Prints numbered list of available ports to console

43

"""

44

45

def list_input_ports(api=rtmidi.API_UNSPECIFIED):

46

"""

47

List available MIDI input ports.

48

49

Parameters:

50

- api: MIDI API to use (determined via get_api_from_environment if API_UNSPECIFIED)

51

52

Raises:

53

- rtmidi.SystemError: If RtMidi backend initialization fails

54

55

Output: Prints numbered list of input ports to console

56

"""

57

58

def list_output_ports(api=rtmidi.API_UNSPECIFIED):

59

"""

60

List available MIDI output ports.

61

62

Parameters:

63

- api: MIDI API to use (determined via get_api_from_environment if API_UNSPECIFIED)

64

65

Raises:

66

- rtmidi.SystemError: If RtMidi backend initialization fails

67

68

Output: Prints numbered list of output ports to console

69

"""

70

```

71

72

### Generic Port Opening

73

74

Flexible port opening function with interactive selection and virtual port support.

75

76

```python { .api }

77

def open_midiport(port=None, type_="input", api=rtmidi.API_UNSPECIFIED,

78

use_virtual=False, interactive=True, client_name=None,

79

port_name=None):

80

"""

81

Open MIDI port with flexible port selection and configuration.

82

83

Parameters:

84

- port: Port number (int), port name substring (str), or None for interactive selection

85

- type_: "input" or "output" to determine MidiIn vs MidiOut instance

86

- api: MIDI API backend (passed to get_api_from_environment)

87

- use_virtual: Create virtual port if no hardware ports or port=None

88

- interactive: Enable console prompts for port selection and virtual port creation

89

- client_name: MIDI client name for the instance

90

- port_name: Name for the opened port (uses default if None)

91

92

Returns:

93

- tuple[MidiIn|MidiOut, str]: (midi_instance, port_name)

94

95

Raises:

96

- KeyboardInterrupt: User pressed Ctrl-C during interactive selection

97

- EOFError: User pressed Ctrl-D during interactive selection

98

- rtmidi.SystemError: RtMidi backend initialization failed

99

- rtmidi.NoDevicesError: No MIDI ports available and virtual not enabled

100

- rtmidi.InvalidPortError: Invalid port specified and interactive=False

101

102

Port Selection Behavior:

103

- port=int: Open specific port number

104

- port=str: Open first port containing substring (case-sensitive)

105

- port=None: Interactive selection or virtual port creation

106

107

Interactive Mode:

108

- Lists available ports with numbers

109

- Prompts user to select port by number

110

- Offers virtual port creation option (if supported by API)

111

- Continues prompting until valid selection or user exits

112

"""

113

```

114

115

### Specialized Port Opening Functions

116

117

Convenience functions for opening specific input or output ports.

118

119

```python { .api }

120

def open_midiinput(port=None, api=rtmidi.API_UNSPECIFIED, use_virtual=False,

121

interactive=True, client_name=None, port_name=None):

122

"""

123

Open MIDI input port using open_midiport with type_="input".

124

125

Parameters: Same as open_midiport (excluding type_ parameter)

126

127

Returns:

128

- tuple[MidiIn, str]: (midi_input_instance, port_name)

129

130

Raises: Same as open_midiport

131

"""

132

133

def open_midioutput(port=None, api=rtmidi.API_UNSPECIFIED, use_virtual=False,

134

interactive=True, client_name=None, port_name=None):

135

"""

136

Open MIDI output port using open_midiport with type_="output".

137

138

Parameters: Same as open_midiport (excluding type_ parameter)

139

140

Returns:

141

- tuple[MidiOut, str]: (midi_output_instance, port_name)

142

143

Raises: Same as open_midiport

144

"""

145

```

146

147

## Usage Examples

148

149

### Environment-based API Selection

150

151

```python

152

import os

153

import rtmidi.midiutil as midiutil

154

155

# Set preferred MIDI API via environment

156

os.environ['RTMIDI_API'] = 'LINUX_ALSA' # or 'UNIX_JACK', 'MACOSX_CORE', etc.

157

158

# Use environment setting

159

api = midiutil.get_api_from_environment()

160

print(f"Using API: {api}")

161

162

# Override environment setting

163

api = midiutil.get_api_from_environment(rtmidi.API_UNIX_JACK)

164

print(f"Using API: {api}") # Will use JACK regardless of environment

165

```

166

167

### Listing Available Ports

168

169

```python

170

import rtmidi.midiutil as midiutil

171

172

# List all input ports using default API

173

print("MIDI Input Ports:")

174

midiutil.list_input_ports()

175

176

# List all output ports using specific API

177

print("MIDI Output Ports (ALSA):")

178

midiutil.list_output_ports(api=rtmidi.API_LINUX_ALSA)

179

```

180

181

Output example:

182

```

183

MIDI Input Ports:

184

Available MIDI input ports:

185

186

[0] Midi Through:Midi Through Port-0 14:0

187

[1] USB MIDI Device:USB MIDI Device MIDI 1 20:0

188

189

MIDI Output Ports (ALSA):

190

Available MIDI output ports:

191

192

[0] Midi Through:Midi Through Port-0 14:0

193

[1] USB MIDI Device:USB MIDI Device MIDI 1 20:0

194

```

195

196

### Interactive Port Opening

197

198

```python

199

import rtmidi.midiutil as midiutil

200

201

# Interactive input port selection

202

try:

203

midiin, port_name = midiutil.open_midiinput(

204

interactive=True,

205

use_virtual=True,

206

client_name="My MIDI App"

207

)

208

print(f"Opened input port: {port_name}")

209

210

# Use the MIDI input

211

# ... your code here ...

212

213

finally:

214

midiin.close_port()

215

del midiin

216

```

217

218

### Programmatic Port Opening

219

220

```python

221

import rtmidi.midiutil as midiutil

222

223

# Open specific port by number

224

try:

225

midiout, port_name = midiutil.open_midioutput(

226

port=0, # First available port

227

interactive=False,

228

port_name="My Output Port"

229

)

230

print(f"Opened output port: {port_name}")

231

232

except rtmidi.InvalidPortError:

233

print("Port 0 not available")

234

except rtmidi.NoDevicesError:

235

print("No MIDI output ports found")

236

237

# Open port by name substring

238

try:

239

midiout, port_name = midiutil.open_midioutput(

240

port="USB MIDI", # Matches first port containing "USB MIDI"

241

interactive=False

242

)

243

print(f"Opened output port: {port_name}")

244

245

except rtmidi.InvalidPortError:

246

print("No port matching 'USB MIDI' found")

247

```

248

249

### Virtual Port Creation

250

251

```python

252

import rtmidi.midiutil as midiutil

253

254

# Create virtual port automatically if no hardware ports

255

try:

256

midiin, port_name = midiutil.open_midiinput(

257

port=None, # No specific port

258

use_virtual=True, # Enable virtual port creation

259

interactive=False, # Don't prompt user

260

port_name="Virtual Input App"

261

)

262

print(f"Created/opened: {port_name}")

263

264

# Virtual port is now available for other applications to connect to

265

print("Waiting for MIDI input...")

266

while True:

267

message = midiin.get_message()

268

if message:

269

print(f"Received: {message}")

270

271

except KeyboardInterrupt:

272

print("Exiting...")

273

finally:

274

midiin.close_port()

275

del midiin

276

```

277

278

### Comprehensive Example with Error Handling

279

280

```python

281

import rtmidi

282

import rtmidi.midiutil as midiutil

283

import time

284

285

def setup_midi_io():

286

"""Set up MIDI input and output with comprehensive error handling."""

287

288

try:

289

# Try to open specific devices by name

290

midiin, in_name = midiutil.open_midiinput(

291

port="Keystation", # Look for keyboard with "Keystation" in name

292

use_virtual=True, # Fall back to virtual if not found

293

interactive=False, # Don't prompt user

294

client_name="MIDI Processor"

295

)

296

print(f"MIDI Input: {in_name}")

297

298

midiout, out_name = midiutil.open_midioutput(

299

port="TiMidity", # Look for software synth

300

use_virtual=True, # Fall back to virtual if not found

301

interactive=False,

302

client_name="MIDI Processor"

303

)

304

print(f"MIDI Output: {out_name}")

305

306

return midiin, midiout

307

308

except rtmidi.SystemError as e:

309

print(f"MIDI system error: {e}")

310

return None, None

311

except Exception as e:

312

print(f"Unexpected error: {e}")

313

return None, None

314

315

def main():

316

midiin, midiout = setup_midi_io()

317

if not midiin or not midiout:

318

print("Failed to set up MIDI I/O")

319

return

320

321

try:

322

# Process MIDI for 30 seconds

323

print("Processing MIDI for 30 seconds...")

324

start_time = time.time()

325

326

while time.time() - start_time < 30:

327

message = midiin.get_message()

328

if message:

329

# Echo received message to output

330

midiout.send_message(message[0])

331

print(f"Echoed: {message[0]}")

332

time.sleep(0.01)

333

334

except KeyboardInterrupt:

335

print("Interrupted by user")

336

finally:

337

# Clean up

338

midiin.close_port()

339

midiout.close_port()

340

del midiin

341

del midiout

342

print("MIDI I/O closed")

343

344

if __name__ == "__main__":

345

main()

346

```

347

348

### Custom Port Selection Logic

349

350

```python

351

import rtmidi

352

import rtmidi.midiutil as midiutil

353

354

def find_preferred_ports():

355

"""Find preferred MIDI ports based on custom criteria."""

356

357

# Get all available ports

358

midiin = rtmidi.MidiIn()

359

input_ports = midiin.get_ports()

360

midiin.delete()

361

362

midiout = rtmidi.MidiOut()

363

output_ports = midiout.get_ports()

364

midiout.delete()

365

366

# Custom port selection logic

367

preferred_input = None

368

preferred_output = None

369

370

# Prefer hardware controllers for input

371

for i, port in enumerate(input_ports):

372

if any(keyword in port.lower() for keyword in ['keyboard', 'controller', 'keystation']):

373

preferred_input = i

374

break

375

376

# Prefer software synths for output

377

for i, port in enumerate(output_ports):

378

if any(keyword in port.lower() for keyword in ['timidity', 'fluidsynth', 'synth']):

379

preferred_output = i

380

break

381

382

return preferred_input, preferred_output, input_ports, output_ports

383

384

def open_preferred_ports():

385

"""Open MIDI ports using custom selection logic."""

386

387

in_port, out_port, in_ports, out_ports = find_preferred_ports()

388

389

# Open input

390

if in_port is not None:

391

midiin, in_name = midiutil.open_midiinput(port=in_port, interactive=False)

392

print(f"Opened preferred input: {in_name}")

393

else:

394

print("No preferred input found, using interactive selection:")

395

midiin, in_name = midiutil.open_midiinput(interactive=True)

396

397

# Open output

398

if out_port is not None:

399

midiout, out_name = midiutil.open_midioutput(port=out_port, interactive=False)

400

print(f"Opened preferred output: {out_name}")

401

else:

402

print("No preferred output found, using interactive selection:")

403

midiout, out_name = midiutil.open_midioutput(interactive=True)

404

405

return midiin, midiout

406

407

# Usage

408

try:

409

midiin, midiout = open_preferred_ports()

410

# ... use MIDI I/O ...

411

finally:

412

midiin.close_port()

413

midiout.close_port()

414

del midiin

415

del midiout

416

```