From ff122d0fe8fde6a8a4edc71f9dbba5d161036300 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 8 Nov 2009 16:28:21 +0000 Subject: monster commit: transport mgmt changes from 2.X (omnibus edition); make slave use nframes64_t ; avoid crashes in Drags when commiting reversible transactions that do not exist git-svn-id: svn://localhost/ardour2/branches/3.0@6034 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/session.h | 184 +++++++++--------- libs/ardour/ardour/slave.h | 50 ++--- libs/ardour/audio_diskstream.cc | 3 +- libs/ardour/enums.cc | 3 +- libs/ardour/filesystem_paths.cc | 35 ++-- libs/ardour/jack_slave.cc | 5 +- libs/ardour/midi_clock_slave.cc | 32 ++-- libs/ardour/midi_diskstream.cc | 2 +- libs/ardour/mtc_slave.cc | 8 +- libs/ardour/session.cc | 10 +- libs/ardour/session_butler.cc | 4 +- libs/ardour/session_events.cc | 40 +--- libs/ardour/session_export.cc | 2 +- libs/ardour/session_process.cc | 2 +- libs/ardour/session_state.cc | 3 +- libs/ardour/session_time.cc | 6 +- libs/ardour/session_transport.cc | 394 ++++++++++++++++++++++----------------- libs/ardour/slave.cc | 8 +- 18 files changed, 418 insertions(+), 373 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 3a980982c3..6ac36f98b6 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -132,8 +132,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable Recording = 2 }; - struct Event { - enum Type { + struct Event { + enum Type { SetTransportSpeed, SetDiskstreamSpeed, Locate, @@ -148,78 +148,82 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable SetSlaveSource, Audition, InputConfigurationChange, - SetAudioRange, - SetPlayRange, - + SetPlayAudioRange, + /* only one of each of these events can be queued at any one time */ - + StopOnce, AutoLoop }; - - enum Action { - Add, - Remove, - Replace, - Clear - }; - - Type type; - Action action; - nframes_t action_frame; - nframes_t target_frame; - double speed; - - union { - void* ptr; - bool yes_or_no; - nframes_t target2_frame; - SlaveSource slave; - Route* route; - }; - - std::list audio_range; - std::list music_range; - - boost::shared_ptr region; - - Event(Type t, Action a, nframes_t when, nframes_t where, double spd, bool yn = false) + + enum Action { + Add, + Remove, + Replace, + Clear + }; + + Type type; + Action action; + nframes64_t action_frame; + nframes64_t target_frame; + double speed; + + union { + void* ptr; + bool yes_or_no; + nframes64_t target2_frame; + SlaveSource slave; + Route* route; + }; + + union { + bool second_yes_or_no; + }; + + std::list audio_range; + std::list music_range; + + boost::shared_ptr region; + + Event(Type t, Action a, nframes_t when, nframes_t where, double spd, bool yn = false, bool yn2 = false) : type (t) , action (a) , action_frame (when) , target_frame (where) , speed (spd) , yes_or_no (yn) + , second_yes_or_no (yn2) {} - void set_ptr (void* p) { - ptr = p; - } - - bool before (const Event& other) const { - return action_frame < other.action_frame; - } - - bool after (const Event& other) const { - return action_frame > other.action_frame; - } - - static bool compare (const Event *e1, const Event *e2) { - return e1->before (*e2); - } - - void *operator new (size_t) { - return pool.alloc (); - } - - void operator delete (void *ptr, size_t /*size*/) { - pool.release (ptr); - } - - static const nframes_t Immediate = 0; - - private: - static MultiAllocSingleReleasePool pool; + void set_ptr (void* p) { + ptr = p; + } + + bool before (const Event& other) const { + return action_frame < other.action_frame; + } + + bool after (const Event& other) const { + return action_frame > other.action_frame; + } + + static bool compare (const Event *e1, const Event *e2) { + return e1->before (*e2); + } + + void *operator new (size_t) { + return pool.alloc (); + } + + void operator delete (void *ptr, size_t /*size*/) { + pool.release (ptr); + } + + static const nframes_t Immediate = 0; + + private: + static MultiAllocSingleReleasePool pool; }; /* creating from an XML file */ @@ -375,9 +379,9 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* Transport mechanism signals */ sigc::signal TransportStateChange; /* generic */ - sigc::signal PositionChanged; /* sent after any non-sequential motion */ + sigc::signal PositionChanged; /* sent after any non-sequential motion */ sigc::signal DurationChanged; - sigc::signal Xrun; + sigc::signal Xrun; sigc::signal TransportLooped; /** emitted when a locate has occurred */ @@ -388,7 +392,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable void request_roll_at_and_return (nframes_t start, nframes_t return_to); void request_bounded_roll (nframes_t start, nframes_t end); - void request_stop (bool abort = false); + void request_stop (bool abort = false, bool clear_state = false); void request_locate (nframes_t frame, bool with_roll = false); void request_play_loop (bool yn, bool leave_rolling = false); @@ -406,7 +410,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable void request_diskstream_speed (Diskstream&, double speed); void request_input_change_handling (); - bool locate_pending() const { return static_cast(post_transport_work&PostTransportLocate); } + bool locate_pending() const { return static_cast(post_transport_work()&PostTransportLocate); } bool transport_locked () const; int wipe (); @@ -533,8 +537,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* Time */ - nframes_t transport_frame () const {return _transport_frame; } - nframes_t audible_frame () const; + nframes64_t transport_frame () const {return _transport_frame; } + nframes64_t audible_frame () const; nframes64_t requested_return_frame() const { return _requested_return_frame; } enum PullupFormat { @@ -914,10 +918,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* ranges */ - void set_audio_range (std::list&); - void set_music_range (std::list&); - - void request_play_range (bool yn, bool leave_rolling = false); + void request_play_range (std::list*, bool leave_rolling = false); bool get_play_range () const { return _play_range; } /* buffers for gain and pan */ @@ -997,7 +998,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable nframes_t _nominal_frame_rate; //ignores audioengine setting, "native" SR int transport_sub_state; mutable gint _record_status; - volatile nframes_t _transport_frame; + volatile nframes64_t _transport_frame; Location* end_location; Location* start_location; Slave* _slave; @@ -1010,7 +1011,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable CubicInterpolation interpolation; bool auto_play_legal; - nframes_t _last_slave_transport_frame; + nframes64_t _last_slave_transport_frame; nframes_t maximum_output_latency; volatile nframes64_t _requested_return_frame; BufferSet* _scratch_buffers; @@ -1026,6 +1027,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable bool _non_soloed_outs_muted; uint32_t _listen_cnt; bool _writable; + bool _was_seamless; void set_worst_io_latencies (); void set_worst_io_latencies_x (IOChange, void *) { @@ -1180,7 +1182,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable PostTransportScrub = 0x8000, PostTransportReverse = 0x10000, PostTransportInputChange = 0x20000, - PostTransportCurveRealloc = 0x40000 + PostTransportCurveRealloc = 0x40000, + PostTransportClearSubstate = 0x80000 }; static const PostTransportWork ProcessCannotProceedMask = @@ -1192,9 +1195,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable PostTransportScrub| PostTransportAudition| PostTransportLocate| - PostTransportStop); + PostTransportStop| + PostTransportClearSubstate); - PostTransportWork post_transport_work; + gint _post_transport_work; /* accessed only atomic ops */ + PostTransportWork post_transport_work() const { return (PostTransportWork) g_atomic_int_get (&_post_transport_work); } + void set_post_transport_work (PostTransportWork ptw) { g_atomic_int_set (&_post_transport_work, (gint) ptw); } + void add_post_transport_work (PostTransportWork ptw); uint32_t cumulative_rf_motion; uint32_t rf_scale; @@ -1337,8 +1344,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable int no_roll (nframes_t nframes); int fail_roll (nframes_t nframes); - bool non_realtime_work_pending() const { return static_cast(post_transport_work); } - bool process_can_proceed() const { return !(post_transport_work & ProcessCannotProceedMask); } + bool non_realtime_work_pending() const { return static_cast(post_transport_work()); } + bool process_can_proceed() const { return !(post_transport_work() & ProcessCannotProceedMask); } struct MIDIRequest { enum Type { @@ -1361,18 +1368,19 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable void change_midi_ports (); int use_config_midi_ports (); - void set_play_loop (bool yn, bool leave_rolling); + void set_play_loop (bool yn); + void unset_play_loop (); void overwrite_some_buffers (Diskstream*); void flush_all_inserts (); int micro_locate (nframes_t distance); - void locate (nframes_t, bool with_roll, bool with_flush, bool with_loop=false); - void start_locate (nframes_t, bool with_roll, bool with_flush, bool with_loop=false); - void force_locate (nframes_t frame, bool with_roll = false); + void locate (nframes64_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false); + void start_locate (nframes64_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false); + void force_locate (nframes64_t frame, bool with_roll = false); void set_diskstream_speed (Diskstream*, double speed); - void set_transport_speed (double speed, bool abort = false); - void stop_transport (bool abort = false); + void set_transport_speed (double speed, bool abort = false, bool clear_state = false); + void stop_transport (bool abort = false, bool clear_state = false); void start_transport (); - void realtime_stop (bool abort); + void realtime_stop (bool abort, bool clear_state); void non_realtime_start_scrub (); void non_realtime_set_speed (); void non_realtime_locate (); @@ -1619,8 +1627,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable std::list current_audio_range; bool _play_range; - void set_play_range (bool yn, bool leave_rolling); - void setup_auto_play (); + void set_play_range (std::list&, bool leave_rolling); + void unset_play_range (); /* main outs */ uint32_t main_outs; diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 0f005d6f1b..9036c97a27 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -107,7 +107,7 @@ class Slave { * @param position - The transport position requested * @return - The return value is currently ignored (see Session::follow_slave) */ - virtual bool speed_and_position (double& speed, nframes_t& position) = 0; + virtual bool speed_and_position (double& speed, nframes64_t& position) = 0; /** * reports to ARDOUR whether the Slave is currently synced to its external @@ -161,13 +161,13 @@ class Slave { class ISlaveSessionProxy { public: virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); } - virtual nframes_t frame_rate() const { return 0; } - virtual nframes_t audible_frame () const { return 0; } - virtual nframes_t transport_frame () const { return 0; } - virtual nframes_t frames_since_cycle_start () const { return 0; } - virtual nframes_t frame_time () const { return 0; } + virtual nframes_t frame_rate() const { return 0; } + virtual nframes64_t audible_frame () const { return 0; } + virtual nframes64_t transport_frame () const { return 0; } + virtual nframes_t frames_since_cycle_start () const { return 0; } + virtual nframes64_t frame_time () const { return 0; } - virtual void request_locate (nframes_t /*frame*/, bool with_roll = false) { + virtual void request_locate (nframes64_t /*frame*/, bool with_roll = false) { (void) with_roll; } virtual void request_transport_speed (double /*speed*/) {} @@ -181,14 +181,14 @@ class SlaveSessionProxy : public ISlaveSessionProxy { public: SlaveSessionProxy(Session &s) : session(s) {} - TempoMap& tempo_map() const; - nframes_t frame_rate() const; - nframes_t audible_frame () const; - nframes_t transport_frame () const; - nframes_t frames_since_cycle_start () const; - nframes_t frame_time () const; + TempoMap& tempo_map() const; + nframes_t frame_rate() const; + nframes64_t audible_frame () const; + nframes64_t transport_frame () const; + nframes_t frames_since_cycle_start () const; + nframes64_t frame_time () const; - void request_locate (nframes_t frame, bool with_roll = false); + void request_locate (nframes64_t frame, bool with_roll = false); void request_transport_speed (double speed); }; @@ -211,7 +211,7 @@ class MTC_Slave : public Slave, public sigc::trackable { ~MTC_Slave (); void rebind (MIDI::Port&); - bool speed_and_position (double&, nframes_t&); + bool speed_and_position (double&, nframes64_t&); bool locked() const; bool ok() const; @@ -256,7 +256,7 @@ class MIDIClock_Slave : public Slave, public sigc::trackable { ~MIDIClock_Slave (); void rebind (MIDI::Port&); - bool speed_and_position (double&, nframes_t&); + bool speed_and_position (double&, nframes64_t&); bool locked() const; bool ok() const; @@ -311,17 +311,17 @@ class MIDIClock_Slave : public Slave, public sigc::trackable { double b, c, omega; void reset (); - void start (MIDI::Parser& parser, nframes_t timestamp); - void contineu (MIDI::Parser& parser, nframes_t timestamp); - void stop (MIDI::Parser& parser, nframes_t timestamp); + void start (MIDI::Parser& parser, nframes64_t timestamp); + void contineu (MIDI::Parser& parser, nframes64_t timestamp); + void stop (MIDI::Parser& parser, nframes64_t timestamp); void position (MIDI::Parser& parser, MIDI::byte* message, size_t size); // we can't use continue because it is a C++ keyword - void calculate_one_ppqn_in_frames_at(nframes_t time); - nframes_t calculate_song_position(uint16_t song_position_in_sixteenth_notes); + void calculate_one_ppqn_in_frames_at(nframes64_t time); + nframes64_t calculate_song_position(uint16_t song_position_in_sixteenth_notes); void calculate_filter_coefficients(); - void update_midi_clock (MIDI::Parser& parser, nframes_t timestamp); + void update_midi_clock (MIDI::Parser& parser, nframes64_t timestamp); void read_current (SafeTime *) const; - bool stop_if_no_more_clock_events(nframes_t& pos, nframes_t now); + bool stop_if_no_more_clock_events(nframes64_t& pos, nframes64_t now); /// whether transport should be rolling bool _started; @@ -337,7 +337,7 @@ class ADAT_Slave : public Slave ADAT_Slave () {} ~ADAT_Slave () {} - bool speed_and_position (double& speed, nframes_t& pos) { + bool speed_and_position (double& speed, nframes64_t& pos) { speed = 0; pos = 0; return false; @@ -355,7 +355,7 @@ class JACK_Slave : public Slave JACK_Slave (jack_client_t*); ~JACK_Slave (); - bool speed_and_position (double& speed, nframes_t& pos); + bool speed_and_position (double& speed, nframes64_t& pos); bool starting() const { return _starting; } bool locked() const; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index fbd10b92e3..3248cd9b2d 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -626,6 +626,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can nframes_t total = chaninfo->playback_vector.len[0] + chaninfo->playback_vector.len[1]; if (necessary_samples > total) { + cerr << _name << " Need " << necessary_samples << " total = " << total << endl; cerr << "underrun for " << _name << endl; DiskUnderrun (); goto out; @@ -1754,7 +1755,7 @@ AudioDiskstream::get_state () if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) { snprintf (buf, sizeof (buf), "%" PRId64, pi->start()); } else { - snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame()); + snprintf (buf, sizeof (buf), "%" PRId64, _session.transport_frame()); } cs_child->add_property (X_("at"), buf); diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 8ab2a6f8cf..885ebeb27a 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -299,8 +299,7 @@ setup_enum_writer () REGISTER_CLASS_ENUM (Session::Event, SetSlaveSource); REGISTER_CLASS_ENUM (Session::Event, Audition); REGISTER_CLASS_ENUM (Session::Event, InputConfigurationChange); - REGISTER_CLASS_ENUM (Session::Event, SetAudioRange); - REGISTER_CLASS_ENUM (Session::Event, SetPlayRange); + REGISTER_CLASS_ENUM (Session::Event, SetPlayAudioRange); REGISTER_CLASS_ENUM (Session::Event, StopOnce); REGISTER_CLASS_ENUM (Session::Event, AutoLoop); REGISTER (_Session_Event_Type); diff --git a/libs/ardour/filesystem_paths.cc b/libs/ardour/filesystem_paths.cc index 2f2afe3c7b..932416ef41 100644 --- a/libs/ardour/filesystem_paths.cc +++ b/libs/ardour/filesystem_paths.cc @@ -16,6 +16,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "pbd/error.h" #include "pbd/filesystem_paths.h" @@ -36,18 +37,30 @@ using std::string; sys::path user_config_directory () { - const string home_dir = Glib::get_home_dir (); - - if (home_dir.empty ()) { - const string error_msg = "Unable to determine home directory"; - - // log the error - error << error_msg << endmsg; - - throw sys::filesystem_error(error_msg); + const char* c = 0; + sys::path p; + + /* adopt freedesktop standards, and put .ardour3 into $XDG_CONFIG_HOME or ~/.config + */ + + if ((c = getenv ("XDG_CONFIG_HOME")) != 0) { + p = c; + } else { + const string home_dir = Glib::get_home_dir(); + + if (home_dir.empty ()) { + const string error_msg = "Unable to determine home directory"; + + // log the error + error << error_msg << endmsg; + + throw sys::filesystem_error(error_msg); + } + + p = home_dir; + p /= ".config"; } - - sys::path p(home_dir); + p /= user_config_dir_name; return p; diff --git a/libs/ardour/jack_slave.cc b/libs/ardour/jack_slave.cc index 9f92f1b21f..0f425d09c6 100644 --- a/libs/ardour/jack_slave.cc +++ b/libs/ardour/jack_slave.cc @@ -36,7 +36,7 @@ JACK_Slave::JACK_Slave (jack_client_t* j) : jack (j) { double x; - nframes_t p; + nframes64_t p; /* call this to initialize things */ speed_and_position (x, p); } @@ -64,10 +64,11 @@ JACK_Slave::ok() const } bool -JACK_Slave::speed_and_position (double& sp, nframes_t& position) +JACK_Slave::speed_and_position (double& sp, nframes64_t& position) { jack_position_t pos; jack_transport_state_t state; + state = jack_transport_query (jack, &pos); switch (state) { diff --git a/libs/ardour/midi_clock_slave.cc b/libs/ardour/midi_clock_slave.cc index a41864571d..53f819e54a 100644 --- a/libs/ardour/midi_clock_slave.cc +++ b/libs/ardour/midi_clock_slave.cc @@ -87,7 +87,7 @@ MIDIClock_Slave::rebind (MIDI::Port& p) } void -MIDIClock_Slave::calculate_one_ppqn_in_frames_at(nframes_t time) +MIDIClock_Slave::calculate_one_ppqn_in_frames_at(nframes64_t time) { const Tempo& current_tempo = session->tempo_map().tempo_at(time); const Meter& current_meter = session->tempo_map().meter_at(time); @@ -101,14 +101,14 @@ MIDIClock_Slave::calculate_one_ppqn_in_frames_at(nframes_t time) one_ppqn_in_frames = frames_per_quarter_note / double (ppqn); } -ARDOUR::nframes_t +ARDOUR::nframes64_t MIDIClock_Slave::calculate_song_position(uint16_t song_position_in_sixteenth_notes) { - nframes_t song_position_frames = 0; + nframes64_t song_position_frames = 0; for (uint16_t i = 1; i <= song_position_in_sixteenth_notes; ++i) { // one quarter note contains ppqn pulses, so a sixteenth note is ppqn / 4 pulses calculate_one_ppqn_in_frames_at(song_position_frames); - song_position_frames += one_ppqn_in_frames * nframes_t(ppqn / 4); + song_position_frames += one_ppqn_in_frames * (nframes64_t)(ppqn / 4); } return song_position_frames; @@ -124,7 +124,7 @@ MIDIClock_Slave::calculate_filter_coefficients() } void -MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, nframes_t timestamp) +MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, nframes64_t timestamp) { // some pieces of hardware send MIDI Clock all the time if ( (!_starting) && (!_started) ) { @@ -133,7 +133,7 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, nframes_t timestamp) calculate_one_ppqn_in_frames_at(should_be_position); - nframes_t elapsed_since_start = timestamp - first_timestamp; + nframes64_t elapsed_since_start = timestamp - first_timestamp; double error = 0; if (_starting || last_timestamp == 0) { @@ -195,7 +195,7 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, nframes_t timestamp) } void -MIDIClock_Slave::start (Parser& /*parser*/, nframes_t /*timestamp*/) +MIDIClock_Slave::start (Parser& /*parser*/, nframes64_t /*timestamp*/) { #ifdef DEBUG_MIDI_CLOCK cerr << "MIDIClock_Slave got start message at time " << timestamp << " engine time: " << session->frame_time() << endl; @@ -223,7 +223,7 @@ MIDIClock_Slave::reset () } void -MIDIClock_Slave::contineu (Parser& /*parser*/, nframes_t /*timestamp*/) +MIDIClock_Slave::contineu (Parser& /*parser*/, nframes64_t /*timestamp*/) { #ifdef DEBUG_MIDI_CLOCK std::cerr << "MIDIClock_Slave got continue message" << endl; @@ -236,7 +236,7 @@ MIDIClock_Slave::contineu (Parser& /*parser*/, nframes_t /*timestamp*/) void -MIDIClock_Slave::stop (Parser& /*parser*/, nframes_t /*timestamp*/) +MIDIClock_Slave::stop (Parser& /*parser*/, nframes64_t /*timestamp*/) { #ifdef DEBUG_MIDI_CLOCK std::cerr << "MIDIClock_Slave got stop message" << endl; @@ -255,7 +255,7 @@ MIDIClock_Slave::stop (Parser& /*parser*/, nframes_t /*timestamp*/) // that is the position of the last MIDI Clock // message and that is probably what the master // expects where we are right now - nframes_t stop_position = should_be_position; + nframes64_t stop_position = should_be_position; // find out the last MIDI beat: go back #midi_clocks mod 6 // and lets hope the tempo didnt change in those last 6 beats :) @@ -282,7 +282,7 @@ MIDIClock_Slave::position (Parser& /*parser*/, byte* message, size_t size) assert((lsb <= 0x7f) && (msb <= 0x7f)); uint16_t position_in_sixteenth_notes = (uint16_t(msb) << 7) | uint16_t(lsb); - nframes_t position_in_frames = calculate_song_position(position_in_sixteenth_notes); + nframes64_t position_in_frames = calculate_song_position(position_in_sixteenth_notes); #ifdef DEBUG_MIDI_CLOCK cerr << "Song Position: " << position_in_sixteenth_notes << " frames: " << position_in_frames << endl; @@ -313,7 +313,7 @@ MIDIClock_Slave::starting() const } bool -MIDIClock_Slave::stop_if_no_more_clock_events(nframes_t& pos, nframes_t now) +MIDIClock_Slave::stop_if_no_more_clock_events(nframes64_t& pos, nframes64_t now) { /* no timecode for 1/4 second ? conclude that its stopped */ if (last_timestamp && @@ -332,7 +332,7 @@ MIDIClock_Slave::stop_if_no_more_clock_events(nframes_t& pos, nframes_t now) } bool -MIDIClock_Slave::speed_and_position (double& speed, nframes_t& pos) +MIDIClock_Slave::speed_and_position (double& speed, nframes64_t& pos) { if (!_started || _starting) { speed = 0.0; @@ -340,7 +340,7 @@ MIDIClock_Slave::speed_and_position (double& speed, nframes_t& pos) return true; } - nframes_t engine_now = session->frame_time(); + nframes64_t engine_now = session->frame_time(); if (stop_if_no_more_clock_events(pos, engine_now)) { return false; @@ -353,8 +353,8 @@ MIDIClock_Slave::speed_and_position (double& speed, nframes_t& pos) if (engine_now > last_timestamp) { // we are in between MIDI clock messages // so we interpolate position according to speed - nframes_t elapsed = engine_now - last_timestamp; - pos = nframes_t (should_be_position + double(elapsed) * speed); + nframes64_t elapsed = engine_now - last_timestamp; + pos = (nframes64_t) (should_be_position + double(elapsed) * speed); } else { // A new MIDI clock message has arrived this cycle pos = should_be_position; diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index f61211def8..f06b00ae00 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -1223,7 +1223,7 @@ MidiDiskstream::get_state () if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) { snprintf (buf, sizeof (buf), "%" PRId64, pi->start()); } else { - snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame()); + snprintf (buf, sizeof (buf), "%" PRId64, _session.transport_frame()); } cs_child->add_property (X_("at"), buf); diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 4034ef32be..3619cc4c69 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -72,7 +72,7 @@ void MTC_Slave::update_mtc_qtr (Parser& /*p*/) { cycles_t cnow = get_cycles (); - nframes_t now = session.engine().frame_time(); + nframes64_t now = session.engine().frame_time(); nframes_t qtr; static cycles_t last_qtr = 0; @@ -91,7 +91,7 @@ MTC_Slave::update_mtc_qtr (Parser& /*p*/) void MTC_Slave::update_mtc_time (const byte *msg, bool was_full) { - nframes_t now = session.engine().frame_time(); + nframes64_t now = session.engine().frame_time(); Timecode::Time timecode; timecode.hours = msg[3]; @@ -258,9 +258,9 @@ MTC_Slave::ok() const } bool -MTC_Slave::speed_and_position (double& speed, nframes_t& pos) +MTC_Slave::speed_and_position (double& speed, nframes64_t& pos) { - nframes_t now = session.engine().frame_time(); + nframes64_t now = session.engine().frame_time(); SafeTime last; nframes_t frame_rate; nframes_t elapsed; diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 031c2aa58a..8b3d832204 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -132,7 +132,6 @@ Session::Session (AudioEngine &eng, pending_events (2048), state_tree (0), _butler (new Butler (this)), - post_transport_work((PostTransportWork)0), _send_timecode_update (false), midi_thread (pthread_t (0)), midi_requests (128), // the size of this should match the midi request pool size @@ -218,7 +217,6 @@ Session::Session (AudioEngine &eng, pending_events (2048), state_tree (0), _butler (new Butler (this)), - post_transport_work((PostTransportWork)0), _send_timecode_update (false), midi_thread (pthread_t (0)), midi_requests (16), @@ -1229,12 +1227,12 @@ Session::maybe_enable_record () set_dirty(); } -nframes_t +nframes64_t Session::audible_frame () const { - nframes_t ret; + nframes64_t ret; + nframes64_t tf; nframes_t offset; - nframes_t tf; /* the first of these two possible settings for "offset" mean that the audible frame is stationary until @@ -3517,7 +3515,7 @@ void Session::set_audition (boost::shared_ptr r) { pending_audition_region = r; - post_transport_work = PostTransportWork (post_transport_work | PostTransportAudition); + add_post_transport_work (PostTransportAudition); _butler->schedule_transport_work (); } diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc index 41b4851ce5..0ffc14ff3a 100644 --- a/libs/ardour/session_butler.cc +++ b/libs/ardour/session_butler.cc @@ -68,7 +68,7 @@ static inline uint32_t next_power_of_two (uint32_t n) void Session::schedule_curve_reallocation () { - post_transport_work = PostTransportWork (post_transport_work | PostTransportCurveRealloc); + add_post_transport_work (PostTransportCurveRealloc); _butler->schedule_transport_work (); } @@ -100,7 +100,7 @@ Session::overwrite_some_buffers (Diskstream* ds) } } - post_transport_work = PostTransportWork (post_transport_work | PostTransportOverWrite); + add_post_transport_work (PostTransportOverWrite); _butler->schedule_transport_work (); } diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index 65635b773f..fb993faa68 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -23,6 +23,7 @@ #include "ardour/timestamps.h" #include "pbd/error.h" +#include "pbd/enumwriter.h" #include #include "ardour/ardour.h" @@ -38,28 +39,6 @@ using namespace PBD; MultiAllocSingleReleasePool Session::Event::pool ("event", sizeof (Session::Event), 512); -static const char* event_names[] = { - "SetTransportSpeed", - "SetDiskstreamSpeed", - "Locate", - "LocateRoll", - "LocateRollLocate", - "SetLoop", - "PunchIn", - "PunchOut", - "RangeStop", - "RangeLocate", - "Overwrite", - "SetSlaveSource", - "Audition", - "InputConfigurationChange", - "SetAudioRange", - "SetMusicRange", - "SetPlayRange", - "StopOnce", - "AutoLoop" -}; - void Session::add_event (nframes_t frame, Event::Type type, nframes_t target_frame) { @@ -161,7 +140,7 @@ Session::merge_event (Event* ev) for (Events::iterator i = events.begin(); i != events.end(); ++i) { if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) { error << string_compose(_("Session: cannot have two events of type %1 at the same frame (%2)."), - event_names[ev->type], ev->action_frame) << endmsg; + enum_2_string (ev->type), ev->action_frame) << endmsg; return; } } @@ -321,7 +300,7 @@ Session::process_event (Event* ev) switch (ev->type) { case Event::SetLoop: - set_play_loop (ev->yes_or_no, (ev->speed == 1.0f)); + set_play_loop (ev->yes_or_no); break; case Event::AutoLoop: @@ -362,7 +341,7 @@ Session::process_event (Event* ev) case Event::SetTransportSpeed: - set_transport_speed (ev->speed, ev->yes_or_no); + set_transport_speed (ev->speed, ev->yes_or_no, ev->second_yes_or_no); break; case Event::PunchIn: @@ -425,17 +404,12 @@ Session::process_event (Event* ev) break; case Event::InputConfigurationChange: - post_transport_work = PostTransportWork (post_transport_work | PostTransportInputChange); + add_post_transport_work (PostTransportInputChange); _butler->schedule_transport_work (); break; - case Event::SetAudioRange: - current_audio_range = ev->audio_range; - setup_auto_play (); - break; - - case Event::SetPlayRange: - set_play_range (ev->yes_or_no, (ev->speed == 1.0f)); + case Event::SetPlayAudioRange: + set_play_range (ev->audio_range, (ev->speed == 1.0f)); break; default: diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 3eda11bab7..0bf87591cd 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -210,7 +210,7 @@ Session::stop_audio_export () stuff that stop_transport() implements. */ - realtime_stop (true); + realtime_stop (true, true); _butler->schedule_transport_work (); if (!export_status->aborted()) { diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index ea63e71307..4bbe852687 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -480,7 +480,7 @@ bool Session::follow_slave (nframes_t nframes) { double slave_speed; - nframes_t slave_transport_frame; + nframes64_t slave_transport_frame; nframes_t this_delta; int dir; bool starting; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index f60cf8e85f..1a4758186e 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -197,11 +197,10 @@ Session::first_stage_init (string fullpath, string snapshot_name) _worst_input_latency = 0; _worst_track_latency = 0; _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading); - + _was_seamless = Config->get_seamless_loop (); _slave = 0; session_send_mmc = false; session_send_mtc = false; - post_transport_work = PostTransportWork (0); g_atomic_int_set (&_playback_load, 100); g_atomic_int_set (&_capture_load, 100); g_atomic_int_set (&_playback_load_min, 100); diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc index 9a6eebbaf8..1e1ecd3ed9 100644 --- a/libs/ardour/session_time.cc +++ b/libs/ardour/session_time.cc @@ -452,7 +452,7 @@ Session::jack_sync_callback (jack_transport_state_t state, switch (state) { case JackTransportStopped: - if (slave && _transport_frame != pos->frame && post_transport_work == 0) { + if (slave && _transport_frame != pos->frame && post_transport_work() == 0) { request_locate (pos->frame, false); // cerr << "SYNC: stopped, locate to " << pos->frame << " from " << _transport_frame << endl; return false; @@ -461,9 +461,9 @@ Session::jack_sync_callback (jack_transport_state_t state, } case JackTransportStarting: - // cerr << "SYNC: starting @ " << pos->frame << " a@ " << _transport_frame << " our work = " << post_transport_work << " pos matches ? " << (_transport_frame == pos->frame) << endl; + // cerr << "SYNC: starting @ " << pos->frame << " a@ " << _transport_frame << " our work = " << post_transport_work() << " pos matches ? " << (_transport_frame == pos->frame) << endl; if (slave) { - return _transport_frame == pos->frame && post_transport_work == 0; + return _transport_frame == pos->frame && post_transport_work() == 0; } else { return true; } diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 16ba54a369..10429e9639 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -50,6 +50,25 @@ using namespace ARDOUR; using namespace sigc; using namespace PBD; +void +Session::add_post_transport_work (PostTransportWork ptw) +{ + PostTransportWork oldval; + PostTransportWork newval; + int tries = 0; + + while (tries < 8) { + oldval = (PostTransportWork) g_atomic_int_get (&_post_transport_work); + newval = PostTransportWork (oldval | ptw); + if (g_atomic_int_compare_and_exchange (&_post_transport_work, oldval, newval)) { + /* success */ + return; + } + } + + error << "Could not set post transport work! Crazy thread madness, call the programmers" << endmsg; +} + void Session::request_input_change_handling () { @@ -63,12 +82,21 @@ void Session::request_slave_source (SlaveSource src) { Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, 0, 0.0); + bool seamless; + + seamless = Config->get_seamless_loop (); if (src == JACK) { - /* could set_seamless_loop() be disposed of entirely?*/ + /* JACK cannot support seamless looping at present */ Config->set_seamless_loop (false); + } else { + /* reset to whatever the value was before we last switched slaves */ + Config->set_seamless_loop (_was_seamless); } + /* save value of seamless from before the switch */ + _was_seamless = seamless; + ev->slave = src; queue_event (ev); } @@ -89,9 +117,9 @@ Session::request_diskstream_speed (Diskstream& ds, double speed) } void -Session::request_stop (bool abort) +Session::request_stop (bool abort, bool clear_state) { - Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0, abort); + Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0, abort, clear_state); queue_event (ev); } @@ -103,7 +131,7 @@ Session::request_locate (nframes_t target_frame, bool with_roll) } void -Session::force_locate (nframes_t target_frame, bool with_roll) +Session::force_locate (nframes64_t target_frame, bool with_roll) { Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, true); queue_event (ev); @@ -132,8 +160,22 @@ Session::request_play_loop (bool yn, bool leave_rolling) } void -Session::realtime_stop (bool abort) +Session::request_play_range (list* range, bool leave_rolling) +{ + Event* ev = new Event (Event::SetPlayAudioRange, Event::Add, Event::Immediate, 0, (leave_rolling ? 1.0 : 0.0)); + if (range) { + ev->audio_range = *range; + } else { + ev->audio_range.clear (); + } + queue_event (ev); +} + +void +Session::realtime_stop (bool abort, bool clear_state) { + PostTransportWork todo = PostTransportWork (0); + /* assume that when we start, we'll be moving forwards */ // FIXME: where should this really be? [DR] @@ -142,9 +184,9 @@ Session::realtime_stop (bool abort) deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); if (_transport_speed < 0.0f) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse); + todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse)); } else { - post_transport_work = PostTransportWork (post_transport_work | PostTransportStop); + todo = PostTransportWork (todo | PostTransportStop); } if (actively_recording()) { @@ -158,11 +200,19 @@ Session::realtime_stop (bool abort) /* the duration change is not guaranteed to have happened, but is likely */ - post_transport_work = PostTransportWork (post_transport_work | PostTransportDuration); + todo = PostTransportWork (todo | PostTransportDuration); } if (abort) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportAbort); + todo = PostTransportWork (todo | PostTransportAbort); + } + + if (clear_state) { + todo = PostTransportWork (todo | PostTransportClearSubstate); + } + + if (todo) { + add_post_transport_work (todo); } _clear_event_type (Event::StopOnce); @@ -188,29 +238,30 @@ Session::butler_transport_work () { restart: bool finished; + PostTransportWork ptw; boost::shared_ptr r = routes.reader (); boost::shared_ptr dsl = diskstreams.reader(); int on_entry = g_atomic_int_get (&_butler->should_do_transport_work); finished = true; - - if (post_transport_work & PostTransportCurveRealloc) { + ptw = post_transport_work(); + if (ptw & PostTransportCurveRealloc) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->curve_reallocate(); } } - if (post_transport_work & PostTransportInputChange) { + if (ptw & PostTransportInputChange) { for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->non_realtime_input_change (); } } - if (post_transport_work & PostTransportSpeed) { + if (ptw & PostTransportSpeed) { non_realtime_set_speed (); } - if (post_transport_work & PostTransportReverse) { + if (ptw & PostTransportReverse) { clear_clicks(); cumulative_rf_motion = 0; @@ -218,7 +269,7 @@ Session::butler_transport_work () /* don't seek if locate will take care of that in non_realtime_stop() */ - if (!(post_transport_work & PostTransportLocate)) { + if (!(ptw & PostTransportLocate)) { for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if (!(*i)->hidden()) { @@ -233,19 +284,19 @@ Session::butler_transport_work () } } - if (post_transport_work & PostTransportLocate) { + if (ptw & PostTransportLocate) { non_realtime_locate (); } - if (post_transport_work & PostTransportStop) { - non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished); + if (ptw & PostTransportStop) { + non_realtime_stop (ptw & PostTransportAbort, on_entry, finished); if (!finished) { g_atomic_int_dec_and_test (&_butler->should_do_transport_work); goto restart; } } - if (post_transport_work & PostTransportOverWrite) { + if (ptw & PostTransportOverWrite) { non_realtime_overwrite (on_entry, finished); if (!finished) { g_atomic_int_dec_and_test (&_butler->should_do_transport_work); @@ -253,7 +304,7 @@ Session::butler_transport_work () } } - if (post_transport_work & PostTransportAudition) { + if (ptw & PostTransportAudition) { non_realtime_set_audition (); } @@ -305,6 +356,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) time_t xnow; bool did_record; bool saved; + PostTransportWork ptw = post_transport_work(); did_record = false; saved = false; @@ -390,7 +442,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) (Config->get_slave_source() == None && config.get_auto_return()); if (auto_return_enabled || - (post_transport_work & PostTransportLocate) || + (ptw & PostTransportLocate) || (_requested_return_frame >= 0) || synced_to_jack()) { @@ -399,7 +451,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) && - !(post_transport_work & PostTransportLocate)) { + !(ptw & PostTransportLocate)) { /* no explicit locate queued */ @@ -461,6 +513,14 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } + /* do this before seeking, because otherwise the Diskstreams will do the wrong thing in seamless loop mode. + */ + + if (ptw & PostTransportClearSubstate) { + _play_range = false; + unset_play_loop (); + } + /* this for() block can be put inside the previous if() and has the effect of ... ??? what */ @@ -481,24 +541,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) deliver_mmc (MIDI::MachineControl::cmdStop, 0); deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); - if (did_record) { - - /* XXX its a little odd that we're doing this here - when realtime_stop(), which has already executed, - will have done this. - JLC - so let's not because it seems unnecessary and breaks loop record - */ -#if 0 - if (!Config->get_latched_record_enable()) { - g_atomic_int_set (&_record_status, Disabled); - } else { - g_atomic_int_set (&_record_status, Enabled); - } - RecordStateChanged (); /* emit signal */ -#endif - } - - if ((post_transport_work & PostTransportLocate) && get_record_enabled()) { + if ((ptw & PostTransportLocate) && get_record_enabled()) { /* capture start has been changed, so save pending state */ save_state ("", true); saved = true; @@ -514,23 +557,21 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) save_state (_current_snapshot_name); } - if (post_transport_work & PostTransportDuration) { + if (ptw & PostTransportDuration) { DurationChanged (); /* EMIT SIGNAL */ } - if (post_transport_work & PostTransportStop) { + if (ptw & PostTransportStop) { _play_range = false; play_loop = false; } - nframes_t tf = _transport_frame; - - PositionChanged (tf); /* EMIT SIGNAL */ + PositionChanged ((nframes64_t) _transport_frame); /* EMIT SIGNAL */ TransportStateChange (); /* EMIT SIGNAL */ /* and start it up again if relevant */ - if ((post_transport_work & PostTransportLocate) && Config->get_slave_source() == None && pending_locate_roll) { + if ((ptw & PostTransportLocate) && Config->get_slave_source() == None && pending_locate_roll) { request_transport_speed (1.0); pending_locate_roll = false; } @@ -561,35 +602,48 @@ Session::check_declick_out () } void -Session::set_play_loop (bool yn, bool leave_rolling) +Session::unset_play_loop () +{ + play_loop = false; + clear_events (Event::AutoLoop); + + // set all diskstreams to NOT use internal looping + boost::shared_ptr dsl = diskstreams.reader(); + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { + if (!(*i)->hidden()) { + (*i)->set_loop (0); + } + } +} + +void +Session::set_play_loop (bool yn) { /* Called from event-handling context */ Location *loc; - if (yn == play_loop) { - return; - } - - if ((actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) { + if (yn == play_loop || (actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) { + /* nothing to do, or can't change loop status while recording */ return; } - + set_dirty(); - + if (yn && Config->get_seamless_loop() && synced_to_jack()) { warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n" "Recommend changing the configured options") << endmsg; return; } + + if (yn) { - - if ((play_loop = yn)) { + play_loop = true; if (loc) { - set_play_range (false, true); + unset_play_range (); if (Config->get_seamless_loop()) { // set all diskstreams to use internal looping @@ -609,34 +663,26 @@ Session::set_play_loop (bool yn, bool leave_rolling) } } } - - /* stick in the loop event */ - + + /* put the loop event into the event list */ + Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f); merge_event (event); - - // locate to start of loop and roll - event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack()); - merge_event (event); - } + /* locate to start of loop and roll. If doing seamless loop, force a + locate+buffer refill even if we are positioned there already. + */ + start_locate (loc->start(), true, true, false, Config->get_seamless_loop()); + } } else { - clear_events (Event::AutoLoop); - - // set all diskstreams to NOT use internal looping - boost::shared_ptr dsl = diskstreams.reader(); - for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { - if (!(*i)->hidden()) { - (*i)->set_loop (0); - } - } + unset_play_loop (); } - TransportStateChange (); /* EMIT SIGNAL */ -} + TransportStateChange (); +} void Session::flush_all_inserts () { @@ -648,12 +694,12 @@ Session::flush_all_inserts () } void -Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop) +Session::start_locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force) { if (synced_to_jack()) { double sp; - nframes_t pos; + nframes64_t pos; _slave->speed_and_position (sp, pos); @@ -672,7 +718,7 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush, } } else { - locate (target_frame, with_roll, with_flush, with_loop); + locate (target_frame, with_roll, with_flush, with_loop, force); } } @@ -696,13 +742,13 @@ Session::micro_locate (nframes_t distance) } void -Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool with_loop) +Session::locate (nframes64_t target_frame, bool with_roll, bool with_flush, bool with_loop, bool force) { if (actively_recording() && !with_loop) { return; } - if (_transport_frame == target_frame && !loop_changing && !with_loop) { + if (!force && _transport_frame == target_frame && !loop_changing && !with_loop) { if (with_roll) { set_transport_speed (1.0, false); } @@ -730,17 +776,18 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w } if (transport_rolling() && (!auto_play_legal || !config.get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) { - realtime_stop (false); + realtime_stop (false, true); // XXX paul - check if the 2nd arg is really correct } - if ( !with_loop || loop_changing) { + if (force || !with_loop || loop_changing) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate); + PostTransportWork todo = PostTransportLocate; if (with_roll) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll); - } + todo = PostTransportWork (todo | PostTransportRoll); + } + add_post_transport_work (todo); _butler->schedule_transport_work (); } else { @@ -792,7 +839,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w if (al && (_transport_frame < al->start() || _transport_frame > al->end())) { // cancel looping directly, this is called from event handling context - set_play_loop (false, false); + set_play_loop (false); } else if (al && _transport_frame == al->start()) { if (with_loop) { @@ -824,7 +871,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w * @param abort */ void -Session::set_transport_speed (double speed, bool abort) +Session::set_transport_speed (double speed, bool abort, bool clear_state) { if (_transport_speed == speed) { return; @@ -859,6 +906,13 @@ Session::set_transport_speed (double speed, bool abort) } if (synced_to_jack ()) { + if (clear_state) { + /* do this here because our response to the slave won't + take care of it. + */ + _play_range = false; + unset_play_loop (); + } _engine.transport_stop (); } else { stop_transport (abort); @@ -919,9 +973,11 @@ Session::set_transport_speed (double speed, bool abort) /* if we are reversing relative to the current speed, or relative to the speed before the last stop, then we have to do extra work. */ + + PostTransportWork todo = PostTransportWork (0); if ((_transport_speed && speed * _transport_speed < 0.0) || (_last_transport_speed * speed < 0.0) || (_last_transport_speed == 0.0f && speed < 0.0f)) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse); + todo = PostTransportWork (todo | PostTransportReverse); } _last_transport_speed = _transport_speed; @@ -930,11 +986,13 @@ Session::set_transport_speed (double speed, bool abort) boost::shared_ptr dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); + todo = PostTransportWork (todo | PostTransportSpeed); + break; } } - if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) { + if (todo) { + add_post_transport_work (todo); _butler->schedule_transport_work (); } } @@ -943,7 +1001,7 @@ Session::set_transport_speed (double speed, bool abort) /** Stop the transport. */ void -Session::stop_transport (bool abort) +Session::stop_transport (bool abort, bool clear_state) { if (_transport_speed == 0.0f) { return; @@ -979,7 +1037,7 @@ Session::stop_transport (bool abort) return; } - realtime_stop (abort); + realtime_stop (abort, clear_state); _butler->schedule_transport_work (); } @@ -1031,7 +1089,9 @@ Session::start_transport () void Session::post_transport () { - if (post_transport_work & PostTransportAudition) { + PostTransportWork ptw = post_transport_work (); + + if (ptw & PostTransportAudition) { if (auditioner && auditioner->active()) { process_function = &Session::process_audition; } else { @@ -1039,14 +1099,14 @@ Session::post_transport () } } - if (post_transport_work & PostTransportStop) { + if (ptw & PostTransportStop) { transport_sub_state = 0; } - if (post_transport_work & PostTransportLocate) { + if (ptw & PostTransportLocate) { - if (((Config->get_slave_source() == None && (auto_play_legal && config.get_auto_play())) && !_exporting) || (post_transport_work & PostTransportRoll)) { + if (((Config->get_slave_source() == None && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) { start_transport (); } else { @@ -1055,8 +1115,10 @@ Session::post_transport () } set_next_event (); - - post_transport_work = PostTransportWork (0); + /* XXX is this really safe? shouldn't we just be unsetting the bits that we actually + know were handled ? + */ + set_post_transport_work (PostTransportWork (0)); } void @@ -1161,7 +1223,7 @@ Session::set_slave_source (SlaveSource src) } if (non_rt_required) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); + add_post_transport_work (PostTransportSpeed); _butler->schedule_transport_work (); } @@ -1171,7 +1233,7 @@ Session::set_slave_source (SlaveSource src) void Session::reverse_diskstream_buffers () { - post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse); + add_post_transport_work (PostTransportReverse); _butler->schedule_transport_work (); } @@ -1179,124 +1241,113 @@ void Session::set_diskstream_speed (Diskstream* stream, double speed) { if (stream->realtime_set_speed (speed, false)) { - post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); + add_post_transport_work (PostTransportSpeed); _butler->schedule_transport_work (); set_dirty (); } } void -Session::set_audio_range (list& range) -{ - Event *ev = new Event (Event::SetAudioRange, Event::Add, Event::Immediate, 0, 0.0f); - ev->audio_range = range; - queue_event (ev); -} - -void -Session::request_play_range (bool yn, bool leave_rolling) -{ - Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, (leave_rolling ? 1.0f : 0.0f), yn); - queue_event (ev); -} - -void -Session::set_play_range (bool yn, bool leave_rolling) +Session::unset_play_range () { - /* Called from event-processing context */ - - if (yn) { - /* cancel loop play */ - set_play_range (false, true); - } - - _play_range = yn; - setup_auto_play (); - - - if (!_play_range && !leave_rolling) { - /* stop transport */ - Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false); - merge_event (ev); - } - TransportStateChange (); /* EMIT SIGNAL */ + _play_range = false; + _clear_event_type (Event::RangeStop); + _clear_event_type (Event::RangeLocate); } void -Session::setup_auto_play () +Session::set_play_range (list& range, bool leave_rolling) { - /* Called from event-processing context */ - Event* ev; - _clear_event_type (Event::RangeStop); - _clear_event_type (Event::RangeLocate); + /* Called from event-processing context */ - if (!_play_range) { + unset_play_range (); + + if (range.empty()) { + /* _play_range set to false in unset_play_range() + */ + if (!leave_rolling) { + /* stop transport */ + Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false); + merge_event (ev); + } return; } - list::size_type sz = current_audio_range.size(); + _play_range = true; - if (sz > 1) { + /* cancel loop play */ + unset_play_loop (); - list::iterator i = current_audio_range.begin(); + list::size_type sz = range.size(); + + if (sz > 1) { + + list::iterator i = range.begin(); list::iterator next; - - while (i != current_audio_range.end()) { - + + while (i != range.end()) { + next = i; ++next; - + /* locating/stopping is subject to delays for declicking. */ - + nframes_t requested_frame = (*i).end; - + if (requested_frame > current_block_size) { requested_frame -= current_block_size; } else { requested_frame = 0; } - - if (next == current_audio_range.end()) { + + if (next == range.end()) { ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f); } else { ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f); } - + merge_event (ev); - + i = next; } - + } else if (sz == 1) { - ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f); + ev = new Event (Event::RangeStop, Event::Add, range.front().end, 0, 0.0f); merge_event (ev); + + } - } + /* save range so we can do auto-return etc. */ + + current_audio_range = range; /* now start rolling at the right place */ - ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false); + ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, range.front().start, 0.0f, false); merge_event (ev); + + TransportStateChange (); } void -Session::request_roll_at_and_return (nframes_t start, nframes_t return_to) +Session::request_bounded_roll (nframes_t start, nframes_t end) { - Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0); - ev->target2_frame = start; - queue_event (ev); -} + AudioRange ar (start, end, 0); + list lar; + lar.push_back (ar); + request_play_range (&lar, true); +} void -Session::request_bounded_roll (nframes_t start, nframes_t end) +Session::request_roll_at_and_return (nframes_t start, nframes_t return_to) { - Event *ev = new Event (Event::StopOnce, Event::Replace, end, Event::Immediate, 0.0); + Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0); + ev->target2_frame = start; queue_event (ev); - request_locate (start, true); } void @@ -1312,10 +1363,10 @@ Session::engine_halted () */ g_atomic_int_set (&_butler->should_do_transport_work, 0); - post_transport_work = PostTransportWork (0); + set_post_transport_work (PostTransportWork (0)); _butler->stop (); - realtime_stop (false); + realtime_stop (false, true); non_realtime_stop (false, 0, ignored); transport_sub_state = 0; @@ -1326,7 +1377,7 @@ Session::engine_halted () void Session::xrun_recovery () { - Xrun (transport_frame()); //EMIT SIGNAL + Xrun ((nframes64_t)_transport_frame); //EMIT SIGNAL if (Config->get_stop_recording_on_xrun() && actively_recording()) { @@ -1342,12 +1393,14 @@ void Session::update_latency_compensation (bool with_stop, bool abort) { bool update_jack = false; + PostTransportWork ptw; if (_state_of_the_state & Deletion) { return; } _worst_track_latency = 0; + ptw = post_transport_work(); #undef DEBUG_LATENCY #ifdef DEBUG_LATENCY @@ -1359,8 +1412,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (with_stop) { - (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), - (!(post_transport_work & PostTransportLocate) || pending_locate_flush)); + (*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush)); } nframes_t old_latency = (*i)->output()->signal_latency (); diff --git a/libs/ardour/slave.cc b/libs/ardour/slave.cc index f07ea4c872..be88fe223c 100644 --- a/libs/ardour/slave.cc +++ b/libs/ardour/slave.cc @@ -35,13 +35,13 @@ SlaveSessionProxy::frame_rate() const return session.frame_rate(); } -nframes_t +nframes64_t SlaveSessionProxy::audible_frame() const { return session.audible_frame(); } -nframes_t +nframes64_t SlaveSessionProxy::transport_frame() const { return session.transport_frame(); @@ -53,14 +53,14 @@ SlaveSessionProxy::frames_since_cycle_start() const return session.engine().frames_since_cycle_start(); } -nframes_t +nframes64_t SlaveSessionProxy::frame_time() const { return session.engine().frame_time(); } void -SlaveSessionProxy::request_locate(nframes_t frame, bool with_roll) +SlaveSessionProxy::request_locate(nframes64_t frame, bool with_roll) { session.request_locate(frame, with_roll); } -- cgit v1.2.3