aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/diagram.drawio4
-rw-r--r--solo-tool-project/src/solo_tool/handlers.py5
-rw-r--r--solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py4
-rw-r--r--solo-tool-project/src/solo_tool/player_vlc.py4
-rw-r--r--solo-tool-project/src/solo_tool/solo_tool.py4
-rw-r--r--solo-tool-project/test/midi_launchpad_mini_integrationtest.py56
-rw-r--r--solo-tool-project/test/notifier_unittest.py2
-rw-r--r--solo-tool-project/test/player_mock.py27
-rw-r--r--solo-tool-project/test/solo_tool_integrationtest.py30
-rw-r--r--web-project/src/solo_tool_web.py2
10 files changed, 42 insertions, 96 deletions
diff --git a/doc/diagram.drawio b/doc/diagram.drawio
index 424570a..3c37bc7 100644
--- a/doc/diagram.drawio
+++ b/doc/diagram.drawio
@@ -1,4 +1,4 @@
-<mxfile host="Electron" modified="2025-02-24T11:00:29.036Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="9_vGhwK_Mq_I_v5YUap0" version="22.1.2" type="device" pages="2">
+<mxfile host="Electron" modified="2025-02-25T14:57:34.998Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="YTK2v8-32YjVXFJp_mJd" version="22.1.2" type="device" pages="2">
<diagram id="PyNSc7ezSt42GBdjTBvd" name="Launchpad">
<mxGraphModel dx="1562" dy="963" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
<root>
@@ -22,7 +22,7 @@
<mxCell id="ZtjfeE3uwfRsFhnWfLYL-44" value="80" style="rounded=1;whiteSpace=wrap;html=1;container=0;" parent="ZtjfeE3uwfRsFhnWfLYL-1" vertex="1">
<mxGeometry x="40" y="476" width="80" height="80" as="geometry" />
</mxCell>
- <mxCell id="ZtjfeE3uwfRsFhnWfLYL-45" value="96&lt;br&gt;stop" style="rounded=1;whiteSpace=wrap;html=1;container=0;fillColor=#f8cecc;strokeColor=#b85450;" parent="ZtjfeE3uwfRsFhnWfLYL-1" vertex="1">
+ <mxCell id="ZtjfeE3uwfRsFhnWfLYL-45" value="96&lt;br&gt;jump to start" style="rounded=1;whiteSpace=wrap;html=1;container=0;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="ZtjfeE3uwfRsFhnWfLYL-1" vertex="1">
<mxGeometry x="40" y="564" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="ZtjfeE3uwfRsFhnWfLYL-46" value="112&lt;br&gt;play/&lt;br&gt;pause" style="rounded=1;whiteSpace=wrap;html=1;container=0;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="ZtjfeE3uwfRsFhnWfLYL-1" vertex="1">
diff --git a/solo-tool-project/src/solo_tool/handlers.py b/solo-tool-project/src/solo_tool/handlers.py
index 975ce8d..ab7309e 100644
--- a/solo-tool-project/src/solo_tool/handlers.py
+++ b/solo-tool-project/src/solo_tool/handlers.py
@@ -30,6 +30,11 @@ def seekRelative(st: SoloTool, delta: float) -> Callable[[], None]:
st.position += delta
return f
+def seekAbsolute(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
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 38b7cce..08d55cd 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
@@ -32,7 +32,7 @@ class MidiController:
def _registerHandlers(self):
self._handlers = {
- 96 : self._soloTool.stop,
+ 96 : handlers.seekAbsolute(self._soloTool, 0.0),
114 : self._soloTool.jump,
112 : handlers.playPause(self._soloTool),
118 : handlers.changeKeyPoint(self._soloTool, -1),
@@ -112,7 +112,7 @@ class MidiController:
self._updateRateRow(self._soloTool.rate)
# playback control
- self._setButtonLED(6, 0, MidiController.LED_RED)
+ self._setButtonLED(6, 0, MidiController.LED_YELLOW)
self._updatePlayPauseButton(self._soloTool.playing)
# Key point control
diff --git a/solo-tool-project/src/solo_tool/player_vlc.py b/solo-tool-project/src/solo_tool/player_vlc.py
index 283102e..dade61f 100644
--- a/solo-tool-project/src/solo_tool/player_vlc.py
+++ b/solo-tool-project/src/solo_tool/player_vlc.py
@@ -7,9 +7,6 @@ class Player:
def play(self):
self._player.play()
- def stop(self):
- self._player.stop()
-
def pause(self):
self._player.pause()
@@ -36,7 +33,6 @@ class Player:
return self._player.audio_get_volume() / 100.0
def setCurrentSong(self, path):
- self._player.stop()
media = vlc.Media(path)
self._player.set_media(media)
diff --git a/solo-tool-project/src/solo_tool/solo_tool.py b/solo-tool-project/src/solo_tool/solo_tool.py
index 0489517..ec4caa1 100644
--- a/solo-tool-project/src/solo_tool/solo_tool.py
+++ b/solo-tool-project/src/solo_tool/solo_tool.py
@@ -15,6 +15,7 @@ class SoloTool:
def _updateSong(self, index):
previousSong = self._song
self._song = index
+ self._player.pause()
self._player.setCurrentSong(self._songs[index])
self._notifier.notify(Notifier.CURRENT_SONG_EVENT, index)
@@ -86,9 +87,6 @@ class SoloTool:
def pause(self):
self._player.pause()
- def stop(self):
- self._player.stop()
-
@property
def playing(self) -> bool:
return self._player.isPlaying()
diff --git a/solo-tool-project/test/midi_launchpad_mini_integrationtest.py b/solo-tool-project/test/midi_launchpad_mini_integrationtest.py
index 642733d..c731539 100644
--- a/solo-tool-project/test/midi_launchpad_mini_integrationtest.py
+++ b/solo-tool-project/test/midi_launchpad_mini_integrationtest.py
@@ -20,7 +20,7 @@ rwd25PcButton = 49
previousSongButton = 48
playPauseButton = 112
-stopButton = 96
+jumpToStartButton = 96
nextKeyPositionButton = 119
previousKeyPositionButton = 118
@@ -67,60 +67,34 @@ def midiWrapperMock():
def uut(soloTool, midiWrapperMock):
return MidiController(soloTool, midiWrapperMock)
-def test_startStopAndPauseButtons(uut, midiWrapperMock, playerMock):
+def test_startAndPauseButtons(uut, midiWrapperMock, playerMock):
uut.connect()
- assert playerMock.state == PlayerMock.STOPPED
+ assert not playerMock.playing
midiWrapperMock.simulateInput(playPauseButton)
- assert playerMock.state == PlayerMock.PLAYING
+ assert playerMock.playing
assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_GREEN, 0)
- midiWrapperMock.simulateInput(stopButton)
- assert playerMock.state == PlayerMock.STOPPED
- assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_YELLOW, 0)
-
- midiWrapperMock.simulateInput(playPauseButton)
- assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_GREEN, 0)
-
midiWrapperMock.simulateInput(playPauseButton)
+ assert not playerMock.playing
assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_YELLOW, 0)
- assert playerMock.state == PlayerMock.PAUSED
-
- midiWrapperMock.simulateInput(playPauseButton)
- assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_GREEN, 0)
- assert playerMock.state == PlayerMock.PLAYING
-
- midiWrapperMock.simulateInput(playPauseButton)
- assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_YELLOW, 0)
-
- midiWrapperMock.simulateInput(stopButton)
- assert playerMock.state == PlayerMock.STOPPED
def test_startPauseButtonLed(uut, midiWrapperMock, playerMock, soloTool):
uut.connect()
- assert playerMock.state == PlayerMock.STOPPED
+ assert not playerMock.playing
- playerMock.state = PlayerMock.PLAYING
+ playerMock.playing = True
playerMock.simulatePlayingStateChanged()
assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_GREEN, 0)
- playerMock.state = PlayerMock.STOPPED
- playerMock.simulatePlayingStateChanged()
- assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_YELLOW, 0)
-
- playerMock.state = PlayerMock.PAUSED
+ playerMock.playing = False
playerMock.simulatePlayingStateChanged()
assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_YELLOW, 0)
- playerMock.state = PlayerMock.PLAYING
- playerMock.simulatePlayingStateChanged()
- assert midiWrapperMock.getLatestMessage() == (playPauseButton, MidiController.LED_GREEN, 0)
-
def test_jumpToKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock):
soloTool.addSong("test.flac")
- soloTool.song = 0
uut.connect()
soloTool.keyPoint = 0.5
@@ -129,6 +103,10 @@ def test_jumpToKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock):
midiWrapperMock.simulateInput(jumpToKeyPositionButton)
assert playerMock.position == 0.5
+# TODO implement
+def test_jumpToStartButton(uut, midiWrapperMock, soloTool, playerMock):
+ pass
+
def test_previousAndNextSongButtons(uut, midiWrapperMock, soloTool, playerMock):
songs = [
"test.flac",
@@ -156,7 +134,6 @@ def test_previousAndNextKeyPositionButtons(uut, midiWrapperMock, soloTool, playe
keyPoints = [0.2, 0.1]
soloTool.addSong(song)
- soloTool.song = 0
soloTool.keyPoints = keyPoints
uut.connect()
@@ -318,7 +295,7 @@ 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),
+ (jumpToStartButton, LED_YELLOW, 0),
(playPauseButton, LED_YELLOW, 0),
(jumpToKeyPositionButton, LED_YELLOW, 0),
(previousKeyPositionButton, LED_RED, 0),
@@ -357,19 +334,17 @@ def test_playingFeedbackWhenChangingSong(uut, midiWrapperMock, soloTool, playerM
soloTool.addSong(s)
uut.connect()
- soloTool.song = 0
soloTool.play()
- assert playerMock.state == PlayerMock.PLAYING
+ assert playerMock.playing
assert midiWrapperMock.getLatestMessage() == (playPauseButton, LED_GREEN, 0)
soloTool.song = 1
- assert playerMock.state == PlayerMock.STOPPED
+ assert not playerMock.playing
assert midiWrapperMock.getLatestMessage() == (playPauseButton, LED_YELLOW, 0)
def test_setKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock):
song = "test.flac"
soloTool.addSong(song)
- soloTool.song = 0
uut.connect()
@@ -388,7 +363,6 @@ def test_setKeyPositionButton(uut, midiWrapperMock, soloTool, playerMock):
def test_seekButtons(uut, midiWrapperMock, soloTool, playerMock):
song = "test.flac"
soloTool.addSong(song)
- soloTool.song = 0
uut.connect()
diff --git a/solo-tool-project/test/notifier_unittest.py b/solo-tool-project/test/notifier_unittest.py
index 4ab6096..5749149 100644
--- a/solo-tool-project/test/notifier_unittest.py
+++ b/solo-tool-project/test/notifier_unittest.py
@@ -60,7 +60,7 @@ def test_eventsWithMockPlayer(uut, mockPlayer):
assert called
assert receivedValue == expectedValue
- mockPlayer.state = 1
+ mockPlayer.playing = True
mockPlayer.volume = 75
checkEvent(Notifier.PLAYING_STATE_EVENT, mockPlayer.simulatePlayingStateChanged, True)
diff --git a/solo-tool-project/test/player_mock.py b/solo-tool-project/test/player_mock.py
index 3162e0f..e9e9ead 100644
--- a/solo-tool-project/test/player_mock.py
+++ b/solo-tool-project/test/player_mock.py
@@ -1,10 +1,6 @@
class Player():
- STOPPED = 0
- PLAYING = 1
- PAUSED = 2
-
def __init__(self):
- self.state = Player.STOPPED
+ self.playing = False
self.rate = 1.0
self.position = 0.0
self.volume = 1.0
@@ -13,25 +9,19 @@ class Player():
self.playbackVolumeChangedCallback = None
def play(self):
- previousState = self.state
- self.state = Player.PLAYING
- if previousState != Player.PLAYING:
- self.playingStateChangedCallback()
-
- def stop(self):
- previousState = self.state
- self.state = Player.STOPPED
- if previousState != Player.STOPPED:
+ previousState = self.playing
+ self.playing = True
+ if previousState != self.playing:
self.playingStateChangedCallback()
def pause(self):
- previousState = self.state
- self.state = Player.PAUSED
- if previousState != Player.PAUSED:
+ previousState = self.playing
+ self.playing = False
+ if previousState != self.playing:
self.playingStateChangedCallback()
def isPlaying(self):
- return self.state == Player.PLAYING
+ return self.playing
def setPlaybackRate(self, rate):
self.rate = rate
@@ -55,7 +45,6 @@ class Player():
return self.volume
def setCurrentSong(self, path):
- self.stop()
self.currentSong = path
def setPlayingStateChangedCallback(self, callback):
diff --git a/solo-tool-project/test/solo_tool_integrationtest.py b/solo-tool-project/test/solo_tool_integrationtest.py
index fb759b0..f8ed2f1 100644
--- a/solo-tool-project/test/solo_tool_integrationtest.py
+++ b/solo-tool-project/test/solo_tool_integrationtest.py
@@ -26,17 +26,14 @@ def prepared_tmp_path(tmp_path):
return tmp_path
def test_playerControls(uut, mockPlayer):
- assert mockPlayer.state == MockPlayer.STOPPED
- assert uut.playing == False
+ assert not mockPlayer.playing
+ assert not uut.playing
uut.play()
- assert mockPlayer.state == MockPlayer.PLAYING
- assert uut.playing == True
+ assert mockPlayer.playing
+ assert uut.playing
uut.pause()
- assert mockPlayer.state == MockPlayer.PAUSED
- assert uut.playing == False
- uut.stop()
- assert mockPlayer.state == MockPlayer.STOPPED
- assert uut.playing == False
+ assert not mockPlayer.playing
+ assert not uut.playing
assert mockPlayer.rate == 1.0
uut.rate = 0.5
@@ -110,7 +107,6 @@ def test_sanitizePlaybackVolume(uut):
def test_playingStateNotification(uut, mockPlayer):
song = "test.flac"
uut.addSong(song)
- uut.song = 0
called = False
receivedValue = None
@@ -121,7 +117,7 @@ def test_playingStateNotification(uut, mockPlayer):
uut.registerPlayingStateCallback(callback)
- assert mockPlayer.state == MockPlayer.STOPPED
+ assert not mockPlayer.playing
assert not called
uut.play()
@@ -138,18 +134,6 @@ def test_playingStateNotification(uut, mockPlayer):
uut.pause()
assert not called
- uut.play()
- assert called
- assert receivedValue == True
- called = False
-
- uut.stop()
- assert called
- assert receivedValue == False
- called = False
- uut.stop()
- assert not called
-
def test_playbackVolumeNotification(uut, mockPlayer):
song = "test.flac"
uut.addSong(song)
diff --git a/web-project/src/solo_tool_web.py b/web-project/src/solo_tool_web.py
index d0e8bf8..1c039ab 100644
--- a/web-project/src/solo_tool_web.py
+++ b/web-project/src/solo_tool_web.py
@@ -56,7 +56,7 @@ def main():
# Play control
with ui.button_group().classes('w-full').style('height: 90px'):
ui.button(icon='skip_previous', on_click=handlers.changeSong(st, -1)).style('flex: 1')
- ui.button(icon='stop', on_click=st.stop, color='negative').style('flex: 1')
+ ui.button(icon='start', on_click=handlers.seekAbsolute(st, 0.0), color='negative').style('flex: 1')
ui.button(color='positive', on_click=handlers.playPause(st)).bind_icon_from(st, "playing", lambda playing: "pause" if playing else "play_arrow").style('flex: 2')
ui.button(icon='undo', on_click=st.jump, color='secondary').style('flex: 2')
ui.button(icon='skip_next', on_click=handlers.changeSong(st, 1)).style('flex: 1')