v0.39.0: visualizer styles — radial dots and a laser, double-click to enlarge

Preferences → Appearance → Visualizer picks Bars (as before), Radial dots
(the EQ in a circle: angle is frequency, radius is volume, moving dots
leave light-gray ghosts that fade over a set time), or Laser (a mirror on
a speaker membrane bouncing a beam onto a screen: simulated membrane
modes, D·tan(2θ) reflection, dwell-weighted brightness). Double-clicking
the panel opens it big; a click closes it.
This commit is contained in:
2026-10-10 00:26:29 -07:00
parent f079d26416
commit a81ab1e163
8 changed files with 1155 additions and 85 deletions
+17
View File
@@ -172,6 +172,23 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
for every add-to-playlist path. `theme.py` applies the palette (highlight
colors, UI scales) from prefs.
- **`lintunes/gui/visualizer.py`** + **`visualizer_styles.py`** — the
transport-bar visualizer (Round 78). The widget owns PCM intake, the timer,
on/dim/off and the color; a *renderer* (`visualizer_style` pref: `bars`,
`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.
- **`lintunes/importers/itunes_importer.py`** — parses the iTunes XML plist.
Remaps Mac `file:///Volumes/...` paths to the local `--music-root` with
case/Unicode-normalization fuzzy matching (macOS is case-insensitive + NFD vs