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,
247 const dsp::SnapGrid &snap_grid,
249 QObject * parent =
nullptr);
255 bool loopEnabled ()
const {
return loop_enabled (); }
256 void setLoopEnabled (
bool enabled);
257 Q_SIGNAL
void loopEnabledChanged (
bool enabled);
260 void setRecordEnabled (
bool enabled);
261 Q_SIGNAL
void recordEnabledChanged (
bool enabled);
263 bool punchEnabled ()
const {
return punch_enabled (); }
264 void setPunchEnabled (
bool enabled);
265 Q_SIGNAL
void punchEnabledChanged (
bool enabled);
267 PlayState getPlayState ()
const;
268 void setPlayState (PlayState state);
269 Q_SIGNAL
void playStateChanged (PlayState state);
271 dsp::PlayheadQmlWrapper * playhead ()
const
273 return playhead_adapter_.get ();
275 dsp::AtomicPositionQmlAdapter * cuePosition ()
const
277 return cue_position_adapter_.get ();
279 dsp::AtomicPositionQmlAdapter * loopStartPosition ()
const
281 return loop_start_position_adapter_.get ();
283 dsp::AtomicPositionQmlAdapter * loopEndPosition ()
const
285 return loop_end_position_adapter_.get ();
289 return punch_in_position_adapter_.get ();
293 return punch_out_position_adapter_.get ();
296 Q_INVOKABLE
void moveBackward () [[clang::blocking]];
297 Q_INVOKABLE
void moveForward () [[clang::blocking]];
318 return playhead_.position_during_processing_rounded ();
321 std::pair<units::sample_t, units::sample_t>
324 return std::make_pair (
325 loop_start_position_.get_samples (), loop_end_position_.get_samples ());
328 std::pair<units::sample_t, units::sample_t>
331 return std::make_pair (
332 punch_in_position_.get_samples (), punch_out_position_.get_samples ());
335 PlayState get_play_state () const noexcept
override {
return play_state_; }
337 bool loop_enabled () const noexcept
override {
return loop_; }
338 bool punch_enabled () const noexcept
override {
return punch_mode_; }
342 return recording_preroll_frames_remaining_;
346 return countin_frames_remaining_;
351 Q_INVOKABLE
bool isRolling ()
const
353 return play_state_ == PlayState::Rolling;
356 Q_INVOKABLE
bool isPaused ()
const
358 return play_state_ == PlayState::Paused;
367 void set_play_state_rt_safe (PlayState state);
380 void move_playhead (units::precise_tick_t target_ticks,
bool set_cue_point);
392 std::vector<units::precise_tick_t> marker_ticks;
393 static_assert (__cpp_lib_containers_ranges >= 202202L);
394 marker_ticks.append_range (extra_markers);
395 marker_ticks.emplace_back (cue_position_.get_ticks ());
396 marker_ticks.emplace_back (loop_start_position_.get_ticks ());
397 marker_ticks.emplace_back (loop_end_position_.get_ticks ());
398 marker_ticks.emplace_back ();
399 std::ranges::sort (marker_ticks);
406 for (
size_t i = 0; i < marker_ticks.size (); ++i)
408 const auto index = marker_ticks.size () - 1 - i;
409 const auto &marker_tick = marker_ticks[index];
411 if (marker_tick >= playhead_.position_ticks ())
415 isRolling () && index > 0
416 && (playhead_.get_tempo_map ().tick_to_seconds (
417 playhead_.position_ticks ())
418 - playhead_.get_tempo_map ().tick_to_seconds (marker_tick))
419 < REPEATED_BACKWARD_MS)
430 for (
auto &marker : marker_ticks)
432 if (marker > playhead_.position_ticks ())
448 units::precise_tick_t start_pos,
449 units::precise_tick_t pos,
452 bool position_is_inside_punch_range (units::sample_t pos);
454 auto playhead_ticks_before_pause () const [[clang::blocking]]
456 return playhead_before_pause_;
466 assert (countin_frames_remaining_ >= samples);
467 countin_frames_remaining_ -= samples;
477 assert (recording_preroll_frames_remaining_ >= samples);
478 recording_preroll_frames_remaining_ -= samples;
481 auto get_snapshot ()
const
483 return TransportSnapshot{
496 friend void init_from (
498 const Transport &other,
502 static constexpr auto kPlayheadKey =
"playhead"sv;
503 static constexpr auto kCuePosKey =
"cuePos"sv;
504 static constexpr auto kLoopStartPosKey =
"loopStartPos"sv;
505 static constexpr auto kLoopEndPosKey =
"loopEndPos"sv;
506 static constexpr auto kPunchInPosKey =
"punchInPos"sv;
507 static constexpr auto kPunchOutPosKey =
"punchOutPos"sv;
508 static constexpr auto kPositionKey =
"position"sv;
509 friend void to_json (nlohmann::json &j,
const Transport &transport);
510 friend void from_json (
const nlohmann::json &j, Transport &transport);
516 bool can_user_move_playhead ()
const;
520 dsp::Playhead playhead_;
521 utils::QObjectUniquePtr<dsp::PlayheadQmlWrapper> playhead_adapter_;
523 std::unique_ptr<dsp::AtomicPosition::TimeConversionFunctions>
524 time_conversion_funcs_;
527 dsp::AtomicPosition cue_position_;
528 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter> cue_position_adapter_;
531 dsp::AtomicPosition loop_start_position_;
532 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
533 loop_start_position_adapter_;
536 dsp::AtomicPosition loop_end_position_;
537 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
538 loop_end_position_adapter_;
541 dsp::AtomicPosition punch_in_position_;
542 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
543 punch_in_position_adapter_;
546 dsp::AtomicPosition punch_out_position_;
547 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
548 punch_out_position_adapter_;
554 bool punch_mode_{
false };
558 bool recording_{
false };
561 units::sample_t recording_preroll_frames_remaining_;
564 units::sample_t countin_frames_remaining_;
571 units::precise_tick_t playhead_before_pause_;
574 PlayState play_state_{ PlayState::Paused };
583 QTimer * property_notification_timer_ =
nullptr;
584 std::atomic<bool> needs_property_notification_{
false };
588 const dsp::SnapGrid &snap_grid_;