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
This commit is contained in:
Paul Davis 2009-11-08 16:28:21 +00:00
parent 660fd702af
commit ff122d0fe8
24 changed files with 492 additions and 404 deletions

View file

@ -1549,7 +1549,7 @@ ARDOUR_UI::transport_roll ()
}
void
ARDOUR_UI::toggle_roll (bool with_abort)
ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
{
if (!session) {
@ -1573,27 +1573,35 @@ ARDOUR_UI::toggle_roll (bool with_abort)
bool rolling = session->transport_rolling();
bool affect_transport = true;
if (rolling) {
if (rolling && roll_out_of_bounded_mode) {
/* drop out of loop/range playback but leave transport rolling */
if (session->get_play_loop()) {
affect_transport = false;
if (Config->get_seamless_loop()) {
/* the disk buffers contain copies of the loop - we can't
just keep playing, so stop the transport. the user
can restart as they wish.
*/
affect_transport = true;
} else {
/* disk buffers are normal, so we can keep playing */
affect_transport = false;
}
session->request_play_loop (false, true);
} else if (session->get_play_range ()) {
affect_transport = false;
session->request_play_range (false, true);
session->request_play_range (0, true);
}
}
}
if (affect_transport) {
if (rolling) {
session->request_stop (with_abort);
session->request_stop (with_abort, true);
} else {
session->request_transport_speed (1.0f);
}
}
map_transport_state ();
map_transport_state ();
}
void

View file

@ -547,7 +547,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
void transport_forward (int option);
void transport_rewind (int option);
void transport_loop ();
void toggle_roll (bool with_abort);
void toggle_roll (bool with_abort, bool roll_out_of_bounded_mode);
bool _session_is_new;
void connect_to_session (ARDOUR::Session *);

View file

@ -251,10 +251,13 @@ ARDOUR_UI::install_actions ()
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
ActionManager::register_action (transport_actions, X_("ToggleRoll"), _("Start/Stop"), bind (mem_fun (*this, &ARDOUR_UI::toggle_roll), false));
act = ActionManager::register_action (transport_actions, X_("ToggleRoll"), _("Start/Stop"), bind (mem_fun (*this, &ARDOUR_UI::toggle_roll), false, false));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
ActionManager::register_action (transport_actions, X_("ToggleRollForgetCapture"), _("Stop and Forget Capture"), bind (mem_fun(*this, &ARDOUR_UI::toggle_roll), true));
act = ActionManager::register_action (transport_actions, X_("ToggleRollMaybe"), _("Start/Continue/Stop"), bind (mem_fun (*this, &ARDOUR_UI::toggle_roll), false, true));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);
act = ActionManager::register_action (transport_actions, X_("ToggleRollForgetCapture"), _("Stop + Forget Capture"), bind (mem_fun(*this, &ARDOUR_UI::toggle_roll), true, false));
ActionManager::session_sensitive_actions.push_back (act);
ActionManager::transport_sensitive_actions.push_back (act);

View file

@ -50,15 +50,16 @@ using namespace ArdourCanvas;
double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
Drag::Drag (Editor* e, ArdourCanvas::Item* i) :
_editor (e),
_item (i),
_pointer_frame_offset (0),
_grab_frame (0),
_last_pointer_frame (0),
_current_pointer_frame (0),
_had_movement (false),
_move_threshold_passed (false)
Drag::Drag (Editor* e, ArdourCanvas::Item* i)
: _editor (e)
, _item (i)
, _pointer_frame_offset (0)
, _grab_frame (0)
, _last_pointer_frame (0)
, _current_pointer_frame (0)
, _had_movement (false)
, _have_transaction (false)
, _move_threshold_passed (false)
{
}
@ -778,6 +779,8 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
}
}
_have_transaction = true;
changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
@ -1551,6 +1554,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
}
_editor->begin_reversible_command (trim_type);
_have_transaction = true;
for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
(*i)->fake_set_opaque(false);
@ -1576,6 +1580,9 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
return;
}
/* XXX i hope to god that we can really conclude this ... */
_have_transaction = true;
if (left_direction) {
frame_delta = (_last_pointer_frame - _current_pointer_frame);
} else {
@ -1658,15 +1665,19 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
(*i)->fake_set_opaque (true);
}
}
for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
(*p)->thaw ();
_editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
if (_have_transaction) {
_editor->session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
}
}
_editor->motion_frozen_playlists.clear ();
_editor->commit_reversible_command();
if (_have_transaction) {
_editor->commit_reversible_command();
}
} else {
/* no mouse movement */
_editor->point_trim (event);
@ -2853,9 +2864,9 @@ ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
}
SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
: Drag (e, i),
_operation (o),
_copy (false)
: Drag (e, i)
, _operation (o)
, _copy (false)
{
}
@ -2924,6 +2935,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
nframes64_t end = 0;
nframes64_t length;
nframes64_t const pending_position = adjusted_current_frame (event);
/* only alter selection if the current frame is
@ -2956,6 +2968,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
if (first_move) {
_editor->begin_reversible_command (_("range selection"));
_have_transaction = true;
if (_copy) {
/* adding to the selection */
@ -2972,8 +2985,9 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
if (first_move) {
_editor->begin_reversible_command (_("trim selection start"));
_have_transaction = true;
}
start = _editor->selection->time[_editor->clicked_selection].start;
end = _editor->selection->time[_editor->clicked_selection].end;
@ -2988,6 +3002,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
if (first_move) {
_editor->begin_reversible_command (_("trim selection end"));
_have_transaction = true;
}
start = _editor->selection->time[_editor->clicked_selection].start;
@ -3005,6 +3020,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
if (first_move) {
_editor->begin_reversible_command (_("move selection"));
_have_transaction = true;
}
start = _editor->selection->time[_editor->clicked_selection].start;
@ -3040,13 +3056,25 @@ SelectionDrag::motion (GdkEvent* event, bool first_move)
void
SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
{
Session* s = _editor->session;
if (movement_occurred) {
motion (event, false);
/* XXX this is not object-oriented programming at all. ick */
if (_editor->selection->time.consolidate()) {
_editor->selection->TimeChanged ();
}
_editor->commit_reversible_command ();
if (_have_transaction) {
_editor->commit_reversible_command ();
}
/* XXX what if its a music time selection? */
if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
s->request_play_range (&_editor->selection->time, true);
}
} else {
/* just a click, no pointer movement.*/
@ -3055,10 +3083,13 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
_editor->selection->clear_time();
}
if (s && s->get_play_range () && s->transport_rolling()) {
s->request_stop (false, false);
}
}
/* XXX what happens if its a music selection? */
_editor->session->set_audio_range (_editor->selection->time);
_editor->stop_canvas_autoscroll ();
}

View file

@ -136,6 +136,7 @@ protected:
bool _x_constrained; ///< true if x motion is constrained, otherwise false
bool _y_constrained; ///< true if y motion is constrained, otherwise false
bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
private:

View file

@ -2410,7 +2410,7 @@ Editor::play_selection ()
return;
}
session->request_play_range (true);
session->request_play_range (&selection->time, true);
}
void

View file

@ -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;
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;
};
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<AudioRange> audio_range;
std::list<MusicRange> music_range;
boost::shared_ptr<Region> region;
Event(Type t, Action a, nframes_t when, nframes_t where, double spd, bool yn = false)
union {
bool second_yes_or_no;
};
std::list<AudioRange> audio_range;
std::list<MusicRange> music_range;
boost::shared_ptr<Region> 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<void> TransportStateChange; /* generic */
sigc::signal<void,nframes_t> PositionChanged; /* sent after any non-sequential motion */
sigc::signal<void,nframes64_t> PositionChanged; /* sent after any non-sequential motion */
sigc::signal<void> DurationChanged;
sigc::signal<void,nframes_t> Xrun;
sigc::signal<void,nframes64_t> Xrun;
sigc::signal<void> 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<bool>(post_transport_work&PostTransportLocate); }
bool locate_pending() const { return static_cast<bool>(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<AudioRange>&);
void set_music_range (std::list<MusicRange>&);
void request_play_range (bool yn, bool leave_rolling = false);
void request_play_range (std::list<AudioRange>*, 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<bool>(post_transport_work); }
bool process_can_proceed() const { return !(post_transport_work & ProcessCannotProceedMask); }
bool non_realtime_work_pending() const { return static_cast<bool>(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<AudioRange> 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<AudioRange>&, bool leave_rolling);
void unset_play_range ();
/* main outs */
uint32_t main_outs;

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -16,6 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cstdlib>
#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 ();
const char* c = 0;
sys::path p;
if (home_dir.empty ()) {
const string error_msg = "Unable to determine home directory";
/* adopt freedesktop standards, and put .ardour3 into $XDG_CONFIG_HOME or ~/.config
*/
// log the error
error << error_msg << endmsg;
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);
}
throw sys::filesystem_error(error_msg);
p = home_dir;
p /= ".config";
}
sys::path p(home_dir);
p /= user_config_dir_name;
return p;

View file

@ -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) {

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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<Region> r)
{
pending_audition_region = r;
post_transport_work = PostTransportWork (post_transport_work | PostTransportAudition);
add_post_transport_work (PostTransportAudition);
_butler->schedule_transport_work ();
}

View file

@ -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 ();
}

View file

@ -23,6 +23,7 @@
#include "ardour/timestamps.h"
#include "pbd/error.h"
#include "pbd/enumwriter.h"
#include <glibmm/thread.h>
#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:

View file

@ -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()) {

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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<AudioRange>* 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<RouteList> r = routes.reader ();
boost::shared_ptr<DiskstreamList> 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<DiskstreamList> 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) {
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;
}
if ((actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
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<DiskstreamList> 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<DiskstreamList> 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,110 +1241,107 @@ 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<AudioRange>& range)
Session::unset_play_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)
{
/* 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 */
}
void
Session::setup_auto_play ()
{
/* Called from event-processing context */
Event* ev;
_play_range = false;
_clear_event_type (Event::RangeStop);
_clear_event_type (Event::RangeLocate);
}
if (!_play_range) {
void
Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
{
Event* ev;
/* Called from event-processing context */
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<AudioRange>::size_type sz = current_audio_range.size();
_play_range = true;
/* cancel loop play */
unset_play_loop ();
list<AudioRange>::size_type sz = range.size();
if (sz > 1) {
list<AudioRange>::iterator i = current_audio_range.begin();
list<AudioRange>::iterator i = range.begin();
list<AudioRange>::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_bounded_roll (nframes_t start, nframes_t end)
{
AudioRange ar (start, end, 0);
list<AudioRange> lar;
lar.push_back (ar);
request_play_range (&lar, true);
}
void
Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
{
@ -1291,14 +1350,6 @@ Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
queue_event (ev);
}
void
Session::request_bounded_roll (nframes_t start, nframes_t end)
{
Event *ev = new Event (Event::StopOnce, Event::Replace, end, Event::Immediate, 0.0);
queue_event (ev);
request_locate (start, true);
}
void
Session::engine_halted ()
{
@ -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 ();

View file

@ -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);
}