48 bool loopEnabled READ loopEnabled WRITE setLoopEnabled NOTIFY
51 bool recordEnabled READ recordEnabled WRITE setRecordEnabled NOTIFY
54 bool punchEnabled READ punchEnabled WRITE setPunchEnabled NOTIFY
57 PlayState playState READ getPlayState WRITE setPlayState NOTIFY
64 loopStartPosition CONSTANT)
73 punchOutPosition CONSTANT)
78 static constexpr auto REPEATED_BACKWARD_MS = au::milli (units::seconds) (240);
163 std::pair<units::sample_t, units::sample_t> loop_range,
164 std::pair<units::sample_t, units::sample_t> punch_range,
165 units::sample_t playhead_position,
168 PlayState play_state,
172 : loop_range_ (loop_range), punch_range_ (punch_range),
173 playhead_position_ (playhead_position),
176 play_state_ (play_state), loop_enabled_ (loop_enabled),
181 std::pair<units::sample_t, units::sample_t>
186 std::pair<units::sample_t, units::sample_t>
191 PlayState get_play_state () const noexcept
override {
return play_state_; }
195 return playhead_position_;
197 bool loop_enabled () const noexcept
override {
return loop_enabled_; }
199 bool punch_enabled () const noexcept
override {
return punch_enabled_; }
202 return recording_enabled_;
207 return recording_preroll_frames_remaining_;
212 return metronome_countin_frames_remaining_;
215 void set_play_state (dsp::ITransport::PlayState play_state)
217 play_state_ = play_state;
219 void set_position (units::sample_t position)
221 playhead_position_ = position;
223 void consume_metronome_countin_samples (units::sample_t samples)
225 metronome_countin_frames_remaining_ -= samples;
227 void consume_recording_preroll_samples (units::sample_t samples)
229 recording_preroll_frames_remaining_ -= samples;
233 std::pair<units::sample_t, units::sample_t> loop_range_;
234 std::pair<units::sample_t, units::sample_t> punch_range_;
235 units::sample_t playhead_position_;
236 units::sample_t recording_preroll_frames_remaining_;
237 units::sample_t metronome_countin_frames_remaining_;
238 PlayState play_state_;
241 bool recording_enabled_;
245 const dsp::TempoMap &tempo_map,
247 QObject * parent =
nullptr);
253 bool loopEnabled ()
const {
return loop_enabled (); }
254 void setLoopEnabled (
bool enabled);
255 Q_SIGNAL
void loopEnabledChanged (
bool enabled);
258 void setRecordEnabled (
bool enabled);
259 Q_SIGNAL
void recordEnabledChanged (
bool enabled);
261 bool punchEnabled ()
const {
return punch_enabled (); }
262 void setPunchEnabled (
bool enabled);
263 Q_SIGNAL
void punchEnabledChanged (
bool enabled);
265 PlayState getPlayState ()
const;
266 void setPlayState (PlayState state);
267 Q_SIGNAL
void playStateChanged (PlayState state);
269 dsp::PlayheadQmlWrapper * playhead ()
const
271 return playhead_adapter_.get ();
273 dsp::AtomicPositionQmlAdapter * cuePosition ()
const
275 return cue_position_adapter_.get ();
277 dsp::AtomicPositionQmlAdapter * loopStartPosition ()
const
279 return loop_start_position_adapter_.get ();
281 dsp::AtomicPositionQmlAdapter * loopEndPosition ()
const
283 return loop_end_position_adapter_.get ();
287 return punch_in_position_adapter_.get ();
291 return punch_out_position_adapter_.get ();
313 return playhead_.position_during_processing_rounded ();
316 std::pair<units::sample_t, units::sample_t>
319 return std::make_pair (
320 loop_start_position_.get_samples (), loop_end_position_.get_samples ());
323 std::pair<units::sample_t, units::sample_t>
326 return std::make_pair (
327 punch_in_position_.get_samples (), punch_out_position_.get_samples ());
330 PlayState get_play_state () const noexcept
override {
return play_state_; }
332 bool loop_enabled () const noexcept
override {
return loop_; }
333 bool punch_enabled () const noexcept
override {
return punch_mode_; }
337 return recording_preroll_frames_remaining_;
341 return countin_frames_remaining_;
346 Q_INVOKABLE
bool isRolling ()
const
348 return play_state_ == PlayState::Rolling;
351 Q_INVOKABLE
bool isPaused ()
const
353 return play_state_ == PlayState::Paused;
362 void set_play_state_rt_safe (PlayState state);
375 void move_playhead (units::precise_tick_t target_ticks,
bool set_cue_point);
387 std::vector<units::precise_tick_t> marker_ticks;
388 static_assert (__cpp_lib_containers_ranges >= 202202L);
389 marker_ticks.append_range (extra_markers);
390 marker_ticks.emplace_back (cue_position_.get_ticks ());
391 marker_ticks.emplace_back (loop_start_position_.get_ticks ());
392 marker_ticks.emplace_back (loop_end_position_.get_ticks ());
393 marker_ticks.emplace_back ();
394 std::ranges::sort (marker_ticks);
401 for (
size_t i = 0; i < marker_ticks.size (); ++i)
403 const auto index = marker_ticks.size () - 1 - i;
404 const auto &marker_tick = marker_ticks[index];
406 if (marker_tick >= playhead_.position_ticks ())
410 isRolling () && index > 0
411 && (playhead_.get_tempo_map ().tick_to_seconds (
412 playhead_.position_ticks ())
413 - playhead_.get_tempo_map ().tick_to_seconds (marker_tick))
414 < REPEATED_BACKWARD_MS)
425 for (
auto &marker : marker_ticks)
436 bool position_is_inside_punch_range (units::sample_t pos);
438 auto playhead_ticks_before_pause () const [[clang::blocking]]
440 return playhead_before_pause_;
450 assert (countin_frames_remaining_ >= samples);
451 countin_frames_remaining_ -= samples;
461 assert (recording_preroll_frames_remaining_ >= samples);
462 recording_preroll_frames_remaining_ -= samples;
465 auto get_snapshot ()
const
467 return TransportSnapshot{
480 friend void init_from (
482 const Transport &other,
486 static constexpr auto kPlayheadKey =
"playheadPosition"sv;
487 static constexpr auto kCuePosKey =
"cuePosition"sv;
488 static constexpr auto kLoopStartPosKey =
"loopStartPosition"sv;
489 static constexpr auto kLoopEndPosKey =
"loopEndPosition"sv;
490 static constexpr auto kPunchInPosKey =
"punchInPosition"sv;
491 static constexpr auto kPunchOutPosKey =
"punchOutPosition"sv;
492 friend void to_json (nlohmann::json &j,
const Transport &transport);
493 friend void from_json (
const nlohmann::json &j, Transport &transport);
499 bool can_user_move_playhead ()
const;
503 dsp::Playhead playhead_;
504 utils::QObjectUniquePtr<dsp::PlayheadQmlWrapper> playhead_adapter_;
506 std::unique_ptr<dsp::AtomicPosition::TimeConversionFunctions>
507 time_conversion_funcs_;
510 dsp::AtomicPosition cue_position_;
511 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter> cue_position_adapter_;
514 dsp::AtomicPosition loop_start_position_;
515 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
516 loop_start_position_adapter_;
519 dsp::AtomicPosition loop_end_position_;
520 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
521 loop_end_position_adapter_;
524 dsp::AtomicPosition punch_in_position_;
525 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
526 punch_in_position_adapter_;
529 dsp::AtomicPosition punch_out_position_;
530 utils::QObjectUniquePtr<dsp::AtomicPositionQmlAdapter>
531 punch_out_position_adapter_;
537 bool punch_mode_{
false };
541 bool recording_{
false };
544 units::sample_t recording_preroll_frames_remaining_;
547 units::sample_t countin_frames_remaining_;
554 units::precise_tick_t playhead_before_pause_;
557 PlayState play_state_{ PlayState::Paused };
566 QTimer * property_notification_timer_ =
nullptr;
567 std::atomic<bool> needs_property_notification_{
false };