analysis: produce neutral core.Analysis + lock the waveform encoders (modular-backends step 2)#2
Merged
Merged
Conversation
Add Result.Core(), mapping the DSP facts (BPM, beat grid with downbeat flags, key, phrases) onto core.Analysis so backends can consume analysis without Pioneer types. analysis now depends on core. Additive and byte-safe: the encoders and the Result fields the serving path reads (WaveDetail, BeatGridPQT2, …) are untouched — the golden-hash test still passes. The waveform band data and the encoder relocation (PWV/ANLZ packers → link/prolink/anlz, consuming core.Analysis) are the next, byte-sensitive commits.
… 2, part 2) Add BandWaveformDetail / BandWaveformOverview, turning samples into the brand-agnostic per-band (bass/mid/treble) amplitude envelope every backend re-encodes into its own colour waveform. They reuse GenerateDetail's band split (splitBandsAndPeaks) so the neutral data agrees with the PWV5 output. Result.CoreWithBands assembles the full core.Analysis (DSP facts + bands); samples are passed in rather than cached, keeping the band arrays off disk. Additive: no encoder or serving-path change — the golden-hash test still passes.
Lock GenerateColorPreview (PWV4), GeneratePreview3Band (PWV6), and GenerateDetail3Band (PWV7) byte-for-byte against a deterministic tone, matching the existing PWV5 golden test. This is the safety net for the upcoming encoder relocation (step 2, part 3): a byte change in any of these now fails the tests instead of silently altering what a CDJ renders. Test-only — no production code changed.
Move TestPWV5GoldenHash next to the PWV4/6/7 tests and reuse the shared goldenSignal() + checkGolden() helpers, dropping the duplicated signal and the now-unused sha256/hex imports from waveform_test.go. PWV5's hash is unchanged (goldenSignal() produces the identical samples), so the guard is byte-for-byte equivalent — all four colour-waveform golden tests now live in one file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 2 of the modular-backends refactor: the DSP → neutral half.
analysisnow produces the brand-agnostic
core.Analysis(tempo, beat grid, key, phrases,and per-band waveforms), so a future backend can consume analysis without any
Pioneer types. It also lands golden-hash tests over all four colour-waveform
encoders as the safety net for the byte-sensitive encoder relocation still to
come (step 2, part 3).
Additive and byte-safe. No encoder logic or serving-path code changes — the
PWV4/5/6/7 outputs are byte-for-byte identical (proven by the golden tests), so
CDJs render exactly as before.
What's in it
Part 1 —
Result.Core()(analysis/tocore.go): projects the Pioneer-flavouredanalysis.Resultontocore.Analysis— BPM, beat grid (with downbeat flagsderived from
DownbeatIndex), key (both notations), and phrases (reusing theAPI's phrase-name mapping).
analysisnow depends oncore.Part 2 — band-waveform extraction (
analysis/bandwaveform.go):BandWaveformDetail/BandWaveformOverviewturn samples into the neutralbass/mid/treble amplitude envelope (0..1, inter-band energy preserved), reusing
GenerateDetail's own band split (splitBandsAndPeaks) so the neutral dataagrees with the PWV5 output.
Result.CoreWithBands(samples, sr)assembles thefull
core.Analysis; samples are passed in rather than cached, keeping the largefloat arrays off disk.
Golden safety net (
analysis/waveform_golden_test.go): new byte-for-bytetests for PWV4 (
GenerateColorPreview), PWV6 (GeneratePreview3Band),and PWV7 (
GenerateDetail3Band), and the existing PWV5 test moved inbeside them to share the
goldenSignal()/checkGolden()helpers (its hash isunchanged). All four colour waveforms are now locked.
Why now (and what's deliberately not here)
The remaining half of step 2 — relocating the PWV/ANLZ/PQT/PVB/PSSI encoders
into
link/prolink/anlzto consumecore.Analysis, then repointingdbserver/api/proto— changes the wire-serving path and is best done asits own PR. The golden tests in this PR are the guardrail for that move: a
single changed byte will fail them. (PWV5 has always been guarded; this adds
PWV4/6/7.) Even so, that later PR should get a real-CDJ smoke test, since the
golden tests lock the current bytes but can't confirm a deck renders them
end-to-end.
Verification
go build ./...✅ ·go vet ./analysis/✅ ·gofmtclean ✅TestResultCore,TestBandWaveformDetail/Overview,TestCoreWithBands,TestPWV4/5/6/7GoldenHash(deterministic,-count=2) ✅TestPWV5GoldenHashunchanged → encoders byte-identical, additive ✅Where to look
analysis/tocore.goandanalysis/bandwaveform.goare the whole productionsurface;
analysis/waveform_golden_test.goshows the encoder guardrails. Nothingin the serving path (
dbserver,api,proto) is touched.