1""" 2Module for interacting with midi input and output. 3 4The midi module can send output to midi devices, and get input 5from midi devices. It can also list midi devices on the system. 6 7Including real midi devices, and virtual ones. 8 9It uses the portmidi library. Is portable to which ever platforms 10portmidi supports (currently windows, OSX, and linux). 11""" 12 13import atexit 14 15 16 17_init = False 18_pypm = None 19 20 21__all__ = [ "Input", 22 "MidiException", 23 "Output", 24 "get_count", 25 "get_default_input_id", 26 "get_default_output_id", 27 "get_device_info", 28 "init", 29 "quit", 30 "time", 31 ] 32 33__theclasses__ = ["Input", "Output"] 34 35 36def init(): 37 """initialize the midi module 38 pyportmidi.init(): return None 39 40 Call the initialisation function before using the midi module. 41 42 It is safe to call this more than once. 43 """ 44 global _init, _pypm 45 if not _init: 46 import pyportmidi._pyportmidi 47 _pypm = pyportmidi._pyportmidi 48 49 _pypm.Initialize() 50 _init = True 51 atexit.register(quit) 52 53 54def quit(): 55 """uninitialize the midi module 56 pyportmidi.quit(): return None 57 58 59 Called automatically atexit if you don't call it. 60 61 It is safe to call this function more than once. 62 """ 63 global _init, _pypm 64 if _init: 65 # TODO: find all Input and Output classes and close them first? 66 _pypm.Terminate() 67 _init = False 68 del _pypm 69 70def _check_init(): 71 if not _init: 72 raise RuntimeError("pyportmidi not initialised.") 73 74def get_count(): 75 """gets the number of devices. 76 pyportmidi.get_count(): return num_devices 77 78 79 Device ids range from 0 to get_count() -1 80 """ 81 _check_init() 82 return _pypm.CountDevices() 83 84 85 86 87def get_default_input_id(): 88 """gets default input device number 89 pyportmidi.get_default_input_id(): return default_id 90 91 92 Return the default device ID or -1 if there are no devices. 93 The result can be passed to the Input()/Ouput() class. 94 95 On the PC, the user can specify a default device by 96 setting an environment variable. For example, to use device #1. 97 98 set PM_RECOMMENDED_INPUT_DEVICE=1 99 100 The user should first determine the available device ID by using 101 the supplied application "testin" or "testout". 102 103 In general, the registry is a better place for this kind of info, 104 and with USB devices that can come and go, using integers is not 105 very reliable for device identification. Under Windows, if 106 PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is 107 *NOT* found in the environment, then the default device is obtained 108 by looking for a string in the registry under: 109 HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device 110 and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device 111 for a string. The number of the first device with a substring that 112 matches the string exactly is returned. For example, if the string 113 in the registry is "USB", and device 1 is named 114 "In USB MidiSport 1x1", then that will be the default 115 input because it contains the string "USB". 116 117 In addition to the name, get_device_info() returns "interf", which 118 is the interface name. (The "interface" is the underlying software 119 system or API used by PortMidi to access devices. Examples are 120 MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.) 121 At present, the only Win32 interface is "MMSystem", the only Linux 122 interface is "ALSA", and the only Max OS X interface is "CoreMIDI". 123 To specify both the interface and the device name in the registry, 124 separate the two with a comma and a space, e.g.: 125 MMSystem, In USB MidiSport 1x1 126 In this case, the string before the comma must be a substring of 127 the "interf" string, and the string after the space must be a 128 substring of the "name" name string in order to match the device. 129 130 Note: in the current release, the default is simply the first device 131 (the input or output device with the lowest PmDeviceID). 132 """ 133 return _pypm.GetDefaultInputDeviceID() 134 135 136 137 138def get_default_output_id(): 139 """gets default output device number 140 pyportmidi.get_default_output_id(): return default_id 141 142 143 Return the default device ID or -1 if there are no devices. 144 The result can be passed to the Input()/Ouput() class. 145 146 On the PC, the user can specify a default device by 147 setting an environment variable. For example, to use device #1. 148 149 set PM_RECOMMENDED_OUTPUT_DEVICE=1 150 151 The user should first determine the available device ID by using 152 the supplied application "testin" or "testout". 153 154 In general, the registry is a better place for this kind of info, 155 and with USB devices that can come and go, using integers is not 156 very reliable for device identification. Under Windows, if 157 PM_RECOMMENDED_OUTPUT_DEVICE (or PM_RECOMMENDED_INPUT_DEVICE) is 158 *NOT* found in the environment, then the default device is obtained 159 by looking for a string in the registry under: 160 HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Input_Device 161 and HKEY_LOCAL_MACHINE/SOFTWARE/PortMidi/Recommended_Output_Device 162 for a string. The number of the first device with a substring that 163 matches the string exactly is returned. For example, if the string 164 in the registry is "USB", and device 1 is named 165 "In USB MidiSport 1x1", then that will be the default 166 input because it contains the string "USB". 167 168 In addition to the name, get_device_info() returns "interf", which 169 is the interface name. (The "interface" is the underlying software 170 system or API used by PortMidi to access devices. Examples are 171 MMSystem, DirectX (not implemented), ALSA, OSS (not implemented), etc.) 172 At present, the only Win32 interface is "MMSystem", the only Linux 173 interface is "ALSA", and the only Max OS X interface is "CoreMIDI". 174 To specify both the interface and the device name in the registry, 175 separate the two with a comma and a space, e.g.: 176 MMSystem, In USB MidiSport 1x1 177 In this case, the string before the comma must be a substring of 178 the "interf" string, and the string after the space must be a 179 substring of the "name" name string in order to match the device. 180 181 Note: in the current release, the default is simply the first device 182 (the input or output device with the lowest PmDeviceID). 183 """ 184 _check_init() 185 return _pypm.GetDefaultOutputDeviceID() 186 187 188def get_device_info(an_id): 189 """ returns information about a midi device 190 pyportmidi.get_device_info(an_id): return (interf, name, input, output, opened) 191 192 interf - a text string describing the device interface, eg 'ALSA'. 193 name - a text string for the name of the device, eg 'Midi Through Port-0' 194 input - 0, or 1 if the device is an input device. 195 output - 0, or 1 if the device is an output device. 196 opened - 0, or 1 if the device is opened. 197 198 If the id is out of range, the function returns None. 199 """ 200 _check_init() 201 return _pypm.GetDeviceInfo(an_id) 202 203 204class Input(object): 205 """Input is used to get midi input from midi devices. 206 Input(device_id) 207 Input(device_id, buffer_size) 208 209 buffer_size -the number of input events to be buffered waiting to 210 be read using Input.read() 211 """ 212 213 def __init__(self, device_id, buffer_size=4096): 214 """ 215 The buffer_size specifies the number of input events to be buffered 216 waiting to be read using Input.read(). 217 """ 218 _check_init() 219 220 if device_id == -1: 221 raise MidiException("Device id is -1, not a valid output id. -1 usually means there were no default Output devices.") 222 223 try: 224 r = get_device_info(device_id) 225 except TypeError: 226 raise TypeError("an integer is required") 227 except OverflowError: 228 raise OverflowError("long int too large to convert to int") 229 230 # and now some nasty looking error checking, to provide nice error 231 # messages to the kind, lovely, midi using people of whereever. 232 if r: 233 interf, name, input, output, opened = r 234 if input: 235 try: 236 self._input = _pypm.Input(device_id, buffer_size) 237 except TypeError: 238 raise TypeError("an integer is required") 239 self.device_id = device_id 240 241 elif output: 242 raise MidiException("Device id given is not a valid input id, it is an output id.") 243 else: 244 raise MidiException("Device id given is not a valid input id.") 245 else: 246 raise MidiException("Device id invalid, out of range.") 247 248 249 250 251 def _check_open(self): 252 if self._input is None: 253 raise MidiException("midi not open.") 254 255 256 257 def close(self): 258 """ closes a midi stream, flushing any pending buffers. 259 Input.close(): return None 260 261 PortMidi attempts to close open streams when the application 262 exits -- this is particularly difficult under Windows. 263 """ 264 _check_init() 265 if not (self._input is None): 266 self._input.Close() 267 self._input = None 268 269 270 271 def read(self, num_events): 272 """reads num_events midi events from the buffer. 273 Input.read(num_events): return midi_event_list 274 275 Reads from the Input buffer and gives back midi events. 276 [[[status,data1,data2,data3],timestamp], 277 [[status,data1,data2,data3],timestamp],...] 278 """ 279 _check_init() 280 self._check_open() 281 return self._input.Read(num_events) 282 283 284 def poll(self): 285 """returns true if there's data, or false if not. 286 Input.poll(): return Bool 287 288 raises a MidiException on error. 289 """ 290 _check_init() 291 self._check_open() 292 293 r = self._input.Poll() 294 if r == _pypm.TRUE: 295 return True 296 elif r == _pypm.FALSE: 297 return False 298 else: 299 err_text = GetErrorText(r) 300 raise MidiException( (r, err_text) ) 301 302 303 304 305class Output(object): 306 """Output is used to send midi to an output device 307 Output(device_id) 308 Output(device_id, latency = 0) 309 Output(device_id, buffer_size = 4096) 310 Output(device_id, latency, buffer_size) 311 312 The buffer_size specifies the number of output events to be 313 buffered waiting for output. (In some cases -- see below -- 314 PortMidi does not buffer output at all and merely passes data 315 to a lower-level API, in which case buffersize is ignored.) 316 317 latency is the delay in milliseconds applied to timestamps to determine 318 when the output should actually occur. (If latency is < 0, 0 is 319 assumed.) 320 321 If latency is zero, timestamps are ignored and all output is delivered 322 immediately. If latency is greater than zero, output is delayed until 323 the message timestamp plus the latency. (NOTE: time is measured 324 relative to the time source indicated by time_proc. Timestamps are 325 absolute, not relative delays or offsets.) In some cases, PortMidi 326 can obtain better timing than your application by passing timestamps 327 along to the device driver or hardware. Latency may also help you 328 to synchronize midi data to audio data by matching midi latency to 329 the audio buffer latency. 330 331 """ 332 333 def __init__(self, device_id, latency = 0, buffer_size = 4096): 334 """Output(device_id) 335 Output(device_id, latency = 0) 336 Output(device_id, buffer_size = 4096) 337 Output(device_id, latency, buffer_size) 338 339 The buffer_size specifies the number of output events to be 340 buffered waiting for output. (In some cases -- see below -- 341 PortMidi does not buffer output at all and merely passes data 342 to a lower-level API, in which case buffersize is ignored.) 343 344 latency is the delay in milliseconds applied to timestamps to determine 345 when the output should actually occur. (If latency is < 0, 0 is 346 assumed.) 347 348 If latency is zero, timestamps are ignored and all output is delivered 349 immediately. If latency is greater than zero, output is delayed until 350 the message timestamp plus the latency. (NOTE: time is measured 351 relative to the time source indicated by time_proc. Timestamps are 352 absolute, not relative delays or offsets.) In some cases, PortMidi 353 can obtain better timing than your application by passing timestamps 354 along to the device driver or hardware. Latency may also help you 355 to synchronize midi data to audio data by matching midi latency to 356 the audio buffer latency. 357 """ 358 359 _check_init() 360 self._aborted = 0 361 362 if device_id == -1: 363 raise MidiException("Device id is -1, not a valid output id. -1 usually means there were no default Output devices.") 364 365 try: 366 r = get_device_info(device_id) 367 except TypeError: 368 raise TypeError("an integer is required") 369 except OverflowError: 370 raise OverflowError("long int too large to convert to int") 371 372 # and now some nasty looking error checking, to provide nice error 373 # messages to the kind, lovely, midi using people of whereever. 374 if r: 375 interf, name, input, output, opened = r 376 if output: 377 try: 378 self._output = _pypm.Output(device_id, latency) 379 except TypeError: 380 raise TypeError("an integer is required") 381 self.device_id = device_id 382 383 elif input: 384 raise MidiException("Device id given is not a valid output id, it is an input id.") 385 else: 386 raise MidiException("Device id given is not a valid output id.") 387 else: 388 raise MidiException("Device id invalid, out of range.") 389 390 def _check_open(self): 391 if self._output is None: 392 raise MidiException("midi not open.") 393 394 if self._aborted: 395 raise MidiException("midi aborted.") 396 397 398 def close(self): 399 """ closes a midi stream, flushing any pending buffers. 400 Output.close(): return None 401 402 PortMidi attempts to close open streams when the application 403 exits -- this is particularly difficult under Windows. 404 """ 405 _check_init() 406 if not (self._output is None): 407 self._output.Close() 408 self._output = None 409 410 def abort(self): 411 """terminates outgoing messages immediately 412 Output.abort(): return None 413 414 The caller should immediately close the output port; 415 this call may result in transmission of a partial midi message. 416 There is no abort for Midi input because the user can simply 417 ignore messages in the buffer and close an input device at 418 any time. 419 """ 420 421 _check_init() 422 if self._output: 423 self._output.Abort() 424 self._aborted = 1 425 426 427 428 429 430 def write(self, data): 431 """writes a list of midi data to the Output 432 Output.write(data) 433 434 writes series of MIDI information in the form of a list: 435 write([[[status <,data1><,data2><,data3>],timestamp], 436 [[status <,data1><,data2><,data3>],timestamp],...]) 437 <data> fields are optional 438 example: choose program change 1 at time 20000 and 439 send note 65 with velocity 100 500 ms later. 440 write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) 441 notes: 442 1. timestamps will be ignored if latency = 0. 443 2. To get a note to play immediately, send MIDI info with 444 timestamp read from function Time. 445 3. understanding optional data fields: 446 write([[[0xc0,0,0],20000]]) is equivalent to 447 write([[[0xc0],20000]]) 448 449 Can send up to 1024 elements in your data list, otherwise an 450 IndexError exception is raised. 451 """ 452 _check_init() 453 self._check_open() 454 455 self._output.Write(data) 456 457 458 def write_short(self, status, data1 = 0, data2 = 0): 459 """write_short(status <, data1><, data2>) 460 Output.write_short(status) 461 Output.write_short(status, data1 = 0, data2 = 0) 462 463 output MIDI information of 3 bytes or less. 464 data fields are optional 465 status byte could be: 466 0xc0 = program change 467 0x90 = note on 468 etc. 469 data bytes are optional and assumed 0 if omitted 470 example: note 65 on with velocity 100 471 write_short(0x90,65,100) 472 """ 473 _check_init() 474 self._check_open() 475 self._output.WriteShort(status, data1, data2) 476 477 478 def write_sys_ex(self, when, msg): 479 """writes a timestamped system-exclusive midi message. 480 Output.write_sys_ex(when, msg) 481 482 msg - can be a *list* or a *string* 483 when - a timestamp in miliseconds 484 example: 485 (assuming o is an onput MIDI stream) 486 o.write_sys_ex(0,'\\xF0\\x7D\\x10\\x11\\x12\\x13\\xF7') 487 is equivalent to 488 o.write_sys_ex(pyportmidi.time(), 489 [0xF0,0x7D,0x10,0x11,0x12,0x13,0xF7]) 490 """ 491 _check_init() 492 self._check_open() 493 self._output.WriteSysEx(when, msg) 494 495 496 def note_on(self, note, velocity=None, channel = 0): 497 """turns a midi note on. Note must be off. 498 Output.note_on(note, velocity=None, channel = 0) 499 500 Turn a note on in the output stream. The note must already 501 be off for this to work correctly. 502 """ 503 if velocity is None: 504 velocity = 0 505 506 if not (0 <= channel <= 15): 507 raise ValueError("Channel not between 0 and 15.") 508 509 self.write_short(0x90+channel, note, velocity) 510 511 def note_off(self, note, velocity=None, channel = 0): 512 """turns a midi note off. Note must be on. 513 Output.note_off(note, velocity=None, channel = 0) 514 515 Turn a note off in the output stream. The note must already 516 be on for this to work correctly. 517 """ 518 if velocity is None: 519 velocity = 0 520 521 if not (0 <= channel <= 15): 522 raise ValueError("Channel not between 0 and 15.") 523 524 self.write_short(0x80 + channel, note, velocity) 525 526 527 def set_instrument(self, instrument_id, channel = 0): 528 """select an instrument, with a value between 0 and 127 529 Output.set_instrument(instrument_id, channel = 0) 530 531 """ 532 if not (0 <= instrument_id <= 127): 533 raise ValueError("Undefined instrument id: %d" % instrument_id) 534 535 if not (0 <= channel <= 15): 536 raise ValueError("Channel not between 0 and 15.") 537 538 self.write_short(0xc0+channel, instrument_id) 539 540 541 542def time(): 543 """returns the current time in ms of the PortMidi timer 544 pyportmidi.time(): return time 545 546 The time is reset to 0, when the module is inited. 547 """ 548 return _pypm.Time() 549 550 551 552 553 554 555 556 557class MidiException(Exception): 558 """MidiException(errno) that can be raised. 559 """ 560 def __init__(self, value): 561 self.parameter = value 562 def __str__(self): 563 return repr(self.parameter) 564 565 566 567