14namespace tracktion {
inline namespace graph
27 : timelineRange1 (range1), isSplit (
false) {}
30 : timelineRange1 (range1), timelineRange2 (range2), isSplit (
true) {}
158 SyncPositions()
noexcept =
default;
159 int64_t referenceSyncPosition = 0;
160 int64_t playoutSyncPosition = 0;
171 std::atomic<bool> looping {
false }, userDragging {
false }, rollInToLoop {
false };
176 SyncPositions getSyncPositions()
const {
return syncPositions.load(); }
177 void setSyncPositions (SyncPositions newPositions) { syncPositions.store (newPositions); }
201 timelinePlayRange.store (rangeToPlay);
202 looping = looped && (rangeToPlay.
getLength() > 50);
215 play (rangeToPlay,
false);
216 setSyncPositions ({});
238 if (looping && rollInToLoop)
239 newPosition =
std::min (newPosition, timelinePlayRange.load().getEnd());
241 newPosition = timelinePlayRange.load().clipValue (newPosition);
243 SyncPositions newSyncPositions;
244 newSyncPositions.referenceSyncPosition = referenceSampleRange.load().getStart();
245 newSyncPositions.playoutSyncPosition = newPosition;
246 setSyncPositions (newSyncPositions);
262 if (looping != loop || (loop && loopRange !=
getLoopRange()))
266 timelinePlayRange.store (loopRange);
277 SyncPositions newSyncPositions;
278 newSyncPositions.referenceSyncPosition = referenceSampleRange.load().getStart();
279 newSyncPositions.playoutSyncPosition =
std::min (position, timelinePlayRange.load().getEnd());
280 setSyncPositions (newSyncPositions);
297 return userInteractionTime;
303 scrubbingBlockLength = numSamples;
314 const auto syncPos = getSyncPositions();
317 return syncPos.playoutSyncPosition + ((referenceSamplePosition - syncPos.referenceSyncPosition) %
getScrubbingBlockLength());
319 if (looping && ! rollInToLoop)
327 const auto syncPos = getSyncPositions();
328 return syncPos.playoutSyncPosition + (referenceSamplePosition - syncPos.referenceSyncPosition) * speed;
333 const auto syncPos = getSyncPositions();
334 return { syncPos.playoutSyncPosition + (sourceReferenceSampleRange.
getStart() - syncPos.referenceSyncPosition) * speed,
335 syncPos.playoutSyncPosition + (sourceReferenceSampleRange.
getEnd() - syncPos.referenceSyncPosition) * speed };
340 const auto loopStart = loopRange.
getStart();
347 referenceSampleRange.store (sampleRange);
349 if (rollInToLoop &&
getPosition() >= timelinePlayRange.load().getStart())
350 rollInToLoop =
false;
355 return referenceSampleRange.load();
360 return getSyncPositions().playoutSyncPosition;
369 auto e = unloopedRange.getEnd();
375 auto loopEnd = loopStart + loopLen;
383 return { { loopStart, e } };
386 return { { s, loopEnd } };
388 return { { s, loopEnd }, { loopStart, e } };
400 if (s >= pr.getEnd())
return { { pr.getStart(), e } };
401 if (e <= pr.getStart())
return { { s, pr.getEnd() } };
403 return { { s, pr.getEnd() }, { pr.getStart(), e } };
constexpr ValueType getStart() const noexcept
constexpr ValueType getEnd() const noexcept
constexpr ValueType getLength() const noexcept
Wraps a seqlock to allow a thread-safe object with wait-free reads with respect to each other.
Converts a monotonically increasing reference range in to a timeline range.
std::chrono::system_clock::time_point getLastUserInteractionTime() const
Returns the time of the last user interaction, either a setPosition or setUserIsDragging call.
int64_t getPosition() const
Returns the current timeline position.
void stop()
Stops the play head.
void overridePosition(int64_t newPosition)
Adjust position without triggering a 'user interaction' change.
bool isRollingIntoLoop() const noexcept
Returns true is the play head is looping but playing before the loop start position.
int64_t getScrubbingBlockLength() const
Returns the length of the small looped blocks to play while scrubbing.
void setLoopRange(bool loop, juce::Range< int64_t > loopRange, bool updatePosition=true)
Sets a playback range and whether to loop or not.
int64_t referenceSamplePositionToTimelinePositionUnlooped(int64_t referenceSamplePosition) const
Converts a reference sample position to a timeline position as if there was no looping set.
void setUserIsDragging(bool)
Sets the user dragging which logs a user interaction and enables scrubbing mode.
void setScrubbingBlockLength(int64_t numSamples)
Sets the length of the small looped blocks to play while scrubbing.
bool isUserDragging() const
Returns true if the user is dragging.
int64_t referenceSamplePositionToTimelinePosition(int64_t referenceSamplePosition) const
Converts a reference sample position to a timeline position.
juce::Range< int64_t > getReferenceSampleRange() const
Returns the reference sample count.
void setPosition(int64_t newPosition)
Sets the timeline position of the play head and if it is different logs a user interaction.
void play()
Starts playback from the last position.
bool isStopped() const noexcept
Returns true is the play head is currently stopped.
juce::Range< int64_t > getLoopRange() const noexcept
Returns the looped playback range.
void setReferenceSampleRange(juce::Range< int64_t > sampleRange)
Sets the reference sample count, adjusting the timeline if the play head is playing.
int64_t getPlayoutSyncPosition() const
Returns the playout sync position.
void setRollInToLoop(int64_t playbackPosition)
Puts the play head in to roll in to loop mode.
bool isPlaying() const noexcept
Returns true is the play head is currently playing.
bool isLooping() const noexcept
Returns true is the play head is in loop mode.
void playSyncedToRange(juce::Range< int64_t > rangeToPlay)
Takes the play position directly from the playout range.
juce::Range< int64_t > referenceSampleRangeToSourceRangeUnlooped(juce::Range< int64_t > sourceReferenceSampleRange) const
Converts a reference sample range to a timeline range as if there was no looping set.
static int64_t linearPositionToLoopPosition(int64_t position, juce::Range< int64_t > loopRange)
Converts a linear timeline position to a position wrapped in the loop.
PlayHead() noexcept
Creates a PlayHead.
int64_t getUnloopedPosition() const
Returns the current timeline position ignoring any loop range which might have been set.
T is_lock_free(T... args)
IntegerType negativeAwareModulo(IntegerType dividend, const IntegerType divisor) noexcept
Represents a pair of timeline ranges which could be wraped around the loop end.