diff --git a/app/config.py b/app/config.py index 83c1fcd..749919b 100644 --- a/app/config.py +++ b/app/config.py @@ -69,7 +69,6 @@ class Config(object): MAX_MISSING_FILES_TO_REPORT = 10 MILLISECOND_SIGFIGS = 0 MINIMUM_ROW_HEIGHT = 30 - MYSQL_CONNECT = os.environ.get('MYSQL_CONNECT') or "mysql+mysqldb://musicmuster:musicmuster@localhost/musicmuster_v2" # noqa E501 NOTE_TIME_FORMAT = "%H:%M:%S" OBS_HOST = "localhost" OBS_PASSWORD = "auster" diff --git a/app/music.py b/app/music.py index 8161551..bd3df29 100644 --- a/app/music.py +++ b/app/music.py @@ -91,14 +91,6 @@ class Music: fader = FadeTrack(p) pool.start(fader) - def get_playtime(self) -> Optional[int]: - """Return elapsed play time""" - - if not self.player: - return None - - return self.player.get_time() - def get_position(self) -> Optional[float]: """Return current position""" diff --git a/app/musicmuster.py b/app/musicmuster.py index 581d850..734e00c 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -915,6 +915,24 @@ class Window(QMainWindow, Ui_MainWindow): else: return None + def get_playtime(self) -> int: + """ + Return number of milliseconds current track has been playing or + zero if not playing. The vlc function get_time() only updates 3-4 + times a second; this function has much better resolution. + """ + + if ( + self.current_track.track_id is None or + self.current_track.start_time is None + ): + return 0 + + now = datetime.now() + track_start = self.current_track.start_time + elapsed_seconds = (now - track_start).total_seconds() + return int(elapsed_seconds * 1000) + def hide_played(self): """Toggle hide played tracks""" @@ -1671,29 +1689,25 @@ class Window(QMainWindow, Ui_MainWindow): def tick(self) -> None: """ - Carry out clock tick actions. + Called every Config.TIMER_MS milliseconds. Call periodic functions + as required. + """ - self.clock_counter is incrememted at each tick (100ms), and this - value is used to determine the actions to take. + # Get current number of milliseconds + self.clock_counter += Config.TIMER_MS + self.clock_counter %= 1000 - The Fade Volume graph is updated every 10ms. + # Call periodic functions + if self.clock_counter % 10 == 0: + self.tick_10ms() + if self.clock_counter % 500 == 0: + self.tick_500ms() + if self.clock_counter == 0: + self.tick_1000ms() - The Time of Day clock and any cart progress bars are updated - every 500ms. - - All other timers are updated every second. As the timer displays - have a one-second resolution, updating every 500ms can result in - some timers updating and then, 500ms later, other timers - updating. That looks odd. - - Actions required: - - Update Fade Volume graph - - Update TOD clock - - Call cart_tick - - If track is playing: - update track clocks time and colours - - Else: - run stop_track + def tick_10ms(self) -> None: + """ + Called every 10ms """ # Update volume fade curve @@ -1707,74 +1721,84 @@ class Window(QMainWindow, Ui_MainWindow): ).total_seconds() * 1000 self.current_track.fade_graph.tick(play_time) - if self.clock_counter % 20 == 0: - # Update TOD clock - self.lblTOD.setText(datetime.now().strftime( - Config.TOD_TIME_FORMAT)) - # Update carts - self.cart_tick() + def tick_500ms(self) -> None: + """ + Called every 500ms + """ - if self.clock_counter % 50 == 0: - if not self.playing: - return + self.lblTOD.setText(datetime.now().strftime( + Config.TOD_TIME_FORMAT)) + # Update carts + self.cart_tick() - # If track is playing, update track clocks time and colours - # There is a discrete time between starting playing a track and - # player.is_playing() returning True, so assume playing if less - # than Config.PLAY_SETTLE microseconds have passed since - # starting play. - if self.music.player and self.current_track.start_time and ( - self.music.player.is_playing() or - (datetime.now() - self.current_track.start_time) - < timedelta(microseconds=Config.PLAY_SETTLE)): - playtime = self.music.get_playtime() - time_to_fade = (self.current_track.fade_at - playtime) - time_to_silence = ( - self.current_track.silence_at - playtime) - time_to_end = (self.current_track.duration - playtime) + def tick_1000ms(self) -> None: + """ + Called every 1000ms + """ - # Elapsed time - self.label_elapsed_timer.setText(helpers.ms_to_mmss(playtime)) + # Only update play clocks once a second so that their updates + # are synchronised (otherwise it looks odd) - # Time to fade - self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade)) + if not self.playing: + return - # If silent in the next 5 seconds, put warning colour on - # time to silence box and enable play controls - if time_to_silence <= 5500: - self.frame_silent.setStyleSheet( - f"background: {Config.COLOUR_ENDING_TIMER}" - ) - self.enable_play_next_controls() - # Set warning colour on time to silence box when fade starts - elif time_to_fade <= 500: - self.frame_silent.setStyleSheet( - f"background: {Config.COLOUR_WARNING_TIMER}" - ) - # Five seconds before fade starts, set warning colour on - # time to silence box and enable play controls - elif time_to_fade <= 5500: - self.frame_fade.setStyleSheet( - f"background: {Config.COLOUR_WARNING_TIMER}" - ) - self.enable_play_next_controls() - else: - self.frame_silent.setStyleSheet("") - self.frame_fade.setStyleSheet("") + # If track is playing, update track clocks time and colours + # There is a discrete time between starting playing a track and + # player.is_playing() returning True, so assume playing if less + # than Config.PLAY_SETTLE microseconds have passed since + # starting play. + if self.music.player and self.current_track.start_time and ( + self.music.player.is_playing() or + (datetime.now() - self.current_track.start_time) + < timedelta(microseconds=Config.PLAY_SETTLE)): + playtime = self.get_playtime() + time_to_fade = (self.current_track.fade_at - playtime) + time_to_silence = ( + self.current_track.silence_at - playtime) + time_to_end = (self.current_track.duration - playtime) - self.label_silent_timer.setText( - helpers.ms_to_mmss(time_to_silence) + # Elapsed time + self.label_elapsed_timer.setText(helpers.ms_to_mmss(playtime)) + + # Time to fade + self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade)) + + # If silent in the next 5 seconds, put warning colour on + # time to silence box and enable play controls + if time_to_silence <= 5500: + self.frame_silent.setStyleSheet( + f"background: {Config.COLOUR_ENDING_TIMER}" ) - - # Time to end - self.label_end_timer.setText(helpers.ms_to_mmss(time_to_end)) - - # Autoplay next track - # if time_to_silence <= 1500: - # self.play_next() + self.enable_play_next_controls() + # Set warning colour on time to silence box when fade starts + elif time_to_fade <= 500: + self.frame_silent.setStyleSheet( + f"background: {Config.COLOUR_WARNING_TIMER}" + ) + # Five seconds before fade starts, set warning colour on + # time to silence box and enable play controls + elif time_to_fade <= 5500: + self.frame_fade.setStyleSheet( + f"background: {Config.COLOUR_WARNING_TIMER}" + ) + self.enable_play_next_controls() else: - if self.playing: - self.stop_playing() + self.frame_silent.setStyleSheet("") + self.frame_fade.setStyleSheet("") + + self.label_silent_timer.setText( + helpers.ms_to_mmss(time_to_silence) + ) + + # Time to end + self.label_end_timer.setText(helpers.ms_to_mmss(time_to_end)) + + # Autoplay next track + # if time_to_silence <= 1500: + # self.play_next() + else: + if self.playing: + self.stop_playing() def update_headers(self) -> None: """