171 lines
7.1 KiB
Python
171 lines
7.1 KiB
Python
import DBA
|
|
from ui import Ui_MainWindow
|
|
from PyQt5.QtWidgets import QMainWindow, QApplication
|
|
import qdarktheme
|
|
from PyQt5.QtCore import QUrl, QTimer, QFile, QTextStream
|
|
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QAudioProbe
|
|
from PyQt5.QtGui import QStandardItem, QStandardItemModel
|
|
from utils import scan_for_music
|
|
from utils import initialize_library_database
|
|
from utils import AudioVisualizer
|
|
from pyqtgraph import mkBrush
|
|
from components import MusicTable
|
|
|
|
|
|
class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|
def __init__(self, qapp):
|
|
super(ApplicationWindow, self).__init__()
|
|
self.setupUi(self)
|
|
self.setWindowTitle('MusicPom')
|
|
self.selected_song_filepath = None
|
|
self.current_song_filepath = None
|
|
self.current_song_metadata = None
|
|
self.qapp = qapp
|
|
print(f'ApplicationWindow self.qapp: {self.qapp}')
|
|
self.tableView.load_qapp(self.qapp)
|
|
|
|
global stopped
|
|
stopped = False
|
|
|
|
# Initialization
|
|
self.player = QMediaPlayer() # Audio player
|
|
self.probe = QAudioProbe() # Get audio data
|
|
self.timer = QTimer(self) # Audio timing things
|
|
# self.model = QStandardItemModel() # Table library listing
|
|
self.audio_visualizer = AudioVisualizer(self.player)
|
|
self.current_volume = 50
|
|
self.player.setVolume(self.current_volume)
|
|
|
|
# Audio probe for processing audio signal in real time
|
|
# Provides faster updates than move_slider
|
|
self.probe.setSource(self.player)
|
|
self.probe.audioBufferProbed.connect(self.process_probe)
|
|
|
|
# Slider Timer (realtime playback feedback horizontal bar)
|
|
self.timer.start(150) # 150ms update interval solved problem with drag seeking halting playback
|
|
self.timer.timeout.connect(self.move_slider)
|
|
|
|
# Graphics plot
|
|
self.PlotWidget.setXRange(0,100,padding=0) # x axis range
|
|
self.PlotWidget.setYRange(0,0.3,padding=0) # y axis range
|
|
self.PlotWidget.getAxis('bottom').setTicks([]) # Remove x-axis ticks
|
|
self.PlotWidget.getAxis('bottom').setLabel('') # Remove x-axis label
|
|
self.PlotWidget.setLogMode(False,False)
|
|
# Remove y-axis labels and decorations
|
|
self.PlotWidget.getAxis('left').setTicks([]) # Remove y-axis ticks
|
|
self.PlotWidget.getAxis('left').setLabel('') # Remove y-axis label
|
|
|
|
|
|
# Connections
|
|
# ! FIXME moving the slider while playing is happening frequently causes playback to halt - the pyqtgraph is also affected by this
|
|
self.playbackSlider.sliderMoved[int].connect(lambda: self.player.setPosition(self.playbackSlider.value())) # Move slidet to adjust playback time
|
|
self.volumeSlider.sliderMoved[int].connect(lambda: self.volume_changed()) # Move slider to adjust volume
|
|
self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
|
|
# self.pauseButton.clicked.connect(self.on_pause_clicked)
|
|
self.previousButton.clicked.connect(self.on_previous_clicked) # Click to previous song
|
|
self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song
|
|
# self.tableView.clicked.connect(self.set_clicked_cell_filepath)
|
|
self.actionPreferences.triggered.connect(self.actionPreferencesClicked) # Open preferences menu
|
|
self.actionScanLibraries.triggered.connect(self.scan_libraries) # Scan library
|
|
self.actionClearDatabase.triggered.connect(initialize_library_database) # Clear database
|
|
self.tableView.doubleClicked.connect(self.play_audio_file) # Double click to play song
|
|
|
|
|
|
def play_audio_file(self):
|
|
"""Start playback of selected track & moves playback slider"""
|
|
self.current_song_metadata = self.tableView.get_current_song_metadata() # get metadata
|
|
url = QUrl.fromLocalFile(self.tableView.get_current_song_filepath()) # read the file
|
|
content = QMediaContent(url) # load the audio content
|
|
self.player.setMedia(content) # what content to play
|
|
self.player.play() # play
|
|
self.move_slider() # mover
|
|
|
|
# assign metadata
|
|
# FIXME when i change tinytag to something else
|
|
artist = self.current_song_metadata.artist
|
|
album = self.current_song_metadata.album
|
|
title = self.current_song_metadata.title
|
|
# edit labels
|
|
self.artistLabel.setText(artist)
|
|
self.albumLabel.setText(album)
|
|
self.titleLabel.setText(title)
|
|
|
|
def update_audio_visualization(self):
|
|
"""Handles upading points on the pyqtgraph visual"""
|
|
self.clear_audio_visualization()
|
|
self.y = self.audio_visualizer.get_amplitudes()
|
|
self.x = [i for i in range(len(self.y))]
|
|
self.PlotWidget.plot(self.x, self.y, fillLevel=0, fillBrush=mkBrush('b'))
|
|
self.PlotWidget.show()
|
|
|
|
def clear_audio_visualization(self):
|
|
self.PlotWidget.clear()
|
|
|
|
def move_slider(self):
|
|
"""Handles moving the playback slider"""
|
|
if stopped:
|
|
return
|
|
else:
|
|
# Update the slider
|
|
if self.player.state() == QMediaPlayer.PlayingState:
|
|
self.playbackSlider.setMinimum(0)
|
|
self.playbackSlider.setMaximum(self.player.duration())
|
|
slider_position = self.player.position()
|
|
self.playbackSlider.setValue(slider_position)
|
|
|
|
current_minutes, current_seconds = divmod(slider_position / 1000, 60)
|
|
duration_minutes, duration_seconds = divmod(self.player.duration() / 1000, 60)
|
|
|
|
self.startTimeLabel.setText(f"{int(current_minutes):02d}:{int(current_seconds):02d}")
|
|
self.endTimeLabel.setText(f"{int(duration_minutes):02d}:{int(duration_seconds):02d}")
|
|
|
|
def volume_changed(self):
|
|
"""Handles volume changes"""
|
|
try:
|
|
self.current_volume = self.volumeSlider.value()
|
|
self.player.setVolume(self.current_volume)
|
|
except Exception as e:
|
|
print(f"Changing volume error: {e}")
|
|
|
|
def on_play_clicked(self):
|
|
"""Updates the Play & Pause buttons when clicked"""
|
|
if self.player.state() == QMediaPlayer.PlayingState:
|
|
self.player.pause()
|
|
self.playButton.setText("▶️")
|
|
else:
|
|
if self.player.state() == QMediaPlayer.PausedState:
|
|
self.player.play()
|
|
self.playButton.setText("⏸️")
|
|
else:
|
|
self.play_audio_file()
|
|
self.playButton.setText("⏸️")
|
|
|
|
def on_previous_clicked(self):
|
|
""""""
|
|
print('previous')
|
|
|
|
def on_next_clicked(self):
|
|
print('next')
|
|
|
|
def actionPreferencesClicked(self):
|
|
print('preferences')
|
|
|
|
def scan_libraries(self):
|
|
scan_for_music()
|
|
# refresh datatable
|
|
|
|
def process_probe(self, buff):
|
|
buff.startTime()
|
|
self.update_audio_visualization()
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
app = QApplication(sys.argv)
|
|
print(f'main.py app: {app}')
|
|
qdarktheme.setup_theme()
|
|
ui = ApplicationWindow(app)
|
|
ui.show()
|
|
sys.exit(app.exec_()) |