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 void
ARDOUR_UI::toggle_roll (bool with_abort) ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
{ {
if (!session) { if (!session) {
@ -1573,27 +1573,35 @@ ARDOUR_UI::toggle_roll (bool with_abort)
bool rolling = session->transport_rolling(); bool rolling = session->transport_rolling();
bool affect_transport = true; bool affect_transport = true;
if (rolling) { if (rolling && roll_out_of_bounded_mode) {
/* drop out of loop/range playback but leave transport rolling */ /* drop out of loop/range playback but leave transport rolling */
if (session->get_play_loop()) { 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); session->request_play_loop (false, true);
} else if (session->get_play_range ()) { } else if (session->get_play_range ()) {
affect_transport = false; affect_transport = false;
session->request_play_range (false, true); session->request_play_range (0, true);
} }
} }
if (affect_transport) { if (affect_transport) {
if (rolling) { if (rolling) {
session->request_stop (with_abort); session->request_stop (with_abort, true);
} else { } else {
session->request_transport_speed (1.0f); session->request_transport_speed (1.0f);
} }
} }
map_transport_state (); map_transport_state ();
} }
void void

View file

@ -547,7 +547,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
void transport_forward (int option); void transport_forward (int option);
void transport_rewind (int option); void transport_rewind (int option);
void transport_loop (); 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; bool _session_is_new;
void connect_to_session (ARDOUR::Session *); void connect_to_session (ARDOUR::Session *);

View file

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

View file

@ -136,6 +136,7 @@ protected:
bool _x_constrained; ///< true if x motion is constrained, otherwise false bool _x_constrained; ///< true if x motion is constrained, otherwise false
bool _y_constrained; ///< true if y 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 _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: private:

View file

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

View file

@ -132,8 +132,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
Recording = 2 Recording = 2
}; };
struct Event { struct Event {
enum Type { enum Type {
SetTransportSpeed, SetTransportSpeed,
SetDiskstreamSpeed, SetDiskstreamSpeed,
Locate, Locate,
@ -148,78 +148,82 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
SetSlaveSource, SetSlaveSource,
Audition, Audition,
InputConfigurationChange, InputConfigurationChange,
SetAudioRange, SetPlayAudioRange,
SetPlayRange,
/* only one of each of these events can be queued at any one time */ /* only one of each of these events can be queued at any one time */
StopOnce, StopOnce,
AutoLoop 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 { union {
Add, bool second_yes_or_no;
Remove, };
Replace,
Clear std::list<AudioRange> audio_range;
}; std::list<MusicRange> music_range;
Type type; boost::shared_ptr<Region> region;
Action action;
nframes_t action_frame; Event(Type t, Action a, nframes_t when, nframes_t where, double spd, bool yn = false, bool yn2 = false)
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)
: type (t) : type (t)
, action (a) , action (a)
, action_frame (when) , action_frame (when)
, target_frame (where) , target_frame (where)
, speed (spd) , speed (spd)
, yes_or_no (yn) , yes_or_no (yn)
, second_yes_or_no (yn2)
{} {}
void set_ptr (void* p) { void set_ptr (void* p) {
ptr = p; ptr = p;
} }
bool before (const Event& other) const { bool before (const Event& other) const {
return action_frame < other.action_frame; return action_frame < other.action_frame;
} }
bool after (const Event& other) const { bool after (const Event& other) const {
return action_frame > other.action_frame; return action_frame > other.action_frame;
} }
static bool compare (const Event *e1, const Event *e2) { static bool compare (const Event *e1, const Event *e2) {
return e1->before (*e2); return e1->before (*e2);
} }
void *operator new (size_t) { void *operator new (size_t) {
return pool.alloc (); return pool.alloc ();
} }
void operator delete (void *ptr, size_t /*size*/) { void operator delete (void *ptr, size_t /*size*/) {
pool.release (ptr); pool.release (ptr);
} }
static const nframes_t Immediate = 0; static const nframes_t Immediate = 0;
private: private:
static MultiAllocSingleReleasePool pool; static MultiAllocSingleReleasePool pool;
}; };
/* creating from an XML file */ /* creating from an XML file */
@ -375,9 +379,9 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* Transport mechanism signals */ /* Transport mechanism signals */
sigc::signal<void> TransportStateChange; /* generic */ 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> DurationChanged;
sigc::signal<void,nframes_t> Xrun; sigc::signal<void,nframes64_t> Xrun;
sigc::signal<void> TransportLooped; sigc::signal<void> TransportLooped;
/** emitted when a locate has occurred */ /** 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_roll_at_and_return (nframes_t start, nframes_t return_to);
void request_bounded_roll (nframes_t start, nframes_t end); 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_locate (nframes_t frame, bool with_roll = false);
void request_play_loop (bool yn, bool leave_rolling = 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_diskstream_speed (Diskstream&, double speed);
void request_input_change_handling (); 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; bool transport_locked () const;
int wipe (); int wipe ();
@ -533,8 +537,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* Time */ /* Time */
nframes_t transport_frame () const {return _transport_frame; } nframes64_t transport_frame () const {return _transport_frame; }
nframes_t audible_frame () const; nframes64_t audible_frame () const;
nframes64_t requested_return_frame() const { return _requested_return_frame; } nframes64_t requested_return_frame() const { return _requested_return_frame; }
enum PullupFormat { enum PullupFormat {
@ -914,10 +918,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* ranges */ /* ranges */
void set_audio_range (std::list<AudioRange>&); void request_play_range (std::list<AudioRange>*, bool leave_rolling = false);
void set_music_range (std::list<MusicRange>&);
void request_play_range (bool yn, bool leave_rolling = false);
bool get_play_range () const { return _play_range; } bool get_play_range () const { return _play_range; }
/* buffers for gain and pan */ /* 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 nframes_t _nominal_frame_rate; //ignores audioengine setting, "native" SR
int transport_sub_state; int transport_sub_state;
mutable gint _record_status; mutable gint _record_status;
volatile nframes_t _transport_frame; volatile nframes64_t _transport_frame;
Location* end_location; Location* end_location;
Location* start_location; Location* start_location;
Slave* _slave; Slave* _slave;
@ -1010,7 +1011,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
CubicInterpolation interpolation; CubicInterpolation interpolation;
bool auto_play_legal; bool auto_play_legal;
nframes_t _last_slave_transport_frame; nframes64_t _last_slave_transport_frame;
nframes_t maximum_output_latency; nframes_t maximum_output_latency;
volatile nframes64_t _requested_return_frame; volatile nframes64_t _requested_return_frame;
BufferSet* _scratch_buffers; BufferSet* _scratch_buffers;
@ -1026,6 +1027,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
bool _non_soloed_outs_muted; bool _non_soloed_outs_muted;
uint32_t _listen_cnt; uint32_t _listen_cnt;
bool _writable; bool _writable;
bool _was_seamless;
void set_worst_io_latencies (); void set_worst_io_latencies ();
void set_worst_io_latencies_x (IOChange, void *) { void set_worst_io_latencies_x (IOChange, void *) {
@ -1180,7 +1182,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
PostTransportScrub = 0x8000, PostTransportScrub = 0x8000,
PostTransportReverse = 0x10000, PostTransportReverse = 0x10000,
PostTransportInputChange = 0x20000, PostTransportInputChange = 0x20000,
PostTransportCurveRealloc = 0x40000 PostTransportCurveRealloc = 0x40000,
PostTransportClearSubstate = 0x80000
}; };
static const PostTransportWork ProcessCannotProceedMask = static const PostTransportWork ProcessCannotProceedMask =
@ -1192,9 +1195,13 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
PostTransportScrub| PostTransportScrub|
PostTransportAudition| PostTransportAudition|
PostTransportLocate| 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 cumulative_rf_motion;
uint32_t rf_scale; uint32_t rf_scale;
@ -1337,8 +1344,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
int no_roll (nframes_t nframes); int no_roll (nframes_t nframes);
int fail_roll (nframes_t nframes); int fail_roll (nframes_t nframes);
bool non_realtime_work_pending() const { return static_cast<bool>(post_transport_work); } bool non_realtime_work_pending() const { return static_cast<bool>(post_transport_work()); }
bool process_can_proceed() const { return !(post_transport_work & ProcessCannotProceedMask); } bool process_can_proceed() const { return !(post_transport_work() & ProcessCannotProceedMask); }
struct MIDIRequest { struct MIDIRequest {
enum Type { enum Type {
@ -1361,18 +1368,19 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
void change_midi_ports (); void change_midi_ports ();
int use_config_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 overwrite_some_buffers (Diskstream*);
void flush_all_inserts (); void flush_all_inserts ();
int micro_locate (nframes_t distance); int micro_locate (nframes_t distance);
void locate (nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void locate (nframes64_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false);
void start_locate (nframes_t, bool with_roll, bool with_flush, bool with_loop=false); void start_locate (nframes64_t, bool with_roll, bool with_flush, bool with_loop=false, bool force=false);
void force_locate (nframes_t frame, bool with_roll = false); void force_locate (nframes64_t frame, bool with_roll = false);
void set_diskstream_speed (Diskstream*, double speed); void set_diskstream_speed (Diskstream*, double speed);
void set_transport_speed (double speed, bool abort = false); void set_transport_speed (double speed, bool abort = false, bool clear_state = false);
void stop_transport (bool abort = false); void stop_transport (bool abort = false, bool clear_state = false);
void start_transport (); void start_transport ();
void realtime_stop (bool abort); void realtime_stop (bool abort, bool clear_state);
void non_realtime_start_scrub (); void non_realtime_start_scrub ();
void non_realtime_set_speed (); void non_realtime_set_speed ();
void non_realtime_locate (); void non_realtime_locate ();
@ -1619,8 +1627,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
std::list<AudioRange> current_audio_range; std::list<AudioRange> current_audio_range;
bool _play_range; bool _play_range;
void set_play_range (bool yn, bool leave_rolling); void set_play_range (std::list<AudioRange>&, bool leave_rolling);
void setup_auto_play (); void unset_play_range ();
/* main outs */ /* main outs */
uint32_t main_outs; uint32_t main_outs;

View file

@ -107,7 +107,7 @@ class Slave {
* @param position - The transport position requested * @param position - The transport position requested
* @return - The return value is currently ignored (see Session::follow_slave) * @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 * reports to ARDOUR whether the Slave is currently synced to its external
@ -161,13 +161,13 @@ class Slave {
class ISlaveSessionProxy { class ISlaveSessionProxy {
public: public:
virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); } virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); }
virtual nframes_t frame_rate() const { return 0; } virtual nframes_t frame_rate() const { return 0; }
virtual nframes_t audible_frame () const { return 0; } virtual nframes64_t audible_frame () const { return 0; }
virtual nframes_t transport_frame () const { return 0; } virtual nframes64_t transport_frame () const { return 0; }
virtual nframes_t frames_since_cycle_start () const { return 0; } virtual nframes_t frames_since_cycle_start () const { return 0; }
virtual nframes_t frame_time () 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; (void) with_roll;
} }
virtual void request_transport_speed (double /*speed*/) {} virtual void request_transport_speed (double /*speed*/) {}
@ -181,14 +181,14 @@ class SlaveSessionProxy : public ISlaveSessionProxy {
public: public:
SlaveSessionProxy(Session &s) : session(s) {} SlaveSessionProxy(Session &s) : session(s) {}
TempoMap& tempo_map() const; TempoMap& tempo_map() const;
nframes_t frame_rate() const; nframes_t frame_rate() const;
nframes_t audible_frame () const; nframes64_t audible_frame () const;
nframes_t transport_frame () const; nframes64_t transport_frame () const;
nframes_t frames_since_cycle_start () const; nframes_t frames_since_cycle_start () const;
nframes_t frame_time () 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); void request_transport_speed (double speed);
}; };
@ -211,7 +211,7 @@ class MTC_Slave : public Slave, public sigc::trackable {
~MTC_Slave (); ~MTC_Slave ();
void rebind (MIDI::Port&); void rebind (MIDI::Port&);
bool speed_and_position (double&, nframes_t&); bool speed_and_position (double&, nframes64_t&);
bool locked() const; bool locked() const;
bool ok() const; bool ok() const;
@ -256,7 +256,7 @@ class MIDIClock_Slave : public Slave, public sigc::trackable {
~MIDIClock_Slave (); ~MIDIClock_Slave ();
void rebind (MIDI::Port&); void rebind (MIDI::Port&);
bool speed_and_position (double&, nframes_t&); bool speed_and_position (double&, nframes64_t&);
bool locked() const; bool locked() const;
bool ok() const; bool ok() const;
@ -311,17 +311,17 @@ class MIDIClock_Slave : public Slave, public sigc::trackable {
double b, c, omega; double b, c, omega;
void reset (); void reset ();
void start (MIDI::Parser& parser, nframes_t timestamp); void start (MIDI::Parser& parser, nframes64_t timestamp);
void contineu (MIDI::Parser& parser, nframes_t timestamp); void contineu (MIDI::Parser& parser, nframes64_t timestamp);
void stop (MIDI::Parser& parser, nframes_t timestamp); void stop (MIDI::Parser& parser, nframes64_t timestamp);
void position (MIDI::Parser& parser, MIDI::byte* message, size_t size); void position (MIDI::Parser& parser, MIDI::byte* message, size_t size);
// we can't use continue because it is a C++ keyword // we can't use continue because it is a C++ keyword
void calculate_one_ppqn_in_frames_at(nframes_t time); void calculate_one_ppqn_in_frames_at(nframes64_t time);
nframes_t calculate_song_position(uint16_t song_position_in_sixteenth_notes); nframes64_t calculate_song_position(uint16_t song_position_in_sixteenth_notes);
void calculate_filter_coefficients(); 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; 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 /// whether transport should be rolling
bool _started; bool _started;
@ -337,7 +337,7 @@ class ADAT_Slave : public Slave
ADAT_Slave () {} ADAT_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; speed = 0;
pos = 0; pos = 0;
return false; return false;
@ -355,7 +355,7 @@ class JACK_Slave : public Slave
JACK_Slave (jack_client_t*); JACK_Slave (jack_client_t*);
~JACK_Slave (); ~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 starting() const { return _starting; }
bool locked() const; 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]; nframes_t total = chaninfo->playback_vector.len[0] + chaninfo->playback_vector.len[1];
if (necessary_samples > total) { if (necessary_samples > total) {
cerr << _name << " Need " << necessary_samples << " total = " << total << endl;
cerr << "underrun for " << _name << endl; cerr << "underrun for " << _name << endl;
DiskUnderrun (); DiskUnderrun ();
goto out; goto out;
@ -1754,7 +1755,7 @@ AudioDiskstream::get_state ()
if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) { if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) {
snprintf (buf, sizeof (buf), "%" PRId64, pi->start()); snprintf (buf, sizeof (buf), "%" PRId64, pi->start());
} else { } else {
snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame()); snprintf (buf, sizeof (buf), "%" PRId64, _session.transport_frame());
} }
cs_child->add_property (X_("at"), buf); 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, SetSlaveSource);
REGISTER_CLASS_ENUM (Session::Event, Audition); REGISTER_CLASS_ENUM (Session::Event, Audition);
REGISTER_CLASS_ENUM (Session::Event, InputConfigurationChange); REGISTER_CLASS_ENUM (Session::Event, InputConfigurationChange);
REGISTER_CLASS_ENUM (Session::Event, SetAudioRange); REGISTER_CLASS_ENUM (Session::Event, SetPlayAudioRange);
REGISTER_CLASS_ENUM (Session::Event, SetPlayRange);
REGISTER_CLASS_ENUM (Session::Event, StopOnce); REGISTER_CLASS_ENUM (Session::Event, StopOnce);
REGISTER_CLASS_ENUM (Session::Event, AutoLoop); REGISTER_CLASS_ENUM (Session::Event, AutoLoop);
REGISTER (_Session_Event_Type); REGISTER (_Session_Event_Type);

View file

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

View file

@ -36,7 +36,7 @@ JACK_Slave::JACK_Slave (jack_client_t* j)
: jack (j) : jack (j)
{ {
double x; double x;
nframes_t p; nframes64_t p;
/* call this to initialize things */ /* call this to initialize things */
speed_and_position (x, p); speed_and_position (x, p);
} }
@ -64,10 +64,11 @@ JACK_Slave::ok() const
} }
bool 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_position_t pos;
jack_transport_state_t state; jack_transport_state_t state;
state = jack_transport_query (jack, &pos); state = jack_transport_query (jack, &pos);
switch (state) { switch (state) {

View file

@ -87,7 +87,7 @@ MIDIClock_Slave::rebind (MIDI::Port& p)
} }
void 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 Tempo& current_tempo = session->tempo_map().tempo_at(time);
const Meter& current_meter = session->tempo_map().meter_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); 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) 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) { 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 // one quarter note contains ppqn pulses, so a sixteenth note is ppqn / 4 pulses
calculate_one_ppqn_in_frames_at(song_position_frames); 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; return song_position_frames;
@ -124,7 +124,7 @@ MIDIClock_Slave::calculate_filter_coefficients()
} }
void 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 // some pieces of hardware send MIDI Clock all the time
if ( (!_starting) && (!_started) ) { 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); 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; double error = 0;
if (_starting || last_timestamp == 0) { if (_starting || last_timestamp == 0) {
@ -195,7 +195,7 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, nframes_t timestamp)
} }
void void
MIDIClock_Slave::start (Parser& /*parser*/, nframes_t /*timestamp*/) MIDIClock_Slave::start (Parser& /*parser*/, nframes64_t /*timestamp*/)
{ {
#ifdef DEBUG_MIDI_CLOCK #ifdef DEBUG_MIDI_CLOCK
cerr << "MIDIClock_Slave got start message at time " << timestamp << " engine time: " << session->frame_time() << endl; cerr << "MIDIClock_Slave got start message at time " << timestamp << " engine time: " << session->frame_time() << endl;
@ -223,7 +223,7 @@ MIDIClock_Slave::reset ()
} }
void void
MIDIClock_Slave::contineu (Parser& /*parser*/, nframes_t /*timestamp*/) MIDIClock_Slave::contineu (Parser& /*parser*/, nframes64_t /*timestamp*/)
{ {
#ifdef DEBUG_MIDI_CLOCK #ifdef DEBUG_MIDI_CLOCK
std::cerr << "MIDIClock_Slave got continue message" << endl; std::cerr << "MIDIClock_Slave got continue message" << endl;
@ -236,7 +236,7 @@ MIDIClock_Slave::contineu (Parser& /*parser*/, nframes_t /*timestamp*/)
void void
MIDIClock_Slave::stop (Parser& /*parser*/, nframes_t /*timestamp*/) MIDIClock_Slave::stop (Parser& /*parser*/, nframes64_t /*timestamp*/)
{ {
#ifdef DEBUG_MIDI_CLOCK #ifdef DEBUG_MIDI_CLOCK
std::cerr << "MIDIClock_Slave got stop message" << endl; 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 // that is the position of the last MIDI Clock
// message and that is probably what the master // message and that is probably what the master
// expects where we are right now // 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 // find out the last MIDI beat: go back #midi_clocks mod 6
// and lets hope the tempo didnt change in those last 6 beats :) // 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)); assert((lsb <= 0x7f) && (msb <= 0x7f));
uint16_t position_in_sixteenth_notes = (uint16_t(msb) << 7) | uint16_t(lsb); 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 #ifdef DEBUG_MIDI_CLOCK
cerr << "Song Position: " << position_in_sixteenth_notes << " frames: " << position_in_frames << endl; cerr << "Song Position: " << position_in_sixteenth_notes << " frames: " << position_in_frames << endl;
@ -313,7 +313,7 @@ MIDIClock_Slave::starting() const
} }
bool 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 */ /* no timecode for 1/4 second ? conclude that its stopped */
if (last_timestamp && if (last_timestamp &&
@ -332,7 +332,7 @@ MIDIClock_Slave::stop_if_no_more_clock_events(nframes_t& pos, nframes_t now)
} }
bool bool
MIDIClock_Slave::speed_and_position (double& speed, nframes_t& pos) MIDIClock_Slave::speed_and_position (double& speed, nframes64_t& pos)
{ {
if (!_started || _starting) { if (!_started || _starting) {
speed = 0.0; speed = 0.0;
@ -340,7 +340,7 @@ MIDIClock_Slave::speed_and_position (double& speed, nframes_t& pos)
return true; 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)) { if (stop_if_no_more_clock_events(pos, engine_now)) {
return false; return false;
@ -353,8 +353,8 @@ MIDIClock_Slave::speed_and_position (double& speed, nframes_t& pos)
if (engine_now > last_timestamp) { if (engine_now > last_timestamp) {
// we are in between MIDI clock messages // we are in between MIDI clock messages
// so we interpolate position according to speed // so we interpolate position according to speed
nframes_t elapsed = engine_now - last_timestamp; nframes64_t elapsed = engine_now - last_timestamp;
pos = nframes_t (should_be_position + double(elapsed) * speed); pos = (nframes64_t) (should_be_position + double(elapsed) * speed);
} else { } else {
// A new MIDI clock message has arrived this cycle // A new MIDI clock message has arrived this cycle
pos = should_be_position; 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)) { if (_session.config.get_punch_in() && ((pi = _session.locations()->auto_punch_location()) != 0)) {
snprintf (buf, sizeof (buf), "%" PRId64, pi->start()); snprintf (buf, sizeof (buf), "%" PRId64, pi->start());
} else { } else {
snprintf (buf, sizeof (buf), "%" PRIu32, _session.transport_frame()); snprintf (buf, sizeof (buf), "%" PRId64, _session.transport_frame());
} }
cs_child->add_property (X_("at"), buf); cs_child->add_property (X_("at"), buf);

View file

@ -72,7 +72,7 @@ void
MTC_Slave::update_mtc_qtr (Parser& /*p*/) MTC_Slave::update_mtc_qtr (Parser& /*p*/)
{ {
cycles_t cnow = get_cycles (); cycles_t cnow = get_cycles ();
nframes_t now = session.engine().frame_time(); nframes64_t now = session.engine().frame_time();
nframes_t qtr; nframes_t qtr;
static cycles_t last_qtr = 0; static cycles_t last_qtr = 0;
@ -91,7 +91,7 @@ MTC_Slave::update_mtc_qtr (Parser& /*p*/)
void void
MTC_Slave::update_mtc_time (const byte *msg, bool was_full) 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::Time timecode;
timecode.hours = msg[3]; timecode.hours = msg[3];
@ -258,9 +258,9 @@ MTC_Slave::ok() const
} }
bool 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; SafeTime last;
nframes_t frame_rate; nframes_t frame_rate;
nframes_t elapsed; nframes_t elapsed;

View file

@ -132,7 +132,6 @@ Session::Session (AudioEngine &eng,
pending_events (2048), pending_events (2048),
state_tree (0), state_tree (0),
_butler (new Butler (this)), _butler (new Butler (this)),
post_transport_work((PostTransportWork)0),
_send_timecode_update (false), _send_timecode_update (false),
midi_thread (pthread_t (0)), midi_thread (pthread_t (0)),
midi_requests (128), // the size of this should match the midi request pool size 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), pending_events (2048),
state_tree (0), state_tree (0),
_butler (new Butler (this)), _butler (new Butler (this)),
post_transport_work((PostTransportWork)0),
_send_timecode_update (false), _send_timecode_update (false),
midi_thread (pthread_t (0)), midi_thread (pthread_t (0)),
midi_requests (16), midi_requests (16),
@ -1229,12 +1227,12 @@ Session::maybe_enable_record ()
set_dirty(); set_dirty();
} }
nframes_t nframes64_t
Session::audible_frame () const Session::audible_frame () const
{ {
nframes_t ret; nframes64_t ret;
nframes64_t tf;
nframes_t offset; nframes_t offset;
nframes_t tf;
/* the first of these two possible settings for "offset" /* the first of these two possible settings for "offset"
mean that the audible frame is stationary until mean that the audible frame is stationary until
@ -3517,7 +3515,7 @@ void
Session::set_audition (boost::shared_ptr<Region> r) Session::set_audition (boost::shared_ptr<Region> r)
{ {
pending_audition_region = r; pending_audition_region = r;
post_transport_work = PostTransportWork (post_transport_work | PostTransportAudition); add_post_transport_work (PostTransportAudition);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
} }

View file

@ -68,7 +68,7 @@ static inline uint32_t next_power_of_two (uint32_t n)
void void
Session::schedule_curve_reallocation () Session::schedule_curve_reallocation ()
{ {
post_transport_work = PostTransportWork (post_transport_work | PostTransportCurveRealloc); add_post_transport_work (PostTransportCurveRealloc);
_butler->schedule_transport_work (); _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 (); _butler->schedule_transport_work ();
} }

View file

@ -23,6 +23,7 @@
#include "ardour/timestamps.h" #include "ardour/timestamps.h"
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/enumwriter.h"
#include <glibmm/thread.h> #include <glibmm/thread.h>
#include "ardour/ardour.h" #include "ardour/ardour.h"
@ -38,28 +39,6 @@ using namespace PBD;
MultiAllocSingleReleasePool Session::Event::pool ("event", sizeof (Session::Event), 512); 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 void
Session::add_event (nframes_t frame, Event::Type type, nframes_t target_frame) 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) { for (Events::iterator i = events.begin(); i != events.end(); ++i) {
if ((*i)->type == ev->type && (*i)->action_frame == ev->action_frame) { 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)."), 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; return;
} }
} }
@ -321,7 +300,7 @@ Session::process_event (Event* ev)
switch (ev->type) { switch (ev->type) {
case Event::SetLoop: case Event::SetLoop:
set_play_loop (ev->yes_or_no, (ev->speed == 1.0f)); set_play_loop (ev->yes_or_no);
break; break;
case Event::AutoLoop: case Event::AutoLoop:
@ -362,7 +341,7 @@ Session::process_event (Event* ev)
case Event::SetTransportSpeed: 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; break;
case Event::PunchIn: case Event::PunchIn:
@ -425,17 +404,12 @@ Session::process_event (Event* ev)
break; break;
case Event::InputConfigurationChange: case Event::InputConfigurationChange:
post_transport_work = PostTransportWork (post_transport_work | PostTransportInputChange); add_post_transport_work (PostTransportInputChange);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
break; break;
case Event::SetAudioRange: case Event::SetPlayAudioRange:
current_audio_range = ev->audio_range; set_play_range (ev->audio_range, (ev->speed == 1.0f));
setup_auto_play ();
break;
case Event::SetPlayRange:
set_play_range (ev->yes_or_no, (ev->speed == 1.0f));
break; break;
default: default:

View file

@ -210,7 +210,7 @@ Session::stop_audio_export ()
stuff that stop_transport() implements. stuff that stop_transport() implements.
*/ */
realtime_stop (true); realtime_stop (true, true);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
if (!export_status->aborted()) { if (!export_status->aborted()) {

View file

@ -480,7 +480,7 @@ bool
Session::follow_slave (nframes_t nframes) Session::follow_slave (nframes_t nframes)
{ {
double slave_speed; double slave_speed;
nframes_t slave_transport_frame; nframes64_t slave_transport_frame;
nframes_t this_delta; nframes_t this_delta;
int dir; int dir;
bool starting; bool starting;

View file

@ -197,11 +197,10 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_worst_input_latency = 0; _worst_input_latency = 0;
_worst_track_latency = 0; _worst_track_latency = 0;
_state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading); _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading);
_was_seamless = Config->get_seamless_loop ();
_slave = 0; _slave = 0;
session_send_mmc = false; session_send_mmc = false;
session_send_mtc = false; session_send_mtc = false;
post_transport_work = PostTransportWork (0);
g_atomic_int_set (&_playback_load, 100); g_atomic_int_set (&_playback_load, 100);
g_atomic_int_set (&_capture_load, 100); g_atomic_int_set (&_capture_load, 100);
g_atomic_int_set (&_playback_load_min, 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) { switch (state) {
case JackTransportStopped: 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); request_locate (pos->frame, false);
// cerr << "SYNC: stopped, locate to " << pos->frame << " from " << _transport_frame << endl; // cerr << "SYNC: stopped, locate to " << pos->frame << " from " << _transport_frame << endl;
return false; return false;
@ -461,9 +461,9 @@ Session::jack_sync_callback (jack_transport_state_t state,
} }
case JackTransportStarting: 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) { if (slave) {
return _transport_frame == pos->frame && post_transport_work == 0; return _transport_frame == pos->frame && post_transport_work() == 0;
} else { } else {
return true; return true;
} }

View file

@ -50,6 +50,25 @@ using namespace ARDOUR;
using namespace sigc; using namespace sigc;
using namespace PBD; 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 void
Session::request_input_change_handling () Session::request_input_change_handling ()
{ {
@ -63,12 +82,21 @@ void
Session::request_slave_source (SlaveSource src) Session::request_slave_source (SlaveSource src)
{ {
Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, 0, 0.0); Event* ev = new Event (Event::SetSlaveSource, Event::Add, Event::Immediate, 0, 0.0);
bool seamless;
seamless = Config->get_seamless_loop ();
if (src == JACK) { if (src == JACK) {
/* could set_seamless_loop() be disposed of entirely?*/ /* JACK cannot support seamless looping at present */
Config->set_seamless_loop (false); 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; ev->slave = src;
queue_event (ev); queue_event (ev);
} }
@ -89,9 +117,9 @@ Session::request_diskstream_speed (Diskstream& ds, double speed)
} }
void 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); queue_event (ev);
} }
@ -103,7 +131,7 @@ Session::request_locate (nframes_t target_frame, bool with_roll)
} }
void 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); Event *ev = new Event (with_roll ? Event::LocateRoll : Event::Locate, Event::Add, Event::Immediate, target_frame, 0, true);
queue_event (ev); queue_event (ev);
@ -132,8 +160,22 @@ Session::request_play_loop (bool yn, bool leave_rolling)
} }
void 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 */ /* assume that when we start, we'll be moving forwards */
// FIXME: where should this really be? [DR] // FIXME: where should this really be? [DR]
@ -142,9 +184,9 @@ Session::realtime_stop (bool abort)
deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
if (_transport_speed < 0.0f) { if (_transport_speed < 0.0f) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportStop | PostTransportReverse); todo = (PostTransportWork (todo | PostTransportStop | PostTransportReverse));
} else { } else {
post_transport_work = PostTransportWork (post_transport_work | PostTransportStop); todo = PostTransportWork (todo | PostTransportStop);
} }
if (actively_recording()) { if (actively_recording()) {
@ -158,11 +200,19 @@ Session::realtime_stop (bool abort)
/* the duration change is not guaranteed to have happened, but is likely */ /* 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) { 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); _clear_event_type (Event::StopOnce);
@ -188,29 +238,30 @@ Session::butler_transport_work ()
{ {
restart: restart:
bool finished; bool finished;
PostTransportWork ptw;
boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<RouteList> r = routes.reader ();
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
int on_entry = g_atomic_int_get (&_butler->should_do_transport_work); int on_entry = g_atomic_int_get (&_butler->should_do_transport_work);
finished = true; finished = true;
ptw = post_transport_work();
if (post_transport_work & PostTransportCurveRealloc) { if (ptw & PostTransportCurveRealloc) {
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->curve_reallocate(); (*i)->curve_reallocate();
} }
} }
if (post_transport_work & PostTransportInputChange) { if (ptw & PostTransportInputChange) {
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
(*i)->non_realtime_input_change (); (*i)->non_realtime_input_change ();
} }
} }
if (post_transport_work & PostTransportSpeed) { if (ptw & PostTransportSpeed) {
non_realtime_set_speed (); non_realtime_set_speed ();
} }
if (post_transport_work & PostTransportReverse) { if (ptw & PostTransportReverse) {
clear_clicks(); clear_clicks();
cumulative_rf_motion = 0; 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() */ /* 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) { for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if (!(*i)->hidden()) { if (!(*i)->hidden()) {
@ -233,19 +284,19 @@ Session::butler_transport_work ()
} }
} }
if (post_transport_work & PostTransportLocate) { if (ptw & PostTransportLocate) {
non_realtime_locate (); non_realtime_locate ();
} }
if (post_transport_work & PostTransportStop) { if (ptw & PostTransportStop) {
non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished); non_realtime_stop (ptw & PostTransportAbort, on_entry, finished);
if (!finished) { if (!finished) {
g_atomic_int_dec_and_test (&_butler->should_do_transport_work); g_atomic_int_dec_and_test (&_butler->should_do_transport_work);
goto restart; goto restart;
} }
} }
if (post_transport_work & PostTransportOverWrite) { if (ptw & PostTransportOverWrite) {
non_realtime_overwrite (on_entry, finished); non_realtime_overwrite (on_entry, finished);
if (!finished) { if (!finished) {
g_atomic_int_dec_and_test (&_butler->should_do_transport_work); 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 (); non_realtime_set_audition ();
} }
@ -305,6 +356,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
time_t xnow; time_t xnow;
bool did_record; bool did_record;
bool saved; bool saved;
PostTransportWork ptw = post_transport_work();
did_record = false; did_record = false;
saved = 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()); (Config->get_slave_source() == None && config.get_auto_return());
if (auto_return_enabled || if (auto_return_enabled ||
(post_transport_work & PostTransportLocate) || (ptw & PostTransportLocate) ||
(_requested_return_frame >= 0) || (_requested_return_frame >= 0) ||
synced_to_jack()) { 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) && if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) &&
!(post_transport_work & PostTransportLocate)) { !(ptw & PostTransportLocate)) {
/* no explicit locate queued */ /* 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 */ /* 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::cmdStop, 0);
deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame); deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
if (did_record) { if ((ptw & PostTransportLocate) && get_record_enabled()) {
/* 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()) {
/* capture start has been changed, so save pending state */ /* capture start has been changed, so save pending state */
save_state ("", true); save_state ("", true);
saved = true; saved = true;
@ -514,23 +557,21 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
save_state (_current_snapshot_name); save_state (_current_snapshot_name);
} }
if (post_transport_work & PostTransportDuration) { if (ptw & PostTransportDuration) {
DurationChanged (); /* EMIT SIGNAL */ DurationChanged (); /* EMIT SIGNAL */
} }
if (post_transport_work & PostTransportStop) { if (ptw & PostTransportStop) {
_play_range = false; _play_range = false;
play_loop = false; play_loop = false;
} }
nframes_t tf = _transport_frame; PositionChanged ((nframes64_t) _transport_frame); /* EMIT SIGNAL */
PositionChanged (tf); /* EMIT SIGNAL */
TransportStateChange (); /* EMIT SIGNAL */ TransportStateChange (); /* EMIT SIGNAL */
/* and start it up again if relevant */ /* 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); request_transport_speed (1.0);
pending_locate_roll = false; pending_locate_roll = false;
} }
@ -561,35 +602,48 @@ Session::check_declick_out ()
} }
void 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 */ /* Called from event-handling context */
Location *loc; 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; return;
} }
if ((actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
return;
}
set_dirty(); set_dirty();
if (yn && Config->get_seamless_loop() && synced_to_jack()) { if (yn && Config->get_seamless_loop() && synced_to_jack()) {
warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n" warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n"
"Recommend changing the configured options") "Recommend changing the configured options")
<< endmsg; << endmsg;
return; return;
} }
if (yn) {
play_loop = true;
if ((play_loop = yn)) {
if (loc) { if (loc) {
set_play_range (false, true); unset_play_range ();
if (Config->get_seamless_loop()) { if (Config->get_seamless_loop()) {
// set all diskstreams to use internal looping // 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); Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
merge_event (event); merge_event (event);
/* locate to start of loop and roll. If doing seamless loop, force a
// locate to start of loop and roll locate+buffer refill even if we are positioned there already.
event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack()); */
merge_event (event);
}
start_locate (loc->start(), true, true, false, Config->get_seamless_loop());
}
} else { } 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 void
Session::flush_all_inserts () Session::flush_all_inserts ()
{ {
@ -648,12 +694,12 @@ Session::flush_all_inserts ()
} }
void 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()) { if (synced_to_jack()) {
double sp; double sp;
nframes_t pos; nframes64_t pos;
_slave->speed_and_position (sp, 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 { } 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 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) { if (actively_recording() && !with_loop) {
return; return;
} }
if (_transport_frame == target_frame && !loop_changing && !with_loop) { if (!force && _transport_frame == target_frame && !loop_changing && !with_loop) {
if (with_roll) { if (with_roll) {
set_transport_speed (1.0, false); 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)) { 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) { if (with_roll) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll); todo = PostTransportWork (todo | PostTransportRoll);
} }
add_post_transport_work (todo);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
} else { } 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())) { if (al && (_transport_frame < al->start() || _transport_frame > al->end())) {
// cancel looping directly, this is called from event handling context // 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()) { else if (al && _transport_frame == al->start()) {
if (with_loop) { if (with_loop) {
@ -824,7 +871,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
* @param abort * @param abort
*/ */
void void
Session::set_transport_speed (double speed, bool abort) Session::set_transport_speed (double speed, bool abort, bool clear_state)
{ {
if (_transport_speed == speed) { if (_transport_speed == speed) {
return; return;
@ -859,6 +906,13 @@ Session::set_transport_speed (double speed, bool abort)
} }
if (synced_to_jack ()) { 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 (); _engine.transport_stop ();
} else { } else {
stop_transport (abort); 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 /* 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. 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)) { 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; _last_transport_speed = _transport_speed;
@ -930,11 +986,13 @@ Session::set_transport_speed (double speed, bool abort)
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->realtime_set_speed ((*i)->speed(), true)) { 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 (); _butler->schedule_transport_work ();
} }
} }
@ -943,7 +1001,7 @@ Session::set_transport_speed (double speed, bool abort)
/** Stop the transport. */ /** Stop the transport. */
void void
Session::stop_transport (bool abort) Session::stop_transport (bool abort, bool clear_state)
{ {
if (_transport_speed == 0.0f) { if (_transport_speed == 0.0f) {
return; return;
@ -979,7 +1037,7 @@ Session::stop_transport (bool abort)
return; return;
} }
realtime_stop (abort); realtime_stop (abort, clear_state);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
} }
@ -1031,7 +1089,9 @@ Session::start_transport ()
void void
Session::post_transport () Session::post_transport ()
{ {
if (post_transport_work & PostTransportAudition) { PostTransportWork ptw = post_transport_work ();
if (ptw & PostTransportAudition) {
if (auditioner && auditioner->active()) { if (auditioner && auditioner->active()) {
process_function = &Session::process_audition; process_function = &Session::process_audition;
} else { } else {
@ -1039,14 +1099,14 @@ Session::post_transport ()
} }
} }
if (post_transport_work & PostTransportStop) { if (ptw & PostTransportStop) {
transport_sub_state = 0; 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 (); start_transport ();
} else { } else {
@ -1055,8 +1115,10 @@ Session::post_transport ()
} }
set_next_event (); set_next_event ();
/* XXX is this really safe? shouldn't we just be unsetting the bits that we actually
post_transport_work = PostTransportWork (0); know were handled ?
*/
set_post_transport_work (PostTransportWork (0));
} }
void void
@ -1161,7 +1223,7 @@ Session::set_slave_source (SlaveSource src)
} }
if (non_rt_required) { if (non_rt_required) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); add_post_transport_work (PostTransportSpeed);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
} }
@ -1171,7 +1233,7 @@ Session::set_slave_source (SlaveSource src)
void void
Session::reverse_diskstream_buffers () Session::reverse_diskstream_buffers ()
{ {
post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse); add_post_transport_work (PostTransportReverse);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
} }
@ -1179,110 +1241,107 @@ void
Session::set_diskstream_speed (Diskstream* stream, double speed) Session::set_diskstream_speed (Diskstream* stream, double speed)
{ {
if (stream->realtime_set_speed (speed, false)) { if (stream->realtime_set_speed (speed, false)) {
post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); add_post_transport_work (PostTransportSpeed);
_butler->schedule_transport_work (); _butler->schedule_transport_work ();
set_dirty (); set_dirty ();
} }
} }
void 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); _play_range = false;
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;
_clear_event_type (Event::RangeStop); _clear_event_type (Event::RangeStop);
_clear_event_type (Event::RangeLocate); _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; 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) { if (sz > 1) {
list<AudioRange>::iterator i = current_audio_range.begin(); list<AudioRange>::iterator i = range.begin();
list<AudioRange>::iterator next; list<AudioRange>::iterator next;
while (i != current_audio_range.end()) { while (i != range.end()) {
next = i; next = i;
++next; ++next;
/* locating/stopping is subject to delays for declicking. /* locating/stopping is subject to delays for declicking.
*/ */
nframes_t requested_frame = (*i).end; nframes_t requested_frame = (*i).end;
if (requested_frame > current_block_size) { if (requested_frame > current_block_size) {
requested_frame -= current_block_size; requested_frame -= current_block_size;
} else { } else {
requested_frame = 0; 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); ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f);
} else { } else {
ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f); ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f);
} }
merge_event (ev); merge_event (ev);
i = next; i = next;
} }
} else if (sz == 1) { } 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); merge_event (ev);
}
} /* save range so we can do auto-return etc. */
current_audio_range = range;
/* now start rolling at the right place */ /* 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); 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 void
Session::request_roll_at_and_return (nframes_t start, nframes_t return_to) 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); 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 void
Session::engine_halted () Session::engine_halted ()
{ {
@ -1312,10 +1363,10 @@ Session::engine_halted ()
*/ */
g_atomic_int_set (&_butler->should_do_transport_work, 0); g_atomic_int_set (&_butler->should_do_transport_work, 0);
post_transport_work = PostTransportWork (0); set_post_transport_work (PostTransportWork (0));
_butler->stop (); _butler->stop ();
realtime_stop (false); realtime_stop (false, true);
non_realtime_stop (false, 0, ignored); non_realtime_stop (false, 0, ignored);
transport_sub_state = 0; transport_sub_state = 0;
@ -1326,7 +1377,7 @@ Session::engine_halted ()
void void
Session::xrun_recovery () Session::xrun_recovery ()
{ {
Xrun (transport_frame()); //EMIT SIGNAL Xrun ((nframes64_t)_transport_frame); //EMIT SIGNAL
if (Config->get_stop_recording_on_xrun() && actively_recording()) { if (Config->get_stop_recording_on_xrun() && actively_recording()) {
@ -1342,12 +1393,14 @@ void
Session::update_latency_compensation (bool with_stop, bool abort) Session::update_latency_compensation (bool with_stop, bool abort)
{ {
bool update_jack = false; bool update_jack = false;
PostTransportWork ptw;
if (_state_of_the_state & Deletion) { if (_state_of_the_state & Deletion) {
return; return;
} }
_worst_track_latency = 0; _worst_track_latency = 0;
ptw = post_transport_work();
#undef DEBUG_LATENCY #undef DEBUG_LATENCY
#ifdef 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) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (with_stop) { if (with_stop) {
(*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), (*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
(!(post_transport_work & PostTransportLocate) || pending_locate_flush));
} }
nframes_t old_latency = (*i)->output()->signal_latency (); nframes_t old_latency = (*i)->output()->signal_latency ();

View file

@ -35,13 +35,13 @@ SlaveSessionProxy::frame_rate() const
return session.frame_rate(); return session.frame_rate();
} }
nframes_t nframes64_t
SlaveSessionProxy::audible_frame() const SlaveSessionProxy::audible_frame() const
{ {
return session.audible_frame(); return session.audible_frame();
} }
nframes_t nframes64_t
SlaveSessionProxy::transport_frame() const SlaveSessionProxy::transport_frame() const
{ {
return session.transport_frame(); return session.transport_frame();
@ -53,14 +53,14 @@ SlaveSessionProxy::frames_since_cycle_start() const
return session.engine().frames_since_cycle_start(); return session.engine().frames_since_cycle_start();
} }
nframes_t nframes64_t
SlaveSessionProxy::frame_time() const SlaveSessionProxy::frame_time() const
{ {
return session.engine().frame_time(); return session.engine().frame_time();
} }
void 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); session.request_locate(frame, with_roll);
} }