From 3e9f9b12fc7104cde2ba141c95ae9eaa99614330 Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Thu, 22 Oct 2026 22:34:17 +0200 Subject: Multitrack support in the library --- solo-tool-project/src/solo_tool/player_mpv.py | 48 +++++++++++++++++++++++++++ solo-tool-project/src/solo_tool/solo_tool.py | 27 +++++++++++++++ 2 files changed, 75 insertions(+) (limited to 'solo-tool-project/src') diff --git a/solo-tool-project/src/solo_tool/player_mpv.py b/solo-tool-project/src/solo_tool/player_mpv.py index 58902e0..77e0651 100644 --- a/solo-tool-project/src/solo_tool/player_mpv.py +++ b/solo-tool-project/src/solo_tool/player_mpv.py @@ -1,13 +1,45 @@ import mpv +def _complexGraph(tracks): + graph = "" + for i, enabled in tracks.items(): + graph += f"[aid{i}]volume={"1.0" if enabled else "0.0"}[a{i}];" + graph += "[a1][a2][a3][a4][a5][a6]amix=inputs=6:" + graph += "duration=longest:normalize=0[ao]" + return graph + +def _simpleGraph(): + return ( + "[aid1]volume=1.0[a1];" + "[a1]amix=inputs=1:" + "duration=longest:normalize=1[ao]" + ) + class Player: + VOCAL_TRACK = 1 + GUITAR_TRACK = 2 + BASS_TRACK = 3 + PIANO_TRACK =4 + DRUM_TRACK = 5 + OTHER_TRACK = 6 + def __init__(self): self._player = mpv.MPV(ao="jack") self._player.loop = "inf" + self._player.lavfi_complex = _simpleGraph() 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()) + self._player.observe_property("track-list/count", lambda name, value: self._updateGraph()) + self._tracks = { + self.VOCAL_TRACK: True, + self.GUITAR_TRACK: True, + self.BASS_TRACK: True, + self.PIANO_TRACK: True, + self.DRUM_TRACK: True, + self.OTHER_TRACK: True + } def __del__(self): self._player.close() @@ -15,6 +47,12 @@ class Player: def _dummyCallback(self): pass + def _updateGraph(self): + if self.tracksSupported(): + self._player.lavfi_complex = _complexGraph(self._tracks) + else: + self._player.lavfi_complex = _simpleGraph() + def play(self): self._player.pause = False @@ -51,3 +89,13 @@ class Player: def setPlaybackVolumeChangedCallback(self, callback): self._volumeCallback = callback + + def tracksSupported(self): + return len(self._player.track_list) == 6 + + def trackEnabled(self, trackId): + return self._tracks[trackId] + + def setTrackEnabled(self, trackId, enable): + self._tracks[trackId] = enable + self._updateGraph() diff --git a/solo-tool-project/src/solo_tool/solo_tool.py b/solo-tool-project/src/solo_tool/solo_tool.py index c4acaf8..5ac7140 100644 --- a/solo-tool-project/src/solo_tool/solo_tool.py +++ b/solo-tool-project/src/solo_tool/solo_tool.py @@ -14,6 +14,29 @@ class SoloTool: self._volumes = [] self._adHoc = False + tracks = [ + ("vocalTrackEnabled", Player.VOCAL_TRACK), + ("guitarTrackEnabled", Player.GUITAR_TRACK), + ("bassTrackEnabled", Player.BASS_TRACK), + ("pianoTrackEnabled", Player.PIANO_TRACK), + ("drumTrackEnabled", Player.DRUM_TRACK), + ("otherTrackEnabled", Player.OTHER_TRACK) + ] + for trackName, trackId in tracks: + if not hasattr(type(self), trackName): + setattr(type(self), trackName, self._makeTrackProperty(trackId)) + + @staticmethod + def _makeTrackProperty(trackId: int) -> property: + def getter(self) -> bool: + return self._player.trackEnabled(trackId) + + def setter(self, new: bool) -> None: + if new is not None and new != self._player.trackEnabled(trackId): + self._player.setTrackEnabled(trackId, new) + + return property(getter, setter) + def __del__(self): del self._player @@ -165,3 +188,7 @@ class SoloTool: def playingAdHoc(self) -> bool: return self._adHoc + @property + def tracksSupported(self) -> bool: + return self._player.tracksSupported() + -- cgit v1.2.3