v0.40.0: visualizer settings — laser screen angles, radial resolution

Laser: the screen's distance, pitch, yaw and roll are sliders (the beam ray
is intersected with the turned screen; the drawing shrinks only when a
steep screen would push the figure out of view), and the afterimage can be
turned off. The membrane is now a slack 50 Hz balloon whose split rocking
pairs land in the bass, so it draws loops ~60% of the time instead of ~25%.

Radial: fading trails can be turned off; the number of frequency bands and
volume steps are sliders; ghosts fade from the dot's own color into the
background; a 4096-point FFT and interpolation end the flat bass arcs; and
"Even out bass and treble" takes the song's overall tilt out so the dots
sit on a circle.
This commit is contained in:
2026-10-10 00:51:33 -07:00
parent a81ab1e163
commit 751273b14c
7 changed files with 651 additions and 245 deletions
+22 -10
View File
@@ -178,16 +178,28 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
`radial`, `laser`) owns the animation state and paints it into any rect, so
the double-click `VisualizerWindow` paints the **same** renderer bigger
rather than a copy. Since the first press of a double-click already cycled
the brightness, `mouseDoubleClickEvent` puts it back. **Radial** is the EQ
as polar dots (angle = 360 log bands, radius = level in `STEPS` rings), and
a moving dot leaves light-gray ghosts. These are kept as a birth time per
(degree, ring), so a spoke never holds more than `STEPS` and pooling to
fewer spokes is one reshape. **Laser** simulates a mirror on a speaker
membrane: the circular-membrane modes (split degenerate pairs are what turn
lines into rotating loops) run as complex one-pole resonators, vectorized in
`CHUNK`s. Tilt goes through D·tan(2θ) with an auto-gain, and the path is
drawn brighter where it moves slower (dwell). It needs **every** sample, not
the newest FFT window, hence the widget's capped `_pending` queue.
the brightness, `mouseDoubleClickEvent` puts it back. Every tunable is a
`visualizer_*` pref, read through `visualizer_styles.settings()` (clamped to
`LIMITS`, which the Preferences sliders share) and applied live through
`configure()`. **Radial** is the EQ as polar dots (angle = log bands,
radius = level in rings; both counts are settings). A moving dot leaves
ghosts in its own color fading into the background, kept as a birth time
per (spoke, ring) so a spoke never holds more than its ring count. It reads
a **4096**-point FFT and interpolates bands narrower than a bin: with 2048
points, every degree under ~1.3 kHz shared a bin with its neighbours and
drew as a flat arc. "Even out bass and treble" removes a *straight*,
loudness-weighted dB-vs-log-f tilt, clipped to ±24 dB, and never lifts a
band that isn't sounding (a curve fitted to a lone tone lit up silent
treble). **Laser** simulates a mirror on a speaker membrane: the
circular-membrane modes run as complex one-pole resonators, vectorized in
`CHUNK`s. Loops come from the split degenerate pairs, between whose
resonances x and y answer up to 90° apart, hence the slack 50 Hz membrane
with a wide split. The beam ray is intersected with a screen at
`distance`, turned by pitch/yaw/roll; the auto-gain holds the beam
*angle*, so distance is real, and `scale()` shrinks the drawing only when a
steep screen would push the loudest swing out of view. The path is drawn
brighter where it moves slower (dwell). It needs **every** sample, not the
newest FFT window, hence the widget's capped `_pending` queue.
- **`lintunes/importers/itunes_importer.py`** — parses the iTunes XML plist.
Remaps Mac `file:///Volumes/...` paths to the local `--music-root` with