From 0a1196ee93d0def66c00874c1e09cdf810bba715 Mon Sep 17 00:00:00 2001 From: dherrada Date: Sun, 15 Mar 2020 15:57:57 -0400 Subject: [PATCH] Ran black, updated to pylint 2.x --- .github/workflows/build.yml | 2 +- adafruit_midi/__init__.py | 17 +- adafruit_midi/channel_pressure.py | 8 +- adafruit_midi/control_change.py | 13 +- adafruit_midi/midi_message.py | 74 +++--- adafruit_midi/note_off.py | 11 +- adafruit_midi/note_on.py | 11 +- adafruit_midi/pitch_bend.py | 20 +- adafruit_midi/polyphonic_key_pressure.py | 13 +- adafruit_midi/program_change.py | 8 +- adafruit_midi/start.py | 5 +- adafruit_midi/stop.py | 6 +- adafruit_midi/system_exclusive.py | 17 +- adafruit_midi/timing_clock.py | 5 +- docs/conf.py | 112 +++++---- examples/midi_inoutdemo.py | 44 ++-- examples/midi_intest1.py | 15 +- examples/midi_memorycheck.py | 89 ++++--- examples/midi_simpletest.py | 17 +- setup.py | 52 ++-- tests/test_MIDIMessage_unittests.py | 297 +++++++++++++---------- tests/test_MIDI_unittests.py | 266 +++++++++++--------- tests/test_note_parser.py | 59 ++--- 23 files changed, 668 insertions(+), 493 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fff3aa9..1dad804 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: source actions-ci/install.sh - name: Pip install pylint, black, & Sphinx run: | - pip install --force-reinstall pylint==1.9.2 black==19.10b0 Sphinx sphinx-rtd-theme + pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme - name: Library version run: git describe --dirty --always --tags - name: PyLint diff --git a/adafruit_midi/__init__.py b/adafruit_midi/__init__.py index e6aa1d1..bee0070 100644 --- a/adafruit_midi/__init__.py +++ b/adafruit_midi/__init__.py @@ -68,8 +68,16 @@ class MIDI: """ - def __init__(self, midi_in=None, midi_out=None, *, - in_channel=None, out_channel=0, in_buf_size=30, debug=False): + def __init__( + self, + midi_in=None, + midi_out=None, + *, + in_channel=None, + out_channel=0, + in_buf_size=30, + debug=False + ): if midi_in is None and midi_out is None: raise ValueError("No midi_in or midi_out provided") self._midi_in = midi_in @@ -135,8 +143,9 @@ def receive(self): self._in_buf.extend(bytes_in) del bytes_in - (msg, endplusone, - skipped) = MIDIMessage.from_message_bytes(self._in_buf, self._in_channel) + (msg, endplusone, skipped) = MIDIMessage.from_message_bytes( + self._in_buf, self._in_channel + ) if endplusone != 0: # This is not particularly efficient as it's copying most of bytearray # and deleting old one diff --git a/adafruit_midi/channel_pressure.py b/adafruit_midi/channel_pressure.py index 927e987..c26bc92 100644 --- a/adafruit_midi/channel_pressure.py +++ b/adafruit_midi/channel_pressure.py @@ -45,8 +45,8 @@ class ChannelPressure(MIDIMessage): :param int pressure: The pressure, 0-127. """ - _STATUS = 0xd0 - _STATUSMASK = 0xf0 + _STATUS = 0xD0 + _STATUSMASK = 0xF0 LENGTH = 2 def __init__(self, pressure, *, channel=None): @@ -56,11 +56,11 @@ def __init__(self, pressure, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.pressure]) + return bytes([self._STATUS | (self.channel & self.CHANNELMASK), self.pressure]) @classmethod def from_bytes(cls, msg_bytes): return cls(msg_bytes[1], channel=msg_bytes[0] & cls.CHANNELMASK) + ChannelPressure.register_message_type() diff --git a/adafruit_midi/control_change.py b/adafruit_midi/control_change.py index 3c42d0d..c9d9aa5 100644 --- a/adafruit_midi/control_change.py +++ b/adafruit_midi/control_change.py @@ -47,8 +47,8 @@ class ControlChange(MIDIMessage): """ - _STATUS = 0xb0 - _STATUSMASK = 0xf0 + _STATUS = 0xB0 + _STATUSMASK = 0xF0 LENGTH = 3 def __init__(self, control, value, *, channel=None): @@ -59,12 +59,13 @@ def __init__(self, control, value, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.control, self.value]) + return bytes( + [self._STATUS | (self.channel & self.CHANNELMASK), self.control, self.value] + ) @classmethod def from_bytes(cls, msg_bytes): - return cls(msg_bytes[1], msg_bytes[2], - channel=msg_bytes[0] & cls.CHANNELMASK) + return cls(msg_bytes[1], msg_bytes[2], channel=msg_bytes[0] & cls.CHANNELMASK) + ControlChange.register_message_type() diff --git a/adafruit_midi/midi_message.py b/adafruit_midi/midi_message.py index 3fbe8fd..a19a637 100644 --- a/adafruit_midi/midi_message.py +++ b/adafruit_midi/midi_message.py @@ -80,14 +80,12 @@ def note_parser(note): if not 0 <= noteidx <= 6: raise ValueError("Bad note") sharpen = 0 - if note[1] == '#': + if note[1] == "#": sharpen = 1 - elif note[1] == 'b': + elif note[1] == "b": sharpen = -1 # int may throw exception here - midi_note = (int(note[1 + abs(sharpen):]) * 12 - + NOTE_OFFSET[noteidx] - + sharpen) + midi_note = int(note[1 + abs(sharpen) :]) * 12 + NOTE_OFFSET[noteidx] + sharpen return midi_note @@ -108,10 +106,11 @@ class MIDIMessage: This is an *abstract* class. """ + _STATUS = None _STATUSMASK = None LENGTH = None - CHANNELMASK = 0x0f + CHANNELMASK = 0x0F ENDSTATUS = None # Commonly used exceptions to save memory @@ -150,9 +149,9 @@ def register_message_type(cls): insert_idx = idx break - MIDIMessage._statusandmask_to_class.insert(insert_idx, - ((cls._STATUS, cls._STATUSMASK), cls)) - + MIDIMessage._statusandmask_to_class.insert( + insert_idx, ((cls._STATUS, cls._STATUSMASK), cls) + ) # pylint: disable=too-many-arguments @classmethod @@ -171,8 +170,7 @@ def _search_eom_status(cls, buf, eom_status, msgstartidx, msgendidxplusone, endi else: bad_termination = True break - else: - msgendidxplusone += 1 + msgendidxplusone += 1 if good_termination or bad_termination: msgendidxplusone += 1 @@ -199,22 +197,27 @@ def _match_message_status(cls, buf, msgstartidx, msgendidxplusone, endidx): break if msgclass.LENGTH < 0: # indicator of variable length message - (msgendidxplusone, - terminated_msg, - bad_termination) = cls._search_eom_status(buf, - msgclass.ENDSTATUS, - msgstartidx, - msgendidxplusone, - endidx) + ( + msgendidxplusone, + terminated_msg, + bad_termination, + ) = cls._search_eom_status( + buf, msgclass.ENDSTATUS, msgstartidx, msgendidxplusone, endidx + ) if not terminated_msg: complete_msg = False - else: # fixed length message + else: # fixed length message msgendidxplusone = msgstartidx + msgclass.LENGTH break - return (msgclass, status, - known_msg, complete_msg, bad_termination, - msgendidxplusone) + return ( + msgclass, + status, + known_msg, + complete_msg, + bad_termination, + msgendidxplusone, + ) # pylint: disable=too-many-locals,too-many-branches @classmethod @@ -247,15 +250,16 @@ def from_message_bytes(cls, midibytes, channel_in): return (None, endidx + 1, skipped) # Try and match the status byte found in midibytes - (msgclass, - status, - known_message, - complete_message, - bad_termination, - msgendidxplusone) = cls._match_message_status(midibytes, - msgstartidx, - msgendidxplusone, - endidx) + ( + msgclass, + status, + known_message, + complete_message, + bad_termination, + msgendidxplusone, + ) = cls._match_message_status( + midibytes, msgstartidx, msgendidxplusone, endidx + ) channel_match_orna = True if complete_message and not bad_termination: try: @@ -263,7 +267,7 @@ def from_message_bytes(cls, midibytes, channel_in): if msg.channel is not None: channel_match_orna = channel_filter(msg.channel, channel_in) - except(ValueError, TypeError) as ex: + except (ValueError, TypeError) as ex: msg = MIDIBadEvent(midibytes[msgstartidx:msgendidxplusone], ex) # break out of while loop for a complete message on good channel @@ -272,8 +276,8 @@ def from_message_bytes(cls, midibytes, channel_in): if complete_message: if channel_match_orna: break - else: # advance to next message - msgstartidx = msgendidxplusone + # advance to next message + msgstartidx = msgendidxplusone else: # Important case of a known message but one that is not # yet complete - leave bytes in buffer and wait for more @@ -314,6 +318,7 @@ class MIDIUnknownEvent(MIDIMessage): This can either occur because there is no class representing the message or because it is not imported. """ + LENGTH = -1 def __init__(self, status): @@ -331,6 +336,7 @@ class MIDIBadEvent(MIDIMessage): This could be due to status bytes appearing where data bytes are expected. The channel property will not be set. """ + LENGTH = -1 def __init__(self, msg_bytes, exception): diff --git a/adafruit_midi/note_off.py b/adafruit_midi/note_off.py index 3e8382d..5deb5c5 100644 --- a/adafruit_midi/note_off.py +++ b/adafruit_midi/note_off.py @@ -49,7 +49,7 @@ class NoteOff(MIDIMessage): """ _STATUS = 0x80 - _STATUSMASK = 0xf0 + _STATUSMASK = 0xF0 LENGTH = 3 def __init__(self, note, velocity=0, *, channel=None): @@ -60,12 +60,13 @@ def __init__(self, note, velocity=0, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.note, self.velocity]) + return bytes( + [self._STATUS | (self.channel & self.CHANNELMASK), self.note, self.velocity] + ) @classmethod def from_bytes(cls, msg_bytes): - return cls(msg_bytes[1], msg_bytes[2], - channel=msg_bytes[0] & cls.CHANNELMASK) + return cls(msg_bytes[1], msg_bytes[2], channel=msg_bytes[0] & cls.CHANNELMASK) + NoteOff.register_message_type() diff --git a/adafruit_midi/note_on.py b/adafruit_midi/note_on.py index d0ef9fe..a3da76f 100644 --- a/adafruit_midi/note_on.py +++ b/adafruit_midi/note_on.py @@ -49,7 +49,7 @@ class NoteOn(MIDIMessage): """ _STATUS = 0x90 - _STATUSMASK = 0xf0 + _STATUSMASK = 0xF0 LENGTH = 3 def __init__(self, note, velocity=127, *, channel=None): @@ -60,12 +60,13 @@ def __init__(self, note, velocity=127, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.note, self.velocity]) + return bytes( + [self._STATUS | (self.channel & self.CHANNELMASK), self.note, self.velocity] + ) @classmethod def from_bytes(cls, msg_bytes): - return cls(msg_bytes[1], msg_bytes[2], - channel=msg_bytes[0] & cls.CHANNELMASK) + return cls(msg_bytes[1], msg_bytes[2], channel=msg_bytes[0] & cls.CHANNELMASK) + NoteOn.register_message_type() diff --git a/adafruit_midi/pitch_bend.py b/adafruit_midi/pitch_bend.py index ea85af6..6b36bd1 100644 --- a/adafruit_midi/pitch_bend.py +++ b/adafruit_midi/pitch_bend.py @@ -46,8 +46,8 @@ class PitchBend(MIDIMessage): bend from 0 through 8192 (midpoint, no bend) to 16383. """ - _STATUS = 0xe0 - _STATUSMASK = 0xf0 + _STATUS = 0xE0 + _STATUSMASK = 0xF0 LENGTH = 3 def __init__(self, pitch_bend, *, channel=None): @@ -57,13 +57,19 @@ def __init__(self, pitch_bend, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.pitch_bend & 0x7f, - (self.pitch_bend >> 7) & 0x7f]) + return bytes( + [ + self._STATUS | (self.channel & self.CHANNELMASK), + self.pitch_bend & 0x7F, + (self.pitch_bend >> 7) & 0x7F, + ] + ) @classmethod def from_bytes(cls, msg_bytes): - return cls(msg_bytes[2] << 7 | msg_bytes[1], - channel=msg_bytes[0] & cls.CHANNELMASK) + return cls( + msg_bytes[2] << 7 | msg_bytes[1], channel=msg_bytes[0] & cls.CHANNELMASK + ) + PitchBend.register_message_type() diff --git a/adafruit_midi/polyphonic_key_pressure.py b/adafruit_midi/polyphonic_key_pressure.py index 6519ae2..37f6d91 100644 --- a/adafruit_midi/polyphonic_key_pressure.py +++ b/adafruit_midi/polyphonic_key_pressure.py @@ -47,8 +47,8 @@ class PolyphonicKeyPressure(MIDIMessage): :param int pressure: The pressure, 0-127. """ - _STATUS = 0xa0 - _STATUSMASK = 0xf0 + _STATUS = 0xA0 + _STATUSMASK = 0xF0 LENGTH = 3 def __init__(self, note, pressure, *, channel=None): @@ -59,12 +59,13 @@ def __init__(self, note, pressure, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.note, self.pressure]) + return bytes( + [self._STATUS | (self.channel & self.CHANNELMASK), self.note, self.pressure] + ) @classmethod def from_bytes(cls, msg_bytes): - return cls(msg_bytes[1], msg_bytes[2], - channel=msg_bytes[0] & cls.CHANNELMASK) + return cls(msg_bytes[1], msg_bytes[2], channel=msg_bytes[0] & cls.CHANNELMASK) + PolyphonicKeyPressure.register_message_type() diff --git a/adafruit_midi/program_change.py b/adafruit_midi/program_change.py index 5e5d078..3f32c51 100644 --- a/adafruit_midi/program_change.py +++ b/adafruit_midi/program_change.py @@ -45,8 +45,8 @@ class ProgramChange(MIDIMessage): :param int patch: The new program/patch number to use, 0-127. """ - _STATUS = 0xc0 - _STATUSMASK = 0xf0 + _STATUS = 0xC0 + _STATUSMASK = 0xF0 LENGTH = 2 def __init__(self, patch, *, channel=None): @@ -56,11 +56,11 @@ def __init__(self, patch, *, channel=None): raise self._EX_VALUEERROR_OOR def __bytes__(self): - return bytes([self._STATUS | (self.channel & self.CHANNELMASK), - self.patch]) + return bytes([self._STATUS | (self.channel & self.CHANNELMASK), self.patch]) @classmethod def from_bytes(cls, msg_bytes): return cls(msg_bytes[1], channel=msg_bytes[0] & cls.CHANNELMASK) + ProgramChange.register_message_type() diff --git a/adafruit_midi/start.py b/adafruit_midi/start.py index df487c6..efe1018 100644 --- a/adafruit_midi/start.py +++ b/adafruit_midi/start.py @@ -43,8 +43,9 @@ class Start(MIDIMessage): """Start MIDI message. """ - _STATUS = 0xfa - _STATUSMASK = 0xff + _STATUS = 0xFA + _STATUSMASK = 0xFF LENGTH = 1 + Start.register_message_type() diff --git a/adafruit_midi/stop.py b/adafruit_midi/stop.py index 830a18a..f35eb6f 100644 --- a/adafruit_midi/stop.py +++ b/adafruit_midi/stop.py @@ -42,8 +42,10 @@ class Stop(MIDIMessage): """Stop MIDI message. """ - _STATUS = 0xfc - _STATUSMASK = 0xff + + _STATUS = 0xFC + _STATUSMASK = 0xFF LENGTH = 1 + Stop.register_message_type() diff --git a/adafruit_midi/system_exclusive.py b/adafruit_midi/system_exclusive.py index b77e885..d7838ba 100644 --- a/adafruit_midi/system_exclusive.py +++ b/adafruit_midi/system_exclusive.py @@ -49,10 +49,10 @@ class SystemExclusive(MIDIMessage): This message can only be parsed if it fits within the input buffer in :class:MIDI. """ - _STATUS = 0xf0 - _STATUSMASK = 0xff + _STATUS = 0xF0 + _STATUSMASK = 0xFF LENGTH = -1 - ENDSTATUS = 0xf7 + ENDSTATUS = 0xF7 def __init__(self, manufacturer_id, data): self.manufacturer_id = bytes(manufacturer_id) @@ -60,10 +60,12 @@ def __init__(self, manufacturer_id, data): super().__init__() def __bytes__(self): - return (bytes([self._STATUS]) - + self.manufacturer_id - + self.data - + bytes([self.ENDSTATUS])) + return ( + bytes([self._STATUS]) + + self.manufacturer_id + + self.data + + bytes([self.ENDSTATUS]) + ) @classmethod def from_bytes(cls, msg_bytes): @@ -73,4 +75,5 @@ def from_bytes(cls, msg_bytes): else: return cls(msg_bytes[1:4], msg_bytes[4:-1]) + SystemExclusive.register_message_type() diff --git a/adafruit_midi/timing_clock.py b/adafruit_midi/timing_clock.py index f00ff19..078364e 100644 --- a/adafruit_midi/timing_clock.py +++ b/adafruit_midi/timing_clock.py @@ -48,8 +48,9 @@ class TimingClock(MIDIMessage): message to a CircuitPython device to reduce the amount of message processing. """ - _STATUS = 0xf8 - _STATUSMASK = 0xff + _STATUS = 0xF8 + _STATUSMASK = 0xFF LENGTH = 1 + TimingClock.register_message_type() diff --git a/docs/conf.py b/docs/conf.py index 2c71034..50745f7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,8 @@ import os import sys -sys.path.insert(0, os.path.abspath('..')) + +sys.path.insert(0, os.path.abspath("..")) # -- General configuration ------------------------------------------------ @@ -10,10 +11,10 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.napoleon', - 'sphinx.ext.todo', + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.napoleon", + "sphinx.ext.todo", ] # TODO: Please Read! @@ -23,29 +24,32 @@ autodoc_mock_imports = [] -intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} +intersphinx_mapping = { + "python": ("https://docs.python.org/3.4", None), + "CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None), +} # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Adafruit MIDI Library' -copyright = u'2019 Ladyada & Kevin J. Walters' -author = u'Ladyada & Kevin J. Walters' +project = u"Adafruit MIDI Library" +copyright = u"2019 Ladyada & Kevin J. Walters" +author = u"Ladyada & Kevin J. Walters" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'1.0' +version = u"1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +release = u"1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -57,7 +61,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.env', 'CODE_OF_CONDUCT.md'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -69,7 +73,7 @@ add_function_parentheses = True # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False @@ -84,59 +88,62 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" if not on_rtd: # only import and set the theme if we're building docs locally try: import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.'] + + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."] except: - html_theme = 'default' - html_theme_path = ['.'] + html_theme = "default" + html_theme_path = ["."] else: - html_theme_path = ['.'] + html_theme_path = ["."] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # -html_favicon = '_static/favicon.ico' +html_favicon = "_static/favicon.ico" # Output file base name for HTML help builder. -htmlhelp_basename = 'AdafruitMidiLibrarydoc' +htmlhelp_basename = "AdafruitMidiLibrarydoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'AdafruitMIDILibrary.tex', u'AdafruitMIDI Library Documentation', - author, 'manual'), + ( + master_doc, + "AdafruitMIDILibrary.tex", + u"AdafruitMIDI Library Documentation", + author, + "manual", + ), ] # -- Options for manual page output --------------------------------------- @@ -144,8 +151,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'AdafruitMIDIlibrary', u'Adafruit MIDI Library Documentation', - [author], 1) + ( + master_doc, + "AdafruitMIDIlibrary", + u"Adafruit MIDI Library Documentation", + [author], + 1, + ) ] # -- Options for Texinfo output ------------------------------------------- @@ -154,7 +166,13 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'AdafruitMIDILibrary', u'Adafruit MIDI Library Documentation', - author, 'AdafruitMIDILibrary', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "AdafruitMIDILibrary", + u"Adafruit MIDI Library Documentation", + author, + "AdafruitMIDILibrary", + "One line description of project.", + "Miscellaneous", + ), ] diff --git a/examples/midi_inoutdemo.py b/examples/midi_inoutdemo.py index 4f78dc7..f9b742e 100644 --- a/examples/midi_inoutdemo.py +++ b/examples/midi_inoutdemo.py @@ -8,23 +8,26 @@ # Only importing what is used will save a little bit of memory # pylint: disable=unused-import -from adafruit_midi.timing_clock import TimingClock -from adafruit_midi.channel_pressure import ChannelPressure -from adafruit_midi.control_change import ControlChange -from adafruit_midi.note_off import NoteOff -from adafruit_midi.note_on import NoteOn -from adafruit_midi.pitch_bend import PitchBend +from adafruit_midi.timing_clock import TimingClock +from adafruit_midi.channel_pressure import ChannelPressure +from adafruit_midi.control_change import ControlChange +from adafruit_midi.note_off import NoteOff +from adafruit_midi.note_on import NoteOn +from adafruit_midi.pitch_bend import PitchBend from adafruit_midi.polyphonic_key_pressure import PolyphonicKeyPressure -from adafruit_midi.program_change import ProgramChange -from adafruit_midi.start import Start -from adafruit_midi.stop import Stop -from adafruit_midi.system_exclusive import SystemExclusive +from adafruit_midi.program_change import ProgramChange +from adafruit_midi.start import Start +from adafruit_midi.stop import Stop +from adafruit_midi.system_exclusive import SystemExclusive from adafruit_midi.midi_message import MIDIUnknownEvent -midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], - midi_out=usb_midi.ports[1], - in_channel=(1, 2, 3), out_channel=0) +midi = adafruit_midi.MIDI( + midi_in=usb_midi.ports[0], + midi_out=usb_midi.ports[1], + in_channel=(1, 2, 3), + out_channel=0, +) print("Midi Demo in and out") @@ -39,15 +42,22 @@ # For a Note On or Note Off play a major chord # For any other known event just forward it if isinstance(msg_in, NoteOn) and msg_in.velocity != 0: - print("Playing major chord with root", msg_in.note, - "from channel", msg_in.channel + 1) + print( + "Playing major chord with root", + msg_in.note, + "from channel", + msg_in.channel + 1, + ) for offset in major_chord: new_note = msg_in.note + offset if 0 <= new_note <= 127: midi.send(NoteOn(new_note, msg_in.velocity)) - elif (isinstance(msg_in, NoteOff) - or isinstance(msg_in, NoteOn) and msg_in.velocity == 0): + elif ( + isinstance(msg_in, NoteOff) + or isinstance(msg_in, NoteOn) + and msg_in.velocity == 0 + ): for offset in major_chord: new_note = msg_in.note + offset if 0 <= new_note <= 127: diff --git a/examples/midi_intest1.py b/examples/midi_intest1.py index 559550e..b8a3ced 100644 --- a/examples/midi_intest1.py +++ b/examples/midi_intest1.py @@ -4,12 +4,13 @@ # A subset of messages/events # pylint: disable=unused-import -from adafruit_midi.timing_clock import TimingClock -#from adafruit_midi.channel_pressure import ChannelPressure -from adafruit_midi.control_change import ControlChange -from adafruit_midi.note_off import NoteOff -from adafruit_midi.note_on import NoteOn -from adafruit_midi.pitch_bend import PitchBend +from adafruit_midi.timing_clock import TimingClock + +# from adafruit_midi.channel_pressure import ChannelPressure +from adafruit_midi.control_change import ControlChange +from adafruit_midi.note_off import NoteOff +from adafruit_midi.note_on import NoteOn +from adafruit_midi.pitch_bend import PitchBend # 0 is MIDI channel 1 @@ -22,7 +23,7 @@ # play with the pause to simulate code doing other stuff # in the loop -pauses = [0] * 10 + [.010] * 10 + [0.100] * 10 + [1.0] * 10 +pauses = [0] * 10 + [0.010] * 10 + [0.100] * 10 + [1.0] * 10 while True: for pause in pauses: diff --git a/examples/midi_memorycheck.py b/examples/midi_memorycheck.py index a86c3f4..a20b262 100644 --- a/examples/midi_memorycheck.py +++ b/examples/midi_memorycheck.py @@ -10,38 +10,67 @@ import time import random import gc -gc.collect() ; print(gc.mem_free()) + +gc.collect() +print(gc.mem_free()) import usb_midi -gc.collect() ; print(gc.mem_free()) + +gc.collect() +print(gc.mem_free()) import adafruit_midi -gc.collect() ; print(gc.mem_free()) + +gc.collect() +print(gc.mem_free()) # Full monty -from adafruit_midi.channel_pressure import ChannelPressure -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.control_change import ControlChange -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.note_off import NoteOff -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.note_on import NoteOn -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.pitch_bend import PitchBend -gc.collect() ; print(gc.mem_free()) +from adafruit_midi.channel_pressure import ChannelPressure + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.control_change import ControlChange + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.note_off import NoteOff + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.note_on import NoteOn + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.pitch_bend import PitchBend + +gc.collect() +print(gc.mem_free()) from adafruit_midi.polyphonic_key_pressure import PolyphonicKeyPressure -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.program_change import ProgramChange -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.start import Start -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.stop import Stop -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.system_exclusive import SystemExclusive -gc.collect() ; print(gc.mem_free()) -from adafruit_midi.timing_clock import TimingClock -gc.collect() ; print(gc.mem_free()) - -midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], - midi_out=usb_midi.ports[1], - in_channel=0, out_channel=0) - -gc.collect() ; print(gc.mem_free()) + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.program_change import ProgramChange + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.start import Start + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.stop import Stop + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.system_exclusive import SystemExclusive + +gc.collect() +print(gc.mem_free()) +from adafruit_midi.timing_clock import TimingClock + +gc.collect() +print(gc.mem_free()) + +midi = adafruit_midi.MIDI( + midi_in=usb_midi.ports[0], midi_out=usb_midi.ports[1], in_channel=0, out_channel=0 +) + +gc.collect() +print(gc.mem_free()) diff --git a/examples/midi_simpletest.py b/examples/midi_simpletest.py index d85d0f7..1703804 100644 --- a/examples/midi_simpletest.py +++ b/examples/midi_simpletest.py @@ -3,10 +3,10 @@ import random import usb_midi import adafruit_midi -from adafruit_midi.control_change import ControlChange -from adafruit_midi.note_off import NoteOff -from adafruit_midi.note_on import NoteOn -from adafruit_midi.pitch_bend import PitchBend +from adafruit_midi.control_change import ControlChange +from adafruit_midi.note_off import NoteOff +from adafruit_midi.note_on import NoteOn +from adafruit_midi.pitch_bend import PitchBend midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) @@ -14,8 +14,10 @@ # Convert channel numbers at the presentation layer to the ones musicians use print("Default output channel:", midi.out_channel + 1) -print("Listening on input channel:", - midi.in_channel + 1 if midi.in_channel is not None else None) +print( + "Listening on input channel:", + midi.in_channel + 1 if midi.in_channel is not None else None, +) while True: midi.send(NoteOn(44, 120)) # G sharp 2nd octave @@ -24,6 +26,5 @@ midi.send(a_pitch_bend) time.sleep(0.25) # note how a list of messages can be used - midi.send([NoteOff("G#2", 120), - ControlChange(3, 44)]) + midi.send([NoteOff("G#2", 120), ControlChange(3, 44)]) time.sleep(0.5) diff --git a/setup.py b/setup.py index 69ab511..aafeca9 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,7 @@ """ from setuptools import setup, find_packages + # To use a consistent encoding from codecs import open from os import path @@ -13,50 +14,41 @@ here = path.abspath(path.dirname(__file__)) # Get the long description from the README file -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: +with open(path.join(here, "README.rst"), encoding="utf-8") as f: long_description = f.read() setup( - name='adafruit-circuitpython-midi', - + name="adafruit-circuitpython-midi", use_scm_version=True, - setup_requires=['setuptools_scm'], - - description='A CircuitPython helper for encoding/decoding MIDI packets over a MIDI or UART ' - 'connection.', + setup_requires=["setuptools_scm"], + description="A CircuitPython helper for encoding/decoding MIDI packets over a MIDI or UART " + "connection.", long_description=long_description, - long_description_content_type='text/x-rst', - + long_description_content_type="text/x-rst", # The project's main homepage. - url='https://github.com/adafruit/Adafruit_CircuitPython_MIDI', - + url="https://github.com/adafruit/Adafruit_CircuitPython_MIDI", # Author details - author='Adafruit Industries', - author_email='circuitpython@adafruit.com', - - install_requires=['Adafruit-Blinka'], - + author="Adafruit Industries", + author_email="circuitpython@adafruit.com", + install_requires=["Adafruit-Blinka"], # Choose your license - license='MIT', - + license="MIT", # See https://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries', - 'Topic :: System :: Hardware', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Topic :: System :: Hardware", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", ], - # What does your project relate to? - keywords='adafruit blinka circuitpython micropython midi uart encoding decoding', - + keywords="adafruit blinka circuitpython micropython midi uart encoding decoding", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER, # CHANGE `py_modules=['...']` TO `packages=['...']` - py_modules=['adafruit_midi'], + py_modules=["adafruit_midi"], ) diff --git a/tests/test_MIDIMessage_unittests.py b/tests/test_MIDIMessage_unittests.py index 0126ead..e3348d4 100644 --- a/tests/test_MIDIMessage_unittests.py +++ b/tests/test_MIDIMessage_unittests.py @@ -25,190 +25,232 @@ import os -verbose = int(os.getenv('TESTVERBOSE', '2')) + +verbose = int(os.getenv("TESTVERBOSE", "2")) # adafruit_midi had an import usb_midi import sys -#sys.modules['usb_midi'] = MagicMock() + +# sys.modules['usb_midi'] = MagicMock() # Borrowing the dhalbert/tannewt technique from adafruit/Adafruit_CircuitPython_Motor -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) # Import before messages - opposite to other test file import adafruit_midi # Full monty -from adafruit_midi.channel_pressure import ChannelPressure -from adafruit_midi.control_change import ControlChange -from adafruit_midi.note_off import NoteOff -from adafruit_midi.note_on import NoteOn -from adafruit_midi.pitch_bend import PitchBend +from adafruit_midi.channel_pressure import ChannelPressure +from adafruit_midi.control_change import ControlChange +from adafruit_midi.note_off import NoteOff +from adafruit_midi.note_on import NoteOn +from adafruit_midi.pitch_bend import PitchBend from adafruit_midi.polyphonic_key_pressure import PolyphonicKeyPressure -from adafruit_midi.program_change import ProgramChange -from adafruit_midi.start import Start -from adafruit_midi.stop import Stop -from adafruit_midi.system_exclusive import SystemExclusive -from adafruit_midi.timing_clock import TimingClock +from adafruit_midi.program_change import ProgramChange +from adafruit_midi.start import Start +from adafruit_midi.stop import Stop +from adafruit_midi.system_exclusive import SystemExclusive +from adafruit_midi.timing_clock import TimingClock class Test_MIDIMessage_from_message_byte_tests(unittest.TestCase): def test_NoteOn_basic(self): - data = bytes([0x90, 0x30, 0x7f]) + data = bytes([0x90, 0x30, 0x7F]) ichannel = 0 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x30) - self.assertEqual(msg.velocity, 0x7f) + self.assertEqual(msg.velocity, 0x7F) self.assertEqual(msgendidxplusone, 3) self.assertEqual(skipped, 0) self.assertEqual(msg.channel, 0) - + def test_NoteOn_awaitingthirdbyte(self): data = bytes([0x90, 0x30]) ichannel = 0 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsNone(msg) - self.assertEqual(msgendidxplusone, skipped, - "skipped must be 0 as it only indicates bytes before a status byte") - self.assertEqual(msgendidxplusone, 0, - "msgendidxplusone must be 0 as buffer must be lest as is for more data") + self.assertEqual( + msgendidxplusone, + skipped, + "skipped must be 0 as it only indicates bytes before a status byte", + ) + self.assertEqual( + msgendidxplusone, + 0, + "msgendidxplusone must be 0 as buffer must be lest as is for more data", + ) self.assertEqual(skipped, 0) def test_NoteOn_predatajunk(self): data = bytes([0x20, 0x64, 0x90, 0x30, 0x32]) ichannel = 0 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x30) self.assertEqual(msg.velocity, 0x32) - self.assertEqual(msgendidxplusone, 5, - "data bytes from partial message and messages are removed" ) + self.assertEqual( + msgendidxplusone, + 5, + "data bytes from partial message and messages are removed", + ) self.assertEqual(skipped, 2) self.assertEqual(msg.channel, 0) def test_NoteOn_prepartialsysex(self): - data = bytes([0x01, 0x02, 0x03, 0x04, 0xf7, 0x90, 0x30, 0x32]) + data = bytes([0x01, 0x02, 0x03, 0x04, 0xF7, 0x90, 0x30, 0x32]) ichannel = 0 - - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) # MIDIMessage parsing could be improved to return something that # indicates its a truncated end of SysEx self.assertIsInstance(msg, adafruit_midi.midi_message.MIDIUnknownEvent) - self.assertEqual(msg.status, 0xf7) - self.assertEqual(msgendidxplusone, 5, "removal of the end of the partial SysEx data and terminating status byte") + self.assertEqual(msg.status, 0xF7) + self.assertEqual( + msgendidxplusone, + 5, + "removal of the end of the partial SysEx data and terminating status byte", + ) self.assertEqual(skipped, 4, "skipped only counts data bytes so will be 4 here") self.assertIsNone(msg.channel) - - data = data[msgendidxplusone:] - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) - self.assertIsInstance(msg, NoteOn, - "NoteOn is expected if SystemExclusive is loaded otherwise it would be MIDIUnknownEvent") + data = data[msgendidxplusone:] + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) + + self.assertIsInstance( + msg, + NoteOn, + "NoteOn is expected if SystemExclusive is loaded otherwise it would be MIDIUnknownEvent", + ) self.assertEqual(msg.note, 0x30) self.assertEqual(msg.velocity, 0x32) self.assertEqual(msgendidxplusone, 3, "NoteOn message removed") - self.assertEqual(skipped, 0) + self.assertEqual(skipped, 0) self.assertEqual(msg.channel, 0) - + def test_NoteOn_postNoteOn(self): - data = bytes([0x90 | 0x08, 0x30, 0x7f, 0x90 | 0x08, 0x37, 0x64]) + data = bytes([0x90 | 0x08, 0x30, 0x7F, 0x90 | 0x08, 0x37, 0x64]) ichannel = 8 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x30) - self.assertEqual(msg.velocity, 0x7f) + self.assertEqual(msg.velocity, 0x7F) self.assertEqual(msgendidxplusone, 3) self.assertEqual(skipped, 0) self.assertEqual(msg.channel, 8) def test_NoteOn_postpartialNoteOn(self): - data = bytes([0x90, 0x30, 0x7f, 0x90, 0x37]) + data = bytes([0x90, 0x30, 0x7F, 0x90, 0x37]) ichannel = 0 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x30) - self.assertEqual(msg.velocity, 0x7f) - self.assertEqual(msgendidxplusone, 3, - "Only first message is removed") + self.assertEqual(msg.velocity, 0x7F) + self.assertEqual(msgendidxplusone, 3, "Only first message is removed") self.assertEqual(skipped, 0) self.assertEqual(msg.channel, 0) def test_NoteOn_preotherchannel(self): - data = bytes([0x90 | 0x05, 0x30, 0x7f, 0x90 | 0x03, 0x37, 0x64]) + data = bytes([0x90 | 0x05, 0x30, 0x7F, 0x90 | 0x03, 0x37, 0x64]) ichannel = 3 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x37) self.assertEqual(msg.velocity, 0x64) - self.assertEqual(msgendidxplusone, 6, - "Both messages are removed from buffer") + self.assertEqual(msgendidxplusone, 6, "Both messages are removed from buffer") self.assertEqual(skipped, 0) self.assertEqual(msg.channel, 3) def test_NoteOn_preotherchannelplusintermediatejunk(self): - data = bytes([0x90 | 0x05, 0x30, 0x7f, 0x00, 0x00, 0x90 | 0x03, 0x37, 0x64]) + data = bytes([0x90 | 0x05, 0x30, 0x7F, 0x00, 0x00, 0x90 | 0x03, 0x37, 0x64]) ichannel = 3 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x37) self.assertEqual(msg.velocity, 0x64) - self.assertEqual(msgendidxplusone, 8, - "Both messages and junk are removed from buffer") + self.assertEqual( + msgendidxplusone, 8, "Both messages and junk are removed from buffer" + ) self.assertEqual(skipped, 0) self.assertEqual(msg.channel, 3) - + def test_NoteOn_wrongchannel(self): - data = bytes([0x95, 0x30, 0x7f]) + data = bytes([0x95, 0x30, 0x7F]) ichannel = 3 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsNone(msg) - self.assertEqual(msgendidxplusone, 3, - "wrong channel message discarded") + self.assertEqual(msgendidxplusone, 3, "wrong channel message discarded") self.assertEqual(skipped, 0) def test_NoteOn_partialandpreotherchannel1(self): - data = bytes([0x95, 0x30, 0x7f, 0x93]) + data = bytes([0x95, 0x30, 0x7F, 0x93]) ichannel = 3 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsNone(msg) - self.assertEqual(msgendidxplusone, 3, - "first message discarded, second partial left") + self.assertEqual( + msgendidxplusone, 3, "first message discarded, second partial left" + ) self.assertEqual(skipped, 0) - + def test_NoteOn_partialandpreotherchannel2(self): - data = bytes([0x95, 0x30, 0x7f, 0x93, 0x37]) + data = bytes([0x95, 0x30, 0x7F, 0x93, 0x37]) ichannel = 3 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsNone(msg) - self.assertEqual(msgendidxplusone, 3, - "first message discarded, second partial left") + self.assertEqual( + msgendidxplusone, 3, "first message discarded, second partial left" + ) self.assertEqual(skipped, 0) def test_NoteOn_constructor_int(self): - object1 = NoteOn(60, 0x7f) - + object1 = NoteOn(60, 0x7F) + self.assertEqual(object1.note, 60) - self.assertEqual(object1.velocity, 0x7f) + self.assertEqual(object1.velocity, 0x7F) self.assertIsNone(object1.channel) object2 = NoteOn(60, 0x00) # equivalent of NoteOff @@ -230,21 +272,26 @@ def test_NoteOn_constructor_int(self): self.assertIsNone(object4.channel) def test_SystemExclusive_NoteOn(self): - data = bytes([0xf0, 0x42, 0x01, 0x02, 0x03, 0x04, 0xf7, 0x90 | 14, 0x30, 0x60]) + data = bytes([0xF0, 0x42, 0x01, 0x02, 0x03, 0x04, 0xF7, 0x90 | 14, 0x30, 0x60]) ichannel = 14 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, SystemExclusive) - self.assertEqual(msg.manufacturer_id, bytes([0x42])) # Korg + self.assertEqual(msg.manufacturer_id, bytes([0x42])) # Korg self.assertEqual(msg.data, bytes([0x01, 0x02, 0x03, 0x04])) self.assertEqual(msgendidxplusone, 7) - self.assertEqual(skipped, 0, - "If SystemExclusive class is imported then this must be 0") + self.assertEqual( + skipped, 0, "If SystemExclusive class is imported then this must be 0" + ) self.assertIsNone(msg.channel) - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data[msgendidxplusone:], ichannel) - + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data[msgendidxplusone:], ichannel + ) + self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 48) self.assertEqual(msg.velocity, 0x60) @@ -253,22 +300,27 @@ def test_SystemExclusive_NoteOn(self): self.assertEqual(msg.channel, 14) def test_SystemExclusive_NoteOn_premalterminatedsysex(self): - data = bytes([0xf0, 0x42, 0x01, 0x02, 0x03, 0x04, 0xf0, 0x90, 0x30, 0x32]) + data = bytes([0xF0, 0x42, 0x01, 0x02, 0x03, 0x04, 0xF0, 0x90, 0x30, 0x32]) ichannel = 0 - + # 0xf0 is incorrect status to mark end of this message, must be 0xf7 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsNone(msg) self.assertEqual(msgendidxplusone, 7) - self.assertEqual(skipped, 0, - "If SystemExclusive class is imported then this must be 0") + self.assertEqual( + skipped, 0, "If SystemExclusive class is imported then this must be 0" + ) def test_Unknown_SinglebyteStatus(self): - data = bytes([0xfd]) + data = bytes([0xFD]) ichannel = 0 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsInstance(msg, adafruit_midi.midi_message.MIDIUnknownEvent) self.assertEqual(msgendidxplusone, 1) @@ -279,51 +331,53 @@ def test_Empty(self): data = bytes([]) ichannel = 0 - (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes(data, ichannel) + (msg, msgendidxplusone, skipped) = adafruit_midi.MIDIMessage.from_message_bytes( + data, ichannel + ) self.assertIsNone(msg) self.assertEqual(msgendidxplusone, 0) - self.assertEqual(skipped, 0) + self.assertEqual(skipped, 0) + - class Test_MIDIMessage_NoteOn_constructor(unittest.TestCase): def test_NoteOn_constructor_string(self): object1 = NoteOn("C4", 0x64) self.assertEqual(object1.note, 60) self.assertEqual(object1.velocity, 0x64) - object2 = NoteOn("C3", 0x7f) + object2 = NoteOn("C3", 0x7F) self.assertEqual(object2.note, 48) - self.assertEqual(object2.velocity, 0x7f) - + self.assertEqual(object2.velocity, 0x7F) + object3 = NoteOn("C#4", 0x00) self.assertEqual(object3.note, 61) self.assertEqual(object3.velocity, 0) def test_NoteOn_constructor_valueerror1(self): - with self.assertRaises(ValueError): + with self.assertRaises(ValueError): NoteOn(60, 0x80) # pylint is happier if return value not stored - - def test_NoteOn_constructor_valueerror2(self): + + def test_NoteOn_constructor_valueerror2(self): with self.assertRaises(ValueError): - NoteOn(-1, 0x7f) - + NoteOn(-1, 0x7F) + def test_NoteOn_constructor_valueerror3(self): with self.assertRaises(ValueError): - NoteOn(128, 0x7f) + NoteOn(128, 0x7F) def test_NoteOn_constructor_upperrange1(self): - object1 = NoteOn("G9", 0x7f) + object1 = NoteOn("G9", 0x7F) self.assertEqual(object1.note, 127) - self.assertEqual(object1.velocity, 0x7f) - - def test_NoteOn_constructor_upperrange2(self): + self.assertEqual(object1.velocity, 0x7F) + + def test_NoteOn_constructor_upperrange2(self): with self.assertRaises(ValueError): - NoteOn("G#9", 0x7f) # just above max note - + NoteOn("G#9", 0x7F) # just above max note + def test_NoteOn_constructor_bogusstring(self): with self.assertRaises(ValueError): - NoteOn("CC4", 0x7f) + NoteOn("CC4", 0x7F) class Test_MIDIMessage_NoteOff_constructor(unittest.TestCase): @@ -333,10 +387,10 @@ def test_NoteOff_constructor_string(self): self.assertEqual(object1.note, 60) self.assertEqual(object1.velocity, 0x64) - object2 = NoteOff("C3", 0x7f) + object2 = NoteOff("C3", 0x7F) self.assertEqual(object2.note, 48) - self.assertEqual(object2.velocity, 0x7f) - + self.assertEqual(object2.velocity, 0x7F) + object3 = NoteOff("C#4", 0x00) self.assertEqual(object3.note, 61) self.assertEqual(object3.velocity, 0) @@ -348,29 +402,28 @@ def test_NoteOff_constructor_string(self): def test_NoteOff_constructor_valueerror1(self): with self.assertRaises(ValueError): NoteOff(60, 0x80) - - def test_NoteOff_constructor_valueerror2(self): + + def test_NoteOff_constructor_valueerror2(self): with self.assertRaises(ValueError): - NoteOff(-1, 0x7f) - + NoteOff(-1, 0x7F) + def test_NoteOff_constructor_valueerror3(self): with self.assertRaises(ValueError): - NoteOff(128, 0x7f) + NoteOff(128, 0x7F) def test_NoteOff_constructor_upperrange1(self): - object1 = NoteOff("G9", 0x7f) + object1 = NoteOff("G9", 0x7F) self.assertEqual(object1.note, 127) - self.assertEqual(object1.velocity, 0x7f) - - def test_NoteOff_constructor_upperrange2(self): + self.assertEqual(object1.velocity, 0x7F) + + def test_NoteOff_constructor_upperrange2(self): with self.assertRaises(ValueError): - NoteOff("G#9", 0x7f) # just above max note - + NoteOff("G#9", 0x7F) # just above max note + def test_NoteOff_constructor_bogusstring(self): with self.assertRaises(ValueError): - NoteOff("CC4", 0x7f) - - - -if __name__ == '__main__': + NoteOff("CC4", 0x7F) + + +if __name__ == "__main__": unittest.main(verbosity=verbose) diff --git a/tests/test_MIDI_unittests.py b/tests/test_MIDI_unittests.py index e04a437..0809bea 100644 --- a/tests/test_MIDI_unittests.py +++ b/tests/test_MIDI_unittests.py @@ -25,27 +25,29 @@ import random import os -verbose = int(os.getenv('TESTVERBOSE', '2')) + +verbose = int(os.getenv("TESTVERBOSE", "2")) # adafruit_midi had an import usb_midi import sys -#sys.modules['usb_midi'] = MagicMock() + +# sys.modules['usb_midi'] = MagicMock() # Borrowing the dhalbert/tannewt technique from adafruit/Adafruit_CircuitPython_Motor -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) # Full monty -from adafruit_midi.channel_pressure import ChannelPressure -from adafruit_midi.control_change import ControlChange -from adafruit_midi.note_off import NoteOff -from adafruit_midi.note_on import NoteOn -from adafruit_midi.pitch_bend import PitchBend +from adafruit_midi.channel_pressure import ChannelPressure +from adafruit_midi.control_change import ControlChange +from adafruit_midi.note_off import NoteOff +from adafruit_midi.note_on import NoteOn +from adafruit_midi.pitch_bend import PitchBend from adafruit_midi.polyphonic_key_pressure import PolyphonicKeyPressure -from adafruit_midi.program_change import ProgramChange -from adafruit_midi.start import Start -from adafruit_midi.stop import Stop -from adafruit_midi.system_exclusive import SystemExclusive -from adafruit_midi.timing_clock import TimingClock +from adafruit_midi.program_change import ProgramChange +from adafruit_midi.start import Start +from adafruit_midi.stop import Stop +from adafruit_midi.system_exclusive import SystemExclusive +from adafruit_midi.timing_clock import TimingClock # Import after messages - opposite to other test file import adafruit_midi @@ -54,6 +56,7 @@ # For loopback/echo tests def MIDI_mocked_both_loopback(in_c, out_c): usb_data = bytearray() + def write(buffer, length): nonlocal usb_data usb_data.extend(buffer[0:length]) @@ -61,17 +64,19 @@ def write(buffer, length): def read(length): nonlocal usb_data poppedbytes = usb_data[0:length] - usb_data = usb_data[len(poppedbytes):] + usb_data = usb_data[len(poppedbytes) :] return bytes(poppedbytes) mockedPortIn = Mock() mockedPortIn.read = read mockedPortOut = Mock() mockedPortOut.write = write - m = adafruit_midi.MIDI(midi_out=mockedPortOut, midi_in=mockedPortIn, - out_channel=out_c, in_channel=in_c) + m = adafruit_midi.MIDI( + midi_out=mockedPortOut, midi_in=mockedPortIn, out_channel=out_c, in_channel=in_c + ) return m + def MIDI_mocked_receive(in_c, data, read_sizes): usb_data = bytearray(data) chunks = read_sizes @@ -82,8 +87,8 @@ def read(length): # pylint: disable=no-else-return if length != 0 and chunk_idx < len(chunks): # min() to ensure we only read what's asked for and present - poppedbytes = usb_data[0:min(length, chunks[chunk_idx])] - usb_data = usb_data[len(poppedbytes):] + poppedbytes = usb_data[0 : min(length, chunks[chunk_idx])] + usb_data = usb_data[len(poppedbytes) :] if length >= chunks[chunk_idx]: chunk_idx += 1 else: @@ -95,28 +100,32 @@ def read(length): mockedPortIn = Mock() mockedPortIn.read = read - m = adafruit_midi.MIDI(midi_out=None, midi_in=mockedPortIn, - out_channel=in_c, in_channel=in_c) + m = adafruit_midi.MIDI( + midi_out=None, midi_in=mockedPortIn, out_channel=in_c, in_channel=in_c + ) return m - + class Test_MIDI_constructor(unittest.TestCase): def test_no_inout(self): # constructor likes a bit of in out with self.assertRaises(ValueError): adafruit_midi.MIDI() + class Test_MIDI(unittest.TestCase): # pylint: disable=too-many-branches def test_captured_data_one_byte_reads(self): c = 0 # From an M-Audio AXIOM controller - raw_data = bytearray([0x90, 0x3e, 0x5f] - + [ 0xd0, 0x10] - + [ 0x90, 0x40, 0x66 ] - + [ 0xb0, 0x1, 0x08 ] - + [ 0x90, 0x41, 0x74 ] - + [ 0xe0, 0x03, 0x40 ]) + raw_data = bytearray( + [0x90, 0x3E, 0x5F] + + [0xD0, 0x10] + + [0x90, 0x40, 0x66] + + [0xB0, 0x1, 0x08] + + [0x90, 0x41, 0x74] + + [0xE0, 0x03, 0x40] + ) m = MIDI_mocked_receive(c, raw_data, [1] * len(raw_data)) for unused in range(100): # pylint: disable=unused-variable @@ -124,8 +133,8 @@ def test_captured_data_one_byte_reads(self): if msg is not None: break self.assertIsInstance(msg, NoteOn) - self.assertEqual(msg.note, 0x3e) - self.assertEqual(msg.velocity, 0x5f) + self.assertEqual(msg.note, 0x3E) + self.assertEqual(msg.velocity, 0x5F) self.assertEqual(msg.channel, c) # for loops currently absorb any Nones but could @@ -180,11 +189,12 @@ def test_captured_data_one_byte_reads(self): def test_unknown_before_NoteOn(self): c = 0 # From an M-Audio AXIOM controller - raw_data = (bytes([0b11110011, 0x10] # Song Select (not yet implemented) - + [ 0b11110011, 0x20] - + [ 0b11110100 ] - + [ 0b11110101 ]) - + bytes(NoteOn("C5", 0x7f, channel=c))) + raw_data = bytes( + [0b11110011, 0x10] # Song Select (not yet implemented) + + [0b11110011, 0x20] + + [0b11110100] + + [0b11110101] + ) + bytes(NoteOn("C5", 0x7F, channel=c)) m = MIDI_mocked_receive(c, raw_data, [2, 2, 1, 1, 3]) for unused in range(4): # pylint: disable=unused-variable @@ -195,35 +205,39 @@ def test_unknown_before_NoteOn(self): msg = m.receive() self.assertIsInstance(msg, NoteOn) self.assertEqual(msg.note, 0x48) # 0x48 is C5 - self.assertEqual(msg.velocity, 0x7f) + self.assertEqual(msg.velocity, 0x7F) self.assertEqual(msg.channel, c) # See https://github.com/adafruit/Adafruit_CircuitPython_MIDI/issues/8 def test_running_status_when_implemented(self): c = 8 - raw_data = (bytes(NoteOn("C5", 0x7f, channel=c)) - + bytes([0xe8, 0x72, 0x40] - + [0x6d, 0x40] - + [0x05, 0x41]) - + bytes(NoteOn("D5", 0x7f, channel=c))) + raw_data = ( + bytes(NoteOn("C5", 0x7F, channel=c)) + + bytes([0xE8, 0x72, 0x40] + [0x6D, 0x40] + [0x05, 0x41]) + + bytes(NoteOn("D5", 0x7F, channel=c)) + ) m = MIDI_mocked_receive(c, raw_data, [3 + 3 + 2 + 3 + 3]) self.assertIsInstance(m, adafruit_midi.MIDI) # silence pylint! - #self.assertEqual(TOFINISH, WHENIMPLEMENTED) + # self.assertEqual(TOFINISH, WHENIMPLEMENTED) def test_somegood_somemissing_databytes(self): c = 8 - raw_data = (bytes(NoteOn("C5", 0x7f, channel=c)) - + bytes([0xe8, 0x72, 0x40] - + [0xe8, 0x6d ] # Missing last data byte - + [0xe8, 0x5, 0x41 ]) - + bytes(NoteOn("D5", 0x7f, channel=c))) + raw_data = ( + bytes(NoteOn("C5", 0x7F, channel=c)) + + bytes( + [0xE8, 0x72, 0x40] + + [0xE8, 0x6D] # Missing last data byte + + [0xE8, 0x5, 0x41] + ) + + bytes(NoteOn("D5", 0x7F, channel=c)) + ) m = MIDI_mocked_receive(c, raw_data, [3 + 3 + 2 + 3 + 3]) msg1 = m.receive() self.assertIsInstance(msg1, NoteOn) self.assertEqual(msg1.note, 72) - self.assertEqual(msg1.velocity, 0x7f) + self.assertEqual(msg1.velocity, 0x7F) self.assertEqual(msg1.channel, c) msg2 = m.receive() @@ -238,18 +252,18 @@ def test_somegood_somemissing_databytes(self): msg3 = m.receive() self.assertIsInstance(msg3, adafruit_midi.midi_message.MIDIBadEvent) self.assertIsInstance(msg3.data, bytes) - self.assertEqual(msg3.data, bytes([0xe8, 0x6d, 0xe8])) + self.assertEqual(msg3.data, bytes([0xE8, 0x6D, 0xE8])) self.assertIsNone(msg3.channel) - #(msg4, channel4) = m.receive() - #self.assertIsInstance(msg4, PitchBend) - #self.assertEqual(msg4.pitch_bend, 72) - #self.assertEqual(channel4, c) + # (msg4, channel4) = m.receive() + # self.assertIsInstance(msg4, PitchBend) + # self.assertEqual(msg4.pitch_bend, 72) + # self.assertEqual(channel4, c) msg5 = m.receive() self.assertIsInstance(msg5, NoteOn) self.assertEqual(msg5.note, 74) - self.assertEqual(msg5.velocity, 0x7f) + self.assertEqual(msg5.velocity, 0x7F) self.assertEqual(msg5.channel, c) msg6 = m.receive() @@ -258,19 +272,23 @@ def test_somegood_somemissing_databytes(self): def test_smallsysex_between_notes(self): m = MIDI_mocked_both_loopback(3, 3) - m.send([NoteOn("C4", 0x7f), - SystemExclusive([0x1f], [1, 2, 3, 4, 5, 6, 7, 8]), - NoteOff(60, 0x28)]) + m.send( + [ + NoteOn("C4", 0x7F), + SystemExclusive([0x1F], [1, 2, 3, 4, 5, 6, 7, 8]), + NoteOff(60, 0x28), + ] + ) msg1 = m.receive() self.assertIsInstance(msg1, NoteOn) self.assertEqual(msg1.note, 60) - self.assertEqual(msg1.velocity, 0x7f) + self.assertEqual(msg1.velocity, 0x7F) self.assertEqual(msg1.channel, 3) msg2 = m.receive() self.assertIsInstance(msg2, SystemExclusive) - self.assertEqual(msg2.manufacturer_id, bytes([0x1f])) + self.assertEqual(msg2.manufacturer_id, bytes([0x1F])) self.assertEqual(msg2.data, bytes([1, 2, 3, 4, 5, 6, 7, 8])) self.assertEqual(msg2.channel, None) # SysEx does not have a channel @@ -284,10 +302,10 @@ def test_smallsysex_between_notes(self): self.assertIsNone(msg4) def test_smallsysex_bytes_type(self): - s = SystemExclusive([0x1f], [100, 150, 200]) + s = SystemExclusive([0x1F], [100, 150, 200]) self.assertIsInstance(s, SystemExclusive) - self.assertEqual(s.manufacturer_id, bytes([0x1f])) + self.assertEqual(s.manufacturer_id, bytes([0x1F])) self.assertIsInstance(s.manufacturer_id, bytes) # check this really is immutable (pylint also picks this up!) @@ -301,19 +319,24 @@ def test_smallsysex_bytes_type(self): def test_larger_than_buffer_sysex(self): c = 0 monster_data_len = 500 - raw_data = (bytes(NoteOn("C5", 0x7f, channel=c)) - + bytes(SystemExclusive([0x02], - [d & 0x7f for d in range(monster_data_len)])) - + bytes(NoteOn("D5", 0x7f, channel=c))) + raw_data = ( + bytes(NoteOn("C5", 0x7F, channel=c)) + + bytes( + SystemExclusive([0x02], [d & 0x7F for d in range(monster_data_len)]) + ) + + bytes(NoteOn("D5", 0x7F, channel=c)) + ) m = MIDI_mocked_receive(c, raw_data, [len(raw_data)]) buffer_len = m._in_buf_size # pylint: disable=protected-access - self.assertTrue(monster_data_len > buffer_len, - "checking our SysEx truly is larger than buffer") + self.assertTrue( + monster_data_len > buffer_len, + "checking our SysEx truly is larger than buffer", + ) msg1 = m.receive() self.assertIsInstance(msg1, NoteOn) self.assertEqual(msg1.note, 72) - self.assertEqual(msg1.velocity, 0x7f) + self.assertEqual(msg1.velocity, 0x7F) self.assertEqual(msg1.channel, c) # (Ab)using python's rounding down for negative division @@ -326,71 +349,80 @@ def test_larger_than_buffer_sysex(self): # and report it as an unknown msg3 = m.receive() self.assertIsInstance(msg3, adafruit_midi.midi_message.MIDIUnknownEvent) - self.assertEqual(msg3.status, 0xf7) + self.assertEqual(msg3.status, 0xF7) self.assertIsNone(msg3.channel) - #(msg4, channel4) = m.receive() - #self.assertIsInstance(msg4, PitchBend) - #self.assertEqual(msg4.pitch_bend, 72) - #self.assertEqual(channel4, c) + # (msg4, channel4) = m.receive() + # self.assertIsInstance(msg4, PitchBend) + # self.assertEqual(msg4.pitch_bend, 72) + # self.assertEqual(channel4, c) msg5 = m.receive() self.assertIsInstance(msg5, NoteOn) self.assertEqual(msg5.note, 74) - self.assertEqual(msg5.velocity, 0x7f) + self.assertEqual(msg5.velocity, 0x7F) self.assertEqual(msg5.channel, c) msg6 = m.receive() self.assertIsNone(msg6) + # pylint does not like mock_calls - must be a better way to handle this? # pylint: disable=no-member class Test_MIDI_send(unittest.TestCase): def test_send_basic_single(self): - #def printit(buffer, len): + # def printit(buffer, len): # print(buffer[0:len]) mockedPortOut = Mock() - #mockedPortOut.write = printit + # mockedPortOut.write = printit m = adafruit_midi.MIDI(midi_out=mockedPortOut, out_channel=2) # Test sending some NoteOn and NoteOff to various channels nextcall = 0 - m.send(NoteOn(0x60, 0x7f)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x92\x60\x7f', 3)) + m.send(NoteOn(0x60, 0x7F)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x60\x7f", 3) + ) nextcall += 1 - m.send(NoteOn(0x64, 0x3f)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x92\x64\x3f', 3)) + m.send(NoteOn(0x64, 0x3F)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x64\x3f", 3) + ) nextcall += 1 - m.send(NoteOn(0x67, 0x1f)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x92\x67\x1f', 3)) + m.send(NoteOn(0x67, 0x1F)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x67\x1f", 3) + ) nextcall += 1 m.send(NoteOn(0x60, 0x00)) # Alternative to NoteOff - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x92\x60\x00', 3)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x60\x00", 3) + ) nextcall += 1 m.send(NoteOff(0x64, 0x01)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x82\x64\x01', 3)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x82\x64\x01", 3) + ) nextcall += 1 m.send(NoteOff(0x67, 0x02)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x82\x67\x02', 3)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x82\x67\x02", 3) + ) nextcall += 1 # Setting channel to non default - m.send(NoteOn(0x6c, 0x7f), channel=9) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x99\x6c\x7f', 3)) + m.send(NoteOn(0x6C, 0x7F), channel=9) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x99\x6c\x7f", 3) + ) nextcall += 1 - m.send(NoteOff(0x6c, 0x7f), channel=9) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x89\x6c\x7f', 3)) + m.send(NoteOff(0x6C, 0x7F), channel=9) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x89\x6c\x7f", 3) + ) nextcall += 1 def test_send_badnotes(self): @@ -400,46 +432,50 @@ def test_send_badnotes(self): # Test sending some NoteOn and NoteOff to various channels nextcall = 0 - m.send(NoteOn(60, 0x7f)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x92\x3c\x7f', 3)) + m.send(NoteOn(60, 0x7F)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x3c\x7f", 3) + ) nextcall += 1 with self.assertRaises(ValueError): - m.send(NoteOn(64, 0x80)) # Velocity > 127 - illegal value + m.send(NoteOn(64, 0x80)) # Velocity > 127 - illegal value with self.assertRaises(ValueError): m.send(NoteOn(67, -1)) # test after exceptions to ensure sending is still ok - m.send(NoteOn(72, 0x7f)) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x92\x48\x7f', 3)) + m.send(NoteOn(72, 0x7F)) + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x48\x7f", 3) + ) nextcall += 1 def test_send_basic_sequences(self): - #def printit(buffer, len): + # def printit(buffer, len): # print(buffer[0:len]) mockedPortOut = Mock() - #mockedPortOut.write = printit + # mockedPortOut.write = printit m = adafruit_midi.MIDI(midi_out=mockedPortOut, out_channel=2) # Test sending some NoteOn and NoteOff to various channels nextcall = 0 # Test sequences with list syntax and pass a tuple too - note_list = [NoteOn(0x6c, 0x51), - NoteOn(0x70, 0x52), - NoteOn(0x73, 0x53)] + note_list = [NoteOn(0x6C, 0x51), NoteOn(0x70, 0x52), NoteOn(0x73, 0x53)] note_tuple = tuple(note_list) m.send(note_list, channel=10) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x9a\x6c\x51\x9a\x70\x52\x9a\x73\x53', 9), - "The implementation writes in one go, single 9 byte write expected") + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], + call(b"\x9a\x6c\x51\x9a\x70\x52\x9a\x73\x53", 9), + "The implementation writes in one go, single 9 byte write expected", + ) nextcall += 1 m.send(note_tuple, channel=11) - self.assertEqual(mockedPortOut.write.mock_calls[nextcall], - call(b'\x9b\x6c\x51\x9b\x70\x52\x9b\x73\x53', 9), - "The implementation writes in one go, single 9 byte write expected") + self.assertEqual( + mockedPortOut.write.mock_calls[nextcall], + call(b"\x9b\x6c\x51\x9b\x70\x52\x9b\x73\x53", 9), + "The implementation writes in one go, single 9 byte write expected", + ) nextcall += 1 def test_termination_with_random_data(self): @@ -459,5 +495,5 @@ def test_termination_with_random_data(self): self.assertTrue(noinfiniteloops) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main(verbosity=verbose) diff --git a/tests/test_note_parser.py b/tests/test_note_parser.py index d632e53..617db9c 100644 --- a/tests/test_note_parser.py +++ b/tests/test_note_parser.py @@ -25,14 +25,16 @@ import random import os -verbose = int(os.getenv('TESTVERBOSE', '2')) + +verbose = int(os.getenv("TESTVERBOSE", "2")) # adafruit_midi had an import usb_midi import sys -#sys.modules['usb_midi'] = MagicMock() + +# sys.modules['usb_midi'] = MagicMock() # Borrowing the dhalbert/tannewt technique from adafruit/Adafruit_CircuitPython_Motor -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from adafruit_midi.midi_message import note_parser @@ -48,35 +50,36 @@ def text_int_passthru(self): self.assertEqual(note_parser(808), 808) def test_good_text(self): - note_prefix = { "Cb": 11, - "C" : 12, - "C#": 13, - "Db": 13, - "D" : 14, - "D#": 15, - "Eb": 15, - "E" : 16, - "Fb": 16, - "E#": 17, - "F" : 17, - "F#": 18, - "Gb": 18, - "G" : 19, - "G#": 20, - "Ab": 20, - "A" : 21, - "A#": 22, - "Bb": 22, - "B" : 23, - "B#": 24, - } + note_prefix = { + "Cb": 11, + "C": 12, + "C#": 13, + "Db": 13, + "D": 14, + "D#": 15, + "Eb": 15, + "E": 16, + "Fb": 16, + "E#": 17, + "F": 17, + "F#": 18, + "Gb": 18, + "G": 19, + "G#": 20, + "Ab": 20, + "A": 21, + "A#": 22, + "Bb": 22, + "B": 23, + "B#": 24, + } # test from Cb0 to B#8 for prefix, base_value in note_prefix.items(): for octave in range(9): note = prefix + str(octave) - expected_value = base_value + octave * 12 # 12 semitones in octave - self.assertEqual(note_parser(note), expected_value) + expected_value = base_value + octave * 12 # 12 semitones in octave + self.assertEqual(note_parser(note), expected_value) # re-test with simple C4/A4 tests to catch any bugs in above self.assertEqual(note_parser("C4"), 60) @@ -89,5 +92,5 @@ def test_bad_text(self): note_parser(text_note) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main(verbosity=verbose)