This commit is contained in:
tsi-billypom 2025-03-31 11:22:53 -04:00
parent 50c54c709e
commit a115a3c423
3 changed files with 40 additions and 45 deletions

View File

@ -4,14 +4,7 @@ from utils import FFTAnalyser
class AudioVisualizer(QtWidgets.QWidget): class AudioVisualizer(QtWidgets.QWidget):
"""_Audio Visualizer component_ """Audio Visualizer component"""
Args:
QtWidgets (_type_): _description_
Returns:
_type_: _description_
"""
def __init__(self, media_player, x_resolution): def __init__(self, media_player, x_resolution):
super().__init__() super().__init__()
@ -28,14 +21,13 @@ class AudioVisualizer(QtWidgets.QWidget):
# Generate logarithmic frequency scale (20Hz - 20kHz) # Generate logarithmic frequency scale (20Hz - 20kHz)
self.min_freq = 20 self.min_freq = 20
self.max_freq = 23000 self.max_freq = 23000
self.frequency_values = np.logspace(np.log10(self.min_freq), np.log10(self.max_freq), self.x_resolution) self.frequency_values = np.logspace(
np.log10(self.min_freq), np.log10(self.max_freq), self.x_resolution
)
def get_frequency_ticks(self, num_ticks=10): def get_frequency_ticks(self):
"""Returns frequency ticks for x-axis display """Returns frequency ticks for x-axis display
Args:
num_ticks (int): Approximate number of ticks to display
Returns: Returns:
list: List of tuples with (position, label) for each tick list: List of tuples with (position, label) for each tick
""" """
@ -51,7 +43,7 @@ class AudioVisualizer(QtWidgets.QWidget):
if freq < 1000: if freq < 1000:
label = f"{freq}Hz" label = f"{freq}Hz"
else: else:
label = f"{freq/1000:.0f}kHz" label = f"{freq / 1000:.0f}kHz"
ticks.append((idx, label)) ticks.append((idx, label))
return ticks return ticks

51
main.py
View File

@ -12,7 +12,6 @@ from mutagen.id3._frames import APIC
from configparser import ConfigParser from configparser import ConfigParser
from pathlib import Path from pathlib import Path
from appdirs import user_config_dir from appdirs import user_config_dir
from numpy import array as nparray
from logging import debug, error, warning, basicConfig, INFO, DEBUG from logging import debug, error, warning, basicConfig, INFO, DEBUG
from ui import Ui_MainWindow from ui import Ui_MainWindow
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
@ -163,7 +162,9 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.player: QMediaPlayer = QMediaPlayer() # Audio player object self.player: QMediaPlayer = QMediaPlayer() # Audio player object
self.probe: QAudioProbe = QAudioProbe() # Gets audio data self.probe: QAudioProbe = QAudioProbe() # Gets audio data
self.analyzer_x_resolution = 150 self.analyzer_x_resolution = 150
self.audio_visualizer: AudioVisualizer = AudioVisualizer(self.player, self.analyzer_x_resolution) self.audio_visualizer: AudioVisualizer = AudioVisualizer(
self.player, self.analyzer_x_resolution
)
self.timer = QTimer(self) # Audio timing things self.timer = QTimer(self) # Audio timing things
self.clipboard = clipboard self.clipboard = clipboard
self.tableView.load_qapp(self) self.tableView.load_qapp(self)
@ -185,30 +186,36 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
# Set fixed size for album art # Set fixed size for album art
self.albumGraphicsView.setFixedSize(250, 250) self.albumGraphicsView.setFixedSize(250, 250)
# Make sure PlotWidget doesn't exceed album art height
self.PlotWidget.setFixedHeight(225) # Adjust to leave room for playback controls
# Graphics plot # Graphics plot
self.PlotWidget.setXRange(0, self.analyzer_x_resolution, padding=0) # x axis range # Make sure PlotWidget doesn't exceed album art height
self.PlotWidget.setYRange(-96, 0, padding=0) # y axis range for decibels (-96dB to 0dB) # Adjust to leave room for playback controls
self.PlotWidget.setLogMode(x=False, y=False) # Logarithmic x-axis for frequency display self.PlotWidget.setFixedHeight(225)
# x range
self.PlotWidget.setXRange(0, self.analyzer_x_resolution, padding=0)
# y axis range for decibals (-96db to 0db)
self.PlotWidget.setYRange(-96, 0, padding=0)
# Logarithmic x-axis for frequency display
self.PlotWidget.setLogMode(x=False, y=False)
self.PlotWidget.setMouseEnabled(x=False, y=False) self.PlotWidget.setMouseEnabled(x=False, y=False)
self.PlotWidget.showGrid(x=True, y=True)
# Performance optimizations # Performance optimizations
self.PlotWidget.setAntialiasing(False) self.PlotWidget.setAntialiasing(False)
self.PlotWidget.setDownsampling(auto=True, mode='peak') self.PlotWidget.setDownsampling(auto=True, mode="peak")
self.PlotWidget.setClipToView(True) self.PlotWidget.setClipToView(True)
# Add tick marks for common decibel values (expanded range) # Add tick marks for common decibel values (expanded range)
y_ticks = [(-84, '-84dB'), (-60, '-60dB'), y_ticks = [
(-36, '-36dB'), (-12, '-12dB'), (0, '0dB')] (-84, "-84dB"),
self.PlotWidget.getAxis('left').setTicks([y_ticks]) (-60, "-60dB"),
(-36, "-36dB"),
(-12, "-12dB"),
(0, "0dB"),
]
self.PlotWidget.getAxis("left").setTicks([y_ticks])
# Add frequency ticks on x-axis # Add frequency ticks on x-axis
freq_ticks = self.audio_visualizer.get_frequency_ticks() freq_ticks = self.audio_visualizer.get_frequency_ticks()
self.PlotWidget.getAxis('bottom').setTicks([freq_ticks]) self.PlotWidget.getAxis("bottom").setTicks([freq_ticks])
# Display grid for better readability
self.PlotWidget.showGrid(x=True, y=True)
# Connections # Connections
self.playbackSlider.sliderReleased.connect( self.playbackSlider.sliderReleased.connect(
@ -228,10 +235,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.actionExportPlaylist.triggered.connect(self.export_playlist) self.actionExportPlaylist.triggered.connect(self.export_playlist)
# EDIT MENU # EDIT MENU
self.actionPreferences.triggered.connect(self.open_preferences)
# VIEW MENU # VIEW MENU
self.actionPreferences.triggered.connect(
self.open_preferences
) # Open preferences menu
# QUICK ACTIONS MENU # QUICK ACTIONS MENU
self.actionScanLibraries.triggered.connect(self.scan_libraries) self.actionScanLibraries.triggered.connect(self.scan_libraries)
@ -448,9 +453,11 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.audio_visualizer._plot_item = self.PlotWidget.plot( self.audio_visualizer._plot_item = self.PlotWidget.plot(
self.audio_visualizer._x_data, # We'll keep using indices for drawing self.audio_visualizer._x_data, # We'll keep using indices for drawing
y, y,
pen='b', # Use pen instead of fill for better performance pen="b", # Use pen instead of fill for better performance
fillLevel=-96 if self.audio_visualizer.use_decibels else 0, # Fill from -96dB for decibel scale fillLevel=-96
fillBrush=mkBrush("b") if self.audio_visualizer.use_decibels
else 0, # Fill from -96dB for decibel scale
fillBrush=mkBrush("b"),
) )
# else: # else:
# self.audio_visualizer._plot_item.setData(self.audio_visualizer._x_data, y) # self.audio_visualizer._plot_item.setData(self.audio_visualizer._x_data, y)

View File

@ -79,12 +79,8 @@ class FFTAnalyser(QtCore.QThread):
# Logarithmic frequency scaling # Logarithmic frequency scaling
min_freq = np.min(freq[freq > 0]) # minimum positive frequency min_freq = np.min(freq[freq > 0]) # minimum positive frequency
# 20hz # 20hz
# print('min')
# print(min_freq * .05 * self.song.frame_rate)
max_freq = np.max(freq) # maximum frequency max_freq = np.max(freq) # maximum frequency
# 20khz # 20khz
# print('max')
# print(max_freq * .05 * self.song.frame_rate)
log_freqs = np.logspace(np.log10(min_freq), np.log10(max_freq), self.resolution) log_freqs = np.logspace(np.log10(min_freq), np.log10(max_freq), self.resolution)
point_samples = [] point_samples = []
@ -92,10 +88,10 @@ class FFTAnalyser(QtCore.QThread):
if not data.size: if not data.size:
return return
#for i, freq in enumerate(np.arange(0, 1, point_range), start=1): # for i, freq in enumerate(np.arange(0, 1, point_range), start=1):
for i, log_freq in enumerate(log_freqs): for i, log_freq in enumerate(log_freqs):
# get the amps which are in between the frequency range # get the amps which are in between the frequency range
#amps = data[(freq - point_range < data[:, 0]) & (data[:, 0] < freq)] # amps = data[(freq - point_range < data[:, 0]) & (data[:, 0] < freq)]
amps = data[(log_freq - point_range < data[:, 0]) & (data[:, 0] < log_freq)] amps = data[(log_freq - point_range < data[:, 0]) & (data[:, 0] < log_freq)]
if not amps.size: if not amps.size:
point_samples.append(0) point_samples.append(0)
@ -109,7 +105,7 @@ class FFTAnalyser(QtCore.QThread):
) )
# Add the point_samples to the self.points array, the reason we have a separate # Add the point_samples to the self.points array, the reason we have a separate
# array (self.bars) is so that we can fade out the previous amplitudes from # array (self.points) is so that we can fade out the previous amplitudes from
# the past # the past
for n, amp in enumerate(point_samples): for n, amp in enumerate(point_samples):
# amp *= 2 # amp *= 2