aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--solo-tool-project/src/solo_tool/handlers.py21
-rw-r--r--solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py67
-rw-r--r--solo-tool-project/src/solo_tool/solo_tool.py29
-rw-r--r--solo-tool-project/test/midi_launchpad_mini_integrationtest.py60
-rw-r--r--solo-tool-project/test/solo_tool_controller_integrationtest.py4
-rw-r--r--solo-tool-project/test/solo_tool_integrationtest.py79
6 files changed, 131 insertions, 129 deletions
diff --git a/solo-tool-project/src/solo_tool/handlers.py b/solo-tool-project/src/solo_tool/handlers.py
new file mode 100644
index 0000000..13e982b
--- /dev/null
+++ b/solo-tool-project/src/solo_tool/handlers.py
@@ -0,0 +1,21 @@
+from collections.abc import Callable
+
+from solo_tool.solo_tool import SoloTool
+
+def changeSong(st: SoloTool, delta: int) -> Callable[[], None]:
+ def f():
+ if st.song is None:
+ st.song = 0
+ else:
+ st.song += delta
+ return f
+
+def seekRelative(st: SoloTool, delta: float) -> Callable[[], None]:
+ def f():
+ st.position += delta
+ return f
+
+def positionToKeyPoint(st: SoloTool) -> Callable[[], None]:
+ def f():
+ st.keyPoint = st.position
+ return f
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 4fde8fc..3dc8ec6 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,5 +1,5 @@
from .midi_wrapper_mido import MidiWrapper
-from .solo_tool_controller import SoloToolController
+from . import handlers
class MidiController:
DEVICE_NAME = "Launchpad Mini MIDI 1"
@@ -20,7 +20,6 @@ class MidiController:
def __init__(self, soloTool, midiWrapperOverride=None):
self._soloTool = soloTool
- self._soloToolController = SoloToolController(soloTool)
if midiWrapperOverride is not None:
self._midiWrapper = midiWrapperOverride
else:
@@ -28,31 +27,25 @@ class MidiController:
self._registerHandlers()
self._soloTool.registerPlayingStateCallback(self._updatePlayPauseButton)
- self._soloTool.registerPlaybackVolumeCallback(self._updateVolumeRow)
- self._soloTool.registerPlaybackRateCallback(self._updateRateRow)
- self._soloTool.registerAbLimitEnabledCallback(self._updateToggleAbLimitEnableButton)
-
- self._aLimit = 0.0
- self._bLimit = 0.0
+ self._soloTool.registerVolumeCallback(self._updateVolumeRow)
+ self._soloTool.registerRateCallback(self._updateRateRow)
def _registerHandlers(self):
self._handlers = {
96 : self._soloTool.stop,
- 114 : self._soloTool.jumpToA,
+ 114 : self._soloTool.jump,
112 : self._playPause,
- 98 : self._toggleAbLimitEnable,
- 118 : self._soloTool.previousStoredAbLimits,
- 119 : self._soloTool.nextStoredAbLimits,
- 116 : self._setALimit,
- 117 : self._setBLimit,
- 48 : self._soloToolController.previousSong,
- 49 : self._createSeekHandler(-0.25),
- 50 : self._createSeekHandler(-0.05),
- 51 : self._createSeekHandler(-0.01),
- 52 : self._createSeekHandler(0.01),
- 53 : self._createSeekHandler(0.05),
- 54 : self._createSeekHandler(0.25),
- 55 : self._soloToolController.nextSong,
+ #118 : self._soloTool.previousStoredAbLimits,
+ #119 : self._soloTool.nextStoredAbLimits,
+ 117 : handlers.positionToKeyPoint(self._soloTool),
+ 48 : handlers.changeSong(self._soloTool, -1),
+ 49 : handlers.seekRelative(self._soloTool, -0.25),
+ 50 : handlers.seekRelative(self._soloTool, -0.05),
+ 51 : handlers.seekRelative(self._soloTool, -0.01),
+ 52 : handlers.seekRelative(self._soloTool, 0.01),
+ 53 : handlers.seekRelative(self._soloTool, 0.05),
+ 54 : handlers.seekRelative(self._soloTool, 0.25),
+ 55 : handlers.changeSong(self._soloTool, 1),
}
for i in range(0, 8):
@@ -84,24 +77,6 @@ class MidiController:
else:
self._soloTool.play()
- def _createSeekHandler(self, delta):
- def f():
- newPosition = self._soloTool.getPlaybackPosition() + delta
- newPosition = min(1.0, max(0.0, newPosition))
- self._soloTool.setPlaybackPosition(newPosition)
- return f
-
- def _setALimit(self):
- self._aLimit = self._soloTool.getPlaybackPosition()
- self._soloTool.setAbLimits(self._aLimit, self._bLimit)
-
- def _setBLimit(self):
- self._bLimit = self._soloTool.getPlaybackPosition()
- self._soloTool.setAbLimits(self._aLimit, self._bLimit)
-
- def _toggleAbLimitEnable(self):
- self._soloTool.setAbLimitEnable(not self._soloTool.isAbLimitEnabled())
-
def _updatePlayPauseButton(self, playing):
if playing:
self._setButtonLED(7, 0, MidiController.LED_GREEN)
@@ -128,12 +103,12 @@ class MidiController:
def _createSetPlaybackRateCallback(self, rate):
def f():
- self._soloTool.setPlaybackRate(rate)
+ self._soloTool.rate = rate
return f
def _createSetPlaybackVolumeCallback(self, volume):
def f():
- self._soloTool.setPlaybackVolume(volume)
+ self._soloTool.volume = volume
return f
def _setButtonLED(self, row, col, colour):
@@ -153,23 +128,19 @@ class MidiController:
self._allLEDsOff()
# volume buttons
- self._updateVolumeRow(self._soloTool.getPlaybackVolume())
+ self._updateVolumeRow(self._soloTool.volume)
# playback rate buttons
- self._updateRateRow(self._soloTool.getPlaybackRate())
+ self._updateRateRow(self._soloTool.rate)
# playback control
self._setButtonLED(6, 0, MidiController.LED_RED)
self._updatePlayPauseButton(self._soloTool.isPlaying())
- # AB repeat toggle
- self._updateToggleAbLimitEnableButton(self._soloTool.isAbLimitEnabled())
-
# AB 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, 4, MidiController.LED_YELLOW)
self._setButtonLED(7, 5, MidiController.LED_YELLOW)
# Song control
diff --git a/solo-tool-project/src/solo_tool/solo_tool.py b/solo-tool-project/src/solo_tool/solo_tool.py
index 884721b..97c3495 100644
--- a/solo-tool-project/src/solo_tool/solo_tool.py
+++ b/solo-tool-project/src/solo_tool/solo_tool.py
@@ -40,9 +40,10 @@ class SoloTool:
@song.setter
def song(self, new: int) -> None:
- if new is None or new < 0 or new >= len(self._songs):
- raise ValueError()
- if new != self._song:
+ if new is not None \
+ and new >= 0 \
+ and new < len(self._songs) \
+ and new != self._song:
self._updateSong(new)
@property
@@ -53,9 +54,7 @@ class SoloTool:
@keyPoints.setter
def keyPoints(self, new: list[float]) -> None:
- if new is None:
- raise ValueError()
- if self._song is not None:
+ if new is not None and self._song is not None:
sanitized = sorted(list(set([p for p in new if SoloTool._keyPointValid(p)])))
self._keyPoints[self._song] = sanitized
@@ -65,9 +64,7 @@ class SoloTool:
@keyPoint.setter
def keyPoint(self, new: float) -> None:
- if not SoloTool._keyPointValid(new):
- raise ValueError()
- if self._song is not None and new != self._keyPoint:
+ if self._song is not None and SoloTool._keyPointValid(new) and new != self._keyPoint:
self._keyPoint = new
self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, new)
@@ -92,9 +89,7 @@ class SoloTool:
@rate.setter
def rate(self, new: float) -> None:
- if new is None or new <= 0.0:
- raise ValueError()
- if new != self._player.getPlaybackRate():
+ if new is not None and new >= 0.0 and new != self._player.getPlaybackRate():
self._player.setPlaybackRate(new)
self._notifier.notify(Notifier.PLAYBACK_RATE_EVENT, new)
@@ -104,9 +99,7 @@ class SoloTool:
@volume.setter
def volume(self, new: float) -> None:
- if new is None or new < 0.0:
- raise ValueError()
- if new != self._player.getPlaybackVolume():
+ if new is not None and new >= 0.0 and new != self._player.getPlaybackVolume():
self._player.setPlaybackVolume(new)
self._notifier.notify(Notifier.PLAYBACK_VOLUME_EVENT, new)
@@ -116,11 +109,9 @@ class SoloTool:
@position.setter
def position(self, new: float) -> None:
- if new is None or new < 0.0 or new >= 1.0:
- raise ValueError()
# TODO stop playback before changing position?
- if new != self._player.getPlaybackPosition():
- self._player.setPlaybackPosition(new)
+ if new is not None and new != self._player.getPlaybackPosition():
+ self._player.setPlaybackPosition(min(max(0.0, new), 1.0))
def registerPlayingStateCallback(self, callback):
self._notifier.registerCallback(Notifier.PLAYING_STATE_EVENT, callback)
diff --git a/solo-tool-project/test/midi_launchpad_mini_integrationtest.py b/solo-tool-project/test/midi_launchpad_mini_integrationtest.py
index ec41ab2..9588f9f 100644
--- a/solo-tool-project/test/midi_launchpad_mini_integrationtest.py
+++ b/solo-tool-project/test/midi_launchpad_mini_integrationtest.py
@@ -1,8 +1,6 @@
import pytest
from mido import Message
-pytestmark = pytest.mark.skip(reason="not yet implemented")
-
from solo_tool.midi_controller_launchpad_mini import MidiController
from solo_tool.solo_tool import SoloTool
from player_mock import Player as PlayerMock
@@ -125,7 +123,7 @@ def test_jumpToKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock):
soloTool.song = 0
uut.connect()
- soloTool.keyPosition = 0.5
+ soloTool.keyPoint = 0.5
assert playerMock.position == 0.0
midiWrapperMock.simulateInput(jumpToKeyPositionButton)
@@ -147,6 +145,9 @@ def test_previousAndNextSongButtons(uut, midiWrapperMock, soloTool, playerMock):
midiWrapperMock.simulateInput(nextSongButton)
assert playerMock.currentSong == songs[1]
+ midiWrapperMock.simulateInput(nextSongButton)
+ assert playerMock.currentSong == songs[1]
+
midiWrapperMock.simulateInput(previousSongButton)
assert playerMock.currentSong == songs[0]
@@ -155,27 +156,27 @@ def test_previousAndNextSongButtons(uut, midiWrapperMock, soloTool, playerMock):
def test_previousAndNextKeyPositionButtons(uut, midiWrapperMock, soloTool, playerMock):
song = "test.flac"
- keyPositions = [0.2, 0.1]
+ keyPoints = [0.2, 0.1]
soloTool.addSong(song)
soloTool.song = 0
- soloTool.keyPositions = keyPositions
+ soloTool.keyPoints = keyPoints
uut.connect()
- assert soloTool.keyPosition == 0.0
+ assert soloTool.keyPoint == 0.0
midiWrapperMock.simulateInput(nextKeyPositionButton)
- soloTool.keyPosition == 0.1
+ soloTool.keyPoint == 0.1
midiWrapperMock.simulateInput(nextKeyPositionButton)
- soloTool.keyPosition == 0.2
+ soloTool.keyPoint == 0.2
midiWrapperMock.simulateInput(previousKeyPositionButton)
- soloTool.keyPosition == 0.1
+ soloTool.keyPoint == 0.1
midiWrapperMock.simulateInput(previousKeyPositionButton)
- soloTool.keyPosition == 0.1
+ soloTool.keyPoint == 0.1
def test_playbackRateButtons(uut, midiWrapperMock, soloTool, playerMock):
playbackRateOptions = {
@@ -233,9 +234,10 @@ def test_playbackRateLeds(uut, midiWrapperMock, soloTool, playerMock):
assert playerMock.rate == 1.0
for t, (rate, leds) in enumerate(playbackRateOptions):
+ print(t)
midiWrapperMock.sentMessages.clear()
- soloTool.setPlaybackRate(rate)
+ soloTool.rate = rate
assert playerMock.rate == rate
for i, colour in enumerate(leds):
@@ -299,7 +301,7 @@ def test_playbackVolumeLeds(uut, midiWrapperMock, soloTool, playerMock):
for t, (volume, leds) in enumerate(playbackVolumeOptions):
midiWrapperMock.sentMessages.clear()
- soloTool.setPlaybackVolume(volume)
+ soloTool.volume = volume
assert playerMock.volume == volume
for i, colour in enumerate(leds):
@@ -319,22 +321,20 @@ def test_connectDisconnect(uut, midiWrapperMock):
[(i, LED_GREEN, 0) for i in range(0, 6)] + # volume row
[(i, LED_YELLOW, 0) for i in range(16, 22)] + # playback rate row
[
- (stopButton, LED_RED, 0),
- (playPauseButton, LED_YELLOW, 0),
- (abToggleButton, LED_RED, 0),
- (jumpToAButton, LED_YELLOW, 0),
- (previousLimitButton, LED_RED, 0),
- (nextLimitButton, LED_GREEN, 0),
- (setAButton, LED_YELLOW, 0),
- (setBButton, LED_YELLOW, 0),
- (previousSongButton, LED_RED, 0),
- (rwd1PcButton, LED_RED, 0),
- (rwd5PcButton, LED_RED, 0),
- (rwd25PcButton, LED_RED, 0),
- (nextSongButton, LED_GREEN, 0),
- (fwd1PcButton, LED_GREEN, 0),
- (fwd5PcButton, LED_GREEN, 0),
- (fwd25PcButton, LED_GREEN, 0),
+ (stopButton, LED_RED, 0),
+ (playPauseButton, LED_YELLOW, 0),
+ (jumpToKeyPositionButton, LED_YELLOW, 0),
+ (previousKeyPositionButton, LED_RED, 0),
+ (nextKeyPositionButton, LED_GREEN, 0),
+ (setKeyPositionButton, LED_YELLOW, 0),
+ (previousSongButton, LED_RED, 0),
+ (rwd1PcButton, LED_RED, 0),
+ (rwd5PcButton, LED_RED, 0),
+ (rwd25PcButton, LED_RED, 0),
+ (nextSongButton, LED_GREEN, 0),
+ (fwd1PcButton, LED_GREEN, 0),
+ (fwd5PcButton, LED_GREEN, 0),
+ (fwd25PcButton, LED_GREEN, 0),
])
teardownMessages = [(int(i / 8) * 16 + (i % 8), LED_OFF, 0) for i in range(0, 64)] # clear all
@@ -378,11 +378,11 @@ def test_setKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock):
playerMock.position = 0.3
midiWrapperMock.simulateInput(setKeyPositionButton)
- assert soloTool.keyPosition == 0.3
+ assert soloTool.keyPoint == 0.3
playerMock.position = 0.5
midiWrapperMock.simulateInput(setKeyPositionButton)
- assert soloTool.keyPosition == 0.5
+ assert soloTool.keyPoint == 0.5
playerMock.position = 0.7
midiWrapperMock.simulateInput(jumpToKeyPositionButton)
diff --git a/solo-tool-project/test/solo_tool_controller_integrationtest.py b/solo-tool-project/test/solo_tool_controller_integrationtest.py
index e39e5f9..8eb09f9 100644
--- a/solo-tool-project/test/solo_tool_controller_integrationtest.py
+++ b/solo-tool-project/test/solo_tool_controller_integrationtest.py
@@ -2,11 +2,11 @@ import pathlib
import shutil
import pytest
-pytestmark = pytest.mark.skip(reason="not yet implemented")
-
from solo_tool.solo_tool_controller import SoloToolController
from solo_tool.solo_tool import SoloTool
+pytestmark = pytest.mark.skip(reason="not yet implemented")
+
@pytest.fixture
def prepared_tmp_path(tmp_path):
testFiles = [
diff --git a/solo-tool-project/test/solo_tool_integrationtest.py b/solo-tool-project/test/solo_tool_integrationtest.py
index 94d5cef..2a818ed 100644
--- a/solo-tool-project/test/solo_tool_integrationtest.py
+++ b/solo-tool-project/test/solo_tool_integrationtest.py
@@ -54,35 +54,58 @@ def test_playerControls(uut, mockPlayer):
assert uut.volume == 0.5
def test_sanitizePlaybackRate(uut):
- # Valid rates are > 0.0
- with pytest.raises(ValueError):
- uut.rate = -0.1
+ # Initial value
+ assert uut.rate == 1.0
- with pytest.raises(ValueError):
- uut.rate = 0.0
+ # Valid rates are >= 0.0, invalid is ignored
+ uut.rate = -0.1
+ assert uut.rate == 1.0
+
+ uut.rate = 0.0
+ assert uut.rate == 0.0
+
+ uut.rate = 0.0001
+ assert uut.rate == 0.0001
- uut.rate = 1.0
uut.rate = 150.0
+ assert uut.rate == 150.0
def test_sanitizePlaybackPosition(uut):
- # Valid positions are in [0, 1)
- with pytest.raises(ValueError):
- uut.position = -0.1
+ # Initial value
+ assert uut.position == 0.0
+
+ # Valid positions are in [0, 1], invalid is limited
+ uut.position = 0.2
+ assert uut.position == 0.2
+
+ uut.position = -0.1
+ assert uut.position == 0.0
+
+ uut.position = 1.0
+ assert uut.position == 1.0
- uut.position = 0.0
- uut.position = 0.999
+ uut.position = 0.4
+ assert uut.position == 0.4
- with pytest.raises(ValueError):
- uut.position = 1.0
+ uut.position = 1.5
+ assert uut.position == 1.0
def test_sanitizePlaybackVolume(uut):
- # Valid volumes are >= 0.0
- with pytest.raises(ValueError):
- uut.volume = -0.1
+ # Initial value
+ assert uut.volume == 1.0
+
+ # Valid volumes are >= 0.0, invalid is ignored
+ uut.volume = -0.1
+ assert uut.volume == 1.0
uut.volume = 0.0
+ assert uut.volume == 0.0
+
uut.volume = 1.0
+ assert uut.volume == 1.0
+
uut.volume = 150.0
+ assert uut.volume == 150.0
def test_addAndSelectSongs(uut, mockPlayer):
songs = [
@@ -112,17 +135,14 @@ def test_addAndSelectSongs(uut, mockPlayer):
assert uut.song == i
# The current song cannot be de-selected
- with pytest.raises(ValueError):
- uut.song = None
+ uut.song = None
assert uut.song == len(uut.songs) - 1
# Non-existent songs cannot be selected
- with pytest.raises(ValueError):
- uut.song = -1
+ uut.song = -1
assert uut.song == len(uut.songs) - 1
- with pytest.raises(ValueError):
- uut.song = 2
+ uut.song = 2
assert uut.song == len(uut.songs) - 1
def test_addAndJumpToKeyPoints(uut, mockPlayer):
@@ -174,22 +194,21 @@ def test_sanitizeKeyPoint(uut):
# Key point and key point list cannot be none
uut.keyPoint = 0.5
- with pytest.raises(ValueError):
- uut.keyPoint = None
+ uut.keyPoint = None
assert uut.keyPoint == 0.5
- with pytest.raises(ValueError):
- uut.keyPoints = None
+ uut.keyPoints = None
assert uut.keyPoints == [0.1, 0.2, 0.4]
# Valid key points are in [0, 1)
- with pytest.raises(ValueError):
- uut.keyPoint = -0.1
+ uut.keyPoint = -0.1
+ assert uut.keyPoint == 0.5
- with pytest.raises(ValueError):
- uut.keyPoint = 1.0
+ uut.keyPoint = 1.0
+ assert uut.keyPoint == 0.5
uut.keyPoint = 0.999
+ assert uut.keyPoint == 0.999
def test_keyPointsPerSong(uut, mockPlayer):
songs = [