Rewrite thread management for fade graph generation
This commit is contained in:
parent
735c927864
commit
ad391aedc6
@ -1,6 +1,6 @@
|
|||||||
# Standard library imports
|
# Standard library imports
|
||||||
|
from collections import deque
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
# PyQt imports
|
# PyQt imports
|
||||||
from PyQt6.QtCore import (
|
from PyQt6.QtCore import (
|
||||||
@ -25,6 +25,59 @@ import ds
|
|||||||
import helpers
|
import helpers
|
||||||
|
|
||||||
|
|
||||||
|
class FadeGraphGenerator(QObject):
|
||||||
|
finished = pyqtSignal(object, object)
|
||||||
|
task_completed = pyqtSignal()
|
||||||
|
|
||||||
|
def generate_graph(self, plr: "PlaylistRow") -> None:
|
||||||
|
fade_graph = FadeCurve(plr.path, plr.fade_at, plr.silence_at)
|
||||||
|
if not fade_graph:
|
||||||
|
log.error(f"Failed to create FadeCurve for {plr=}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.finished.emit(plr, fade_graph)
|
||||||
|
self.task_completed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
class FadegraphThreadController(QObject):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._thread = None
|
||||||
|
self._generator = None
|
||||||
|
self._request_queue = deque()
|
||||||
|
|
||||||
|
def generate_fade_graph(self, playlist_row):
|
||||||
|
self._request_queue.append(playlist_row) # Use append for enqueue with deque
|
||||||
|
if self._thread is None or not self._thread.isRunning():
|
||||||
|
self._start_next_generation()
|
||||||
|
|
||||||
|
def _start_next_generation(self):
|
||||||
|
if not self._request_queue: # Check if deque is empty
|
||||||
|
return
|
||||||
|
playlist_row = self._request_queue.popleft() # Use popleft for dequeue with deque
|
||||||
|
self._start_thread(playlist_row)
|
||||||
|
|
||||||
|
def _start_thread(self, playlist_row):
|
||||||
|
self._thread = QThread()
|
||||||
|
self._generator = FadeGraphGenerator()
|
||||||
|
self._generator.moveToThread(self._thread)
|
||||||
|
self._generator.finished.connect(lambda row, graph: row.attach_fade_graph(graph))
|
||||||
|
self._generator.task_completed.connect(self._cleanup_thread)
|
||||||
|
self._thread.started.connect(lambda: self._generator.generate_graph(playlist_row))
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def _cleanup_thread(self):
|
||||||
|
if self._thread:
|
||||||
|
self._thread.quit()
|
||||||
|
self._thread.wait()
|
||||||
|
self._thread.deleteLater()
|
||||||
|
self._thread = None
|
||||||
|
self._generator.deleteLater()
|
||||||
|
self._generator = None
|
||||||
|
# Start the next request if any
|
||||||
|
self._start_next_generation()
|
||||||
|
|
||||||
|
|
||||||
class PlaylistRow:
|
class PlaylistRow:
|
||||||
"""
|
"""
|
||||||
Object to manage playlist row and track.
|
Object to manage playlist row and track.
|
||||||
@ -41,7 +94,7 @@ class PlaylistRow:
|
|||||||
self.signals = MusicMusterSignals()
|
self.signals = MusicMusterSignals()
|
||||||
self.end_of_track_signalled: bool = False
|
self.end_of_track_signalled: bool = False
|
||||||
self.end_time: dt.datetime | None = None
|
self.end_time: dt.datetime | None = None
|
||||||
self.fade_graph: Any | None = None
|
self.fade_graph: FadeCurve | None = None
|
||||||
self.fade_graph_start_updates: dt.datetime | None = None
|
self.fade_graph_start_updates: dt.datetime | None = None
|
||||||
self.forecast_end_time: dt.datetime | None = None
|
self.forecast_end_time: dt.datetime | None = None
|
||||||
self.forecast_start_time: dt.datetime | None = None
|
self.forecast_start_time: dt.datetime | None = None
|
||||||
@ -51,6 +104,7 @@ class PlaylistRow:
|
|||||||
self.row_bg: str | None = None
|
self.row_bg: str | None = None
|
||||||
self.row_fg: str | None = None
|
self.row_fg: str | None = None
|
||||||
self.start_time: dt.datetime | None = None
|
self.start_time: dt.datetime | None = None
|
||||||
|
self.fadegraph_thread_controller = FadegraphThreadController()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
track_id = None
|
track_id = None
|
||||||
@ -223,6 +277,9 @@ class PlaylistRow:
|
|||||||
# the change to the database.
|
# the change to the database.
|
||||||
self.dto.row_number = value
|
self.dto.row_number = value
|
||||||
|
|
||||||
|
def attach_fade_graph(self, fade_graph):
|
||||||
|
self.fade_graph = fade_graph
|
||||||
|
|
||||||
def drop3db(self, enable: bool) -> None:
|
def drop3db(self, enable: bool) -> None:
|
||||||
"""
|
"""
|
||||||
If enable is true, drop output by 3db else restore to full volume
|
If enable is true, drop output by 3db else restore to full volume
|
||||||
@ -337,40 +394,6 @@ class PlaylistRow:
|
|||||||
self.fade_graph.tick(self.time_playing())
|
self.fade_graph.tick(self.time_playing())
|
||||||
|
|
||||||
|
|
||||||
class _AddFadeCurve(QObject):
|
|
||||||
"""
|
|
||||||
Initialising a fade curve introduces a noticeable delay so carry out in
|
|
||||||
a thread.
|
|
||||||
"""
|
|
||||||
|
|
||||||
finished = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
plr: PlaylistRow,
|
|
||||||
track_path: str,
|
|
||||||
track_fade_at: int,
|
|
||||||
track_silence_at: int,
|
|
||||||
) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self.plr = plr
|
|
||||||
self.track_path = track_path
|
|
||||||
self.track_fade_at = track_fade_at
|
|
||||||
self.track_silence_at = track_silence_at
|
|
||||||
|
|
||||||
def run(self) -> None:
|
|
||||||
"""
|
|
||||||
Create fade curve and add to PlaylistTrack object
|
|
||||||
"""
|
|
||||||
|
|
||||||
fc = FadeCurve(self.track_path, self.track_fade_at, self.track_silence_at)
|
|
||||||
if not fc:
|
|
||||||
log.error(f"Failed to create FadeCurve for {self.track_path=}")
|
|
||||||
else:
|
|
||||||
self.plr.fade_graph = fc
|
|
||||||
self.finished.emit()
|
|
||||||
|
|
||||||
|
|
||||||
class FadeCurve:
|
class FadeCurve:
|
||||||
GraphWidget: PlotWidget | None = None
|
GraphWidget: PlotWidget | None = None
|
||||||
|
|
||||||
@ -388,10 +411,10 @@ class FadeCurve:
|
|||||||
|
|
||||||
# Start point of curve is Config.FADE_CURVE_MS_BEFORE_FADE
|
# Start point of curve is Config.FADE_CURVE_MS_BEFORE_FADE
|
||||||
# milliseconds before fade starts to silence
|
# milliseconds before fade starts to silence
|
||||||
self.start_ms: int = max(
|
self.start_ms = max(
|
||||||
0, track_fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1
|
0, track_fade_at - Config.FADE_CURVE_MS_BEFORE_FADE - 1
|
||||||
)
|
)
|
||||||
self.end_ms: int = track_silence_at
|
self.end_ms = track_silence_at
|
||||||
audio_segment = audio[self.start_ms : self.end_ms]
|
audio_segment = audio[self.start_ms : self.end_ms]
|
||||||
self.graph_array = np.array(audio_segment.get_array_of_samples())
|
self.graph_array = np.array(audio_segment.get_array_of_samples())
|
||||||
|
|
||||||
@ -470,7 +493,7 @@ class TrackSequence:
|
|||||||
self.next = None
|
self.next = None
|
||||||
else:
|
else:
|
||||||
self.next = plr
|
self.next = plr
|
||||||
self.create_fade_graph()
|
plr.fadegraph_thread_controller.generate_fade_graph(plr)
|
||||||
|
|
||||||
def move_next_to_current(self) -> None:
|
def move_next_to_current(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -506,27 +529,6 @@ class TrackSequence:
|
|||||||
self.next = self.previous
|
self.next = self.previous
|
||||||
self.previous = None
|
self.previous = None
|
||||||
|
|
||||||
def create_fade_graph(self) -> None:
|
|
||||||
"""
|
|
||||||
Initialise and add FadeCurve in a thread as it's slow
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.fadecurve_thread = QThread()
|
|
||||||
if self.next is None:
|
|
||||||
raise ApplicationError("hell in a handcart")
|
|
||||||
self.worker = _AddFadeCurve(
|
|
||||||
self.next,
|
|
||||||
track_path=self.next.path,
|
|
||||||
track_fade_at=self.next.fade_at,
|
|
||||||
track_silence_at=self.next.silence_at,
|
|
||||||
)
|
|
||||||
self.worker.moveToThread(self.fadecurve_thread)
|
|
||||||
self.fadecurve_thread.started.connect(self.worker.run)
|
|
||||||
self.worker.finished.connect(self.fadecurve_thread.quit)
|
|
||||||
self.worker.finished.connect(self.worker.deleteLater)
|
|
||||||
self.fadecurve_thread.finished.connect(self.fadecurve_thread.deleteLater)
|
|
||||||
self.fadecurve_thread.start()
|
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
"""
|
"""
|
||||||
If a PlaylistRow is edited (moved, title changed, etc), the
|
If a PlaylistRow is edited (moved, title changed, etc), the
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user