diff options
Diffstat (limited to 'solo-tool-project/src')
-rw-r--r-- | solo-tool-project/src/solo_tool/abcontroller.py | 82 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/handlers.py | 84 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/midi_controller_launchpad_mini.py | 107 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/notifier.py | 5 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/player_mpv.py | 53 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/player_vlc.py | 55 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/session_manager.py | 35 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/solo_tool.py | 210 | ||||
-rw-r--r-- | solo-tool-project/src/solo_tool/solo_tool_controller.py | 22 |
9 files changed, 290 insertions, 363 deletions
diff --git a/solo-tool-project/src/solo_tool/abcontroller.py b/solo-tool-project/src/solo_tool/abcontroller.py deleted file mode 100644 index cec9fb2..0000000 --- a/solo-tool-project/src/solo_tool/abcontroller.py +++ /dev/null @@ -1,82 +0,0 @@ -from collections import namedtuple - -_AB = namedtuple("_AB", ["a", "b"]) - -class ABController: - def __init__(self, enabled=True, callback=None): - self._setPositionCallback = callback - self._limits = {} # dictionary of all songs - self._songLimits = None # list of limits for selected song - self._currentLimits = _AB(0.0, 0.0) # a/b positions of active limit - self._loadedIndex = None - self._enabled = enabled - - def _ensureSongExists(self, path): - if path not in self._limits: - self._limits[path] = [] - - def setCurrentSong(self, path): - self._ensureSongExists(path) - self._songLimits = self._limits[path] - self._loadedIndex = None - - def storeLimits(self, aLimit, bLimit, song=None): - if song is not None: - self._ensureSongExists(song) - songLimits = self._limits[song] - else: - songLimits = self._songLimits - - if songLimits is None: - return - - ab = _AB(aLimit, bLimit) - songLimits.append(ab) - - def loadLimits(self, index): - if not self._songLimits: - return - - if index >= 0 and index < len(self._songLimits): - self._currentLimits = self._songLimits[index] - self._loadedIndex = index - - def nextStoredAbLimits(self): - if self._loadedIndex is None: - nextIndex = 0 - else: - nextIndex = self._loadedIndex + 1 - self.loadLimits(nextIndex) - - def previousStoredAbLimits(self): - if self._loadedIndex is None: - previousIndex = 0 - else: - previousIndex = self._loadedIndex - 1 - self.loadLimits(previousIndex) - - def setLimits(self, aLimit, bLimit): - self._currentLimits = _AB(aLimit, bLimit) - self._loadedIndex = None - - def positionChanged(self, position): - if position > self._currentLimits.b and self._setPositionCallback and self._enabled: - self._setPositionCallback(self._currentLimits.a) - - def setEnable(self, enable): - self._enabled = enable - - def isEnabled(self): - return self._enabled - - def getStoredLimits(self, song): - return self._limits.get(song) - - def getCurrentLimits(self): - return self._currentLimits - - def getLoadedIndex(self): - return self._loadedIndex - - def clear(self): - self.__init__(enabled=self._enabled, callback=self._setPositionCallback) 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..1820e86 --- /dev/null +++ b/solo-tool-project/src/solo_tool/handlers.py @@ -0,0 +1,84 @@ +from collections.abc import Callable + +from solo_tool.solo_tool import SoloTool + +def playPause(st: SoloTool) -> Callable[[], None]: + def f(): + if st.playing: + st.pause() + else: + st.play() + return f + +def songRelative(st: SoloTool, delta: int) -> Callable[[], None]: + def f(): + if st.song is None: + st.song = 0 + else: + st.song += delta + return f + +def restartOrPreviousSong(st: SoloTool, threshold: float) -> Callable[[], None]: + def f(): + if st.position < threshold and st.song > 0: + st.song -= 1 + else: + st.position = 0.0 + return f + +def songAbsolute(st: SoloTool, index: int, followUp: Callable[[], None]=None) -> Callable[[], None]: + def f(): + st.song = index + if followUp is not None: + followUp() + return f + +def seekRelative(st: SoloTool, delta: float) -> Callable[[], None]: + def f(): + 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 + return f + +def keyPointAbsolute(st: SoloTool, kp: float) -> Callable[[], None]: + def f(): + st.keyPoint = kp + return f + +def keyPointRelative(st: SoloTool, delta: int) -> Callable[[], None]: + from bisect import bisect_right, bisect_left + def f(): + l = sorted(set(st.keyPoints + [st.keyPoint])) + if delta > 0: + pivot = bisect_right(l, st.keyPoint) - 1 + elif delta < 0: + pivot = bisect_left(l, st.keyPoint) + else: + return + new = max(min(pivot + delta, len(l) - 1), 0) + st.keyPoint = l[new] + return f + +def rateAbsolute(st: SoloTool, value: float) -> Callable[[], None]: + def f(): + st.rate = value + return f + +def rateRelative(st: SoloTool, delta: float) -> Callable[[], None]: + def f(): + st.rate += delta + return f + +def volumeAbsolute(st: SoloTool, value: float) -> Callable[[], None]: + def f(): + st.volume = value + 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..625e2ef 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,47 +27,41 @@ 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, - 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, + 96 : handlers.seekAbsolute(self._soloTool, 0.0), + 114 : self._soloTool.jump, + 112 : handlers.playPause(self._soloTool), + 118 : handlers.keyPointRelative(self._soloTool, -1), + 119 : handlers.keyPointRelative(self._soloTool, 1), + 117 : handlers.positionToKeyPoint(self._soloTool), + 48 : handlers.songRelative(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.songRelative(self._soloTool, 1), } for i in range(0, 8): volume = round(MidiController.MIN_PLAYBACK_VOLUME + MidiController.PLAYBACK_VOLUME_STEP * i, 1) - self._handlers[i] = self._createSetPlaybackVolumeCallback(volume) + 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) - self._handlers[button] = self._createSetPlaybackRateCallback(rate) + self._handlers[button] = handlers.rateAbsolute(self._soloTool, rate) def connect(self): self._midiWrapper.connect(MidiController.DEVICE_NAME, self._callback) self._initialiseButtonLEDs() def disconnect(self): - self._allLEDsOff() + self._setAllLEDs(MidiController.LED_OFF) self._midiWrapper.disconnect() def _callback(self, msg): @@ -78,42 +71,12 @@ class MidiController: if msg.note in self._handlers: handler = self._handlers[msg.note]() - def _playPause(self): - if self._soloTool.isPlaying(): - self._soloTool.pause() - 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) else: self._setButtonLED(7, 0, MidiController.LED_YELLOW) - def _updateToggleAbLimitEnableButton(self, enabled): - if enabled: - self._setButtonLED(6, 2, MidiController.LED_GREEN) - else: - self._setButtonLED(6, 2, MidiController.LED_RED) - 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)) @@ -126,16 +89,6 @@ class MidiController: lastColumnLit = t1 - t2 + 1 self._lightRowUntilColumn(1, lastColumnLit, MidiController.LED_YELLOW) - def _createSetPlaybackRateCallback(self, rate): - def f(): - self._soloTool.setPlaybackRate(rate) - return f - - def _createSetPlaybackVolumeCallback(self, volume): - 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) @@ -144,32 +97,28 @@ class MidiController: for col in range(0, 8): self._setButtonLED(row, col, colours[col]) - def _allLEDsOff(self): + def _setAllLEDs(self, colour): for row in range(0, 8): for col in range(0, 8): - self._setButtonLED(row, col, MidiController.LED_OFF) + self._setButtonLED(row, col, colour) def _initialiseButtonLEDs(self): - self._allLEDsOff() + self._setAllLEDs(MidiController.LED_OFF) # 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()) + self._setButtonLED(6, 0, MidiController.LED_YELLOW) + self._updatePlayPauseButton(self._soloTool.playing) - # AB control + # 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, 4, MidiController.LED_YELLOW) self._setButtonLED(7, 5, MidiController.LED_YELLOW) # Song control diff --git a/solo-tool-project/src/solo_tool/notifier.py b/solo-tool-project/src/solo_tool/notifier.py index 9f445b6..5b3539c 100644 --- a/solo-tool-project/src/solo_tool/notifier.py +++ b/solo-tool-project/src/solo_tool/notifier.py @@ -3,8 +3,9 @@ class Notifier: PLAYBACK_VOLUME_EVENT = 1 PLAYBACK_RATE_EVENT = 2 CURRENT_SONG_EVENT = 3 - CURRENT_AB_EVENT = 4 - AB_LIMIT_ENABLED_EVENT = 5 + SONG_LIST_EVENT = 4 + CURRENT_KEY_POINT_EVENT = 5 + KEY_POINT_LIST_EVENT = 6 def __init__(self, player): self._callbacks = dict() diff --git a/solo-tool-project/src/solo_tool/player_mpv.py b/solo-tool-project/src/solo_tool/player_mpv.py new file mode 100644 index 0000000..ff7fd1a --- /dev/null +++ b/solo-tool-project/src/solo_tool/player_mpv.py @@ -0,0 +1,53 @@ +import mpv + +class Player: + def __init__(self): + self._player = mpv.MPV() + self._player.loop = "inf" + self._playingStateCallback = self._dummyCallback + self._volumeCallback = self._dummyCallback + self._player.observe_property("pause", lambda name, value: self._playingStateCallback()) + self._player.observe_property("volume", lambda name, value: self._volumeCallback()) + + def __del__(self): + self._player.close() + + def _dummyCallback(self): + pass + + def play(self): + self._player.pause = False + + def pause(self): + self._player.pause = True + + def isPlaying(self): + return not self._player.pause + + def setPlaybackRate(self, rate): + self._player.speed = rate + + def getPlaybackRate(self): + return self._player.speed + + def setPlaybackPosition(self, position): + self._player.percent_pos = int(position * 100) + + def getPlaybackPosition(self): + return float(self._player.percent_pos or 0.0) / 100.0 + + def setPlaybackVolume(self, volume): + self._player.volume = int(volume * 100) + + def getPlaybackVolume(self): + return float(self._player.volume) / 100.0 + + def setCurrentSong(self, path): + self.pause() + self._player.play(str(path)) + + def setPlayingStateChangedCallback(self, callback): + self._playingStateCallback = callback + + def setPlaybackVolumeChangedCallback(self, callback): + self._volumeCallback = callback diff --git a/solo-tool-project/src/solo_tool/player_vlc.py b/solo-tool-project/src/solo_tool/player_vlc.py deleted file mode 100644 index 283102e..0000000 --- a/solo-tool-project/src/solo_tool/player_vlc.py +++ /dev/null @@ -1,55 +0,0 @@ -import vlc - -class Player: - def __init__(self): - self._player = vlc.MediaPlayer() - - def play(self): - self._player.play() - - def stop(self): - self._player.stop() - - def pause(self): - self._player.pause() - - def isPlaying(self): - playing = self._player.is_playing() == 1 - return playing - - def setPlaybackRate(self, rate): - self._player.set_rate(rate) - - def getPlaybackRate(self): - return self._player.get_rate() - - def setPlaybackPosition(self, position): - self._player.set_position(position) - - def getPlaybackPosition(self): - return self._player.get_position() - - def setPlaybackVolume(self, volume): - self._player.audio_set_volume(int(volume * 100)) - - def getPlaybackVolume(self): - return self._player.audio_get_volume() / 100.0 - - def setCurrentSong(self, path): - self._player.stop() - media = vlc.Media(path) - self._player.set_media(media) - - def setPlayingStateChangedCallback(self, callback): - events = [ - vlc.EventType.MediaPlayerStopped, - vlc.EventType.MediaPlayerPlaying, - vlc.EventType.MediaPlayerPaused - ] - manager = self._player.event_manager() - for e in events: - manager.event_attach(e, callback) - - def setPlaybackVolumeChangedCallback(self, callback): - manager = self._player.event_manager() - manager.event_attach(vlc.EventType.MediaPlayerAudioVolume, callback) diff --git a/solo-tool-project/src/solo_tool/session_manager.py b/solo-tool-project/src/solo_tool/session_manager.py index a4dabc0..cd5ebf7 100644 --- a/solo-tool-project/src/solo_tool/session_manager.py +++ b/solo-tool-project/src/solo_tool/session_manager.py @@ -1,29 +1,30 @@ import json +from . import SoloTool -def loadSession(file, songList, abController): - jsonStr = file.read() - session = json.loads(jsonStr) +def loadSession(file: str, songPool: str, player=None) -> SoloTool: + with open(file, "r") as f: + session = json.load(f) - songList.clear() - abController.clear() + st = SoloTool(songPool, player=player) - for entry in session: + for i, entry in enumerate(session): songPath = entry["path"] - abLimits = entry["ab_limits"] - songList.append(songPath) + keyPoints = entry["key_points"] - if abLimits is not None: - for l in abLimits: - abController.storeLimits(l[0], l[1], songPath) + st.addSong(songPath) + st._keyPoints[i] = keyPoints + + return st -def saveSession(file, songList, abController): - session = list() +def saveSession(soloTool: SoloTool, file: str) -> None: + session = [] - for s in songList: + for i, song in enumerate(soloTool.songs): entry = { - "path": s, - "ab_limits" : abController.getStoredLimits(s) + "path": song, + "key_points" : soloTool._keyPoints[i] } session.append(entry) - file.write(json.dumps(session)) + with open(file, "w") as f: + json.dump(session, f) diff --git a/solo-tool-project/src/solo_tool/solo_tool.py b/solo-tool-project/src/solo_tool/solo_tool.py index a4c7af8..92b5595 100644 --- a/solo-tool-project/src/solo_tool/solo_tool.py +++ b/solo-tool-project/src/solo_tool/solo_tool.py @@ -1,39 +1,56 @@ import os +from pathlib import Path -from .abcontroller import ABController -from .session_manager import loadSession, saveSession from .notifier import Notifier -from .player_vlc import Player +from .player_mpv import Player class SoloTool: - def __init__(self, playerOverride=None): - self._player = Player() if playerOverride is None else playerOverride - self._abController = ABController(enabled=False, callback=self._abControllerCallback) + def __init__(self, songPool: str, player=None): + self._songPool = Path(songPool) + self._player = Player() if player is None else player self._notifier = Notifier(self._player) - self._songList = [] + self._songs = [] self._song = None + self._keyPoints = [] + self._keyPoint = None + + def __del__(self): + del self._player def _updateSong(self, index): + previousSong = self._song self._song = index - path = self._songList[index] - self._player.setCurrentSong(path) - self._abController.setCurrentSong(path) + self._player.pause() + self._player.setCurrentSong(self._songPool / self._songs[index]) self._notifier.notify(Notifier.CURRENT_SONG_EVENT, index) - def _abControllerCallback(self, position): - self._player.setPlaybackPosition(position) + previousKp = self._keyPoint + self._keyPoint = self.keyPoints[0] if len(self.keyPoints) > 0 else 0.0 + if previousKp != self._keyPoint: + self._notifier.notify(Notifier.CURRENT_KEY_POINT_EVENT, self._keyPoint) - def tick(self): - position = self._player.getPlaybackPosition() - self._abController.positionChanged(position) + if previousSong is None or self._keyPoints[previousSong] != self._keyPoints[index]: + self._notifier.notify(Notifier.KEY_POINT_LIST_EVENT, self.keyPoints) - @property - def songList(self) -> list[str]: - return self._songList + @staticmethod + def _keyPointValid(kp: float) -> bool: + return kp is not None and kp >= 0.0 and kp < 1.0 - def addSong(self, path: str) -> None: - if os.path.isfile(path): - self._songList.append(path) + @property + def songs(self) -> list[str]: + return self._songs.copy() + + def addSong(self, fileName: str) -> None: + path = self._songPool / fileName + if not os.path.isfile(path): + raise FileNotFoundError(path) + if path in self._songs: + return + self._songs.append(fileName) + self._keyPoints.append([]) + self._notifier.notify(Notifier.SONG_LIST_EVENT, self.songs) + if self.song is None: + self.song = 0 @property def song(self) -> int: @@ -41,64 +58,34 @@ class SoloTool: @song.setter def song(self, new: int) -> None: - if new >= 0 and new < len(self._songList) and new != self._song: + if new is not None \ + and new >= 0 \ + and new < len(self._songs) \ + and new != self._song: self._updateSong(new) - def storeAbLimits(self, aLimit, bLimit): - self._abController.storeLimits(aLimit, bLimit) - - def loadAbLimits(self, index): - previous = self._abController.getLoadedIndex() - self._abController.loadLimits(index) - new = self._abController.getLoadedIndex() - if previous != new: - self._notifier.notify(Notifier.CURRENT_AB_EVENT, new) - - def setAbLimits(self, aLimit, bLimit): - self._abController.setLimits(aLimit, bLimit) - - def getStoredAbLimits(self): - if self._song is not None: - return self._abController.getStoredLimits(self.songList[self._song]) - else: - return list() - - def setAbLimitEnable(self, enable): - previous = self._abController.isEnabled() - self._abController.setEnable(enable) - new = self._abController.isEnabled() - if previous != new: - self._notifier.notify(Notifier.AB_LIMIT_ENABLED_EVENT, new) - - def isAbLimitEnabled(self): - return self._abController.isEnabled() - - def nextStoredAbLimits(self): - previous = self._abController.getLoadedIndex() - self._abController.nextStoredAbLimits() - new = self._abController.getLoadedIndex() - if previous != new: - self._notifier.notify(Notifier.CURRENT_AB_EVENT, new) - - def previousStoredAbLimits(self): - previous = self._abController.getLoadedIndex() - self._abController.previousStoredAbLimits() - new = self._abController.getLoadedIndex() - if previous != new: - self._notifier.notify(Notifier.CURRENT_AB_EVENT, new) - - def jumpToA(self): - a = self._abController.getCurrentLimits()[0] - # XXX assumes that player.setPlaybackPosition is thread-safe! - self._player.setPlaybackPosition(a) - - def loadSession(self, path): - with open(path, "r") as f: - loadSession(f, self._songList, self._abController) - - def saveSession(self, path): - with open(path, "w") as f: - saveSession(f, self._songList, self._abController) + @property + def keyPoints(self) -> list[float]: + if self._song is None: + return None + return self._keyPoints[self._song].copy() + + @keyPoints.setter + def keyPoints(self, new: list[float]) -> 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.copy() + self._notifier.notify(Notifier.KEY_POINT_LIST_EVENT, self.keyPoints) + + @property + def keyPoint(self) -> float: + return float(self._keyPoint) if self._keyPoint is not None else None + + @keyPoint.setter + def keyPoint(self, new: float) -> None: + 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) def play(self): self._player.play() @@ -106,49 +93,60 @@ class SoloTool: def pause(self): self._player.pause() - def stop(self): - self._player.stop() - - def isPlaying(self): + @property + def playing(self) -> bool: return self._player.isPlaying() - def setPlaybackRate(self, rate): - previous = self._player.getPlaybackRate() - self._player.setPlaybackRate(rate) - new = self._player.getPlaybackRate() - if previous != new: - self._notifier.notify(Notifier.PLAYBACK_RATE_EVENT, new) + def jump(self): + self._player.setPlaybackPosition(self._keyPoint) - def getPlaybackRate(self): + @property + def rate(self) -> float: return self._player.getPlaybackRate() - def setPlaybackPosition(self, position): - self._player.setPlaybackPosition(position) + @rate.setter + def rate(self, new: float) -> None: + 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) - def getPlaybackPosition(self): + @property + def volume(self) -> float: + return self._player.getPlaybackVolume() + + @volume.setter + def volume(self, new: float) -> None: + 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) + + @property + def position(self) -> float: return self._player.getPlaybackPosition() - def setPlaybackVolume(self, volume): - self._player.setPlaybackVolume(volume) + @position.setter + def position(self, new: float) -> None: + if new is not None and new != self._player.getPlaybackPosition(): + self._player.setPlaybackPosition(min(max(0.0, new), 1.0)) - def getPlaybackVolume(self): - return self._player.getPlaybackVolume() + def registerSongSelectionCallback(self, callback): + self._notifier.registerCallback(Notifier.CURRENT_SONG_EVENT, callback) + + def registerSongListCallback(self, callback): + self._notifier.registerCallback(Notifier.SONG_LIST_EVENT, callback) + + def registerKeyPointSelectionCallback(self, callback): + self._notifier.registerCallback(Notifier.CURRENT_KEY_POINT_EVENT, callback) + + def registerKeyPointListCallback(self, callback): + self._notifier.registerCallback(Notifier.KEY_POINT_LIST_EVENT, callback) def registerPlayingStateCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYING_STATE_EVENT, callback) - def registerPlaybackVolumeCallback(self, callback): + def registerVolumeCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYBACK_VOLUME_EVENT, callback) - def registerPlaybackRateCallback(self, callback): + def registerRateCallback(self, callback): self._notifier.registerCallback(Notifier.PLAYBACK_RATE_EVENT, callback) - def registerCurrentSongCallback(self, callback): - self._notifier.registerCallback(Notifier.CURRENT_SONG_EVENT, callback) - - def registerCurrentAbLimitsCallback(self, callback): - self._notifier.registerCallback(Notifier.CURRENT_AB_EVENT, callback) - - def registerAbLimitEnabledCallback(self, callback): - self._notifier.registerCallback(Notifier.AB_LIMIT_ENABLED_EVENT, callback) - diff --git a/solo-tool-project/src/solo_tool/solo_tool_controller.py b/solo-tool-project/src/solo_tool/solo_tool_controller.py deleted file mode 100644 index 0529570..0000000 --- a/solo-tool-project/src/solo_tool/solo_tool_controller.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - -from solo_tool.solo_tool import SoloTool - -class SoloToolController: - def __init__(self, soloTool: SoloTool): - self._soloTool = soloTool - - def nextSong(self): - current = self._soloTool.song - if current is None: - self._soloTool.song = 0 - else: - self._soloTool.song = current + 1 - - def previousSong(self): - current = self._soloTool.song - if current is None: - self._soloTool.song = 0 - else: - self._soloTool.song = current - 1 - |