Skip to content

Add beat-based Clip start/length/end APIs#15

Merged
lucaromagnoli merged 1 commit into
magda_minimalfrom
feat/clip-beat-apis
May 11, 2026
Merged

Add beat-based Clip start/length/end APIs#15
lucaromagnoli merged 1 commit into
magda_minimalfrom
feat/clip-beat-apis

Conversation

@lucaromagnoli

Copy link
Copy Markdown
Contributor

Summary

Stage 2 of #12. Adds beat-based overloads on the base Clip class for clip placement, mirroring the transport beat APIs from #14.

Setters:

  • void setStart(BeatPosition, bool preserveSync, bool keepLength)
  • void setLength(BeatDuration, bool preserveSync)
  • void setEnd(BeatPosition, bool preserveSync)

Getters:

  • BeatPosition getStartBeats() const
  • BeatPosition getEndBeats() const
  • BeatDuration getLengthBeats() const

All implementations convert through Edit::tempoSequence and delegate to the existing time-based setters/storage. Internal storage stays as TimePosition / TimeDuration — this is the same wrapper-overload pattern as the transport change, centralising conversion inside TE instead of duplicating it at every caller.

Why this is more than a thin wrapper

setLength(BeatDuration) is implemented as setEnd(startBeats + length) converted through the tempo sequence at the absolute end position, not as a flat-tempo duration calculation. That means it stays correct across tempo changes inside the clip — which the current MAGDA pattern (length_seconds = beats * 60 / bpm) does not.

What's deliberately not included

setOffset(BeatDuration) is omitted. Offset semantics differ per clip type:

  • MIDI clip offset is source-domain beats
  • Audio clip offset is source seconds scaled by speedRatio

A single base-class beat overload would have ambiguous meaning. That can be added per-subclass later (most likely on MidiClip first) once the MAGDA port forces the question.

Internal change

One TE-internal call site disambiguated: Edit::createBlankClip had setStart({}, false, true) which became ambiguous between TimePosition and BeatPosition. Changed to TimePosition().

Test plan

Adds setStart(BeatPosition,...), setLength(BeatDuration,...),
setEnd(BeatPosition,...), and the matching getStartBeats /
getEndBeats / getLengthBeats on the base Clip class, mirroring
the existing time-based setters. They delegate to the time
versions after converting against Edit::tempoSequence, so the
result is tempo-curve aware rather than the flat-tempo
seconds calculation callers do today.

setLength is implemented in terms of setEnd against the
absolute end beat (start + length, converted via the tempo
sequence), not as a duration-from-zero conversion, so it
behaves correctly across tempo changes inside the clip.

setOffset(BeatDuration) is intentionally not included: offset
semantics differ per clip type (MIDI offset is source-domain
beats, audio offset is source seconds scaled by stretching),
so a single base-class beat overload would have ambiguous
meaning. That can be added per-subclass later if needed.

Disambiguates one internal TE call site
(Edit::createBlankClip) where setStart({}) became ambiguous
between TimePosition and BeatPosition.

Stage 2 of #12.
@lucaromagnoli lucaromagnoli merged commit 28f818f into magda_minimal May 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant