Preview with pygame working
This commit is contained in:
parent
e3d7ae8e0f
commit
553376a99e
@ -1,7 +1,7 @@
|
||||
# Standard library imports
|
||||
from dataclasses import dataclass, field
|
||||
from enum import auto, Enum
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, NamedTuple
|
||||
|
||||
# PyQt imports
|
||||
from PyQt6.QtCore import pyqtSignal, QObject
|
||||
@ -65,3 +65,8 @@ class TrackFileData:
|
||||
obsolete_path: Optional[str] = None
|
||||
tags: dict[str, Any] = field(default_factory=dict)
|
||||
audio_metadata: dict[str, str | int | float] = field(default_factory=dict)
|
||||
|
||||
|
||||
class TrackInfo(NamedTuple):
|
||||
track_id: int
|
||||
row_number: int
|
||||
|
||||
@ -48,9 +48,11 @@ import stackprinter # type: ignore
|
||||
from classes import (
|
||||
MusicMusterSignals,
|
||||
TrackFileData,
|
||||
TrackInfo,
|
||||
)
|
||||
from config import Config
|
||||
from dialogs import TrackSelectDialog, ReplaceFilesDialog
|
||||
from helpers import file_is_unreadable
|
||||
from log import log
|
||||
from models import db, Playdates, PlaylistRows, Playlists, Settings, Tracks
|
||||
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
||||
@ -150,7 +152,10 @@ class PreviewManager:
|
||||
|
||||
def __init__(self) -> None:
|
||||
mixer.init()
|
||||
self.intro: Optional[int] = None
|
||||
self.path: str = ""
|
||||
self.row_number: Optional[int] = None
|
||||
self.track_id: int = 0
|
||||
self.start_time: Optional[dt.datetime] = None
|
||||
|
||||
def back(self, ms: int) -> None:
|
||||
@ -187,17 +192,64 @@ class PreviewManager:
|
||||
def is_playing(self) -> bool:
|
||||
return mixer.music.get_busy()
|
||||
|
||||
def move_to_intro_end(self) -> None:
|
||||
"""
|
||||
Move play position to 'buffer' milliseconds before end of intro.
|
||||
|
||||
If no intro defined, do nothing.
|
||||
"""
|
||||
|
||||
if self.intro is None:
|
||||
return
|
||||
|
||||
position = max(0, self.intro - Config.PREVIEW_END_BUFFER_MS) / 1000
|
||||
mixer.music.set_pos(position)
|
||||
self.start_time = dt.datetime.now() - dt.timedelta(seconds=position)
|
||||
|
||||
def play(self) -> None:
|
||||
mixer.music.play()
|
||||
self.start_time = dt.datetime.now()
|
||||
|
||||
def set_path(self, path) -> None:
|
||||
self.path = path
|
||||
mixer.music.load(path)
|
||||
def restart(self) -> None:
|
||||
"""
|
||||
Restart player from beginning
|
||||
"""
|
||||
|
||||
if not mixer.music.get_busy():
|
||||
return
|
||||
|
||||
mixer.music.set_pos(0)
|
||||
self.start_time = dt.datetime.now()
|
||||
|
||||
def set_intro(self, ms: int) -> None:
|
||||
"""
|
||||
Set intro time
|
||||
"""
|
||||
|
||||
self.intro = ms
|
||||
|
||||
def set_track_info(self, info: TrackInfo) -> None:
|
||||
self.track_id = info.track_id
|
||||
self.row_number = info.row_number
|
||||
|
||||
with db.Session() as session:
|
||||
track = session.get(Tracks, self.track_id)
|
||||
if not track:
|
||||
raise ValueError(f"PreviewManager: unable to retreive track {self.track_id=}")
|
||||
self.intro = track.intro
|
||||
self.path = track.path
|
||||
|
||||
# Check file readable
|
||||
if file_is_unreadable(self.path):
|
||||
raise ValueError(f"PreviewManager.__init__: {track.path=} unreadable")
|
||||
|
||||
mixer.music.load(self.path)
|
||||
|
||||
def stop(self) -> None:
|
||||
mixer.music.stop()
|
||||
self.path = ""
|
||||
self.row_number = None
|
||||
self.track_id = 0
|
||||
self.start_time = None
|
||||
|
||||
|
||||
@ -1114,14 +1166,18 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
|
||||
if self.btnPreview.isChecked():
|
||||
# Get track path for first selected track if there is one
|
||||
track_path = self.active_tab().get_selected_row_track_path()
|
||||
if not track_path:
|
||||
track_info = self.active_tab().get_selected_row_track_info()
|
||||
if not track_info:
|
||||
# Otherwise get track_id to next track to play
|
||||
if track_sequence.next:
|
||||
track_path = track_sequence.next.path
|
||||
if track_path:
|
||||
self.preview_manager.set_path(track_path)
|
||||
self.preview_manager.play()
|
||||
if track_sequence.next.path:
|
||||
track_info = TrackInfo(track_sequence.next.track_id,
|
||||
track_sequence.next.row_number
|
||||
)
|
||||
else:
|
||||
return
|
||||
self.preview_manager.set_track_info(track_info)
|
||||
self.preview_manager.play()
|
||||
else:
|
||||
self.preview_manager.stop()
|
||||
|
||||
@ -1138,8 +1194,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
def preview_end(self) -> None:
|
||||
"""Advance preview file to Config.PREVIEW_END_BUFFER_MS before end of intro"""
|
||||
|
||||
# TODO
|
||||
pass
|
||||
if self.preview_manager:
|
||||
self.preview_manager.move_to_intro_end()
|
||||
|
||||
def preview_fwd(self) -> None:
|
||||
"""Advance preview file"""
|
||||
@ -1149,29 +1205,26 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
def preview_mark(self) -> None:
|
||||
"""Set intro time"""
|
||||
|
||||
# TODO
|
||||
pass
|
||||
# if self.preview_track_manager:
|
||||
# track_id = self.preview_track_manager.track_id
|
||||
# row_number = self.preview_track_manager.row_number
|
||||
# with db.Session() as session:
|
||||
# track = session.get(Tracks, track_id)
|
||||
# if track:
|
||||
# # Save intro as millisends rounded to nearest 0.1
|
||||
# # second because editor spinbox only resolves to 0.1
|
||||
# # seconds
|
||||
# intro = round(self.preview_track_manager.time_playing() / 100) * 100
|
||||
# track.intro = intro
|
||||
# session.commit()
|
||||
# self.preview_track_manager.intro = intro
|
||||
# self.active_tab().source_model.refresh_row(session, row_number)
|
||||
# self.active_tab().source_model.invalidate_row(row_number)
|
||||
if self.preview_manager.is_playing():
|
||||
track_id = self.preview_manager.track_id
|
||||
row_number = self.preview_manager.row_number
|
||||
with db.Session() as session:
|
||||
track = session.get(Tracks, track_id)
|
||||
if track:
|
||||
# Save intro as millisends rounded to nearest 0.1
|
||||
# second because editor spinbox only resolves to 0.1
|
||||
# seconds
|
||||
intro = round(self.preview_manager.get_playtime() / 100) * 100
|
||||
track.intro = intro
|
||||
session.commit()
|
||||
self.preview_manager.set_intro(intro)
|
||||
self.active_tab().source_model.refresh_row(session, row_number)
|
||||
self.active_tab().source_model.invalidate_row(row_number)
|
||||
|
||||
def preview_start(self) -> None:
|
||||
"""Restart preview"""
|
||||
|
||||
# TODO
|
||||
pass
|
||||
self.preview_manager.restart()
|
||||
|
||||
def rename_playlist(self) -> None:
|
||||
"""
|
||||
|
||||
@ -35,7 +35,7 @@ from PyQt6.QtWidgets import (
|
||||
# Third party imports
|
||||
|
||||
# App imports
|
||||
from classes import Col, MusicMusterSignals
|
||||
from classes import Col, MusicMusterSignals, TrackInfo
|
||||
from config import Config
|
||||
from dialogs import TrackSelectDialog
|
||||
from helpers import (
|
||||
@ -644,22 +644,26 @@ class PlaylistTab(QTableView):
|
||||
self.source_model.delete_rows(self.selected_model_row_numbers())
|
||||
self.clear_selection()
|
||||
|
||||
def get_selected_row_track_path(self) -> str:
|
||||
def get_selected_row_track_info(self) -> Optional[TrackInfo]:
|
||||
"""
|
||||
Return the path of the selected row. If no row selected or selected
|
||||
row does not have a track, return empty string.
|
||||
Return the track_path, track_id and row number of the selected
|
||||
row. If no row selected or selected row does not have a track,
|
||||
return None.
|
||||
"""
|
||||
|
||||
log.debug("get_selected_row_track_path() called")
|
||||
selected_row = self.get_selected_row()
|
||||
if selected_row is None:
|
||||
return None
|
||||
|
||||
model_row_number = self.source_model_selected_row_number()
|
||||
if model_row_number is None:
|
||||
result = ""
|
||||
return None
|
||||
else:
|
||||
result = self.source_model.get_row_track_path(model_row_number)
|
||||
|
||||
log.debug(f"get_selected_row_track_path() returned: {result=}")
|
||||
return result
|
||||
track_id = self.source_model.get_row_track_id(model_row_number)
|
||||
if not track_id:
|
||||
return None
|
||||
else:
|
||||
return TrackInfo(track_id, selected_row)
|
||||
|
||||
def get_selected_row(self) -> Optional[int]:
|
||||
"""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user