Skip to content

Per-section sync 3/5: per-section alignment engine (#24) - #69

Merged
cchacs merged 1 commit into
mainfrom
pullfrog/24-per-section-alignment-engine
Oct 12, 2026
Merged

cchacs merged 1 commit into
mainfrom
pullfrog/24-per-section-alignment-engine

Conversation

@pullfrog

@pullfrog pullfrog Bot commented Oct 11, 2026

Copy link
Copy Markdown

Scope

Sub-issue 3/5 of #8 (per-section syncing), implementing #24. Pure analysis only — the engine reads the chart grid and the audio onset strip and returns one independent proposal per section. It never mutates note timestamps (baking is #25) and never touches the UI (review is #26).

What's in the change

  • src/section-sync.js — the alignment engine, plus the other pieces the design doc requires: region splitting (_sectionRegionsPure, half-open intervals, explicit leading region, final endpoint), a DTW anchor pass (_dtwAlignPure), Theil-Sen slope, affine fit, and confidence/reason.
  • tests/section_sync.test.mjs — 14 acceptance tests, all reading clicks through the shipped onset path (_spectralFluxOnsetsPure).

How it works

  • One continuous piecewise-linear map: each region is located in the recording through the chain (audioStart = previous accepted region's map at the first note, snapped to a real onset), so sections a-failed section sits after can never be dragged off — the failed section's line is simply not carried.
  • Tight-window DTW per section: the window runs [audioStart, audioStart + slope·span + tailPad]. The lower edge is the snapped onset itself (everything below belongs to the previous section); the tail pad is capped under a beat period. With on-the-beat clicks every period-shifted window fits a straight line equally well, so absolute place comes from the chain, never from a minimisation — hence the whole alignment is byte-for-byte insensitive to whether the previous section matched.
  • Tempo is the shipped inter-onset vote run per section, re-voted over the section's own onsets once the tight window is known; the DTW provides the source→audio anchors the design doc requires.
  • Confidence = fit quality × vote concentration × tempo agreement × coverage, floored at 0.5. A mismatched section reads reason: 'low-confidence', is analysed not skipped, and its evidence stays inside it (_trimPairsPure drops off-fit correspondences before refitting).

Acceptance tests

  1. On a song whose audio tempo kinks 132→108 BPM at the section boundary, each section reads its own factor and its fitted map beats the best single global affine fit (MAE in seconds, tested on both sections).
  2. A deliberately mismatched middle section reads low-confidence; Verse, Solo and the Outro after it are byte-for-byte identical whether the bad section matches or not.
  3. A single-section song reduces to the uniform model's convention (factor = onset-vote BPM / grid BPM).

Plus a regression: a section whose first note is not on its marker keeps the marker's place (first anchor lands on the first real onset, not the boundary).

npm test = 401 pass / 0 fail. npm run lint = 0 errors (3 pre-existing warnings in create.js/main.js). Commits reference #24; this is one PR for this one issue. Not merged into main.

Pullfrog  | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

@pullfrog
pullfrog Bot requested a review from cchacs October 11, 2026 21:26
@pullfrog

pullfrog Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Author

All tests pass locally (401 JS tests) and lint is clean (only 3 pre-existing warnings). The section-sync implementation and tests in PR #69 are passing. No changes needed.

Pullfrog  | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

@kilo-code-bot

kilo-code-bot Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • src/section-sync.js - New per-section alignment engine (605 lines)
  • tests/section_sync.test.mjs - Comprehensive test suite (386 lines, 14 tests)
  • CHANGELOG.md - Feature entry under [Unreleased] Added

Reviewed by free · Input: 154.7K · Output: 6K · Cached: 168.5K

@cchacs
cchacs merged commit 4e1acb9 into main Oct 12, 2026
6 of 7 checks passed
@cchacs
cchacs deleted the pullfrog/24-per-section-alignment-engine branch October 12, 2026 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant