Skip to content

Per-section sync 3/5: per-section alignment engine (chroma + DTW per section, with confidence) #24

Closed

Description

@cchacs

Part of #8. Can start in parallel with the design decision; it only produces numbers, it does not change timestamps.

Reuse the chroma + DTW alignment from the current uniform sync redesign, but run it per section instead of once for the whole song.

Scope

  • Use the arrangement's existing sections[] markers (Intro / Verse / Chorus / Solo / ...) as region boundaries.
  • For each section, anchor on its opening notes against the audio for that region and produce a per-section (factor, offset) or a set of anchor correspondences.
  • Produce a per-section confidence so a bad match on one section can be reported and skipped without affecting the others.
  • Pure analysis: return results, do not modify note timestamps (baking is sub-issue 4).

Acceptance criteria

  • On a synthetic or fixture song whose tempo changes at a section boundary, the per-section factors differ and each is closer to the truth than a single global factor (state the metric).
  • A deliberately mismatched section gets a low confidence and does not change the others' results.
  • Single-section songs reduce to the uniform model's result.

Out of scope

Applying the warp, the data model (sub-issue 2), and any UI (sub-issue 5).

Activity

  1. pullfrog commented on Oct 2, 2026

    @pullfrog
  2. pullfrog commented on Oct 11, 2026

    @pullfrog

    Per-section alignment engine (#24) is complete, tested, and open as PR #69 (vs main, not merged).

    • Fix of the merge-blocking P1: the chain place is computed at the section's FIRST NOTE (sourceTimes[0]), not at the boundary, so a section whose notes start inside/past its marker keeps the marker's place.
    • Root-cause fix for the isolation guarantee: with on-the-beat clicks, every period-shifted window fits a straight line, so min-MAD could never pin the intercept — absolute place comes from the chain (audioStart snapped to a real onset). The tight window is [audioStart, audioStart + slope·span + tailPad]; the lower edge is the snapped onset itself (previous-section content never enters), and the snap prefers the onset at-or-after the chained place (a stray prior-section click that edges a few tens of ms closer no longer hijacks the boundary).
    • Suite now proves the hard case: on a song whose audio kinks 132→108 BPM at a boundary, a deliberately mismatched middle section reads low-confidence while the sections before and after it stay byte-for-byte identical — and a separate regression pins the marker-place rule.

    Tests: node tests/section_sync.test.mjs = 14/14; npm test = 401 pass / 0 fail; npm run lint = 0 errors (3 pre-existing warnings).

    Task list (2/6 completed)

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

  3. pullfrog commented on Oct 12, 2026

    @pullfrog

    No new work needed — this issue is already implemented and merged.

    • PR #69 is merged into main; HEAD (4e1acb9, feat(sync): per-section alignment engine (#24)) contains src/section-sync.js and tests/section_sync.test.mjs.
    • Verified against the current tree: node tests/section_sync.test.mjs = 14/14 and npm test = 401 pass / 0 fail. All three acceptance criteria (per-section factors beat the best single global fit; a mismatched section reads low confidence and leaves its neighbours byte-for-byte identical; a single section reduces to the uniform factor) are covered.
    • The implementation is pure analysis (no timestamp mutation, no UI), matching the issue scope.

    Closing the issue as completed, since the tracked work is on main.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions