This commit is contained in:
tsi-billypom 2025-04-04 10:02:02 -04:00
parent 6121684c17
commit 5875776442
3 changed files with 102 additions and 69 deletions

View File

@ -74,7 +74,7 @@ class AudioVisualizer(QtWidgets.QWidget):
# Convert to decibels (20*log10 is the standard formula for amplitude to dB) # Convert to decibels (20*log10 is the standard formula for amplitude to dB)
db_values = 20 * np.log10(amplitudes) db_values = 20 * np.log10(amplitudes)
# Clip very low values to have a reasonable floor (e.g. -96dB) # Clip very low values to have a reasonable floor (e.g. -96dB)
db_values = np.maximum(db_values, -2000) db_values = np.maximum(db_values, -96)
return db_values return db_values
def set_rs(self, rs): def set_rs(self, rs):

168
main.py
View File

@ -25,6 +25,7 @@ from PyQt5.QtWidgets import (
QStatusBar, QStatusBar,
) )
from PyQt5.QtCore import ( from PyQt5.QtCore import (
QSize,
QUrl, QUrl,
QTimer, QTimer,
Qt, Qt,
@ -221,9 +222,9 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.playbackSlider.sliderReleased.connect( self.playbackSlider.sliderReleased.connect(
lambda: self.player.setPosition(self.playbackSlider.value()) lambda: self.player.setPosition(self.playbackSlider.value())
) # sliderReleased works better than sliderMoved ) # sliderReleased works better than sliderMoved
self.volumeSlider.sliderMoved[int].connect(lambda: self.volume_changed()) self.volumeSlider.sliderMoved[int].connect(lambda: self.on_volume_changed())
self.speedSlider.sliderMoved.connect( self.speedSlider.sliderMoved.connect(
lambda: self.speed_changed(self.speedSlider.value()) lambda: self.on_speed_changed(self.speedSlider.value())
) )
self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
self.previousButton.clicked.connect(self.on_previous_clicked) self.previousButton.clicked.connect(self.on_previous_clicked)
@ -276,18 +277,12 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.delete_album_art_for_current_song self.delete_album_art_for_current_song
) )
def load_config(self) -> None: # _________________
"""does what it says""" # | |
cfg_file = ( # | |
Path(user_config_dir(appname="musicpom", appauthor="billypom")) # | Built-in Events |
/ "config.ini" # | |
) # |_________________|
self.config.read(cfg_file)
debug("CONFIG LOADED")
def get_thread_pool(self) -> QThreadPool:
"""Returns the threadpool instance"""
return self.threadpool
def resizeEvent(self, a0: typing.Optional[QResizeEvent]) -> None: def resizeEvent(self, a0: typing.Optional[QResizeEvent]) -> None:
"""Do something when the window resizes""" """Do something when the window resizes"""
@ -310,21 +305,87 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
if a0 is not None: if a0 is not None:
super().closeEvent(a0) super().closeEvent(a0)
def show_status_bar_message(self, message: str, timeout: int | None = None) -> None: # ____________________
""" # | |
Show a `message` in the status bar for a length of time - `timeout` in ms # | |
""" # | On action handlers |
if timeout: # | |
self.status_bar.showMessage(message, timeout) # |____________________|
def on_volume_changed(self) -> None:
"""Handles volume changes"""
try:
self.current_volume = self.volumeSlider.value()
self.player.setVolume(self.current_volume)
self.volumeLabel.setText(str(self.current_volume))
except Exception as e:
error(f"main.py on_volume_changed() | Changing volume error: {e}")
def on_speed_changed(self, rate: int) -> None:
"""Handles playback speed changes"""
self.player.setPlaybackRate(rate / 50)
self.speedLabel.setText("{:.2f}".format(rate / 50))
def on_play_clicked(self) -> None:
"""Updates the Play & Pause buttons when clicked"""
if self.player.state() == QMediaPlayer.State.PlayingState:
self.player.pause()
self.playButton.setText("▶️")
else: else:
self.status_bar.showMessage(message) if self.player.state() == QMediaPlayer.State.PausedState:
self.player.play()
self.playButton.setText("⏸️")
else:
self.play_audio_file()
self.playButton.setText("👽")
def on_previous_clicked(self) -> None:
""""""
# TODO: implement this
debug("main.py on_previous_clicked()")
def on_next_clicked(self) -> None:
""""""
# TODO: implement this
debug("main.py on_next_clicked()")
# ____________________
# | |
# | |
# | Verbs |
# | |
# |____________________|
def load_config(self) -> None:
"""does what it says"""
cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom"))
/ "config.ini"
)
self.config.read(cfg_file)
debug("CONFIG LOADED")
def get_thread_pool(self) -> QThreadPool:
"""Returns the threadpool instance"""
return self.threadpool
def set_permanent_status_bar_message(self, message: str) -> None: def set_permanent_status_bar_message(self, message: str) -> None:
""" """
Sets the permanent message label in the status bar Sets the permanent message label in the status bar
""" """
# what does this do?
self.permanent_status_label.setText(message) self.permanent_status_label.setText(message)
def show_status_bar_message(self, message: str, timeout: int | None = None) -> None:
"""
Show a `message` in the status bar for a length of time - `timeout` in ms
(bottom left)
"""
if timeout:
self.status_bar.showMessage(message, timeout)
else:
self.status_bar.showMessage(message)
def play_audio_file(self) -> None: def play_audio_file(self) -> None:
""" """
Start playback of `tableView.current_song_filepath` & moves playback slider Start playback of `tableView.current_song_filepath` & moves playback slider
@ -359,10 +420,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
if "TIT2" in self.current_song_metadata if "TIT2" in self.current_song_metadata
else None else None
) )
debug(artist)
debug(title)
debug(album)
self.artistLabel.setText(artist) self.artistLabel.setText(artist)
self.albumLabel.setText(album) self.albumLabel.setText(album)
self.titleLabel.setText(title) self.titleLabel.setText(title)
@ -414,7 +471,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
def delete_album_art_for_current_song(self) -> None: def delete_album_art_for_current_song(self) -> None:
"""Handles deleting the ID3 tag APIC (album art) for current song""" """Handles deleting the ID3 tag APIC (album art) for current song"""
file = self.tableView.get_current_song_filepath() file = self.tableView.get_current_song_filepath()
# delete APIC data
try: try:
audio = ID3(file) audio = ID3(file)
debug(audio) debug(audio)
@ -430,11 +486,17 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
error( error(
f"delete_album_art_for_current_song() | Error processing this file:\t {file}\n{exctype}\n{value}\n{traceback.format_exc()}" f"delete_album_art_for_current_song() | Error processing this file:\t {file}\n{exctype}\n{value}\n{traceback.format_exc()}"
) )
return
# Load the default album artwork in the qgraphicsview # Load the default album artwork in the qgraphicsview
album_art_data = self.tableView.get_current_song_album_art() # album_art_data = self.tableView.get_current_song_album_art()
album_art_data = get_album_art(None) album_art_data = get_album_art(None)
self.albumGraphicsView.load_album_art(album_art_data) self.albumGraphicsView.load_album_art(album_art_data)
def process_probe(self, buff) -> None:
"""Audio visualizer buffer processing"""
buff.startTime()
self.update_audio_visualization()
def update_audio_visualization(self) -> None: def update_audio_visualization(self) -> None:
"""Handles updating points on the pyqtgraph visual""" """Handles updating points on the pyqtgraph visual"""
if self.audio_visualizer.use_decibels: if self.audio_visualizer.use_decibels:
@ -446,8 +508,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
if len(y) == 0: if len(y) == 0:
return return
# print(y)
# if self.audio_visualizer._plot_item is None: # if self.audio_visualizer._plot_item is None:
# thanks cursor sonnet whatever # thanks cursor sonnet whatever
self.PlotWidget.clear() self.PlotWidget.clear()
@ -493,40 +553,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
f"{int(duration_minutes):02d}:{int(duration_seconds):02d}" f"{int(duration_minutes):02d}:{int(duration_seconds):02d}"
) )
def volume_changed(self) -> None:
"""Handles volume changes"""
try:
self.current_volume = self.volumeSlider.value()
self.player.setVolume(self.current_volume)
self.volumeLabel.setText(str(self.current_volume))
except Exception as e:
error(f"main.py volume_changed() | Changing volume error: {e}")
def speed_changed(self, rate: int) -> None:
"""Handles playback speed changes"""
self.player.setPlaybackRate(rate / 50)
self.speedLabel.setText("{:.2f}".format(rate / 50))
def on_play_clicked(self) -> None:
"""Updates the Play & Pause buttons when clicked"""
if self.player.state() == QMediaPlayer.State.PlayingState:
self.player.pause()
self.playButton.setText("▶️")
else:
if self.player.state() == QMediaPlayer.State.PausedState:
self.player.play()
self.playButton.setText("⏸️")
else:
self.play_audio_file()
self.playButton.setText("👽")
def on_previous_clicked(self) -> None:
""""""
debug("main.py on_previous_clicked()")
def on_next_clicked(self) -> None:
debug("main.py on_next_clicked()")
def add_latest_playlist_to_tree(self) -> None: def add_latest_playlist_to_tree(self) -> None:
"""Refreshes the playlist tree""" """Refreshes the playlist tree"""
self.playlistTreeView.add_latest_playlist_to_tree() self.playlistTreeView.add_latest_playlist_to_tree()
@ -555,6 +581,13 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
""" """
self.show_status_bar_message(data) self.show_status_bar_message(data)
# ____________________
# | |
# | |
# | menubar verbs |
# | |
# |____________________|
# File # File
def create_playlist(self) -> None: def create_playlist(self) -> None:
@ -612,11 +645,6 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
initialize_db() initialize_db()
self.tableView.load_music_table() self.tableView.load_music_table()
def process_probe(self, buff) -> None:
"""Audio visualizer buffer processing"""
buff.startTime()
self.update_audio_visualization()
if __name__ == "__main__": if __name__ == "__main__":
# logging setup # logging setup
@ -689,5 +717,9 @@ if __name__ == "__main__":
# qdarktheme.setup_theme("auto") # qdarktheme.setup_theme("auto")
# Show the UI # Show the UI
ui = ApplicationWindow(clipboard) ui = ApplicationWindow(clipboard)
# window size
width, height = tuple(config.get("settings", "window_size").split(","))
window_size = QSize(int(width), int(height))
ui.resize(window_size)
ui.show() ui.show()
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@ -13,6 +13,7 @@ playlist_relative_path = /relative/suffix/for/playlist/items
# Which file types are scanned # Which file types are scanned
extensions = mp3,wav,ogg,flac extensions = mp3,wav,ogg,flac
volume = 100 volume = 100
window_size=1152,894
[table] [table]
# Music table options # Music table options