aboutsummaryrefslogtreecommitdiff
path: root/src/avp/toolkit/visualizer.py
diff options
context:
space:
mode:
authorBrianna Rainey2026-01-28 17:49:58 -0500
committerGitHub2026-01-28 17:49:58 -0500
commitf66eb99465c61232a7f649e66bee59504bb0e52c (patch)
tree40d4f2e4e7cea033e4a68da025c7d91295e71cfb /src/avp/toolkit/visualizer.py
parent864898419e810055b51e3a32fccb00a62aab9a6b (diff)
v2.2.1 - fix #74, fix #92, add optional 64th bar to Classic Visualizer, improve Conway default (#93)
* update gitignore ignore profiling and coverage data * F1 opens help window, create appName variable, move undostack class * fix kaleidoscope effect, increase default Y values by +4 the increased y values allow the cells to continue animating for more than 60 minutes instead of 30 (at default 60f/t) * update version number * add minimumWidth to undo history window * Classic Visualizer: option to include 64th bar * Waveform component: fix #74 - new animation speed option * move shared visualizer code into toolkit * Waveform component: compress audio by default * Waveform component: fix 100% animation speed * new components receive random color * update to Qt 6 * fix pushbutton stylesheet * fix #92: replace ok/cancel with save/discard/cancel * remove obsolete PaintColor subclass * mv common shadow code into addShadow func * add 3rd option of ok/cancel back to showMessage the 3 options are: - ok - ok/cancel - save/discard/cancel * Image component: add shadow option * small test of rgbFromString * fix color tuple string * test another way to get comp names from CLI * rename component tests, add some more * Image component: scale shadow based on resolution * catch AttributeError if previewRender returns None * Text component: fix blur radius only able to increase the relativeWidgets system causes QDoubleSpinbox to only allow increases, because it really only works with integeres, so I changed the blur radius into a normal QSpinBox. I noted where the problem exists within component.py for future reference. This commit also removes an unneeded VerticalLayout from the ui file * remove unnecessary QVBoxLayout * paste shadow at x,y instead of using offset method * fix tests due to shadow change * don't print warning in connectWidget due to QFontComboBox
Diffstat (limited to 'src/avp/toolkit/visualizer.py')
-rw-r--r--src/avp/toolkit/visualizer.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/avp/toolkit/visualizer.py b/src/avp/toolkit/visualizer.py
new file mode 100644
index 0000000..c55a3f3
--- /dev/null
+++ b/src/avp/toolkit/visualizer.py
@@ -0,0 +1,87 @@
+"""Functions used to transform and manipulate audio for use by visualizers"""
+
+from copy import copy
+import numpy
+
+
+def createSpectrumArray(
+ component,
+ completeAudioArray,
+ sampleSize,
+ smoothConstantDown,
+ smoothConstantUp,
+ scale,
+ progressBarUpdate,
+ progressBarSetText,
+):
+ lastSpectrum = None
+ spectrumArray = {}
+ for i in range(0, len(completeAudioArray), sampleSize):
+ if component.canceled:
+ break
+ lastSpectrum = transformData(
+ i,
+ completeAudioArray,
+ sampleSize,
+ smoothConstantDown,
+ smoothConstantUp,
+ lastSpectrum,
+ scale,
+ )
+ spectrumArray[i] = copy(lastSpectrum)
+
+ progress = int(100 * (i / len(completeAudioArray)))
+ if progress >= 100:
+ progress = 100
+ progressText = f"Analyzing audio: {str(progress)}%"
+ progressBarSetText.emit(progressText)
+ progressBarUpdate.emit(int(progress))
+ return spectrumArray
+
+
+def transformData(
+ i,
+ completeAudioArray,
+ sampleSize,
+ smoothConstantDown,
+ smoothConstantUp,
+ lastSpectrum,
+ scale,
+):
+ if len(completeAudioArray) < (i + sampleSize):
+ sampleSize = len(completeAudioArray) - i
+
+ window = numpy.hanning(sampleSize)
+ data = completeAudioArray[i : i + sampleSize][::1] * window
+ paddedSampleSize = 2048
+ paddedData = numpy.pad(data, (0, paddedSampleSize - sampleSize), "constant")
+ spectrum = numpy.fft.fft(paddedData)
+ sample_rate = 44100
+ frequencies = numpy.fft.fftfreq(len(spectrum), 1.0 / sample_rate)
+
+ y = abs(spectrum[0 : int(paddedSampleSize / 2) - 1])
+
+ # filter the noise away
+ # y[y<80] = 0
+
+ with numpy.errstate(divide="ignore"):
+ y = scale * numpy.log10(y)
+
+ y[numpy.isinf(y)] = 0
+
+ if lastSpectrum is not None:
+ lastSpectrum[y < lastSpectrum] = y[
+ y < lastSpectrum
+ ] * smoothConstantDown + lastSpectrum[y < lastSpectrum] * (
+ 1 - smoothConstantDown
+ )
+
+ lastSpectrum[y >= lastSpectrum] = y[
+ y >= lastSpectrum
+ ] * smoothConstantUp + lastSpectrum[y >= lastSpectrum] * (1 - smoothConstantUp)
+ else:
+ lastSpectrum = y
+
+ x = frequencies[0 : int(paddedSampleSize / 2) - 1]
+
+ return lastSpectrum