From c144a6615fbeb64e6bba227d7cea0d0284c569ce Mon Sep 17 00:00:00 2001 From: MyreMylar Date: Sat, 13 Jun 2020 16:45:04 +0100 Subject: [PATCH] Pylint pass for midi module --- src_py/midi.py | 206 +++++++++++++++++++++++-------------------------- 1 file changed, 98 insertions(+), 108 deletions(-) diff --git a/src_py/midi.py b/src_py/midi.py index f3f3bd2292..1f54ec5927 100644 --- a/src_py/midi.py +++ b/src_py/midi.py @@ -15,11 +15,10 @@ New in pygame 1.9.0. """ - -#TODO: -# - finish writing tests. -# - likely as interactive tests... so you'd need to plug in a midi device. -# - create a background thread version for input threads. +# TODO: finish writing tests. +# - likely as interactive tests... so you'd need to plug in +# a midi device. +# TODO: create a background thread version for input threads. # - that can automatically inject input into the event queue # once the input object is running. Like joysticks. @@ -33,16 +32,12 @@ import pygame import pygame.locals +import pygame.pypm as _pypm # For backward compatibility. MIDIIN = pygame.locals.MIDIIN MIDIOUT = pygame.locals.MIDIOUT - -_init = False -_pypm = None - - __all__ = [ "Input", "MIDIIN", @@ -66,6 +61,21 @@ __theclasses__ = ["Input", "Output"] +def _module_init(state=None): + # this is a sneaky dodge to store module level state in a non-public + # function. Helps us dodge using globals. + if state is not None: + _module_init.value = state + return state + + try: + _module_init.value + except AttributeError: + return False + else: + return _module_init.value + + def init(): """initialize the midi module pygame.midi.init(): return None @@ -74,17 +84,13 @@ def init(): It is safe to call this more than once. """ - global _init, _pypm - if not _init: - import pygame.pypm - _pypm = pygame.pypm - + if not _module_init(): _pypm.Initialize() - _init = True + _module_init(True) atexit.register(quit) -def quit(): +def quit(): # pylint: disable=redefined-builtin """uninitialize the midi module pygame.midi.quit(): return None @@ -93,12 +99,10 @@ def quit(): It is safe to call this function more than once. """ - global _init, _pypm - if _init: + if _module_init(): # TODO: find all Input and Output classes and close them first? _pypm.Terminate() - _init = False - _pypm = None + _module_init(False) def get_init(): @@ -109,13 +113,14 @@ def get_init(): New in pygame 1.9.5. """ - return _init + return _module_init() def _check_init(): - if not _init: + if not _module_init(): raise RuntimeError("pygame.midi not initialised.") + def get_count(): """gets the number of devices. pygame.midi.get_count(): return num_devices @@ -127,8 +132,6 @@ def get_count(): return _pypm.CountDevices() - - def get_default_input_id(): """gets default input device number pygame.midi.get_default_input_id(): return default_id @@ -179,8 +182,6 @@ def get_default_input_id(): return _pypm.GetDefaultInputDeviceID() - - def get_default_output_id(): """gets default output device number pygame.midi.get_default_output_id(): return default_id @@ -233,7 +234,9 @@ def get_default_output_id(): def get_device_info(an_id): """ returns information about a midi device - pygame.midi.get_device_info(an_id): return (interf, name, input, output, opened) + pygame.midi.get_device_info(an_id): return (interf, name, + input, output, + opened) interf - a text string describing the device interface, eg 'ALSA'. name - a text string for the name of the device, eg 'Midi Through Port-0' @@ -264,10 +267,12 @@ def __init__(self, device_id, buffer_size=4096): _check_init() if device_id == -1: - raise MidiException("Device id is -1, not a valid output id. -1 usually means there were no default Output devices.") + raise MidiException("Device id is -1, not a valid output id. " + "-1 usually means there were no default " + "Output devices.") try: - r = get_device_info(device_id) + result = get_device_info(device_id) except TypeError: raise TypeError("an integer is required") except OverflowError: @@ -275,31 +280,28 @@ def __init__(self, device_id, buffer_size=4096): # and now some nasty looking error checking, to provide nice error # messages to the kind, lovely, midi using people of wherever. - if r: - interf, name, input, output, opened = r - if input: + if result: + _, _, is_input, is_output, _ = result + if is_input: try: self._input = _pypm.Input(device_id, buffer_size) except TypeError: raise TypeError("an integer is required") self.device_id = device_id - elif output: - raise MidiException("Device id given is not a valid input id, it is an output id.") + elif is_output: + raise MidiException( + "Device id given is not a valid" + " input id, it is an output id.") else: raise MidiException("Device id given is not a valid input id.") else: raise MidiException("Device id invalid, out of range.") - - - def _check_open(self): if self._input is None: raise MidiException("midi not open.") - - def close(self): """ closes a midi stream, flushing any pending buffers. Input.close(): return None @@ -308,12 +310,10 @@ def close(self): exits -- this is particularly difficult under Windows. """ _check_init() - if not (self._input is None): + if self._input is not None: self._input.Close() self._input = None - - def read(self, num_events): """reads num_events midi events from the buffer. Input.read(num_events): return midi_event_list @@ -326,7 +326,6 @@ def read(self, num_events): self._check_open() return self._input.Read(num_events) - def poll(self): """returns true if there's data, or false if not. Input.poll(): return Bool @@ -336,16 +335,15 @@ def poll(self): _check_init() self._check_open() - r = self._input.Poll() - if r == _pypm.TRUE: + result = self._input.Poll() + if result == _pypm.TRUE: return True - elif r == _pypm.FALSE: - return False - else: - err_text = GetErrorText(r) - raise MidiException( (r, err_text) ) + if result == _pypm.FALSE: + return False + err_text = _pypm.GetErrorText(result) + raise MidiException((result, err_text)) class Output(object): @@ -376,7 +374,7 @@ class Output(object): """ - def __init__(self, device_id, latency = 0, buffer_size = 4096): + def __init__(self, device_id, latency=0, buffer_size=4096): """Output(device_id) Output(device_id, latency = 0) Output(device_id, buffer_size = 4096) @@ -406,30 +404,34 @@ def __init__(self, device_id, latency = 0, buffer_size = 4096): self._aborted = 0 if device_id == -1: - raise MidiException("Device id is -1, not a valid output id. -1 usually means there were no default Output devices.") + raise MidiException("Device id is -1, not a valid output id." + " -1 usually means there were no default " + "Output devices.") try: - r = get_device_info(device_id) + result = get_device_info(device_id) except TypeError: raise TypeError("an integer is required") except OverflowError: raise OverflowError("long int too large to convert to int") # and now some nasty looking error checking, to provide nice error - # messages to the kind, lovely, midi using people of whereever. - if r: - interf, name, input, output, opened = r - if output: + # messages to the kind, lovely, midi using people of wherever. + if result: + _, _, is_input, is_output, _ = result + if is_output: try: self._output = _pypm.Output(device_id, latency) except TypeError: raise TypeError("an integer is required") self.device_id = device_id - elif input: - raise MidiException("Device id given is not a valid output id, it is an input id.") + elif is_input: + raise MidiException("Device id given is not a valid output " + "id, it is an input id.") else: - raise MidiException("Device id given is not a valid output id.") + raise MidiException("Device id given is not a" + " valid output id.") else: raise MidiException("Device id invalid, out of range.") @@ -440,7 +442,6 @@ def _check_open(self): if self._aborted: raise MidiException("midi aborted.") - def close(self): """ closes a midi stream, flushing any pending buffers. Output.close(): return None @@ -449,7 +450,7 @@ def close(self): exits -- this is particularly difficult under Windows. """ _check_init() - if not (self._output is None): + if self._output is not None: self._output.Close() self._output = None @@ -469,10 +470,6 @@ def abort(self): self._output.Abort() self._aborted = 1 - - - - def write(self, data): """writes a list of midi data to the Output Output.write(data) @@ -547,7 +544,7 @@ def note_on(self, note, velocity, channel=0): Turn a note on in the output stream. The note must already be off for this to work correctly. """ - if not (0 <= channel <= 15): + if not 0 <= channel <= 15: raise ValueError("Channel not between 0 and 15.") self.write_short(0x90 + channel, note, velocity) @@ -563,22 +560,21 @@ def note_off(self, note, velocity=0, channel=0): Turn a note off in the output stream. The note must already be on for this to work correctly. """ - if not (0 <= channel <= 15): + if not 0 <= channel <= 15: raise ValueError("Channel not between 0 and 15.") self.write_short(0x80 + channel, note, velocity) - def set_instrument(self, instrument_id, channel=0): """select an instrument for a channel, with a value between 0 and 127 Output.set_instrument(instrument_id, channel=0) Also called "patch change" or "program change". """ - if not (0 <= instrument_id <= 127): + if not 0 <= instrument_id <= 127: raise ValueError("Undefined instrument id: %d" % instrument_id) - if not (0 <= channel <= 15): + if not 0 <= channel <= 15: raise ValueError("Channel not between 0 and 15.") self.write_short(0xc0 + channel, instrument_id) @@ -595,10 +591,10 @@ def pitch_bend(self, value=0, channel=0): If no value is given, the pitch bend is returned to "no change". """ - if not (0 <= channel <= 15): + if not 0 <= channel <= 15: raise ValueError("Channel not between 0 and 15.") - if not (-8192 <= value <= 8191): + if not -8192 <= value <= 8191: raise ValueError("Pitch bend value must be between " "-8192 and +8191, not %d." % value) @@ -606,25 +602,21 @@ def pitch_bend(self, value=0, channel=0): # 0x2000 is the center corresponding to the normal pitch of the note # (no pitch change)." so value=0 should send 0x2000 value = value + 0x2000 - LSB = value & 0x7f # keep least 7 bits - MSB = value >> 7 - self.write_short(0xe0 + channel, LSB, MSB) - + lsb = value & 0x7f # keep least 7 bits + msb = value >> 7 + self.write_short(0xe0 + channel, lsb, msb) -""" -MIDI commands - - 0x80 Note Off (note_off) - 0x90 Note On (note_on) - 0xA0 Aftertouch - 0xB0 Continuous controller - 0xC0 Patch change (set_instrument?) - 0xD0 Channel Pressure - 0xE0 Pitch bend - 0xF0 (non-musical commands) -""" - +# MIDI commands +# +# 0x80 Note Off (note_off) +# 0x90 Note On (note_on) +# 0xA0 Aftertouch +# 0xB0 Continuous controller +# 0xC0 Patch change (set_instrument?) +# 0xD0 Channel Pressure +# 0xE0 Pitch bend +# 0xF0 (non-musical commands) def time(): @@ -637,7 +629,6 @@ def time(): return _pypm.Time() - def midis2events(midis, device_id): """converts midi events to pygame events pygame.midi.midis2events(midis, device_id): return [Event, ...] @@ -646,36 +637,33 @@ def midis2events(midis, device_id): """ evs = [] for midi in midis: + ((status, data1, data2, data3), timestamp) = midi - ((status,data1,data2,data3),timestamp) = midi - - e = pygame.event.Event(MIDIIN, - status=status, - data1=data1, - data2=data2, - data3=data3, - timestamp=timestamp, - vice_id = device_id) - evs.append( e ) - + event = pygame.event.Event(MIDIIN, + status=status, + data1=data1, + data2=data2, + data3=data3, + timestamp=timestamp, + vice_id=device_id) + evs.append(event) return evs - - - class MidiException(Exception): """exception that pygame.midi functions and classes can raise MidiException(errno) """ + def __init__(self, value): + super(MidiException, self).__init__(value) self.parameter = value + def __str__(self): return repr(self.parameter) - def frequency_to_midi(frequency): """ converts a frequency into a MIDI note. @@ -698,6 +686,7 @@ def frequency_to_midi(frequency): ) ) + def midi_to_frequency(midi_note): """ Converts a midi note to a frequency. @@ -710,7 +699,8 @@ def midi_to_frequency(midi_note): >>> midi_to_frequency(108) 4186.0 """ - return round(440.0 * 2 ** ((midi_note - 69) * (1./12.)), 1) + return round(440.0 * 2 ** ((midi_note - 69) * (1. / 12.)), 1) + def midi_to_ansi_note(midi_note): """ returns the Ansi Note name for a midi number.