From 328d9ae201cabe8e4189736cd806ecea7b675200 Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Sat, 1 Jan 2022 15:49:06 +0100 Subject: Added previous/next song buttons to MIDI interface, updated known issues --- known-issues.md | 1 + midi_controller_launchpad_mini.py | 11 ++++------- midi_launchpad_mini_unittest.py | 41 +++++++++++++++++++++++++++++++++++++++ playlist.py | 14 +++++++++++++ playlist_unittest.py | 35 +++++++++++++++++++++++++++++++++ solo_tool.py | 10 ++++++++-- solo_tool_integrationtest.py | 24 +++++++++++++++++++++++ 7 files changed, 127 insertions(+), 9 deletions(-) diff --git a/known-issues.md b/known-issues.md index 81f2181..0307e4c 100644 --- a/known-issues.md +++ b/known-issues.md @@ -8,6 +8,7 @@ * automatically play next song when current song ends * playback doesn't stop when jumping to next/previous song * should this be the default anyway? +* Add buttons to write current playback position to A or B limit sliders # Closed Issues diff --git a/midi_controller_launchpad_mini.py b/midi_controller_launchpad_mini.py index 16c819c..55c0ec0 100644 --- a/midi_controller_launchpad_mini.py +++ b/midi_controller_launchpad_mini.py @@ -12,8 +12,10 @@ class MidiController: self._handlers = { 112 : self._playPause, - 96 : self._stop, - 101 : self._jumpToA + 96 : self._soloTool.stop, + 101 : self._soloTool.jumpToA, + 118 : self._soloTool.previousSong, + 119 : self._soloTool.nextSong } def connect(self): @@ -33,8 +35,3 @@ class MidiController: else: self._soloTool.play() - def _stop(self): - self._soloTool.stop() - - def _jumpToA(self): - self._soloTool.jumpToA() diff --git a/midi_launchpad_mini_unittest.py b/midi_launchpad_mini_unittest.py index 09f12df..55ca6c8 100644 --- a/midi_launchpad_mini_unittest.py +++ b/midi_launchpad_mini_unittest.py @@ -30,6 +30,8 @@ class SoloToolMock: self.state = SoloToolMock.STOPPED self.position = 0.0 self.currentAbLimit = (0.0, 0.0) + self.currentLoadedAbLimitIndex = None + self.currentSong = None def play(self): self.state = SoloToolMock.PLAYING @@ -46,6 +48,24 @@ class SoloToolMock: def jumpToA(self): self.position = self.currentAbLimit[0] + def loadAbLimits(self, index): + self.currentLoadedAbLimitIndex = index + + def setSong(self, index): + self.currentSong = index + + def nextSong(self): + if self.currentSong is None: + self.currentSong = 0 + else: + self.currentSong += 1 + + def previousSong(self): + if self.currentSong is None: + self.currentSong = 0 + else: + self.currentSong = max(self.currentSong - 1, 0) + def test_connect(): expectedDevice = "Launchpad Mini MIDI 1" @@ -97,6 +117,26 @@ def test_jumpToAButton(): midiWrapperMock.simulateInput(101) assert soloToolMock.position == ab[0] +def test_previousAndNextSongButtons(): + soloToolMock = SoloToolMock() + midiWrapperMock = MidiWrapperMock() + uut = MidiController(soloToolMock, midiWrapperMock) + uut.connect() + + assert soloToolMock.currentSong == None + midiWrapperMock.simulateInput(119) + assert soloToolMock.currentSong == 0 + + midiWrapperMock.simulateInput(119) + assert soloToolMock.currentSong == 1 + + midiWrapperMock.simulateInput(118) + assert soloToolMock.currentSong == 0 + + midiWrapperMock.simulateInput(118) + assert soloToolMock.currentSong == 0 + +""" def test_unprogrammedButton(): unusedButton = 48 midiWrapperMock = MidiWrapperMock() @@ -105,3 +145,4 @@ def test_unprogrammedButton(): # expect no crash midiWrapperMock.simulateInput(48) +""" diff --git a/playlist.py b/playlist.py index d25395b..2880733 100644 --- a/playlist.py +++ b/playlist.py @@ -22,3 +22,17 @@ class Playlist: def clear(self): self.__init__(self._setSongCallback) + + def nextSong(self): + if self._currentSong is None: + nextSong = 0 + else: + nextSong = self._currentSong + 1 + self.setCurrentSong(nextSong) + + def previousSong(self): + if self._currentSong is None: + prevSong = 0 + else: + prevSong = self._currentSong - 1 + self.setCurrentSong(prevSong) diff --git a/playlist_unittest.py b/playlist_unittest.py index 9dd3700..24d3a59 100644 --- a/playlist_unittest.py +++ b/playlist_unittest.py @@ -93,3 +93,38 @@ def test_clearPlaylist(): assert uut.getSongs() == [] assert uut.getCurrentSong() == None +def test_nextSong(): + songAddedByUser = ["/path/to/song", "/path/to/second/song"] + + uut = Playlist(lambda index: None) + for s in songAddedByUser: + uut.addSong(s) + assert uut.getCurrentSong() == None + + uut.nextSong() + assert uut.getCurrentSong() == songAddedByUser[0] + + uut.nextSong() + assert uut.getCurrentSong() == songAddedByUser[1] + + uut.nextSong() + assert uut.getCurrentSong() == songAddedByUser[1] + +def test_previousSong(): + songAddedByUser = ["/path/to/song", "/path/to/second/song"] + + uut = Playlist(lambda index: None) + for s in songAddedByUser: + uut.addSong(s) + assert uut.getCurrentSong() == None + + uut.previousSong() + assert uut.getCurrentSong() == songAddedByUser[0] + + uut.previousSong() + assert uut.getCurrentSong() == songAddedByUser[0] + + uut.setCurrentSong(1) + assert uut.getCurrentSong() == songAddedByUser[1] + uut.previousSong() + assert uut.getCurrentSong() == songAddedByUser[0] diff --git a/solo_tool.py b/solo_tool.py index c32d3e8..d2147bf 100644 --- a/solo_tool.py +++ b/solo_tool.py @@ -6,8 +6,8 @@ from session_manager import SessionManager from player_vlc import Player class SoloTool: - def __init__(self, player=None): - self._player = Player() if player is None else player + def __init__(self, playerOverride=None): + self._player = Player() if playerOverride is None else playerOverride self._playlist = Playlist(self._playlistCallback) self._abController = ABController(enabled=False, callback=self._abControllerCallback) self._sessionManager = SessionManager(self._playlist, self._abController) @@ -30,6 +30,12 @@ class SoloTool: def setSong(self, index): self._playlist.setCurrentSong(index) + def nextSong(self): + self._playlist.nextSong() + + def previousSong(self): + self._playlist.previousSong() + def getSongs(self): return self._playlist.getSongs() diff --git a/solo_tool_integrationtest.py b/solo_tool_integrationtest.py index af0a921..2fa923a 100644 --- a/solo_tool_integrationtest.py +++ b/solo_tool_integrationtest.py @@ -47,6 +47,30 @@ def test_addAndSetSongs(): uut.setSong(i) assert mockPlayer.currentSong == songs[i] +def test_nextAndPreviousSong(): + songs = [ + "test.flac", + "test.mp3" + ] + mockPlayer = MockPlayer() + uut = SoloTool(mockPlayer) + + for s in songs: + uut.addSong(s) + assert mockPlayer.currentSong == None + + uut.nextSong() + assert mockPlayer.currentSong == songs[0] + + uut.previousSong() + assert mockPlayer.currentSong == songs[0] + + uut.nextSong() + assert mockPlayer.currentSong == songs[1] + + uut.nextSong() + assert mockPlayer.currentSong == songs[1] + def test_addAndSetAbLimits(): song = "test.flac" abLimits = [ -- cgit v1.2.3