Some improvements to performance with crossfades: don't recompute a whole track's...
[ardour.git] / libs / ardour / session_transport.cc
index cc94595f8c1b04f7fbc069624ece18c554d1793c..a20856b818700417c5629d50515531bdf2a9d125 100644 (file)
 #include <sigc++/bind.h>
 #include <sigc++/retype.h>
 
-#include <pbd/undo.h>
-#include <pbd/error.h>
+#include "pbd/undo.h"
+#include "pbd/error.h"
 #include <glibmm/thread.h>
-#include <pbd/pthread_utils.h>
-#include <pbd/memento_command.h>
-#include <pbd/stacktrace.h>
+#include "pbd/pthread_utils.h"
+#include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
 
-#include <midi++/mmc.h>
-#include <midi++/port.h>
+#include "midi++/mmc.h"
+#include "midi++/port.h"
 
-#include <ardour/ardour.h>
-#include <ardour/audioengine.h>
-#include <ardour/session.h>
-#include <ardour/audio_diskstream.h>
-#include <ardour/auditioner.h>
-#include <ardour/slave.h>
-#include <ardour/location.h>
+#include "ardour/ardour.h"
+#include "ardour/audioengine.h"
+#include "ardour/session.h"
+#include "ardour/audio_diskstream.h"
+#include "ardour/auditioner.h"
+#include "ardour/slave.h"
+#include "ardour/location.h"
 
 #include "i18n.h"
 
@@ -74,14 +74,14 @@ Session::request_slave_source (SlaveSource src)
 }
 
 void
-Session::request_transport_speed (float speed)
+Session::request_transport_speed (double speed)
 {
        Event* ev = new Event (Event::SetTransportSpeed, Event::Add, Event::Immediate, 0, speed);
        queue_event (ev);
 }
 
 void
-Session::request_diskstream_speed (Diskstream& ds, float speed)
+Session::request_diskstream_speed (Diskstream& ds, double speed)
 {
        Event* ev = new Event (Event::SetDiskstreamSpeed, Event::Add, Event::Immediate, 0, speed);
        ev->set_ptr (&ds);
@@ -176,12 +176,13 @@ Session::realtime_stop (bool abort)
        reset_slave_state ();
 
        _transport_speed = 0;
+       _target_transport_speed = 0;
 
-       if (Config->get_use_video_sync()) {
+       if (config.get_use_video_sync()) {
                waiting_for_sync_offset = true;
        }
 
-       transport_sub_state = ((Config->get_slave_source() == None && Config->get_auto_return()) ? AutoReturning : 0);
+       transport_sub_state = ((Config->get_slave_source() == None && config.get_auto_return()) ? AutoReturning : 0);
 }
 
 void
@@ -212,8 +213,7 @@ Session::butler_transport_work ()
        }
 
        if (post_transport_work & PostTransportReverse) {
-
-
+               
                clear_clicks();
                cumulative_rf_motion = 0;
                reset_rf_scale (0);
@@ -224,12 +224,7 @@ Session::butler_transport_work ()
 
                        for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
                                if (!(*i)->hidden()) {
-                                       if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
-                                               (*i)->seek ((nframes_t) (_transport_frame * (double) (*i)->speed()));
-                                       }
-                                       else {
-                                               (*i)->seek (_transport_frame);
-                                       }
+                                       (*i)->non_realtime_locate (_transport_frame);
                                }
                                if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) {
                                        /* new request, stop seeking, and start again */
@@ -348,7 +343,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
 
                        /* stopped recording before current end */
 
-                       if (_end_location_is_free) {
+                       if (config.get_end_marker_is_free()) {
 
                                /* first capture for this session, move end back to where we are */
 
@@ -369,7 +364,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                         add_command (new MementoCommand<Location>(*loc, &before, &after));
                }
 
-               _end_location_is_free = false;
+               config.set_end_marker_is_free (false);
                _have_captured = true;
        }
 
@@ -393,7 +388,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                update_latency_compensation (true, abort);
        }
 
-       if ((Config->get_slave_source() == None && Config->get_auto_return()) ||
+       bool const auto_return_enabled =
+               (Config->get_slave_source() == None && config.get_auto_return());
+       
+       if (auto_return_enabled ||
            (post_transport_work & PostTransportLocate) ||
            (_requested_return_frame >= 0) ||
            synced_to_jack()) {
@@ -402,9 +400,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                        flush_all_inserts ();
                }
 
-               if (((Config->get_slave_source() == None && Config->get_auto_return()) ||
-                    synced_to_jack() ||
-                    _requested_return_frame >= 0) &&
+               if ((auto_return_enabled || synced_to_jack() || _requested_return_frame >= 0) &&
                    !(post_transport_work & PostTransportLocate)) {
 
                        bool do_locate = false;
@@ -414,8 +410,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                                _requested_return_frame = -1;
                                do_locate = true;
                        } else {
-                               _transport_frame = last_stop_frame;
-                               _requested_return_frame = -1;
+                               _transport_frame = _last_roll_location;
                        }
 
                        if (synced_to_jack() && !play_loop) {
@@ -434,12 +429,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
 
                for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
                        if (!(*i)->hidden()) {
-                               if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
-                                       (*i)->seek ((nframes_t) (_transport_frame * (double) (*i)->speed()));
-                               }
-                               else {
-                                       (*i)->seek (_transport_frame);
-                               }
+                               (*i)->non_realtime_locate (_transport_frame);
                        }
                        if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) {
                                finished = false;
@@ -452,12 +442,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        }
 #endif
 
-        if (_requested_return_frame < 0) {
-               last_stop_frame = _transport_frame;
-       } else {
-               last_stop_frame = _requested_return_frame;
-               _requested_return_frame = -1;
-       }
+        have_looped = false; 
+
+        send_full_time_code (0);
+       deliver_mmc (MIDI::MachineControl::cmdStop, 0);
+       deliver_mmc (MIDI::MachineControl::cmdLocate, _transport_frame);
 
        if (did_record) {
 
@@ -633,7 +622,7 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush,
 {
        if (synced_to_jack()) {
 
-               float sp;
+               double sp;
                nframes_t pos;
 
                _slave->speed_and_position (sp, pos);
@@ -653,7 +642,6 @@ Session::start_locate (nframes_t target_frame, bool with_roll, bool with_flush,
                }
 
        } else {
-
                locate (target_frame, with_roll, with_flush, with_loop);
        }
 }
@@ -711,7 +699,7 @@ 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);
        }
 
@@ -750,7 +738,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
                        for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
                                if ((*i)->record_enabled ()) {
                                        //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
-                                       (*i)->monitor_input (!Config->get_auto_input());
+                                       (*i)->monitor_input (!config.get_auto_input());
                                }
                        }
                }
@@ -789,7 +777,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
                                        }
                                }
                        }
-
+                       have_looped = true;
                        TransportLooped(); // EMIT SIGNAL
                }
        }
@@ -797,6 +785,8 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
        loop_changing = false;
 
        _send_smpte_update = true;
+
+       Located (); /* EMIT SIGNAL */
 }
 
 /** Set the transport speed.
@@ -804,16 +794,22 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
  * @param abort
  */
 void
-Session::set_transport_speed (float speed, bool abort)
+Session::set_transport_speed (double speed, bool abort)
 {
        if (_transport_speed == speed) {
                return;
        }
 
+       _target_transport_speed = fabs(speed);
+
+       /* 8.0 max speed is somewhat arbitrary but based on guestimates regarding disk i/o capability
+          and user needs. We really need CD-style "skip" playback for ffwd and rewind.
+       */
+       
        if (speed > 0) {
-               speed = min (8.0f, speed);
+               speed = min (8.0, speed);
        } else if (speed < 0) {
-               speed = max (-8.0f, speed);
+               speed = max (-8.0, speed);
        }
 
        if (transport_rolling() && speed == 0.0) {
@@ -851,7 +847,7 @@ Session::set_transport_speed (float speed, bool abort)
                        boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
 
                        for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                               if (Config->get_auto_input() && (*i)->record_enabled ()) {
+                               if (config.get_auto_input() && (*i)->record_enabled ()) {
                                        //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
                                        (*i)->monitor_input (false);
                                }
@@ -880,11 +876,11 @@ Session::set_transport_speed (float speed, bool abort)
                        return;
                }
 
-               if (speed > 0.0f && _transport_frame == current_end_frame()) {
+               if (speed > 0.0 && _transport_frame == current_end_frame()) {
                        return;
                }
 
-               if (speed < 0.0f && _transport_frame == 0) {
+               if (speed < 0.0 && _transport_frame == 0) {
                        return;
                }
 
@@ -894,7 +890,7 @@ Session::set_transport_speed (float speed, bool abort)
                   before the last stop, then we have to do extra work.
                */
 
-               if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_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);
                }
 
@@ -961,6 +957,7 @@ void
 Session::start_transport ()
 {
        _last_roll_location = _transport_frame;
+       have_looped = false;
 
        /* if record status is Enabled, move it to Recording. if its
           already Recording, move it to Disabled.
@@ -968,7 +965,7 @@ Session::start_transport ()
 
        switch (record_status()) {
        case Enabled:
-               if (!Config->get_punch_in()) {
+               if (!config.get_punch_in()) {
                        enable_record ();
                }
                break;
@@ -983,20 +980,10 @@ Session::start_transport ()
                break;
        }
 
-       if (!synced_to_jack() || _exporting) {
-               actually_start_transport ();
-       } else {
-               waiting_to_start = true;
-       }
-}
-
-void
-Session::actually_start_transport ()
-{
-       waiting_to_start = false;
-
        transport_sub_state |= PendingDeclickIn;
+       
        _transport_speed = 1.0;
+       _target_transport_speed = 1.0;
 
        boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
        for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
@@ -1029,7 +1016,7 @@ Session::post_transport ()
 
        if (post_transport_work & 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) || (post_transport_work & PostTransportRoll)) {
                        start_transport ();
 
                } else {
@@ -1077,10 +1064,8 @@ Session::set_slave_source (SlaveSource src)
 //             return;
 //     }
 
-       if (_slave) {
-               delete _slave;
-               _slave = 0;
-       }
+       delete _slave;
+       _slave = 0;
 
        if (_transport_speed < 0.0) {
                reverse = true;
@@ -1105,7 +1090,6 @@ Session::set_slave_source (SlaveSource src)
                        error << _("No MTC port defined: MTC slaving is impossible.") << endmsg;
                        return;
                }
-               _desired_transport_speed = _transport_speed;
                break;
 
        case MIDIClock:
@@ -1122,12 +1106,10 @@ Session::set_slave_source (SlaveSource src)
                        error << _("No MIDI Clock port defined: MIDI Clock slaving is impossible.") << endmsg;
                        return;
                }
-               _desired_transport_speed = _transport_speed;
                break;
 
        case JACK:
                _slave = new JACK_Slave (_engine.jack());
-               _desired_transport_speed = _transport_speed;
                break;
 
        };
@@ -1164,7 +1146,7 @@ Session::reverse_diskstream_buffers ()
 }
 
 void
-Session::set_diskstream_speed (Diskstream* stream, float speed)
+Session::set_diskstream_speed (Diskstream* stream, double speed)
 {
        if (stream->realtime_set_speed (speed, false)) {
                post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed);
@@ -1347,11 +1329,12 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                                                        (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
                }
 
-               nframes_t old_latency = (*i)->signal_latency ();
+               nframes_t old_latency = (*i)->output()->signal_latency ();
                nframes_t track_latency = (*i)->update_total_latency ();
 
                if (old_latency != track_latency) {
-                       (*i)->update_port_total_latencies ();
+                       (*i)->input()->update_port_total_latencies ();
+                       (*i)->output()->update_port_total_latencies ();
                        update_jack = true;
                }