|
| enum class | EditIntentKind : std::uint8_t { EditIntentKind::Draw
, EditIntentKind::Erase
, EditIntentKind::Move
, EditIntentKind::Resize
} |
| | What an editing gesture does to the document. More...
|
| enum class | NoteEditIntentKind : std::uint8_t {
NoteEditIntentKind::Insert
, NoteEditIntentKind::Erase
, NoteEditIntentKind::Move
, NoteEditIntentKind::Resize
,
NoteEditIntentKind::SetVelocity
} |
| | What a piano-roll gesture does to one note. More...
|
| enum class | EditGestureIdentityState : std::uint8_t { EditGestureIdentityState::AwaitingBegin
, EditGestureIdentityState::Open
, EditGestureIdentityState::Closed
, EditGestureIdentityState::Exhausted
} |
| | Confirmed lifecycle state of one continuous edit gesture. More...
|
| enum class | EditGestureIdentityError : std::uint8_t {
EditGestureIdentityError::InvalidWriter
, EditGestureIdentityError::WriterMismatch
, EditGestureIdentityError::InvalidPhase
, EditGestureIdentityError::GestureClosed
,
EditGestureIdentityError::IdentityExhausted
, EditGestureIdentityError::IdentityPending
, EditGestureIdentityError::ForeignOrStaleIssue
, EditGestureIdentityError::IntentLoweringFailed
,
EditGestureIdentityError::SubmissionResultMismatch
} |
| | Why an edit-gesture identity operation was refused. More...
|
| enum class | NoteLoweringError : std::uint8_t {
NoteLoweringError::ContinuousGestureUnsupported
, NoteLoweringError::DuplicateNoteIdentity
, NoteLoweringError::NoteNotInClip
, NoteLoweringError::ExpectedNoteMismatch
,
NoteLoweringError::InvalidIdentity
} |
| | Why a note intent could not be lowered to a transaction. More...
|
| enum class | GridLineLevel : std::uint8_t { Bar
, Beat
} |
| | Identifies the musical boundary represented by a grid line. More...
|
| enum class | GridLineError : std::uint8_t {
None
, NonFiniteSpacing
, NonPositiveSpacing
, RangeOverflow
,
OutputTooSmall
} |
| | Reports why grid-line generation stopped. More...
|
| enum class | ProjectedHitRegion : std::uint8_t { ProjectedHitRegion::Body
, ProjectedHitRegion::LeadingEdge
, ProjectedHitRegion::TrailingEdge
} |
| | The horizontal part of a projected item selected by a hit test. More...
|
| enum class | LoopRangeError : std::uint8_t { LoopRangeError::CollapsedSpan
} |
| | Why an already-snapped loop range could not be constructed. More...
|
| enum class | UiTransportState : std::uint8_t { Stopped
, Playing
, Scrubbing
} |
| | Whether the playhead is moving, and why. More...
|
| enum class | AuditionStatus : std::uint8_t { Started
, Unsupported
, Busy
, Rejected
} |
| enum class | IntentStatus : std::uint8_t { Accepted
, Deferred
, Rejected
} |
| enum class | SnapDirection : std::uint8_t { SnapDirection::AtOrBefore
, SnapDirection::Nearest
, SnapDirection::AtOrAfter
} |
| | Which inclusive grid boundary a gesture requests. More...
|
| enum class | SnapGridError : std::uint8_t { SnapGridError::InvalidInterval
, SnapGridError::InvalidSwingRatio
} |
| enum class | TrackEditIntentKind : std::uint8_t { TrackEditIntentKind::Reorder
} |
| | What a track-arrangement gesture does to the document. More...
|
| enum class | TrackHeaderProjectionError : std::uint8_t {
EmptyTrackOrder
, InvalidTrackId
, DuplicateTrackId
, NonFiniteGeometry
,
NonPositiveRowHeight
, NonFiniteCoordinate
, MissingMovingTrack
} |
| | Construction and query failures for track-header projection. More...
|
| enum class | ViewportProjectionError : std::uint8_t {
NonFinitePixelSpan
, NonPositivePixelExtent
, NonPositiveTickDuration
, TickRangeOverflow
,
InvalidPitchRange
} |
|
| std::optional< timeline::ModelError > | validate_note_edit_intent (const NoteEditIntent &intent) noexcept |
| | Returns the first structural or note-domain error, or nullopt when valid.
|
| runtime::Result< timeline::Transaction, NoteLoweringError > | lower_note_edit_intent (const ValidatedNoteEditIntent &intent, std::span< const timeline::NoteEvent > current_notes, const EditIntentIdentity &identity) |
| | Lowers one note intent to the granular transaction that performs it.
|
| runtime::Result< timeline::Transaction, timeline::ModelError > | lower_edit_intent (const EditIntent &intent, const EditIntentIdentity &identity) |
| | Lowers one intent to the ordinary transaction that performs it.
|
| UndoGestureBudget | undo_gesture_budget (const timeline::UndoLimits &limits, std::span< const timeline::Command > step_forward, std::span< const timeline::Command > step_inverse) noexcept |
| | Returns what one open gesture of uniform per-step cost may spend.
|
| GridLineResult | generate_grid_lines (const TickProjection &projection, const timebase::CompiledMeterMap &meter, float minimum_spacing_px, std::span< GridLine > output) noexcept |
| | Emits visible bar lines and beat lines that are at least minimum_spacing_px from their enclosing bar line.
|
| std::optional< ProjectedHit > | hit_test_projected_items (std::span< const ProjectedHitCandidate > back_to_front, float x_px, float y_px, float tolerance_px) noexcept |
| | Selects one projected timeline item using already-resolved pixel tolerance.
|
| runtime::Result< timebase::LoopRegion, LoopRangeError > | loop_region_from_snapped_endpoints (timebase::TickPosition first, timebase::TickPosition second) noexcept |
| | Build an enabled, structurally canonical loop candidate.
|
| constexpr timebase::LoopRegion | with_loop_enabled (timebase::LoopRegion loop, bool enabled) noexcept |
| | Return loop with only its enabled state changed.
|
| runtime::Result< timeline::Transaction, timeline::ModelError > | lower_track_edit_intent (const TrackEditIntent &intent, const EditIntentIdentity &identity) |
| | Lowers one track intent to the ordinary transaction that performs it.
|
| runtime::Result< timeline::Transaction, timeline::ModelError > | lower_track_create_intent (const TrackCreateIntent &intent, const EditIntentIdentity &identity) |
| | Lowers one complete track-creation intent to InsertTrack.
|
| runtime::Result< timeline::Transaction, timeline::ModelError > | lower_track_arrangement_intent (const TrackArrangementIntent &intent, const EditIntentIdentity &identity) |
| | Lowers either complete track-arrangement alternative.
|
ScriptedUiHost is a SequencerUiHost whose playhead is written by the caller instead of an engine, and which keeps what a view emitted so a test can read it back.
SequencerUiHost is the whole coupling a timeline editor view has toward playback.
It is the seam that makes an editor view testable with no audio, no transport, and no mocking framework — the same job PumpResult does for a hostless StepGridView, done from the other side of the interface.
It is not only a test fixture. A host that has no audio yet is a legitimate deployment: an editor embedded in a tool that only writes files gets a stopped playhead and Unsupported auditions, and stays fully usable.
The scripted program is deliberately heap-owned and genuinely replaced by swap_program(). A UiPlayhead is required to be a self-contained value, and that requirement is only worth stating if something can catch a violation: after a swap the previous program's storage is freed, so a reading that borrowed from it reads freed memory rather than quietly disagreeing.
A view reads where the playhead is, asks to hear something, and hands out the intents a gesture produced; it never links, includes, or names a playback type to do any of it. The interface is declared here, beside the editor, and implemented by whoever owns audio — the product shell, or a plugin that drives its own engine and wants a piano roll over it.
Two properties carry the contract, and both are mechanically checked:
- EVERYTHING CROSSES BY VALUE. A playhead reading is a self-contained value with no pointer into engine-owned storage, so a program swap on the audio side cannot dangle or tear a reading the view already holds. TransportSnapshot is the counterexample this exists to avoid: it carries a const CompiledTempoMap* borrowed from the compiled program, which is correct for a block renderer and fatal for a view that keeps a copy across a frame.
- THE VOCABULARY IS DOCUMENT-SIDE. Positions are timebase ticks and subjects are timeline::ItemIds — the same identities the document model and the edit commands already use. Nothing here describes how audio is produced.
Structure, following the StepGridViewBase/StepGridViewT split:
- SequencerUiHost — non-template. Playhead snapshots and audition, both independent of how edits are expressed.
- SequencerUiHostT<Intent> — thin templated shim adding intent submission for one intent vocabulary. Edit intents are the editor's own type; the host is only their destination, so parameterizing here keeps the intent vocabulary and the playback seam free to evolve apart.
A host is driven from the UI/message thread. Implementations bridge to the audio thread themselves (SeqLock for the playhead, an SPSC queue for audition and intents is the shape that already works elsewhere); this interface deliberately says nothing about that bridge, so a host backed by a real transport and a host backed by a scripted value are interchangeable.