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