Fix EQ+crossfade noise + expand unit tests
Two changes in one commit — they share the tree touched by the
recent EQ / tone / crossfade work.
DSP transients during overlap
- The previous shared-DSP approach routed both tracks through the same
`CODEC_IDX_AUDIO` config every tick. Rockbox biquad delay lines are
per-config, so alternating between the two tracks corrupted the state
and produced the "small noises" the user reported.
- Add a `VoiceDsp` wrapper around Rockbox's second config
(`CODEC_IDX_VOICE`). Coefficients (`dsp_set_eq_coefs`, `tone_*`) are
global — same EQ curve on both configs — but the delay lines are
independent, so the two tracks stop stepping on each other's state.
- A new `DspProcess` trait lets `decode_one_packet` and `apply_dsp`
accept either config without duplicating the packet loop.
- Both configs are flushed at crossfade preload start and at promotion
so stale delay-line state doesn't leak between tracks.
Unit tests (+52 across the workspace, 73→125)
- fin-player::queue: RepeatMode label/next cycle, advance()/back()
under Off/One/All, peek_next_item across all repeat modes, shuffle
preserves the current item, reshuffle_all pins current at index 0.
- fin-player::persist: PersistedQueue round-trip via write_atomically
+ load, malformed / missing file returns None, legacy JSON with
missing fields loads with #[serde(default)] filled in, no `.tmp`
sibling left behind.
- fin-config: RepeatMode / ReplayGainMode / CrossfadeMode label + cycle
+ is_active helpers; default_eq_band_settings has 10 monotonic ISO
bands; ensure_eq_bands fills empty and pads short lists, leaves full
lists alone.
- fin-tui::screens: Screen::ALL matches tab order, next/prev wrap and
are inverses; icon/label lookups; fmt_dur across the H:MM:SS
threshold; RowLayout sums to total width, hides subtitle on narrow
terminals, gives title ~55% of the middle; truncate honors width
budgets and produces bare "…" at width 1.