Move player functionality into music.py
This commit is contained in:
parent
4a5fe74a9f
commit
be0fc27896
67
app/music.py
67
app/music.py
@ -1,18 +1,23 @@
|
||||
# Standard library imports
|
||||
import datetime as dt
|
||||
import threading
|
||||
from time import sleep
|
||||
from typing import Optional
|
||||
|
||||
# Third party imports
|
||||
import vlc # type: ignore
|
||||
|
||||
from config import Config
|
||||
from helpers import file_is_unreadable
|
||||
from typing import Optional
|
||||
from time import sleep
|
||||
|
||||
from log import log
|
||||
|
||||
# PyQt imports
|
||||
from PyQt6.QtCore import (
|
||||
QRunnable,
|
||||
QThreadPool,
|
||||
)
|
||||
|
||||
# App imports
|
||||
from config import Config
|
||||
from helpers import file_is_unreadable
|
||||
from log import log
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
|
||||
@ -57,6 +62,7 @@ class Music:
|
||||
self.VLC = vlc.Instance()
|
||||
self.player = None
|
||||
self.max_volume = Config.VOLUME_VLC_DEFAULT
|
||||
self.start_dt: Optional[dt.datetime] = None
|
||||
|
||||
def fade(self, fade_seconds: int = Config.FADEOUT_SECONDS) -> None:
|
||||
"""
|
||||
@ -83,6 +89,21 @@ class Music:
|
||||
pool = QThreadPool.globalInstance()
|
||||
fader = FadeTrack(p, fade_seconds=fade_seconds)
|
||||
pool.start(fader)
|
||||
self.start_dt = 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.start_dt is None:
|
||||
return 0
|
||||
|
||||
now = dt.datetime.now()
|
||||
elapsed_seconds = (now - self.start_dt).total_seconds()
|
||||
return int(elapsed_seconds * 1000)
|
||||
|
||||
def get_position(self) -> Optional[float]:
|
||||
"""Return current position"""
|
||||
@ -91,6 +112,23 @@ class Music:
|
||||
return None
|
||||
return self.player.get_position()
|
||||
|
||||
def is_playing(self) -> bool:
|
||||
"""Return True if playing"""
|
||||
|
||||
# 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.
|
||||
return (
|
||||
self.player is not None
|
||||
and self.start_dt is not None
|
||||
and (
|
||||
self.player.is_playing()
|
||||
or (dt.datetime.now() - self.start_dt)
|
||||
< dt.timedelta(microseconds=Config.PLAY_SETTLE)
|
||||
)
|
||||
)
|
||||
|
||||
def play(self, path: str, position: Optional[float] = None) -> None:
|
||||
"""
|
||||
Start playing the track at path.
|
||||
@ -109,8 +147,10 @@ class Music:
|
||||
if self.player:
|
||||
_ = self.player.play()
|
||||
self.set_volume(self.max_volume)
|
||||
|
||||
if position:
|
||||
self.player.set_position(position)
|
||||
self.start_dt = dt.datetime.now()
|
||||
|
||||
def set_volume(self, volume=None, set_default=True) -> None:
|
||||
"""Set maximum volume used for player"""
|
||||
@ -125,6 +165,18 @@ class Music:
|
||||
volume = Config.VOLUME_VLC_DEFAULT
|
||||
|
||||
self.player.audio_set_volume(volume)
|
||||
# Ensure volume correct
|
||||
# For as-yet unknown reasons. sometimes the volume gets
|
||||
# reset to zero within 200mS or so of starting play. This
|
||||
# only happened since moving to Debian 12, which uses
|
||||
# Pipewire for sound (which may be irrelevant).
|
||||
for _ in range(3):
|
||||
current_volume = self.player.audio_get_volume()
|
||||
if current_volume < volume:
|
||||
self.player.audio_set_volume(volume)
|
||||
log.debug(f"Reset from {volume=}")
|
||||
break
|
||||
sleep(0.1)
|
||||
|
||||
def stop(self) -> float:
|
||||
"""Immediately stop playing"""
|
||||
@ -136,6 +188,7 @@ class Music:
|
||||
|
||||
p = self.player
|
||||
self.player = None
|
||||
self.start_dt = None
|
||||
|
||||
with lock:
|
||||
position = p.get_position()
|
||||
|
||||
@ -781,21 +781,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
|
||||
self.stop_playing(fade=True)
|
||||
|
||||
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 track_sequence.now.track_id is None or track_sequence.now.start_time is None:
|
||||
return 0
|
||||
|
||||
now = dt.datetime.now()
|
||||
track_start = track_sequence.now.start_time
|
||||
elapsed_seconds = (now - track_start).total_seconds()
|
||||
return int(elapsed_seconds * 1000)
|
||||
|
||||
def hide_played(self):
|
||||
"""Toggle hide played tracks"""
|
||||
|
||||
@ -1146,7 +1131,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
- Clear next track
|
||||
- Restore volume if -3dB active
|
||||
- Play (new) current track.
|
||||
- Ensure 100% volume
|
||||
- Show closing volume graph
|
||||
- Notify model
|
||||
- Note that track is now playing
|
||||
@ -1204,20 +1188,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
return
|
||||
self.music.play(track_sequence.now.path, position)
|
||||
|
||||
# Ensure 100% volume
|
||||
# For as-yet unknown reasons. sometimes the volume gets
|
||||
# reset to zero within 200mS or so of starting play. This
|
||||
# only happened since moving to Debian 12, which uses
|
||||
# Pipewire for sound (which may be irrelevant).
|
||||
for _ in range(3):
|
||||
if self.music.player:
|
||||
volume = self.music.player.audio_get_volume()
|
||||
if volume < Config.VOLUME_VLC_DEFAULT:
|
||||
self.music.set_volume()
|
||||
log.debug(f"Reset from {volume=}")
|
||||
break
|
||||
sleep(0.1)
|
||||
|
||||
# Show closing volume graph
|
||||
if track_sequence.now.fade_graph:
|
||||
track_sequence.now.fade_graph.plot()
|
||||
@ -1693,20 +1663,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
return
|
||||
|
||||
# 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 track_sequence.now.start_time
|
||||
and (
|
||||
self.music.player.is_playing()
|
||||
or (dt.datetime.now() - track_sequence.now.start_time)
|
||||
< dt.timedelta(microseconds=Config.PLAY_SETTLE)
|
||||
)
|
||||
):
|
||||
playtime = self.get_playtime()
|
||||
if self.music.player and self.music.player.is_playing():
|
||||
playtime = self.music.player.get_playtime()
|
||||
time_to_fade = track_sequence.now.fade_at - playtime
|
||||
time_to_silence = track_sequence.now.silence_at - playtime
|
||||
|
||||
|
||||
@ -614,7 +614,7 @@ class PlaylistTab(QTableView):
|
||||
else:
|
||||
result = self.source_model.get_row_track_path(model_row_number)
|
||||
|
||||
log.info(f"get_selected_row_track_path() returned: {result=}")
|
||||
log.debug(f"get_selected_row_track_path() returned: {result=}")
|
||||
return result
|
||||
|
||||
def get_selected_rows(self) -> List[int]:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user