feat: scale time zoom by duration, decouple the two axes
The minimum visible time window was a flat 2% of the file, but view.start and view.end are normalized to the whole signal — so the achievable time resolution scaled with file length. A 30-minute recording could never show less than a 36-second span, while a 30-second one reached 0.6 s. Long captures were effectively unreadable at the sample level no matter how far you scrolled. Derive the floor from the STFT hop instead (MinTimeViewWidth): segments sit fftSize/HOP_RATIO samples apart, so the real limit is the point where only a handful of segments span the viewport and further zoom would interpolate rather than reveal. The floor is now a constant ~43 ms at 48 kHz/1024 regardless of duration — an 844x improvement on a 30-minute file, and it tightens further with a smaller FFT. Guards cover the unloaded (sampleRate 0) and shorter-than-the-floor cases. Zooming is also no longer forced to move both axes together. The bare wheel keeps the existing coupled behaviour; Shift+wheel is time-only and Ctrl+wheel frequency-only, so a long capture can be stretched along time without collapsing the frequency range to match. Time-axis labels now pick their precision from the span between adjacent ticks (1 to 4 decimals, and m:ss.sss past a minute). At the spans this change makes reachable the old fixed "%.1fs" printed the same value in every slot, which read as a frozen axis. Adds a `wheel X Y N [mod]` action to shot_input.sh for exercising zoom headlessly, and known_bugs.md for behaviour that is unspecified rather than broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V8ZWfr5XZyyDttvkhJUgHN
This commit is contained in:
@@ -129,7 +129,9 @@ or pressing **O** for the file browser. Try the bundled sample:
|
||||
| Input | Action |
|
||||
|-------|--------|
|
||||
| **O** | Open file browser |
|
||||
| **Mouse wheel** | Zoom time/frequency |
|
||||
| **Mouse wheel** | Zoom both axes (preserves aspect ratio) |
|
||||
| **Shift+wheel** | Zoom the time axis only |
|
||||
| **Ctrl+wheel** | Zoom the frequency axis only |
|
||||
| **Alt+drag** / **middle-drag** | Pan the view |
|
||||
| **LMB drag** | Select a time + frequency region |
|
||||
| **Space** | Play / stop the selected region |
|
||||
@@ -229,6 +231,13 @@ paths.
|
||||
frequency resolution `sampleRate / fftSize` Hz per bin. Amplitude in dB.
|
||||
- **Axes** — X = time (s), Y = frequency (Hz, scaled to the file's Nyquist),
|
||||
colour = amplitude.
|
||||
- **Time zoom limit** — the tightest visible window is derived from the STFT hop
|
||||
(`fftSize / HOP_RATIO` samples), not from a fixed fraction of the file, so time
|
||||
resolution does not degrade as files get longer: a 30-minute recording zooms in
|
||||
just as far as a 30-second one. At 48 kHz / 2048-point FFT the floor is ~85 ms
|
||||
across the viewport; a smaller FFT zooms correspondingly tighter. Past that
|
||||
point there are no further STFT segments to show, so the view would only
|
||||
interpolate.
|
||||
- **Playback / WAV export** share one processing path: the selected time span,
|
||||
FFT-bandpassed to the selected frequency box, peak-normalised.
|
||||
- **mLnL parsing** — walks the WAV's RIFF chunks for the four-CC `mLnL` chunk
|
||||
@@ -253,3 +262,6 @@ src/
|
||||
See [`raylib_for_desktop_applications.md`](raylib_for_desktop_applications.md)
|
||||
for the performance / idle-CPU lessons behind the desktop build, and
|
||||
[`AGENTS.md`](AGENTS.md) for the headless-testing playbook.
|
||||
|
||||
Known rough edges — behaviour that is unspecified or awkward rather than simply
|
||||
broken — are tracked in [`known_bugs.md`](known_bugs.md).
|
||||
|
||||
Reference in New Issue
Block a user