diff --git a/adafruit_midi/channel_pressure.py b/adafruit_midi/channel_pressure.py index 4bab4c0..14216d9 100644 --- a/adafruit_midi/channel_pressure.py +++ b/adafruit_midi/channel_pressure.py @@ -28,6 +28,7 @@ class ChannelPressure(MIDIMessage): :param int pressure: The pressure, 0-127. """ + _message_slots = ["pressure", "channel"] _STATUS = 0xD0 _STATUSMASK = 0xF0 LENGTH = 2 diff --git a/adafruit_midi/control_change.py b/adafruit_midi/control_change.py index bd6e92a..9582bbc 100644 --- a/adafruit_midi/control_change.py +++ b/adafruit_midi/control_change.py @@ -30,6 +30,7 @@ class ControlChange(MIDIMessage): """ + _message_slots = ["control", "value", "channel"] _STATUS = 0xB0 _STATUSMASK = 0xF0 LENGTH = 3 diff --git a/adafruit_midi/midi_continue.py b/adafruit_midi/midi_continue.py index 5df644e..8499215 100644 --- a/adafruit_midi/midi_continue.py +++ b/adafruit_midi/midi_continue.py @@ -25,6 +25,8 @@ class Continue(MIDIMessage): """Continue MIDI message.""" + _message_slots = [] + _STATUS = 0xFB _STATUSMASK = 0xFF LENGTH = 1 diff --git a/adafruit_midi/midi_message.py b/adafruit_midi/midi_message.py index 029497d..d9ee4de 100755 --- a/adafruit_midi/midi_message.py +++ b/adafruit_midi/midi_message.py @@ -285,6 +285,20 @@ def from_bytes(cls, msg_bytes): representation of the MIDI message.""" return cls() + def __str__(self): + """Print an instance""" + cls = self.__class__ + if slots := getattr(cls, "_message_slots", None): + # pylint: disable=not-an-iterable + args = ", ".join( + f"{name}={repr(getattr(self, name, None))}" for name in slots + ) + else: + args = "..." + return f"{self.__class__.__name__}({args})" + + __repr__ = __str__ + # DO NOT try to register these messages class MIDIUnknownEvent(MIDIMessage): @@ -296,6 +310,7 @@ class MIDIUnknownEvent(MIDIMessage): or because it is not imported. """ + _message_slots = ["status"] LENGTH = -1 def __init__(self, status): @@ -316,6 +331,8 @@ class MIDIBadEvent(MIDIMessage): LENGTH = -1 + _message_slots = ["msg_bytes", "exception"] + def __init__(self, msg_bytes, exception): self.data = bytes(msg_bytes) self.exception_text = repr(exception) diff --git a/adafruit_midi/mtc_quarter_frame.py b/adafruit_midi/mtc_quarter_frame.py index fe3b56b..d350b88 100644 --- a/adafruit_midi/mtc_quarter_frame.py +++ b/adafruit_midi/mtc_quarter_frame.py @@ -41,6 +41,8 @@ class MtcQuarterFrame(MIDIMessage): :param value: The quarter frame value for the specified type. """ + _message_slots = ["msgtype", "value"] + _STATUS = 0xF1 _STATUSMASK = 0xFF LENGTH = 2 diff --git a/adafruit_midi/note_off.py b/adafruit_midi/note_off.py index babe5ce..3e0f942 100644 --- a/adafruit_midi/note_off.py +++ b/adafruit_midi/note_off.py @@ -31,6 +31,7 @@ class NoteOff(MIDIMessage): # pylint: disable=duplicate-code """ + _message_slots = ["note", "velocity", "channel"] _STATUS = 0x80 _STATUSMASK = 0xF0 LENGTH = 3 diff --git a/adafruit_midi/note_on.py b/adafruit_midi/note_on.py index 409e0d2..eb3920c 100644 --- a/adafruit_midi/note_on.py +++ b/adafruit_midi/note_on.py @@ -31,6 +31,8 @@ class NoteOn(MIDIMessage): to a Note Off, defaults to 127. """ + _message_slots = ["note", "velocity", "channel"] + _STATUS = 0x90 _STATUSMASK = 0xF0 LENGTH = 3 diff --git a/adafruit_midi/pitch_bend.py b/adafruit_midi/pitch_bend.py index c247ca2..c513593 100644 --- a/adafruit_midi/pitch_bend.py +++ b/adafruit_midi/pitch_bend.py @@ -29,6 +29,7 @@ class PitchBend(MIDIMessage): bend from 0 through 8192 (midpoint, no bend) to 16383. """ + _message_slots = ["pitch_bend", "channel"] _STATUS = 0xE0 _STATUSMASK = 0xF0 LENGTH = 3 diff --git a/adafruit_midi/polyphonic_key_pressure.py b/adafruit_midi/polyphonic_key_pressure.py index af69ee9..f6ec395 100644 --- a/adafruit_midi/polyphonic_key_pressure.py +++ b/adafruit_midi/polyphonic_key_pressure.py @@ -30,6 +30,7 @@ class PolyphonicKeyPressure(MIDIMessage): :param int pressure: The pressure, 0-127. """ + _message_slots = ["note", "pressure", "channel"] _STATUS = 0xA0 _STATUSMASK = 0xF0 LENGTH = 3 diff --git a/adafruit_midi/program_change.py b/adafruit_midi/program_change.py index b55cf63..a0f6cb0 100644 --- a/adafruit_midi/program_change.py +++ b/adafruit_midi/program_change.py @@ -28,6 +28,7 @@ class ProgramChange(MIDIMessage): :param int patch: The new program/patch number to use, 0-127. """ + _message_slots = ["patch", "channel"] _STATUS = 0xC0 _STATUSMASK = 0xF0 LENGTH = 2 diff --git a/adafruit_midi/start.py b/adafruit_midi/start.py index ed6732f..bb1a64f 100644 --- a/adafruit_midi/start.py +++ b/adafruit_midi/start.py @@ -28,6 +28,7 @@ class Start(MIDIMessage): _STATUS = 0xFA _STATUSMASK = 0xFF LENGTH = 1 + _message_slots = [] Start.register_message_type() diff --git a/adafruit_midi/stop.py b/adafruit_midi/stop.py index d11dc9f..89401b5 100644 --- a/adafruit_midi/stop.py +++ b/adafruit_midi/stop.py @@ -28,6 +28,7 @@ class Stop(MIDIMessage): _STATUS = 0xFC _STATUSMASK = 0xFF LENGTH = 1 + _message_slots = [] Stop.register_message_type() diff --git a/adafruit_midi/system_exclusive.py b/adafruit_midi/system_exclusive.py index 2d9fa2a..352e9e0 100644 --- a/adafruit_midi/system_exclusive.py +++ b/adafruit_midi/system_exclusive.py @@ -32,6 +32,7 @@ class SystemExclusive(MIDIMessage): This message can only be parsed if it fits within the input buffer in :class:MIDI. """ + _message_slots = ["manufacturer_id", "data"] _STATUS = 0xF0 _STATUSMASK = 0xFF LENGTH = -1 diff --git a/adafruit_midi/timing_clock.py b/adafruit_midi/timing_clock.py index 5a56919..1649a94 100644 --- a/adafruit_midi/timing_clock.py +++ b/adafruit_midi/timing_clock.py @@ -34,6 +34,7 @@ class TimingClock(MIDIMessage): _STATUS = 0xF8 _STATUSMASK = 0xFF LENGTH = 1 + _slots = [] TimingClock.register_message_type() diff --git a/docs/conf.py b/docs/conf.py index a6014cb..4d8e49c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,9 +4,9 @@ # # SPDX-License-Identifier: MIT +import datetime import os import sys -import datetime sys.path.insert(0, os.path.abspath("..")) diff --git a/examples/midi_inoutdemo.py b/examples/midi_inoutdemo.py index 2a395d7..e6b3faa 100644 --- a/examples/midi_inoutdemo.py +++ b/examples/midi_inoutdemo.py @@ -4,16 +4,13 @@ # midi_inoutdemo - demonstrates receiving and sending MIDI events import usb_midi -import adafruit_midi -# TimingClock is worth importing first if present as it -# will make parsing more efficient for this high frequency event -# Only importing what is used will save a little bit of memory +import adafruit_midi # 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.midi_message import MIDIUnknownEvent from adafruit_midi.note_off import NoteOff from adafruit_midi.note_on import NoteOn from adafruit_midi.pitch_bend import PitchBend @@ -22,8 +19,12 @@ 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 + +# TimingClock is worth importing first if present as it +# will make parsing more efficient for this high frequency event +# Only importing what is used will save a little bit of memory -from adafruit_midi.midi_message import MIDIUnknownEvent midi = adafruit_midi.MIDI( midi_in=usb_midi.ports[0], diff --git a/examples/midi_intest1.py b/examples/midi_intest1.py index 2527d64..3bb5037 100644 --- a/examples/midi_intest1.py +++ b/examples/midi_intest1.py @@ -2,36 +2,28 @@ # SPDX-License-Identifier: MIT import time + import usb_midi + import adafruit_midi -# 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 # 0 is MIDI channel 1 midi = adafruit_midi.MIDI(midi_in=usb_midi.ports[0], in_channel=0) -print("Midi input test with pauses") +print("Midi input test") # Convert channel numbers at the presentation layer to the ones musicians use print("Input channel:", midi.in_channel + 1) -# play with the pause to simulate code doing other stuff -# in the loop -pauses = [0] * 10 + [0.010] * 10 + [0.100] * 10 + [1.0] * 10 - while True: - for pause in pauses: - msg = midi.receive() - if msg is not None: - print(time.monotonic(), msg) - if pause: - time.sleep(pause) + msg = midi.receive() + if msg is not None: + print(time.monotonic(), msg) diff --git a/examples/midi_memorycheck.py b/examples/midi_memorycheck.py index 1d0b109..d03ab6b 100644 --- a/examples/midi_memorycheck.py +++ b/examples/midi_memorycheck.py @@ -10,9 +10,9 @@ # # E: 8,21: Module 'gc' has no 'mem_free' member (no-member) -import time -import random import gc +import random +import time gc.collect() print(gc.mem_free()) diff --git a/examples/midi_simpletest.py b/examples/midi_simpletest.py index 4cf0b4c..00d25c0 100644 --- a/examples/midi_simpletest.py +++ b/examples/midi_simpletest.py @@ -1,9 +1,11 @@ # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT # simple_test -import time import random +import time + import usb_midi + import adafruit_midi from adafruit_midi.control_change import ControlChange from adafruit_midi.note_off import NoteOff diff --git a/tests/test_MIDIMessage_unittests.py b/tests/test_MIDIMessage_unittests.py index d038067..1b938ad 100644 --- a/tests/test_MIDIMessage_unittests.py +++ b/tests/test_MIDIMessage_unittests.py @@ -4,10 +4,8 @@ # pylint: disable=invalid-name -import unittest - - import os +import unittest verbose = int(os.getenv("TESTVERBOSE", "2")) diff --git a/tests/test_MIDI_unittests.py b/tests/test_MIDI_unittests.py index 457e90f..178a760 100644 --- a/tests/test_MIDI_unittests.py +++ b/tests/test_MIDI_unittests.py @@ -4,12 +4,11 @@ # pylint: disable=invalid-name +import os +import random import unittest from unittest.mock import Mock, call -import random -import os - verbose = int(os.getenv("TESTVERBOSE", "2")) # pylint: disable=wrong-import-position @@ -21,6 +20,9 @@ # Borrowing the dhalbert/tannewt technique from adafruit/Adafruit_CircuitPython_Motor sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +# Import after 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 @@ -29,9 +31,6 @@ from adafruit_midi.pitch_bend import PitchBend from adafruit_midi.system_exclusive import SystemExclusive -# Import after messages - opposite to other test file -import adafruit_midi - # pylint: enable=wrong-import-position diff --git a/tests/test_note_parser.py b/tests/test_note_parser.py index e439b87..2d29373 100644 --- a/tests/test_note_parser.py +++ b/tests/test_note_parser.py @@ -2,9 +2,8 @@ # # SPDX-License-Identifier: MIT -import unittest - import os +import unittest verbose = int(os.getenv("TESTVERBOSE", "2"))