diff --git a/app/music.py b/app/music.py index f575ea9..6d090f2 100644 --- a/app/music.py +++ b/app/music.py @@ -10,9 +10,53 @@ from time import sleep from log import log +from PyQt5.QtCore import ( + QRunnable, + QThreadPool, +) + lock = threading.Lock() +class FadeTrack(QRunnable): + + def __init__(self, player: vlc.MediaPlayer) -> None: + super().__init__() + self.player = player + + def run(self): + """ + Implementation of fading the player + """ + + if not self.player: + return + + fade_time = Config.FADE_TIME / 1000 + steps = Config.FADE_STEPS + sleep_time = fade_time / steps + original_volume = self.player.audio_get_volume() + + # We reduce volume by one mesure first, then by two measures, + # then three, and so on. + # The sum of the arithmetic sequence 1, 2, 3, ..n is + # (n**2 + n) / 2 + total_measures_count = (steps**2 + steps) / 2 + + measures_to_reduce_by = 0 + + for i in range(1, steps + 1): + measures_to_reduce_by += i + volume_factor = 1 - ( + measures_to_reduce_by / total_measures_count) + self.player.audio_set_volume(int(original_volume * volume_factor)) + sleep(sleep_time) + + self.player.stop() + log.debug(f"Releasing player {self.player=}") + self.player.release() + + class Music: """ Manage the playing of music tracks @@ -37,46 +81,15 @@ class Music: if not self.player.get_position() > 0 and self.player.is_playing(): return - thread = threading.Thread(target=self._fade) - thread.start() - - def _fade(self) -> None: - """ - Implementation of fading the current track in a separate thread. - """ - # Take a copy of current player to allow another track to be # started without interfering here with lock: p = self.player self.player = None - # Sanity check - if not p: - return - - fade_time = Config.FADE_TIME / 1000 - steps = Config.FADE_STEPS - sleep_time = fade_time / steps - - # We reduce volume by one mesure first, then by two measures, - # then three, and so on. - # The sum of the arithmetic sequence 1, 2, 3, ..n is - # (n**2 + n) / 2 - total_measures_count = (steps**2 + steps) / 2 - - measures_to_reduce_by = 0 - for i in range(1, steps + 1): - measures_to_reduce_by += i - volume_factor = 1 - ( - measures_to_reduce_by / total_measures_count) - p.audio_set_volume(int(self.max_volume * volume_factor)) - sleep(sleep_time) - - with lock: - p.stop() - log.debug(f"Releasing player {p=}") - p.release() + pool = QThreadPool.globalInstance() + fader = FadeTrack(p) + pool.start(fader) def get_playtime(self) -> Optional[int]: """Return elapsed play time""" @@ -117,13 +130,6 @@ class Music: return status -# -# def set_position(self, ms): -# """Set current play time in milliseconds from start""" -# -# with lock: -# return self.player.set_time(ms) - def set_volume(self, volume, set_default=True): """Set maximum volume used for player""" @@ -138,13 +144,15 @@ class Music: def stop(self) -> float: """Immediately stop playing""" - with lock: - if not self.player: - return 0.0 + if not self.player: + return 0.0 - position = self.player.get_position() - self.player.stop() - self.player.release() - # Ensure we don't reference player after release - self.player = None + p = self.player + self.player = None + + with lock: + position = p.get_position() + p.stop() + p.release() + p = None return position