feat(editor): audition trainer — loop-and-step-up + grid-locked click subdivision (P2-10) - #260
Conversation
|
Warning Review limit reached
Next review available in: 28 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughAdds a session-scoped Audition trainer activated from the transport bar. It loops an enabled range, increases playback from 50% to 75% to 100% after completed passes, optionally uses count-in restarts, and schedules finer grid-locked metronome subdivisions while slowed. ChangesAudition trainer
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant TransportBar
participant EditorAPI
participant Playback
participant GuideScheduler
TransportBar->>EditorAPI: toggle audition trainer
Playback->>Playback: count loop wrap and advance rate
Playback->>Playback: restart with optional count-in
GuideScheduler->>GuideScheduler: schedule grid-locked subdivisions
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/audio.js`:
- Around line 777-790: Preserve the A/B phase in the count-in restart branch
after _trainerOnLoopWrap() flips it: because startPlayback() resets _abPhase to
'recording', restore the flipped phase after startPlayback() or use an existing
restart path that retains A/B state. Keep the current stop, cursor reset,
display update, and scheduled-tick behavior unchanged.
In `@src/transport-bar.js`:
- Line 467: Update the buildBar rerender flow around the editor-tp-trainer
handler so the recreated trainer button immediately reflects the shared armed
state, preserving aria-pressed and visual state without waiting for
_trainerRefreshBtn(). Reapply the trainer state after rebuilding, or have
buildBar render it from the existing trainer state.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 89286406-c7d6-4606-952b-6259d7e48f62
📒 Files selected for processing (5)
CHANGELOG.mdsrc/audio.jssrc/main.jssrc/transport-bar.jstests/audition_trainer.test.mjs
10fb20a to
f2c2278
Compare
|
Both CodeRabbit findings were live — fixed in f2c2278, alongside two more from my own read:
Two more from the review:
Gates green: lint 0 errors (3 pre-existing warnings), node --test 148/148, pytest 257/257, trainer suite 9/9. |
f2c2278 to
2c22dd2
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai full review |
✅ Action performedFull review finished. Your plan includes PR reviews subject to rate limits. More reviews will be available in 7 minutes. |
P2-10: Step-up toggle in the transport bar counts completed loop passes and climbs the audition-rate ladder (50-75-100) every N passes; a wrap routes through the full start path when a count-in is armed so the pre-roll precedes each pass. Metronome subdivides (8ths/16ths) while slowed, click times a pure function of S.beats — never rate-warped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
Review of the audition trainer found four real defects, all in the lifecycle around the feature rather than in the ladder itself: - The Step↑ lamp toggled a `editor-tp-on` class that exists in no stylesheet. The transport bar styles "on" off `.editor-transport-btn[aria-pressed="true"]` — and it re-seats every other button's pressed state from the source of truth each tick, so a bar rebuild (audio arriving/leaving flips the Tempo cell's species and rebuilds) silently dropped the trainer's. Now `_transportBarTick` reads the lamp from `_trainerActive()`, which is what that export was for. - `_trainerActive()` now means armed AND looping, like `_abActive()`. Turning Loop off under an armed trainer left a lit button over a trainer that could never see another wrap. - No exit disarmed it. A/B disarms when the loop region is cleared (`_updateLoopRegionControls`), on song load (`_resetAuditionForNewSong`) and on screen teardown; the trainer rode along on none of them, so a new song came up with the trainer armed at 100% — the top of the ladder, where it can only spam the status line on every pass, forever. `_trainerDisarm()` now hangs off the same three exits. - The rate step re-seated live playback at S.cursorTime, which at the wrap still sits PAST the loop end: the step restarted the recording beyond the loop for the few ms until the wrap's own restart. Seat the cursor at the wrap before stepping. Also: with A/B + trainer + count-in all armed, the count-in wrap path's startPlayback reset the A/B pass to 'recording' every wrap, so A/B never reached a guide pass. Carry the phase across that restart. And the subdivision window guard (`t1 <= from - (t1 - t0)`) said, at length, "this span ends before the window" — say that instead. Test: the trainer reads OFF when its loop does, and a disarm sticks.
2c22dd2 to
2b1fcc0
Compare
What
The fast-follow on merged #247 (audition speed) that turns the rate transform into a real practice trainer:
S.beats(_metroSubdivClicksPure): the click is locked to the grid at every speed, so the student hears micro-timing against the intended pulse, never a wobbling click. Rate only enters through the same chart→ctx mapping every scheduled voice uses.Tests
tests/audition_trainer.test.mjs(8): ladder climb + clamp at 1.0 + off-ladder tolerance; pass counting/reset and the earned step; top-of-ladder proposes nothing; subdivision selector thresholds; subdivision clicks bisect each span exactly with beats excluded; grid-locked pin (an uneven rubato bar subdivides unevenly with its own spans — rate is not even an input); window clipping; arming refuses without an enabled loop and starts the ladder at its slowest step. All fail on main. Full suite green, lint 0 errors (3 pre-existing warnings),routes.pyuntouched.Live-verified
On a real project (Insomnium — Where the Last Wave Broke), 2-bar loop with metronome on: armed at 50% → passes wrap at 8.2s intervals (4s loop ÷ 0.5 — the transform math visible in wall-clock), steps to 75% after 3 (passes tighten to ~5.4s), reaches 100%, auto-disarms, playback continues — zero page errors. Second run with a 1-bar count-in armed: each pass restarts through the pre-roll, still wrapping cleanly, zero errors.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EBQCHCNA81E9tHmSDHSe2Q
Summary by CodeRabbit