fuck u sonnet

This commit is contained in:
billypom on debian 2025-03-31 00:19:18 -04:00
parent dcdfeac607
commit 50c54c709e
6 changed files with 159 additions and 29 deletions

View File

@ -1,6 +1,7 @@
import os import os
import tempfile import tempfile
from logging import debug from logging import debug
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QAbstractScrollArea, QAbstractScrollArea,
QGraphicsPixmapItem, QGraphicsPixmapItem,
@ -32,6 +33,9 @@ class AlbumArtGraphicsView(QGraphicsView):
self.setAcceptDrops(True) self.setAcceptDrops(True)
self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.setMinimumSize(200, 200) self.setMinimumSize(200, 200)
self.setMaximumSize(200, 200) # Also set maximum size to maintain square shape
# self.setSizePolicy(Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed) # Keep fixed size
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.setSizeAdjustPolicy(QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored) self.setSizeAdjustPolicy(QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored)

View File

@ -23,9 +23,61 @@ class AudioVisualizer(QtWidgets.QWidget):
self.amps = np.array([]) self.amps = np.array([])
self._plot_item = None self._plot_item = None
self._x_data = np.arange(self.x_resolution) self._x_data = np.arange(self.x_resolution)
self.use_decibels = True # Set to True to use decibel scale
# Generate logarithmic frequency scale (20Hz - 20kHz)
self.min_freq = 20
self.max_freq = 23000
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):
"""Returns frequency ticks for x-axis display
Args:
num_ticks (int): Approximate number of ticks to display
Returns:
list: List of tuples with (position, label) for each tick
"""
# Standard frequency bands for audio visualization
standard_freqs = [20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000]
# Map frequencies to x-axis positions
ticks = []
for freq in standard_freqs:
# Find closest index to this frequency
idx = np.argmin(np.abs(self.frequency_values - freq))
# Format labels: Hz for <1000, kHz for >=1000
if freq < 1000:
label = f"{freq}Hz"
else:
label = f"{freq/1000:.0f}kHz"
ticks.append((idx, label))
return ticks
def get_frequencies(self):
"""Return the frequency values for x-axis"""
return self.frequency_values
def get_amplitudes(self): def get_amplitudes(self):
return self.amps return self.amps
def get_decibels(self):
"""Convert amplitude values to decibel scale
Formula: dB = 20 * log10(amplitude)
For normalized amplitude values, this gives a range of approx -96dB to 0dB
With a noise floor cutoff at around -96dB (for very small values)
"""
# Avoid log(0) by adding a small epsilon
epsilon = 1e-10
amplitudes = np.maximum(self.amps, epsilon)
# Convert to decibels (20*log10 is the standard formula for amplitude to dB)
db_values = 20 * np.log10(amplitudes)
# Clip very low values to have a reasonable floor (e.g. -96dB)
db_values = np.maximum(db_values, -96)
return db_values
def set_amplitudes(self, amps): def set_amplitudes(self, amps):
self.amps = np.array(amps) self.amps = np.array(amps)

48
main.py
View File

@ -182,25 +182,32 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.timer.start(100) self.timer.start(100)
self.timer.timeout.connect(self.move_slider) self.timer.timeout.connect(self.move_slider)
# Set fixed size for album art
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 self.PlotWidget.setXRange(0, self.analyzer_x_resolution, padding=0) # x axis range
self.PlotWidget.setYRange(0, 1, padding=0) # y axis range self.PlotWidget.setYRange(-96, 0, padding=0) # y axis range for decibels (-96dB to 0dB)
self.PlotWidget.setLogMode(False, False) self.PlotWidget.setLogMode(x=False, y=False) # Logarithmic x-axis for frequency display
self.PlotWidget.setMouseEnabled(x=False, y=False) self.PlotWidget.setMouseEnabled(x=False, y=False)
# 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)
# Remove x-axis ticks
# ticks = ['20', '31.25', '62.5', '125', '250', '500', '1000', '2000', '4000', '10000', '20000']
# self.PlotWidget.getAxis("bottom").setTicks([])
# self.PlotWidget.getAxis("bottom").setLabel("") # Remove x-axis label
# ticks = nparray([0, 31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 15000, 20000])
# Remove y-axis labels and decorations # Add tick marks for common decibel values (expanded range)
# self.PlotWidget.getAxis("left").setTicks([[(str(tick), tick) for tick in ticks]]) y_ticks = [(-84, '-84dB'), (-60, '-60dB'),
# self.PlotWidget.getAxis("left").setTicks([]) (-36, '-36dB'), (-12, '-12dB'), (0, '0dB')]
# self.PlotWidget.getAxis("left").setLabel("") # Remove y-axis label self.PlotWidget.getAxis('left').setTicks([y_ticks])
# Add frequency ticks on x-axis
freq_ticks = self.audio_visualizer.get_frequency_ticks()
self.PlotWidget.getAxis('bottom').setTicks([freq_ticks])
# Display grid for better readability
self.PlotWidget.showGrid(x=True, y=True) self.PlotWidget.showGrid(x=True, y=True)
# Connections # Connections
@ -424,22 +431,29 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.albumGraphicsView.load_album_art(album_art_data) self.albumGraphicsView.load_album_art(album_art_data)
def update_audio_visualization(self) -> None: def update_audio_visualization(self) -> None:
"""Handles upading points on the pyqtgraph visual""" """Handles updating points on the pyqtgraph visual"""
if self.audio_visualizer.use_decibels:
# Use decibel values instead of raw amplitudes
y = self.audio_visualizer.get_decibels()
else:
y = self.audio_visualizer.get_amplitudes() y = self.audio_visualizer.get_amplitudes()
if len(y) == 0: if len(y) == 0:
return return
if self.audio_visualizer._plot_item is None: # if self.audio_visualizer._plot_item is None:
# thanks cursor sonnet whatever
self.PlotWidget.clear() self.PlotWidget.clear()
# Use the actual frequency values for x-axis
self.audio_visualizer._plot_item = self.PlotWidget.plot( self.audio_visualizer._plot_item = self.PlotWidget.plot(
self.audio_visualizer._x_data, 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=0, fillLevel=-96 if self.audio_visualizer.use_decibels else 0, # Fill from -96dB for decibel scale
fillBrush=mkBrush("b") 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)
def clear_audio_visualization(self) -> None: def clear_audio_visualization(self) -> None:
self.PlotWidget.clear() self.PlotWidget.clear()

16
ui.py
View File

@ -25,11 +25,19 @@ class Ui_MainWindow(object):
self.verticalLayout.setSpacing(6) self.verticalLayout.setSpacing(6)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.hLayoutHead = QtWidgets.QHBoxLayout() self.hLayoutHead = QtWidgets.QHBoxLayout()
self.hLayoutHead.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.hLayoutHead.setObjectName("hLayoutHead") self.hLayoutHead.setObjectName("hLayoutHead")
self.vlayoutAlbumArt = QtWidgets.QVBoxLayout() self.vlayoutAlbumArt = QtWidgets.QVBoxLayout()
self.vlayoutAlbumArt.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) self.vlayoutAlbumArt.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.vlayoutAlbumArt.setObjectName("vlayoutAlbumArt") self.vlayoutAlbumArt.setObjectName("vlayoutAlbumArt")
self.albumGraphicsView = AlbumArtGraphicsView(self.centralwidget) self.albumGraphicsView = AlbumArtGraphicsView(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.albumGraphicsView.sizePolicy().hasHeightForWidth())
self.albumGraphicsView.setSizePolicy(sizePolicy)
self.albumGraphicsView.setMinimumSize(QtCore.QSize(200, 200))
self.albumGraphicsView.setMaximumSize(QtCore.QSize(200, 200))
self.albumGraphicsView.setObjectName("albumGraphicsView") self.albumGraphicsView.setObjectName("albumGraphicsView")
self.vlayoutAlbumArt.addWidget(self.albumGraphicsView) self.vlayoutAlbumArt.addWidget(self.albumGraphicsView)
self.hLayoutHead.addLayout(self.vlayoutAlbumArt) self.hLayoutHead.addLayout(self.vlayoutAlbumArt)
@ -37,8 +45,10 @@ class Ui_MainWindow(object):
self.vLayoutSongDetails.setObjectName("vLayoutSongDetails") self.vLayoutSongDetails.setObjectName("vLayoutSongDetails")
self.hLayoutHead.addLayout(self.vLayoutSongDetails) self.hLayoutHead.addLayout(self.vLayoutSongDetails)
self.vLayoutPlaybackVisuals = QtWidgets.QVBoxLayout() self.vLayoutPlaybackVisuals = QtWidgets.QVBoxLayout()
self.vLayoutPlaybackVisuals.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
self.vLayoutPlaybackVisuals.setObjectName("vLayoutPlaybackVisuals") self.vLayoutPlaybackVisuals.setObjectName("vLayoutPlaybackVisuals")
self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
self.horizontalLayout.setObjectName("horizontalLayout") self.horizontalLayout.setObjectName("horizontalLayout")
self.playbackSlider = QtWidgets.QSlider(self.centralwidget) self.playbackSlider = QtWidgets.QSlider(self.centralwidget)
self.playbackSlider.setOrientation(QtCore.Qt.Horizontal) self.playbackSlider.setOrientation(QtCore.Qt.Horizontal)
@ -91,6 +101,12 @@ class Ui_MainWindow(object):
self.horizontalLayout.setStretch(3, 1) self.horizontalLayout.setStretch(3, 1)
self.vLayoutPlaybackVisuals.addLayout(self.horizontalLayout) self.vLayoutPlaybackVisuals.addLayout(self.horizontalLayout)
self.PlotWidget = PlotWidget(self.centralwidget) self.PlotWidget = PlotWidget(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.PlotWidget.sizePolicy().hasHeightForWidth())
self.PlotWidget.setSizePolicy(sizePolicy)
self.PlotWidget.setMaximumSize(QtCore.QSize(16777215, 150))
self.PlotWidget.setObjectName("PlotWidget") self.PlotWidget.setObjectName("PlotWidget")
self.vLayoutPlaybackVisuals.addWidget(self.PlotWidget) self.vLayoutPlaybackVisuals.addWidget(self.PlotWidget)
self.hLayoutHead.addLayout(self.vLayoutPlaybackVisuals) self.hLayoutHead.addLayout(self.vLayoutPlaybackVisuals)

45
ui.ui
View File

@ -28,13 +28,35 @@
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="hLayoutHead" stretch="1,0,6"> <layout class="QHBoxLayout" name="hLayoutHead" stretch="1,0,6">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item> <item>
<layout class="QVBoxLayout" name="vlayoutAlbumArt"> <layout class="QVBoxLayout" name="vlayoutAlbumArt">
<property name="sizeConstraint"> <property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum> <enum>QLayout::SetFixedSize</enum>
</property> </property>
<item> <item>
<widget class="AlbumArtGraphicsView" name="albumGraphicsView"/> <widget class="AlbumArtGraphicsView" name="albumGraphicsView">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@ -43,8 +65,14 @@
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="vLayoutPlaybackVisuals"> <layout class="QVBoxLayout" name="vLayoutPlaybackVisuals">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="4,0,4,1"> <layout class="QHBoxLayout" name="horizontalLayout" stretch="4,0,4,1">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item> <item>
<widget class="QSlider" name="playbackSlider"> <widget class="QSlider" name="playbackSlider">
<property name="orientation"> <property name="orientation">
@ -137,7 +165,20 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="PlotWidget" name="PlotWidget" native="true"/> <widget class="PlotWidget" name="PlotWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>150</height>
</size>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>

View File

@ -56,6 +56,9 @@ class FFTAnalyser(QtCore.QThread):
start_index : start_index + sample_count start_index : start_index + sample_count
] # samples to analyse ] # samples to analyse
# Use a window function to reduce spectral leakage
window = np.hanning(len(v_sample))
v_sample = v_sample * window
# use FFTs to analyse frequency and amplitudes # use FFTs to analyse frequency and amplitudes
fourier = np.fft.fft(v_sample) fourier = np.fft.fft(v_sample)
@ -117,11 +120,11 @@ class FFTAnalyser(QtCore.QThread):
or self.player.state() or self.player.state()
in (self.player.PausedState, self.player.StoppedState) in (self.player.PausedState, self.player.StoppedState)
): ):
self.points[n] -= self.points[n] / 10 # fade out self.points[n] -= self.points[n] / 5 # fade out
elif abs(self.points[n] - amp) > self.visual_delta_threshold: elif abs(self.points[n] - amp) > self.visual_delta_threshold:
self.points[n] = amp self.points[n] = amp
if self.points[n] < 1: if self.points[n] < 1:
self.points[n] = 1e-5 self.points[n] = 1e-12
# interpolate points # interpolate points
rs = gaussian_filter1d(self.points, sigma=1.5) rs = gaussian_filter1d(self.points, sigma=1.5)