fix: track the playhead against the region actually playing
PlaySelectedRegion copies, bandpasses and normalises the selected span up front, so the audio in flight is fixed the moment Space is pressed. The playhead, though, was drawn against the live app.sel and its duration re-derived from the live selection — so moving or resizing the selection mid-playback made the marker jump, overrun, or scale against a region that had nothing to do with what was audible. Snapshot the played region (playSelStart/playSelEnd) and take the duration from the buffer's own sample count rather than app.signal.duration, which is derived pre-mono-downmix and disagrees for stereo files. The playhead and the scope cursor both read the snapshot; playheadT is clamped at 1. Also: a sub-threshold click inside an existing selection no longer clears it. Silently resetting to full range there changes what Space plays, which is surprising when the click was an aborted drag. A click on empty space still resets as before. The *semantics* of editing a selection during playback remain undefined — whether audio should follow the box, stop, or keep going as it does now. This commit only makes the marker honest about what is coming out of the speakers. Recorded in known_bugs.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V8ZWfr5XZyyDttvkhJUgHN
This commit is contained in:
+15
-7
@@ -945,11 +945,14 @@ int main(int argc, char* argv[])
|
||||
app.isPlaying = false;
|
||||
app.playbackFinished = true;
|
||||
}
|
||||
// Track playhead position manually
|
||||
// Track playhead position manually, against the length of the buffer
|
||||
// that's actually playing (see playDuration) rather than a length
|
||||
// re-derived from the live selection — the user can move the
|
||||
// selection mid-playback without the marker jumping.
|
||||
app.playheadElapsed += GetFrameTime();
|
||||
float selectionDuration = (app.sel.timeEnd - app.sel.timeStart) * app.signal.duration;
|
||||
if (selectionDuration > 0) {
|
||||
app.playheadT = app.playheadElapsed / selectionDuration;
|
||||
if (app.playDuration > 0.0f) {
|
||||
app.playheadT = app.playheadElapsed / app.playDuration;
|
||||
if (app.playheadT > 1.0f) app.playheadT = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1324,8 +1327,13 @@ int main(int argc, char* argv[])
|
||||
app.sel.freqStart = app.sel.freqEnd;
|
||||
app.sel.freqEnd = tmp;
|
||||
}
|
||||
} else {
|
||||
// Drag too small - revert to full range
|
||||
} else if (!hoverInsideSelection) {
|
||||
// Sub-threshold drag outside any existing selection: treat
|
||||
// as a click on empty space and reset to full range. A
|
||||
// stray click *inside* the current box leaves it alone —
|
||||
// silently clearing it there changes what Space plays.
|
||||
// (hoverInsideSelection, not clickInsideSelection: the
|
||||
// latter is press-frame-only and is always false here.)
|
||||
ClearSelection();
|
||||
}
|
||||
app.sel.isTimeSelecting = false;
|
||||
@@ -1715,7 +1723,7 @@ int main(int argc, char* argv[])
|
||||
app.scopeView.data.sampleRate = app.signal.sampleRate;
|
||||
// Show playhead if playing
|
||||
if (app.isPlaying) {
|
||||
DrawScopeView(&app.scopeView, app.sel.timeStart + app.playheadT * (app.sel.timeEnd - app.sel.timeStart));
|
||||
DrawScopeView(&app.scopeView, app.playSelStart + app.playheadT * (app.playSelEnd - app.playSelStart));
|
||||
} else {
|
||||
DrawScopeView(&app.scopeView, -1.0f);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user