Show the pitch track and notes filling in while recording - #12
Open
novikov-alexander wants to merge 6 commits into
Open
novikov-alexander wants to merge 6 commits into
novikov-alexander wants to merge 6 commits into
Conversation
Qt's qyieldcpu.h calls the ACLE intrinsic __yield() under __has_builtin(__yield) without including <arm_acle.h>. Apple clang 21 reports the builtin as available but makes the resulting implicit declaration an error, so every translation unit reaching <QtCore/qatomic.h> fails to compile. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pure functions deciding which region of a growing recording to analyse next, and discarding transform output that falls outside the region asked for. Adjacent, non-overlapping, monotone ranges, so results can be concatenated with nothing to merge. Adds a test target for main/, run by meson test alongside the svcore suites. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Off by default, from a new item in the Analysis menu. When enabled, the pitch track is filled in as the recording proceeds, one region at a time, so that a performer can see something as they go. This is only ever a preview: everything it adds is removed again when recording stops, and the pitch and note layers are then regenerated in full from the completed audio as they always were. The recordCompleted path is untouched. The transform output model comes from ModelTransformerFactory rather than Document, so it belongs to us: no layer is created for it, it is not registered with the document, and nothing reaches the undo history. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
recordStatusChanged(true) is emitted from startRecording(), before record() has closed the old session, created the new document, set the main model and built the analysis layers. Starting the preview there attached it to the session about to be discarded, so fileClosed() abandoned it and nothing was ever drawn. The first duration update arrives 200ms later, by which time all of that has happened, so start there instead. One attempt per recording, so a failure is not retried on every update. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Notes have duration, so a region boundary falling inside one would cut it in two. Each pass now reaches back over a short tail of the previous one and replaces the preview's contents there, giving the note tracker the surrounding audio so it can emit the note whole. Replacing rather than merging is possible because everything drawn is the preview's own: it is a delete followed by an add, with no heuristic deciding between overlapping notes. Both outputs come from a single run of the plugin. Note frames need shifting and pitch frames do not, because pYIN's notes output derives its timestamps from a frame index counting from zero while its smoothedpitchtrack output carries the host's block timestamps. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each pass removed what it had previously drawn in the revisited region with a stable_partition across the whole record of added events. That record grows at around 170 events a second, and Event holds QStrings, so the cost was quadratic in the length of the take: after several minutes the passes were doing enough work on the GUI thread to make the application progressively less responsive. The record is sorted by frame, because each pass prunes from its region start and then appends that region in order, and the region start only moves forward. So the cut point can be found by binary search. Also make the completion connection queued: completionChanged is emitted from the transform's own thread and the handler releases the model that emitted it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
An off-by-default option, in the Analysis menu, that fills in the pitch
track and notes as a recording is made, so the performer can see
something as they go.
It cannot change Tony's output. Everything it adds is removed again when
recording stops, and the
recordCompletedpath is untouched:analyseNow()→analyseExistingFile()removes both layers and re-runsthe full analysis exactly as today, and MainWindowBase's
refreshModelstill fires. The worst case is a wrong-looking preview that is deleted a
moment later.
Notes on the implementation:
ModelTransformerFactoryrather thanDocument, so they belong to the preview: no layer is created for them,they are not registered with the document, and nothing reaches the undo
history. (
Document::addLayerToViewandremoveLayerFromViewboth pushundoable commands holding a raw
Layer *, so creating and destroyingtransient layers is not safe.)
preview's contents there, rather than merging. Notes have duration and
would otherwise be cut in two at a region boundary; because the preview
owns everything it draws, replacing a region is a delete and an add,
with no heuristic choosing between overlapping notes.
smoothedpitchtrackcarries the host's block timestamps, while
notesderives timestampsfrom a frame index counting from zero. Handled explicitly where they are
read, with a range filter as a backstop either way.
Analyser::getAnalysisSettings()so itflows through the same single-source-of-truth map as the others.
Adds a
tony-maintest target formain/, run bymeson testalongsidethe svcore suites. 11 files changed, +1238 −3, of which around 240 are
tests.
The first commit is the macOS/Qt build fix submitted separately as #11; it
will drop out on rebase once that lands, or I can remove it now.
This supersedes the approach in #6.