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() 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 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 = 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 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()