trying other stuff
This commit is contained in:
parent
a115a3c423
commit
c906922372
@ -11,7 +11,7 @@ class AudioVisualizer(QtWidgets.QWidget):
|
|||||||
self.media_player = media_player
|
self.media_player = media_player
|
||||||
self.x_resolution = x_resolution
|
self.x_resolution = x_resolution
|
||||||
self.fft_analyser = FFTAnalyser(self.media_player, self.x_resolution)
|
self.fft_analyser = FFTAnalyser(self.media_player, self.x_resolution)
|
||||||
self.fft_analyser.calculated_visual.connect(self.set_amplitudes)
|
self.fft_analyser.calculatedVisual.connect(self.set_amplitudes)
|
||||||
self.fft_analyser.start()
|
self.fft_analyser.start()
|
||||||
self.amps = np.array([])
|
self.amps = np.array([])
|
||||||
self._plot_item = None
|
self._plot_item = None
|
||||||
@ -63,7 +63,7 @@ class AudioVisualizer(QtWidgets.QWidget):
|
|||||||
With a noise floor cutoff at around -96dB (for very small values)
|
With a noise floor cutoff at around -96dB (for very small values)
|
||||||
"""
|
"""
|
||||||
# Avoid log(0) by adding a small epsilon
|
# Avoid log(0) by adding a small epsilon
|
||||||
epsilon = 1e-10
|
epsilon = 1e-30
|
||||||
amplitudes = np.maximum(self.amps, epsilon)
|
amplitudes = np.maximum(self.amps, epsilon)
|
||||||
# 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)
|
||||||
@ -72,4 +72,9 @@ class AudioVisualizer(QtWidgets.QWidget):
|
|||||||
return db_values
|
return db_values
|
||||||
|
|
||||||
def set_amplitudes(self, amps):
|
def set_amplitudes(self, amps):
|
||||||
|
"""
|
||||||
|
This function is hooked into the calculatedVisual signal from FFTAnalyzer() object
|
||||||
|
Amps are assigned here, based on values passed by the signal
|
||||||
|
"""
|
||||||
|
# self.amps = np.maximum(np.array(amps), 1e-12) # Set a very small threshold
|
||||||
self.amps = np.array(amps)
|
self.amps = np.array(amps)
|
||||||
|
|||||||
5
main.py
5
main.py
@ -11,6 +11,7 @@ from mutagen.id3 import ID3
|
|||||||
from mutagen.id3._frames import APIC
|
from mutagen.id3._frames import APIC
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from numpy import where as npwhere
|
||||||
from appdirs import user_config_dir
|
from appdirs import user_config_dir
|
||||||
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
|
||||||
@ -161,7 +162,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
|
|||||||
self.config.read(self.cfg_file)
|
self.config.read(self.cfg_file)
|
||||||
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 = 100
|
||||||
self.audio_visualizer: AudioVisualizer = AudioVisualizer(
|
self.audio_visualizer: AudioVisualizer = AudioVisualizer(
|
||||||
self.player, self.analyzer_x_resolution
|
self.player, self.analyzer_x_resolution
|
||||||
)
|
)
|
||||||
@ -446,6 +447,8 @@ 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()
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from logging import debug, info
|
|||||||
class FFTAnalyser(QtCore.QThread):
|
class FFTAnalyser(QtCore.QThread):
|
||||||
"""Analyses a song using FFTs."""
|
"""Analyses a song using FFTs."""
|
||||||
|
|
||||||
calculated_visual = QtCore.pyqtSignal(np.ndarray)
|
calculatedVisual = QtCore.pyqtSignal(np.ndarray)
|
||||||
|
|
||||||
def __init__(self, player, x_resolution): # noqa: F821
|
def __init__(self, player, x_resolution): # noqa: F821
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -25,7 +25,7 @@ class FFTAnalyser(QtCore.QThread):
|
|||||||
# of the audio at a specific point in time
|
# of the audio at a specific point in time
|
||||||
# in this case, it takes 5% of the samples at some point in time
|
# in this case, it takes 5% of the samples at some point in time
|
||||||
self.sampling_window_length = 0.05
|
self.sampling_window_length = 0.05
|
||||||
self.visual_delta_threshold = 1000
|
self.visual_delta_threshold = 100
|
||||||
self.sensitivity = 10
|
self.sensitivity = 10
|
||||||
|
|
||||||
def reset_media(self):
|
def reset_media(self):
|
||||||
@ -52,9 +52,8 @@ class FFTAnalyser(QtCore.QThread):
|
|||||||
|
|
||||||
sample_count = int(self.song.frame_rate * self.sampling_window_length)
|
sample_count = int(self.song.frame_rate * self.sampling_window_length)
|
||||||
start_index = int((self.player.position() / 1000) * self.song.frame_rate)
|
start_index = int((self.player.position() / 1000) * self.song.frame_rate)
|
||||||
v_sample = self.samples[
|
# samples to analyse
|
||||||
start_index : start_index + sample_count
|
v_sample = self.samples[start_index : start_index + sample_count]
|
||||||
] # samples to analyse
|
|
||||||
|
|
||||||
# Use a window function to reduce spectral leakage
|
# Use a window function to reduce spectral leakage
|
||||||
window = np.hanning(len(v_sample))
|
window = np.hanning(len(v_sample))
|
||||||
@ -65,6 +64,7 @@ class FFTAnalyser(QtCore.QThread):
|
|||||||
freq = np.fft.fftfreq(fourier.size, d=self.sampling_window_length)
|
freq = np.fft.fftfreq(fourier.size, d=self.sampling_window_length)
|
||||||
amps = 2 / v_sample.size * np.abs(fourier)
|
amps = 2 / v_sample.size * np.abs(fourier)
|
||||||
data = np.array([freq, amps]).T
|
data = np.array([freq, amps]).T
|
||||||
|
# TEST:
|
||||||
# print(freq * .05 * self.song.frame_rate)
|
# print(freq * .05 * self.song.frame_rate)
|
||||||
|
|
||||||
# NOTE:
|
# NOTE:
|
||||||
@ -108,26 +108,29 @@ class FFTAnalyser(QtCore.QThread):
|
|||||||
# array (self.points) 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
|
if self.player.state() in (
|
||||||
|
self.player.PausedState,
|
||||||
if (
|
self.player.StoppedState,
|
||||||
self.points[n] > 0
|
|
||||||
and amp < self.points[n]
|
|
||||||
or self.player.state()
|
|
||||||
in (self.player.PausedState, self.player.StoppedState)
|
|
||||||
):
|
):
|
||||||
self.points[n] -= self.points[n] / 5 # fade out
|
# More aggressive decay when no audio is playing
|
||||||
elif abs(self.points[n] - amp) > self.visual_delta_threshold:
|
self.points[n] *= 0.7 # Faster fade out when paused/stopped
|
||||||
|
elif amp < self.points[n]:
|
||||||
|
# Faster fade for frequencies that are decreasing
|
||||||
|
self.points[n] = self.points[n] * 0.8 + amp * 0.2 # Smoother transition
|
||||||
|
else:
|
||||||
|
# Rise quickly to new peaks
|
||||||
self.points[n] = amp
|
self.points[n] = amp
|
||||||
if self.points[n] < 1:
|
|
||||||
self.points[n] = 1e-12
|
# Set a lower threshold to properly reach zero
|
||||||
|
if self.points[n] < 1e-4:
|
||||||
|
self.points[n] = 0
|
||||||
|
|
||||||
# interpolate points
|
# interpolate points
|
||||||
rs = gaussian_filter1d(self.points, sigma=1.5)
|
rs = gaussian_filter1d(self.points, sigma=1)
|
||||||
|
|
||||||
# divide by the highest sample in the song to normalise the
|
# divide by the highest sample in the song to normalise the
|
||||||
# amps in terms of decimals from 0 -> 1
|
# amps in terms of decimals from 0 -> 1
|
||||||
self.calculated_visual.emit(rs / self.max_sample)
|
self.calculatedVisual.emit(rs / self.max_sample)
|
||||||
# self.calculated_visual.emit(rs)
|
# self.calculated_visual.emit(rs)
|
||||||
# print(rs)
|
# print(rs)
|
||||||
# print(rs/self.max_sample)
|
# print(rs/self.max_sample)
|
||||||
@ -139,6 +142,6 @@ class FFTAnalyser(QtCore.QThread):
|
|||||||
try:
|
try:
|
||||||
self.calculate_amps()
|
self.calculate_amps()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.calculated_visual.emit(np.zeros(self.resolution))
|
self.calculatedVisual.emit(np.zeros(self.resolution))
|
||||||
self.start_animate = False
|
self.start_animate = False
|
||||||
time.sleep(0.033)
|
time.sleep(0.033)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user