monster commit: transport mgmt changes from 2.X (omnibus edition); make slave use...
authorPaul Davis <paul@linuxaudiosystems.com>
Sun, 8 Nov 2009 16:28:21 +0000 (16:28 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Sun, 8 Nov 2009 16:28:21 +0000 (16:28 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6034 d708f5d6-7413-0410-9779-e7cbd77b26cf

24 files changed:
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/ardour_ui_ed.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/editor_ops.cc
libs/ardour/ardour/session.h
libs/ardour/ardour/slave.h
libs/ardour/audio_diskstream.cc
libs/ardour/enums.cc
libs/ardour/filesystem_paths.cc
libs/ardour/jack_slave.cc
libs/ardour/midi_clock_slave.cc
libs/ardour/midi_diskstream.cc
libs/ardour/mtc_slave.cc
libs/ardour/session.cc
libs/ardour/session_butler.cc
libs/ardour/session_events.cc
libs/ardour/session_export.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/session_time.cc
libs/ardour/session_transport.cc
libs/ardour/slave.cc

index 8dc5680a1e4ee350f84110c4c18558a0831ed56b..16a96f1e4500ac174245486c9125bbda5f0f9f8e 100644 (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
index 0ec3069217ae9ccdca98673fc1770e3931680680..59a5f226651bf23b53542739dbe93039a3b42c82 100644 (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 *);
index 21a4fb5c44e5557d3ad9f10eac454a89b25596c2..eef1c6c3a73a133248e16f1bf8c21ede24a14c86 100644 (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);
 
index ac0c4f304e7234d0d8a848ca722ac2f1585c88b5..df12ddf94c0058b9bbda94beb4e605dd96f571d6 100644 (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 ();
 }
 
index 8475e9e315f2246326ba85d0fe7bf112905e94ca..d2593b24632604f40b293c3736ea1c446d852c7c 100644 (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:
 
index 8c6da6c1deab3ce18a50b20053665a9607f6e90e..c9a5870df08f99985a707729941208ece596e531 100644 (file)
@@ -2410,7 +2410,7 @@ Editor::play_selection ()
                return;
        }
 
-       session->request_play_range (true);
+       session->request_play_range (&selection->time, true);
 }
 
 void
index 3a980982c38eccaac1188a6b28b8b588b78ae888..6ac36f98b61badf8944a1b222931a905c7954cbe 100644 (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;
-               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)
+           
+                enum Action {
+                        Add,
+                        Remove,
+                        Replace,
+                        Clear
+                };
+           
+           Type             type;
+           Action           action;
+           nframes64_t      action_frame;
+           nframes64_t      target_frame;
+           double           speed;
+           
+           union {
+               void*        ptr;
+               bool         yes_or_no;
+               nframes64_t  target2_frame;
+               SlaveSource  slave;
+               Route*       route;
+           };
+
+           union {
+               bool second_yes_or_no;
+           };
+           
+           std::list<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;
index 0f005d6f1b71f8d764dfbe5c244faaa9c5b46fd2..9036c97a27daf2d6cdf19cc86fb871f671e40b42 100644 (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;
index fbd10b92e35f9e216a518e67e368228e94362c7f..3248cd9b2d84a6ac8b3c86a416a5736a245eec72 100644 (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);
index 8ab2a6f8cf7ec17496fdc774027416f8d0769203..885ebeb27a5b44c6f4900468282d0a610716ac9b 100644 (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);
index 2f2afe3c7bbe5eea6606da9c160d03d3d71de0d7..932416ef413afd4e8b403c8833079dc5161baf05 100644 (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 ();
-
-       if (home_dir.empty ()) {
-               const string error_msg = "Unable to determine home directory";
-
-               // log the error
-               error << error_msg << endmsg;
-
-               throw sys::filesystem_error(error_msg);
+       const char* c = 0;
+       sys::path p;
+
+       /* adopt freedesktop standards, and put .ardour3 into $XDG_CONFIG_HOME or ~/.config
+        */
+
+       if ((c = getenv ("XDG_CONFIG_HOME")) != 0) {
+               p = c;
+       } else {
+               const string home_dir = Glib::get_home_dir();
+       
+               if (home_dir.empty ()) {
+                       const string error_msg = "Unable to determine home directory";
+                       
+                       // log the error
+                       error << error_msg << endmsg;
+                       
+                       throw sys::filesystem_error(error_msg);
+               }
+
+               p = home_dir;
+               p /= ".config";
        }
-
-       sys::path p(home_dir);
+       
        p /= user_config_dir_name;
 
        return p;
index 9f92f1b21f8ff0100ad0761d5b15556f74905917..0f425d09c6855c2bf665fd68ef72efb902b1bc0a 100644 (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) {
index a41864571d83c60efc2ee458c99f10f10b56799c..53f819e54adf9fe7e4c657be89aba58e639ffa32 100644 (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;
index f61211def8bf94efdd282d4d114e9f3ea600d4d4..f06b00ae007f7ef7b1843020aec2839042990474 100644 (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);
index 4034ef32be3c46be1aa821b1a6552941a85e05e3..3619cc4c69583ed4077f8e0b4cf0d7895bb01e14 100644 (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;
index 031c2aa58a69cee081d0565e579d993acb9a0b85..8b3d8322044d8096fb86cd53b529803b0fdd03f4 100644 (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 ();
 }
 
index 41b4851ce5a0112622255cedf9cf70176ffc2f2b..0ffc14ff3a9bc9fff17bc63316c9601661cb361c 100644 (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 ();
 }
 
index 65635b773f9c8b13868ef6dea15fee2c9d650977..fb993faa68ff6032635e2ae53c86d95e070aa7dc 100644 (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:
index 3eda11bab73a045c97039b0f1f03c4146b882253..0bf87591cd7608e537cfcf11951a046037154b90 100644 (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()) {
index ea63e71307b9ae3e9519ef07fcdadefed94e080d..4bbe852687aaacbfa8b09e9b025bbfc6b175343d 100644 (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;
index f60cf8e85f451a916a6b33917f9ebefa9511b930..1a4758186eac9aee5c99545ee9f7e49f14d4c557 100644 (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);
index 9a6eebbaf81afc0b3a9aace1c36efd3927a1ca46..1e1ecd3ed9da0b9a4cac3c20dea2bc747b832eda 100644 (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;
                }
index 16ba54a3696c0c9da69613aa172d39d4b3f58981..10429e96395aba3ebbcd5db5663043bdb952e524 100644 (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) {
-               return;
-       }
-
-       if ((actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
+       if (yn == play_loop || (actively_recording() && yn) || (loc = _locations.auto_loop_location()) == 0) {
+               /* nothing to do, or can't change loop status while recording */
                return;
        }
-
+       
        set_dirty();
-
+       
        if (yn && Config->get_seamless_loop() && synced_to_jack()) {
                warning << _("Seamless looping cannot be supported while Ardour is using JACK transport.\n"
                             "Recommend changing the configured options")
                        << endmsg;
                return;
        }
+       
+       if (yn) {
 
-
-       if ((play_loop = yn)) {
+               play_loop = true;
 
                if (loc) {
 
-                       set_play_range (false, true);
+                       unset_play_range ();
 
                        if (Config->get_seamless_loop()) {
                                // set all diskstreams to use internal looping
@@ -609,34 +663,26 @@ Session::set_play_loop (bool yn, bool leave_rolling)
                                        }
                                }
                        }
-
-                       /* stick in the loop event */
-
+                       
+                       /* put the loop event into the event list */
+                       
                        Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f);
                        merge_event (event);
 
-                       
-                       // locate to start of loop and roll
-                       event = new Event (Event::LocateRoll, Event::Add, Event::Immediate, loc->start(), 0, !synced_to_jack());
-                       merge_event (event);
-               }
+                       /* locate to start of loop and roll. If doing seamless loop, force a 
+                          locate+buffer refill even if we are positioned there already.
+                       */
 
+                       start_locate (loc->start(), true, true, false, Config->get_seamless_loop());
+               }
 
        } else {
-               clear_events (Event::AutoLoop);
-
-               // set all diskstreams to NOT use internal looping
-               boost::shared_ptr<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,124 +1241,113 @@ void
 Session::set_diskstream_speed (Diskstream* stream, double speed)
 {
        if (stream->realtime_set_speed (speed, false)) {
-               post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
+               add_post_transport_work (PostTransportSpeed);
                _butler->schedule_transport_work ();
                set_dirty ();
        }
 }
 
 void
-Session::set_audio_range (list<AudioRange>& range)
-{
-       Event *ev = new Event (Event::SetAudioRange, Event::Add, Event::Immediate, 0, 0.0f);
-       ev->audio_range = range;
-       queue_event (ev);
-}
-
-void
-Session::request_play_range (bool yn, bool leave_rolling)
-{
-       Event* ev = new Event (Event::SetPlayRange, Event::Add, Event::Immediate, 0, (leave_rolling ? 1.0f : 0.0f), yn);
-       queue_event (ev);
-}
-
-void
-Session::set_play_range (bool yn, bool leave_rolling)
+Session::unset_play_range ()
 {
-       /* Called from event-processing context */
-
-       if (yn) {
-               /* cancel loop play */
-               set_play_range (false, true);
-       }
-
-       _play_range = yn;
-       setup_auto_play ();
-
-
-       if (!_play_range && !leave_rolling) {
-               /* stop transport */
-               Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
-               merge_event (ev);
-       }
-       TransportStateChange (); /* EMIT SIGNAL */
+       _play_range = false;
+       _clear_event_type (Event::RangeStop);
+       _clear_event_type (Event::RangeLocate);
 }
 
 void
-Session::setup_auto_play ()
+Session::set_play_range (list<AudioRange>& range, bool leave_rolling)
 {
-       /* Called from event-processing context */
-
        Event* ev;
 
-       _clear_event_type (Event::RangeStop);
-       _clear_event_type (Event::RangeLocate);
+       /* Called from event-processing context */
 
-       if (!_play_range) {
+       unset_play_range ();
+       
+       if (range.empty()) {
+               /* _play_range set to false in unset_play_range()
+                */
+               if (!leave_rolling) {
+                       /* stop transport */
+                       Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, 0.0f, false);
+                       merge_event (ev);
+               }
                return;
        }
 
-       list<AudioRange>::size_type sz = current_audio_range.size();
+       _play_range = true;
 
-       if (sz > 1) {
+       /* cancel loop play */
+       unset_play_loop ();
 
-               list<AudioRange>::iterator i = current_audio_range.begin();
+       list<AudioRange>::size_type sz = range.size();
+       
+       if (sz > 1) {
+               
+               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_roll_at_and_return (nframes_t start, nframes_t return_to)
+Session::request_bounded_roll (nframes_t start, nframes_t end)
 {
-       Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0);
-       ev->target2_frame = start;
-       queue_event (ev);
-}
+       AudioRange ar (start, end, 0);
+       list<AudioRange> lar;
 
+       lar.push_back (ar);
+       request_play_range (&lar, true);
+}
 void
-Session::request_bounded_roll (nframes_t start, nframes_t end)
+Session::request_roll_at_and_return (nframes_t start, nframes_t return_to)
 {
-       Event *ev = new Event (Event::StopOnce, Event::Replace, end, Event::Immediate, 0.0);
+       Event *ev = new Event (Event::LocateRollLocate, Event::Add, Event::Immediate, return_to, 1.0);
+       ev->target2_frame = start;
        queue_event (ev);
-       request_locate (start, true);
 }
 
 void
@@ -1312,10 +1363,10 @@ Session::engine_halted ()
        */
 
        g_atomic_int_set (&_butler->should_do_transport_work, 0);
-       post_transport_work = PostTransportWork (0);
+       set_post_transport_work (PostTransportWork (0));
        _butler->stop ();
 
-       realtime_stop (false);
+       realtime_stop (false, true);
        non_realtime_stop (false, 0, ignored);
        transport_sub_state = 0;
 
@@ -1326,7 +1377,7 @@ Session::engine_halted ()
 void
 Session::xrun_recovery ()
 {
-       Xrun (transport_frame()); //EMIT SIGNAL
+       Xrun ((nframes64_t)_transport_frame); //EMIT SIGNAL
 
        if (Config->get_stop_recording_on_xrun() && actively_recording()) {
 
@@ -1342,12 +1393,14 @@ void
 Session::update_latency_compensation (bool with_stop, bool abort)
 {
        bool update_jack = false;
+       PostTransportWork ptw;
 
        if (_state_of_the_state & Deletion) {
                return;
        }
 
        _worst_track_latency = 0;
+       ptw = post_transport_work();
 
 #undef DEBUG_LATENCY
 #ifdef DEBUG_LATENCY
@@ -1359,8 +1412,7 @@ Session::update_latency_compensation (bool with_stop, bool abort)
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 
                if (with_stop) {
-                       (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
-                                                       (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
+                       (*i)->handle_transport_stopped (abort, (ptw & PostTransportLocate), (!(ptw & PostTransportLocate) || pending_locate_flush));
                }
 
                nframes_t old_latency = (*i)->output()->signal_latency ();
index f07ea4c872dd4faffee6bc5ee60b3f09784e38dc..be88fe223cbbc94a29356787db9cd8ac38afc916 100644 (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);
 }