File: _midiout.py

package info (click to toggle)
python-expyriment 0.7.0%2Bgit34-g55a4e7e-3.2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,504 kB
  • ctags: 2,094
  • sloc: python: 12,766; makefile: 150
file content (212 lines) | stat: -rw-r--r-- 5,208 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
"""MIDI output.

This module contains a class implementing a MIDI output device.

"""

__author__ = 'Florian Krause <florian@expyriment.org>, \
Oliver Lindemann <oliver@expyriment.org>'
__version__ = '0.7.0'
__revision__ = '55a4e7e'
__date__ = 'Wed Mar 26 14:33:37 2014 +0100'


import _midiout_defaults as defaults
import expyriment
from expyriment.io._input_output import Output

try:
    from pygame import midi as _midi
    _midi.init()
except:
    _midi = None

class MidiOut(Output):
    """A class implementing a MIDI output.

    **EXPERIMENTAL!**

    Due to a bug in Pygame's midi module, closing a MidiOut (or the programme)
    will cause an error message. Until this is fixed in Pygame, MidiOut will
    stay in extras.

    """

    @staticmethod
    def get_devices():
        """Get a list of all MIDI output devices connected to the system."""

        if _midi is None:
            return
        outdevices = []
        all_ids = _midi.get_count()
        for device_id in all_ids:
            info = _midi.get_device_info(device_id)
            if info[3] == 1:
                outdevices.add([device_id, info[1]])
        return outdevices

    def __init__(self, device, latency=None, buffer_size=None):
        """Create a MIDI output.

        Parameters
        ----------
        device : int or str
            id or name of the MIDI device
        latency : int, optional
            delay in ms applied to timestamp
        buffer_size : int, optional
            number of events to be buffered

        """

        import types
        if type(_midi) is not types.ModuleType:
            raise ImportError("""Sorry, MIDI output is not supported on this computer.""")

        if not expyriment._active_exp.is_initialized:
            raise RuntimeError(
                "Cannot create MidiOut before expyriment.initialize()!")
        _midi.init()
        Output.__init__(self)
        self._id = device
        if buffer_size is None:
            buffer_size = defaults.midiout_buffer_size
        self._buffer_size = buffer_size
        if latency is None:
            latency = defaults.midiout_latency
        self._latency = latency
        self.output = _midi.Output(device, latency, buffer_size)

    @property
    def id(self):
        """Getter for id."""

        return self._id

    @property
    def buffer_size(self):
        """Getter for buffer_size."""

        return self._buffer_size

    @property
    def latency(self):
        """Getter for latency."""

        return self._latency

    def close(self, abort=False):
        """Close the MIDI interface.

        Parameters
        ----------
        abort : bool, optional
            abort messages in the buffer (default=True)

        """

        if abort:
            self.output.abort()
        self.output.close()

    def abort(self):
        """Terminates outgoing messages immediately."""

        self.output.abort()

    def send(self, event_list):
        """Send a list of MIDI events.

        Each event should have the following format:
            [status, data1, data2, data3], timestamp]

        Notes
        -----
        The data fields are optional.

        Parameters
        ----------
        event_list : list
            list of events to send

        """

        self.output.write(event_list)

    def send_short(self, status, data1=0, data2=0):
        """Send MIDI events of 3 bytes or less.

        Parameters
        ----------
        status : int
            status of the event to send
        data1 : int, optional
            data1 of the event to send
        data2 : int, optional
            data2 of the event to send

        """

        self.output.write_short(status, data1, data2)


    def send_sysex(self, timestamp, message):
        """Send a System Exlusive message.

        Parameters
        ----------
        timestamp : int
            when (in ms) to send the message
        message : sit or list
            message to send

        """

        self.output.wirte_sys_ex(timestamp, message)

    def select_instrument(self, instrument_id, channel=0):
        """Select an instrument.

        Parameters
        ----------
        instrument_id : int
            id (0-127) of the instrument
        channel : int, optional
            MIDI channel for the instrument (default=0)

        """

        self.output.set_instrument(instrument_id, channel)

    def send_note_on(self, note, velocity=None, channel=0):
        """Send a note-on event.

        Parameters
        ----------
        note : int
            note value
        velocity : int, optional
            velocity of the note
        channel : int, optional
            MIDI channel of the note (default=0)

        """

        self.output.note_on(note, velocity, channel)

    def send_note_off(self, note, velocity=None, channel=0):
        """Send a note-off event.

        Parameters
        ----------
        note : int
            note value
        velocity : int, optional
            velocity of the note
        channel : int, optional
            MIDI channel of the note (default=0)

        """

        self.output.note_off(note, velocity, channel)