aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--midi.py50
-rw-r--r--midi_controller_launchpad_mini.py45
-rw-r--r--midi_launchpad_mini_integrationtest.py36
-rw-r--r--midi_wrapper_mido.py6
4 files changed, 80 insertions, 57 deletions
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)