diff options
| -rw-r--r-- | midi.py | 50 | ||||
| -rw-r--r-- | midi_controller_launchpad_mini.py | 45 | ||||
| -rw-r--r-- | midi_launchpad_mini_integrationtest.py | 36 | ||||
| -rw-r--r-- | midi_wrapper_mido.py | 6 | 
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) | 
