# import os # import threading # import vlc # # from config import Config # from datetime import datetime # from time import sleep # # from log import log.debug, log.error # # lock = threading.Lock() # # # class Music: # """ # Manage the playing of music tracks # """ # # def __init__(self): # self.current_track_start_time = None # self.fading = 0 # self.VLC = vlc.Instance() # self.player = None # self.track_path = None # self.max_volume = Config.VOLUME_VLC_DEFAULT # # def fade(self): # """ # Fade the currently playing track. # # The actual management of fading runs in its own thread so as not # to hold up the UI during the fade. # """ # # log.debug("music.fade()", True) # # if not self.player: # return # # if not self.player.get_position() > 0 and self.player.is_playing(): # return # # self.fading += 1 # # thread = threading.Thread(target=self._fade) # thread.start() # # def _fade(self): # """ # 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 # # log.debug(f"music._fade(), {self.player=}", True) # # with lock: # p = self.player # self.player = None # # log.debug("music._fade() post-lock", True) # # 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: # log.debug(f"music._fade(), stopping {p=}", True) # # p.stop() # log.debug(f"Releasing player {p=}", True) # p.release() # # self.fading -= 1 # # def get_playtime(self): # """Return elapsed play time""" # # with lock: # if not self.player: # return None # # return self.player.get_time() # # def get_position(self): # """Return current position""" # # with lock: # log.debug("music.get_position", True) # # print(f"get_position, {self.player=}") # if not self.player: # return # return self.player.get_position() # # def play(self, path): # """ # Start playing the track at path. # # Log and return if path not found. # """ # # log.debug(f"music.play({path=})", True) # # if not os.access(path, os.R_OK): # log.error(f"play({path}): path not found") # return # # self.track_path = path # # self.player = self.VLC.media_player_new(path) # self.player.audio_set_volume(self.max_volume) # log.debug(f"music.play({path=}), {self.player}", True) # self.player.play() # self.current_track_start_time = datetime.now() # # def playing(self): # """ # Return True if currently playing a track, else False # # vlc.is_playing() returns True if track was faded out. # get_position seems more reliable. # """ # # with lock: # if self.player: # if self.player.get_position() > 0 and self.player.is_playing(): # return True # # # We take a copy of the player when fading, so we could be # # playing in a fade nowFalse # return self.fading > 0 # # 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""" # # with lock: # if not self.player: # return # # if set_default: # self.max_volume = volume # # self.player.audio_set_volume(volume) # # def stop(self): # """Immediately stop playing""" # # log.debug(f"music.stop(), {self.player=}", True) # # with lock: # if not self.player: # return # # position = self.player.get_position() # self.player.stop() # log.debug(f"music.stop(): Releasing player {self.player=}", True) # self.player.release() # # Ensure we don't reference player after release # self.player = None # return position