49 bool loopEnabled READ loopEnabled WRITE setLoopEnabled NOTIFY
52 bool recordEnabled READ recordEnabled WRITE setRecordEnabled NOTIFY
55 bool punchEnabled READ punchEnabled WRITE setPunchEnabled NOTIFY
58 PlayState playState READ getPlayState WRITE setPlayState NOTIFY
65 loopStartPosition CONSTANT)
74 punchOutPosition CONSTANT)
79 static constexpr auto REPEATED_BACKWARD_MS = au::milli (units::seconds) (240);
164 std::pair<units::sample_t, units::sample_t> loop_range,
165 std::pair<units::sample_t, units::sample_t> punch_range,
166 units::sample_t playhead_position,
169 PlayState play_state,
173 : loop_range_ (loop_range), punch_range_ (punch_range),
174 playhead_position_ (playhead_position),
177 play_state_ (play_state), loop_enabled_ (loop_enabled),
182 std::pair<units::sample_t, units::sample_t>
187 std::pair<units::sample_t, units::sample_t>
192 PlayState get_play_state () const noexcept
override {
return play_state_; }
196 return playhead_position_;
198 bool loop_enabled () const noexcept
override {
return loop_enabled_; }
200 bool punch_enabled () const noexcept
override {
return punch_enabled_; }
203 return recording_enabled_;
208 return recording_preroll_frames_remaining_;
213 return metronome_countin_frames_remaining_;
216 void set_play_state (dsp::ITransport::PlayState play_state)
218 play_state_ = play_state;
220 void set_position (units::sample_t position)
222 playhead_position_ = position;
224 void consume_metronome_countin_samples (units::sample_t samples)
226 metronome_countin_frames_remaining_ -= samples;
228 void consume_recording_preroll_samples (units::sample_t samples)
230 recording_preroll_frames_remaining_ -= samples;
234 std::pair<units::sample_t, units::sample_t> loop_range_;
235 std::pair<units::sample_t, units::sample_t> punch_range_;
236 units::sample_t playhead_position_;
237 units::sample_t recording_preroll_frames_remaining_;
238 units::sample_t metronome_countin_frames_remaining_;
239 PlayState play_state_;
242 bool recording_enabled_;
246 const dsp::TempoMap &tempo_map,
248 QObject * parent =
nullptr);
254 bool loopEnabled ()
const {
return loop_enabled (); }
255 void setLoopEnabled (
bool enabled);
256 Q_SIGNAL
void loopEnabledChanged (
bool enabled);
259 void setRecordEnabled (
bool enabled);
260 Q_SIGNAL
void recordEnabledChanged (
bool enabled);
262 bool punchEnabled ()
const {
return punch_enabled (); }
263 void setPunchEnabled (
bool enabled);
264 Q_SIGNAL
void punchEnabledChanged (
bool enabled);
266 PlayState getPlayState ()
const;
267 void setPlayState (PlayState state);
268 Q_SIGNAL
void playStateChanged (PlayState state);
270 dsp::PlayheadQmlWrapper * playhead ()
const
272 return playhead_adapter_.get ();
274 dsp::AtomicPositionQmlAdapter * cuePosition ()
const
276 return cue_position_adapter_.get ();
278 dsp::AtomicPositionQmlAdapter * loopStartPosition ()
const
280 return loop_start_position_adapter_.get ();
282 dsp::AtomicPositionQmlAdapter * loopEndPosition ()
const
284 return loop_end_position_adapter_.get ();
288 return punch_in_position_adapter_.get ();
292 return punch_out_position_adapter_.get ();
303 Q_INVOKABLE
void requestRoll () [[clang::blocking]];
325 return playhead_.position_during_processing_rounded ();
328 std::pair<units::sample_t, units::sample_t>
331 return std::make_pair (
332 loop_start_position_.get_samples (), loop_end_position_.get_samples ());
335 std::pair<units::sample_t, units::sample_t>
338 return std::make_pair (
339 punch_in_position_.get_samples (), punch_out_position_.get_samples ());
342 PlayState get_play_state () const noexcept
override {
return play_state_; }
344 bool loop_enabled () const noexcept
override {
return loop_; }
345 bool punch_enabled () const noexcept
override {
return punch_mode_; }
349 return recording_preroll_frames_remaining_;
353 return countin_frames_remaining_;
358 Q_INVOKABLE
bool isRolling ()
const
360 return play_state_ == PlayState::Rolling;
363 Q_INVOKABLE
bool isPaused ()
const
365 return play_state_ == PlayState::Paused;
374 void set_play_state_rt_safe (PlayState state);
388 void move_playhead (units::precise_tick_t target_ticks,
bool set_cue_point);
400 std::vector<units::precise_tick_t> marker_ticks;
401 static_assert (__cpp_lib_containers_ranges >= 202202L);
402 marker_ticks.append_range (extra_markers);
403 marker_ticks.emplace_back (cue_position_.get_ticks ());
404 marker_ticks.emplace_back (loop_start_position_.get_ticks ());
405 marker_ticks.emplace_back (loop_end_position_.get_ticks ());
406 marker_ticks.emplace_back ();
407 std::ranges::sort (marker_ticks);
412 const auto &[index, marker_tick] :
413 marker_ticks | utils::views::enumerate | std::views::reverse)
415 if (marker_tick >= playhead_.position_ticks ())
419 isRolling () && index > 0
420 && (playhead_.get_tempo_map ().tick_to_seconds (
421 playhead_.position_ticks ())
422 - playhead_.get_tempo_map ().tick_to_seconds (marker_tick))
423 < REPEATED_BACKWARD_MS)
434 for (
auto &marker : marker_ticks)
445 bool position_is_inside_punch_range (units::sample_t pos);
447 auto playhead_ticks_before_pause () const [[clang::blocking]]
449 return playhead_before_pause_;
459 assert (countin_frames_remaining_ >= samples);
460 countin_frames_remaining_ -= samples;
470 assert (recording_preroll_frames_remaining_ >= samples);
471 recording_preroll_frames_remaining_ -= samples;
474 auto get_snapshot ()
const
476 return TransportSnapshot{
489 friend void init_from (
491 const Transport &other,
495 static constexpr auto kPlayheadKey =
"playheadPosition"sv;
496 static constexpr auto kCuePosKey =
"cuePosition"sv;
497 static constexpr auto kLoopStartPosKey =
"loopStartPosition"sv;
498 static constexpr auto kLoopEndPosKey =
"loopEndPosition"sv;
499 static constexpr auto kPunchInPosKey =
"punchInPosition"sv;
500 static constexpr auto kPunchOutPosKey =
"punchOutPosition"sv;
501 friend void to_json (nlohmann::json &j,
const Transport &transport);
502 friend void from_json (
const nlohmann::json &j, Transport &transport);
508 bool can_user_move_playhead ()
const;
512 dsp::Playhead playhead_;
513 utils::QObjectUniquePtr<dsp::PlayheadQmlWrapper> playhead_adapter_;
515 std::unique_ptr<dsp::AtomicPosition::TimeConversionFunctions>
516 time_conversion_funcs_;
519 dsp::AtomicPosition cue_position_;
520 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter> cue_position_adapter_;
523 dsp::AtomicPosition loop_start_position_;
524 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
525 loop_start_position_adapter_;
528 dsp::AtomicPosition loop_end_position_;
529 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
530 loop_end_position_adapter_;
533 dsp::AtomicPosition punch_in_position_;
534 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
535 punch_in_position_adapter_;
538 dsp::AtomicPosition punch_out_position_;
539 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
540 punch_out_position_adapter_;
546 bool punch_mode_{
false };
550 bool recording_{
false };
553 units::sample_t recording_preroll_frames_remaining_;
556 units::sample_t countin_frames_remaining_;
563 units::precise_tick_t playhead_before_pause_;
566 PlayState play_state_{ PlayState::Paused };
575 QTimer * property_notification_timer_ =
nullptr;
576 std::atomic<bool> needs_property_notification_{
false };