aboutsummaryrefslogtreecommitdiffstats
path: root/solo-tool-project/src
diff options
context:
space:
mode:
authorEddy Pedroni <epedroni@pm.me>2025-08-21 18:56:43 +0200
committerEddy Pedroni <epedroni@pm.me>2025-08-21 18:56:43 +0200
commit4ea8344fba863d3ff113cf790b6327d44ced62ee (patch)
tree0db18a3b5039258567d36d782687b83ed0ff9baa /solo-tool-project/src
parent748f056faf16b08ac41de991b1aeb664f2b86d8e (diff)
Actition controller prototype
Diffstat (limited to 'solo-tool-project/src')
-rw-r--r--solo-tool-project/src/solo_tool/handlers.py4
-rw-r--r--solo-tool-project/src/solo_tool/midi_controller_actition.py43
-rw-r--r--solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py89
-rw-r--r--solo-tool-project/src/solo_tool/midi_wrapper_mido.py28
4 files changed, 103 insertions, 61 deletions
diff --git a/solo-tool-project/src/solo_tool/handlers.py b/solo-tool-project/src/solo_tool/handlers.py
index 1820e86..3beb0fb 100644
--- a/solo-tool-project/src/solo_tool/handlers.py
+++ b/solo-tool-project/src/solo_tool/handlers.py
@@ -38,9 +38,9 @@ def seekRelative(st: SoloTool, delta: float) -> Callable[[], None]:
st.position += delta
return f
-def seekAbsolute(st: SoloTool, delta: float) -> Callable[[], None]:
+def seekAbsolute(st: SoloTool, new: float) -> Callable[[], None]:
def f():
- st.position = delta
+ st.position = new
return f
def positionToKeyPoint(st: SoloTool) -> Callable[[], None]:
diff --git a/solo-tool-project/src/solo_tool/midi_controller_actition.py b/solo-tool-project/src/solo_tool/midi_controller_actition.py
new file mode 100644
index 0000000..184b9c8
--- /dev/null
+++ b/solo-tool-project/src/solo_tool/midi_controller_actition.py
@@ -0,0 +1,43 @@
+import mido
+from collections.abc import Callable
+
+from . import handlers
+from .solo_tool import SoloTool
+
+class ActitionController:
+ class _MidoMidiWrapper:
+ def __init__(self):
+ self._callback = None
+ self._inPort = mido.open_input("f_midi")
+ self._inPort.callback = self._midoCallback
+
+ def setCallback(self, callback: Callable[[int, int], None]) -> None:
+ self._callback = callback
+
+ def _midoCallback(msg: mido.Message) -> None:
+ if msg.type != "control_change":
+ return
+ if self._callback:
+ self._callback(msg.control, msg.channel)
+
+ def __init__(self, midiWrapperOverride=None):
+ self._handlers = {}
+ if midiWrapperOverride:
+ self._midiWrapper = midiWrapperOverride
+ else:
+ self._midiWrapper = ActitionController._MidoMidiWrapper()
+ self._midiWrapper.setCallback(self._callback)
+
+ def _callback(self, control: int, channel: int) -> None:
+ if channel != 15:
+ return
+ if control in self._handlers:
+ self._handlers[control]()
+
+ def setSoloTool(self, soloTool: SoloTool) -> None:
+ self._handlers = {
+ 102: handlers.seekAbsolute(soloTool, 0.0),
+ 103: handlers.positionToKeyPoint(soloTool),
+ 104: soloTool.jump,
+ 105: handlers.playPause(soloTool)
+ }
diff --git a/solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py b/solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py
index 625e2ef..e79b60c 100644
--- a/solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py
+++ b/solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py
@@ -1,7 +1,34 @@
-from .midi_wrapper_mido import MidiWrapper
+import mido
from . import handlers
+from .solo_tool import SoloTool
-class MidiController:
+class MidiWrapper:
+ def __init__(self):
+ self._inPort = None
+ self._outPort = None
+
+ def connect(self, deviceName, callback):
+ if self._inPort is None and self._outPort is None:
+ self._inPort = mido.open_input(deviceName)
+ self._inPort.callback = callback
+ self._outPort = mido.open_output(deviceName)
+
+ def disconnect(self):
+ if self._inPort is not None:
+ self._inPort.close()
+ self._inPort = None
+
+ if self._outPort is not None:
+ self._outPort.reset()
+ self._outPort.close()
+ self._outPort = None
+
+ def sendNoteOn(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)
+
+class LaunchpadMiniController:
DEVICE_NAME = "Launchpad Mini MIDI 1"
LIGHT_CONTROL_CHANNEL = 0
LED_GREEN = 124
@@ -18,7 +45,7 @@ class MidiController:
MAX_PLAYBACK_VOLUME = 1.2
PLAYBACK_VOLUME_STEP = 0.1
- def __init__(self, soloTool, midiWrapperOverride=None):
+ def __init__(self, soloTool: SoloTool, midiWrapperOverride=None):
self._soloTool = soloTool
if midiWrapperOverride is not None:
self._midiWrapper = midiWrapperOverride
@@ -49,19 +76,19 @@ class MidiController:
}
for i in range(0, 8):
- volume = round(MidiController.MIN_PLAYBACK_VOLUME + MidiController.PLAYBACK_VOLUME_STEP * i, 1)
+ volume = round(LaunchpadMiniController.MIN_PLAYBACK_VOLUME + LaunchpadMiniController.PLAYBACK_VOLUME_STEP * i, 1)
self._handlers[i] = handlers.volumeAbsolute(self._soloTool, volume)
for i, button in enumerate(range(16, 24)):
- rate = round(MidiController.MIN_PLAYBACK_RATE + MidiController.PLAYBACK_RATE_STEP * i, 1)
+ rate = round(LaunchpadMiniController.MIN_PLAYBACK_RATE + LaunchpadMiniController.PLAYBACK_RATE_STEP * i, 1)
self._handlers[button] = handlers.rateAbsolute(self._soloTool, rate)
def connect(self):
- self._midiWrapper.connect(MidiController.DEVICE_NAME, self._callback)
+ self._midiWrapper.connect(LaunchpadMiniController.DEVICE_NAME, self._callback)
self._initialiseButtonLEDs()
def disconnect(self):
- self._setAllLEDs(MidiController.LED_OFF)
+ self._setAllLEDs(LaunchpadMiniController.LED_OFF)
self._midiWrapper.disconnect()
def _callback(self, msg):
@@ -73,27 +100,27 @@ class MidiController:
def _updatePlayPauseButton(self, playing):
if playing:
- self._setButtonLED(7, 0, MidiController.LED_GREEN)
+ self._setButtonLED(7, 0, LaunchpadMiniController.LED_GREEN)
else:
- self._setButtonLED(7, 0, MidiController.LED_YELLOW)
+ self._setButtonLED(7, 0, LaunchpadMiniController.LED_YELLOW)
def _updateVolumeRow(self, volume):
- t1 = int(round(volume / MidiController.PLAYBACK_VOLUME_STEP, 1))
- t2 = int(round(MidiController.MIN_PLAYBACK_VOLUME / MidiController.PLAYBACK_VOLUME_STEP, 1))
+ t1 = int(round(volume / LaunchpadMiniController.PLAYBACK_VOLUME_STEP, 1))
+ t2 = int(round(LaunchpadMiniController.MIN_PLAYBACK_VOLUME / LaunchpadMiniController.PLAYBACK_VOLUME_STEP, 1))
lastColumnLit = t1 - t2 + 1
- self._lightRowUntilColumn(0, lastColumnLit, MidiController.LED_GREEN)
+ self._lightRowUntilColumn(0, lastColumnLit, LaunchpadMiniController.LED_GREEN)
def _updateRateRow(self, rate):
- t1 = int(round(rate / MidiController.PLAYBACK_RATE_STEP, 1))
- t2 = int(round(MidiController.MIN_PLAYBACK_RATE / MidiController.PLAYBACK_RATE_STEP, 1))
+ t1 = int(round(rate / LaunchpadMiniController.PLAYBACK_RATE_STEP, 1))
+ t2 = int(round(LaunchpadMiniController.MIN_PLAYBACK_RATE / LaunchpadMiniController.PLAYBACK_RATE_STEP, 1))
lastColumnLit = t1 - t2 + 1
- self._lightRowUntilColumn(1, lastColumnLit, MidiController.LED_YELLOW)
+ self._lightRowUntilColumn(1, lastColumnLit, LaunchpadMiniController.LED_YELLOW)
def _setButtonLED(self, row, col, colour):
- self._midiWrapper.sendMessage(MidiController.BUTTON_MATRIX[row][col], colour, MidiController.LIGHT_CONTROL_CHANNEL)
+ self._midiWrapper.sendNoteOn(LaunchpadMiniController.BUTTON_MATRIX[row][col], colour, LaunchpadMiniController.LIGHT_CONTROL_CHANNEL)
def _lightRowUntilColumn(self, row, column, litColour):
- colours = [litColour] * column + [MidiController.LED_OFF] * (8 - column)
+ colours = [litColour] * column + [LaunchpadMiniController.LED_OFF] * (8 - column)
for col in range(0, 8):
self._setButtonLED(row, col, colours[col])
@@ -103,7 +130,7 @@ class MidiController:
self._setButtonLED(row, col, colour)
def _initialiseButtonLEDs(self):
- self._setAllLEDs(MidiController.LED_OFF)
+ self._setAllLEDs(LaunchpadMiniController.LED_OFF)
# volume buttons
self._updateVolumeRow(self._soloTool.volume)
@@ -112,22 +139,22 @@ class MidiController:
self._updateRateRow(self._soloTool.rate)
# playback control
- self._setButtonLED(6, 0, MidiController.LED_YELLOW)
+ self._setButtonLED(6, 0, LaunchpadMiniController.LED_YELLOW)
self._updatePlayPauseButton(self._soloTool.playing)
# Key point control
- self._setButtonLED(7, 2, MidiController.LED_YELLOW)
- self._setButtonLED(7, 6, MidiController.LED_RED)
- self._setButtonLED(7, 7, MidiController.LED_GREEN)
- self._setButtonLED(7, 5, MidiController.LED_YELLOW)
+ self._setButtonLED(7, 2, LaunchpadMiniController.LED_YELLOW)
+ self._setButtonLED(7, 6, LaunchpadMiniController.LED_RED)
+ self._setButtonLED(7, 7, LaunchpadMiniController.LED_GREEN)
+ self._setButtonLED(7, 5, LaunchpadMiniController.LED_YELLOW)
# Song control
- self._setButtonLED(3, 0, MidiController.LED_RED)
- self._setButtonLED(3, 1, MidiController.LED_RED)
- self._setButtonLED(3, 2, MidiController.LED_RED)
- self._setButtonLED(3, 3, MidiController.LED_RED)
- self._setButtonLED(3, 4, MidiController.LED_GREEN)
- self._setButtonLED(3, 5, MidiController.LED_GREEN)
- self._setButtonLED(3, 6, MidiController.LED_GREEN)
- self._setButtonLED(3, 7, MidiController.LED_GREEN)
+ self._setButtonLED(3, 0, LaunchpadMiniController.LED_RED)
+ self._setButtonLED(3, 1, LaunchpadMiniController.LED_RED)
+ self._setButtonLED(3, 2, LaunchpadMiniController.LED_RED)
+ self._setButtonLED(3, 3, LaunchpadMiniController.LED_RED)
+ self._setButtonLED(3, 4, LaunchpadMiniController.LED_GREEN)
+ self._setButtonLED(3, 5, LaunchpadMiniController.LED_GREEN)
+ self._setButtonLED(3, 6, LaunchpadMiniController.LED_GREEN)
+ self._setButtonLED(3, 7, LaunchpadMiniController.LED_GREEN)
diff --git a/solo-tool-project/src/solo_tool/midi_wrapper_mido.py b/solo-tool-project/src/solo_tool/midi_wrapper_mido.py
deleted file mode 100644
index 34f1031..0000000
--- a/solo-tool-project/src/solo_tool/midi_wrapper_mido.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import mido
-
-class MidiWrapper:
- def __init__(self):
- self._inPort = None
- self._outPort = None
-
- def connect(self, deviceName, callback):
- if self._inPort is None and self._outPort is None:
- self._inPort = mido.open_input(deviceName)
- self._inPort.callback = callback
- self._outPort = mido.open_output(deviceName)
-
- def disconnect(self):
- if self._inPort is not None:
- self._inPort.close()
- self._inPort = None
-
- if self._outPort is not None:
- self._outPort.reset()
- self._outPort.close()
- self._outPort = None
-
- 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)
-