From 430466b0e3a4dd762d8c4a44403437691d9d6118 Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Sun, 2 Jan 2022 09:34:37 +0100 Subject: Added basic LED support for launchpad, removed old MIDI code --- midi.py | 50 ---------------------------------- midi_controller_launchpad_mini.py | 45 +++++++++++++++++++++++++++++- midi_launchpad_mini_integrationtest.py | 36 ++++++++++++++++++++++-- midi_wrapper_mido.py | 6 ++-- 4 files changed, 80 insertions(+), 57 deletions(-) delete mode 100644 midi.py diff --git a/midi.py b/midi.py deleted file mode 100644 index 7eca87e..0000000 --- a/midi.py +++ /dev/null @@ -1,50 +0,0 @@ -import mido - -lp_key = [[j for j in range(i * 16, i * 16 + 8)] for i in range(0,8)] - -GREEN = 124 -YELLOW = 126 -RED = 3 - -_light_ctrl_msg = mido.Message('note_on', channel=0) -_inport = None -_outport = None - -_callbacks_on_press = dict() -_callbacks_on_release = dict() - -_debug = False - -def midi_init(device_name="Launchpad Mini MIDI 1"): - global _inport, _outport - _inport = mido.open_input(device_name) - _outport = mido.open_output(device_name) - - _inport.callback = _callback - -def button_on(button, colour): - if _debug: print(f"outport: {_outport}") - - if _outport: - msg = _light_ctrl_msg.copy(note=button, velocity=colour) - if _debug: print(f"sending {msg}") - _outport.send(msg) - -def button_off(button): - if _outport: - msg = _light_ctrl_msg.copy(note=button, velocity=0) - _outport.send(msg) - -def on_press(button, function): - _callbacks_on_press[button] = function - -def on_release(button, function): - _callbacks_on_release[button] = function - -def _callback(msg): - if msg.velocity == 0: - if msg.note in _callbacks_on_release: - _callbacks_on_release[msg.note]() - elif msg.velocity == 127: - if msg.note in _callbacks_on_press: - _callbacks_on_press[msg.note]() diff --git a/midi_controller_launchpad_mini.py b/midi_controller_launchpad_mini.py index bc2ed8a..1f430c2 100644 --- a/midi_controller_launchpad_mini.py +++ b/midi_controller_launchpad_mini.py @@ -2,6 +2,12 @@ from midi_wrapper_mido import MidiWrapper class MidiController: DEVICE_NAME = "Launchpad Mini MIDI 1" + LIGHT_CONTROL_CHANNEL = 0 + LED_GREEN = 124 + LED_YELLOW = 126 + LED_RED = 3 + LED_OFF = 0 + BUTTON_MATRIX = [[x for x in range(y * 16, y * 16 + 8)] for y in range(0,8)] # address as [row][col] def __init__(self, soloTool, midiWrapperOverride=None): self._soloTool = soloTool @@ -10,6 +16,9 @@ class MidiController: else: self._midiWrapper = MidiWrapper() + self._registerHandlers() + + def _registerHandlers(self): self._handlers = { 96 : self._soloTool.stop, 112 : self._playPause, @@ -29,8 +38,9 @@ class MidiController: self._handlers[i] = self._createSetPlaybackRateCallback(rate) def connect(self): - self._midiWrapper.connect(MidiController.DEVICE_NAME) self._midiWrapper.setCallback(self._callback) + self._midiWrapper.connect(MidiController.DEVICE_NAME) + self._initialiseButtonLEDs() def _callback(self, msg): if msg.velocity < 127: @@ -54,3 +64,36 @@ class MidiController: def f(): self._soloTool.setPlaybackVolume(volume) return f + + def _setButtonLED(self, row, col, colour): + self._midiWrapper.sendMessage(MidiController.BUTTON_MATRIX[row][col], colour, MidiController.LIGHT_CONTROL_CHANNEL) + + def _allLEDsOff(self): + for row in range(0, 8): + for col in range(0, 8): + self._setButtonLED(row, col, MidiController.LED_OFF) + + def _initialiseButtonLEDs(self): + self._allLEDsOff() + + # volume buttons + for col in range(0, 8): + self._setButtonLED(0, col, MidiController.LED_GREEN) + + # playback rate buttons + for col in range(0, 6): + self._setButtonLED(1, col, MidiController.LED_YELLOW) + + # playback control + self._setButtonLED(6, 0, MidiController.LED_RED) + self._setButtonLED(7, 0, MidiController.LED_GREEN) + + # AB control + self._setButtonLED(6, 5, MidiController.LED_YELLOW) + self._setButtonLED(6, 6, MidiController.LED_RED) + self._setButtonLED(6, 7, MidiController.LED_GREEN) + + # Song control + self._setButtonLED(7, 6, MidiController.LED_RED) + self._setButtonLED(7, 7, MidiController.LED_GREEN) + diff --git a/midi_launchpad_mini_integrationtest.py b/midi_launchpad_mini_integrationtest.py index 275bd33..13b18e7 100644 --- a/midi_launchpad_mini_integrationtest.py +++ b/midi_launchpad_mini_integrationtest.py @@ -6,9 +6,10 @@ from player_mock import Player as PlayerMock class MidiWrapperMock: def __init__(self): + from queue import SimpleQueue self.callback = None self.connectedDevice = None - self.lastMessageSent = None + self.sentMessages = SimpleQueue() def setCallback(self, callback): self.callback = callback @@ -16,8 +17,8 @@ class MidiWrapperMock: def connect(self, deviceName): self.connectedDevice = deviceName - def sendMessage(self, note, velocity=127, channel=0): - pass + def sendMessage(self, note, velocity, channel): + self.sentMessages.put((note, velocity, channel)) def simulateInput(self, note, velocity=127, channel=0): if self.callback is not None: @@ -193,3 +194,32 @@ def test_unassignedButton(uut, midiWrapperMock): midiWrapperMock.simulateInput(unassignedButton) # XXX would be better to assert that nothing changed in the solo tool +def test_initializationMessages(uut, midiWrapperMock): + green = 124 + yellow = 126 + red = 3 + off = 0 + + expectedMessages = set( + [(int(i / 8) * 16 + (i % 8), off, 0) for i in range(0, 64)] + # clear all + [(i, green, 0) for i in range(0, 8)] + # volume row + [(i, yellow, 0) for i in range(16, 22)] + # playback rate row + [ + (96, red, 0), + (101, yellow, 0), + (102, red, 0), + (103, green, 0), + (112, green, 0), + (118, red, 0), + (119, green, 0) + ] + ) + + uut.connect() + + sentMessages = set() + while (not midiWrapperMock.sentMessages.empty()): + sentMessages.add(midiWrapperMock.sentMessages.get()) + + assert sentMessages == expectedMessages + diff --git a/midi_wrapper_mido.py b/midi_wrapper_mido.py index ee0d6d5..bf3aa85 100644 --- a/midi_wrapper_mido.py +++ b/midi_wrapper_mido.py @@ -13,9 +13,9 @@ class MidiWrapper: self._inPort = mido.open_input(deviceName) self._inPort.callback = self._callback self._outPort = mido.open_output(deviceName) - - def sendMessage(note, velocity=127, channel=0): + + def sendMessage(self, note, velocity, channel): if self._outPort is not None: msg = mido.Message('note_on', channel=channel, velocity=velocity, note=note) - self.outPort.send(msg) + self._outPort.send(msg) -- cgit v1.2.3