Fix thinko in 9581cb26 - scratch-buffer can't be used recursively.
[ardour.git] / libs / ardour / session_transport.cc
index 47e0baaf5f03f9b3ec04fdfa8459687ff678871c..65a9748ce60ebfe6187f533bac973cc2e140621d 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "ardour/audioengine.h"
 #include "ardour/auditioner.h"
+#include "ardour/automation_watch.h"
 #include "ardour/butler.h"
 #include "ardour/click.h"
 #include "ardour/debug.h"
 #include "ardour/scene_changer.h"
 #include "ardour/session.h"
 #include "ardour/slave.h"
+#include "ardour/tempo.h"
 #include "ardour/operations.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -160,6 +162,75 @@ Session::force_locate (framepos_t target_frame, bool with_roll)
        queue_event (ev);
 }
 
+void
+Session::unset_preroll_record_punch ()
+{
+       if (_preroll_record_punch_pos >= 0) {
+               remove_event (_preroll_record_punch_pos, SessionEvent::RecordStart);
+       }
+       _preroll_record_punch_pos = -1;
+}
+
+void
+Session::unset_preroll_record_trim ()
+{
+       _preroll_record_trim_len = 0;
+}
+
+void
+Session::request_preroll_record_punch (framepos_t rec_in, framecnt_t preroll)
+{
+       if (actively_recording ()) {
+               return;
+       }
+       unset_preroll_record_punch ();
+       unset_preroll_record_trim ();
+       framepos_t start = std::max ((framepos_t)0, rec_in - preroll);
+
+       _preroll_record_punch_pos = rec_in;
+       if (_preroll_record_punch_pos >= 0) {
+               replace_event (SessionEvent::RecordStart, _preroll_record_punch_pos);
+               config.set_punch_in (false);
+               config.set_punch_out (false);
+       }
+       maybe_enable_record ();
+       request_locate (start, true);
+       set_requested_return_frame (rec_in);
+}
+
+void
+Session::request_preroll_record_trim (framepos_t rec_in, framecnt_t preroll)
+{
+       if (actively_recording ()) {
+               return;
+       }
+       unset_preroll_record_punch ();
+       unset_preroll_record_trim ();
+
+       config.set_punch_in (false);
+       config.set_punch_out (false);
+
+       framepos_t pos = std::max ((framepos_t)0, rec_in - preroll);
+       _preroll_record_trim_len = preroll;
+       maybe_enable_record ();
+       request_locate (pos, true);
+       set_requested_return_frame (rec_in);
+}
+
+void
+Session::request_count_in_record ()
+{
+       if (actively_recording ()) {
+               return;
+       }
+       if (transport_rolling()) {
+               return;
+       }
+       maybe_enable_record ();
+       _count_in_once = true;
+       request_transport_speed (1.0, true);
+}
+
 void
 Session::request_play_loop (bool yn, bool change_transport_roll)
 {
@@ -746,6 +817,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
                        flush_all_inserts ();
                }
 
+               // rg: what is the logic behind this case?
+               // _requested_return_frame should be ignored when synced_to_engine/slaved.
+               // currently worked around in MTC_Slave by forcing _requested_return_frame to -1
+               // 2016-01-10
                if ((auto_return_enabled || synced_to_engine() || _requested_return_frame >= 0) &&
                    !(ptw & PostTransportLocate)) {
 
@@ -785,6 +860,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        }
 
        clear_clicks();
+       unset_preroll_record_trim ();
 
        /* do this before seeking, because otherwise the tracks will do the wrong thing in seamless loop mode.
        */
@@ -871,6 +947,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
        PositionChanged (_transport_frame); /* EMIT SIGNAL */
        DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC with speed = %1\n", _transport_speed));
        TransportStateChange (); /* EMIT SIGNAL */
+       AutomationWatch::instance().transport_stop_automation_watches (_transport_frame);
 
        /* and start it up again if relevant */
 
@@ -1156,12 +1233,9 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
        }
 
        // Update Timecode time
-       // [DR] FIXME: find out exactly where this should go below
        _transport_frame = target_frame;
        _last_roll_or_reversal_location = target_frame;
        timecode_time(_transport_frame, transmitting_timecode_time);
-       outbound_mtc_timecode_frame = _transport_frame;
-       next_quarter_frame_to_send = 0;
 
        /* do "stopped" stuff if:
         *
@@ -1268,7 +1342,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                                        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
 
-                                       if (tr && tr->record_enabled ()) {
+                                       if (tr && tr->rec_enable_control()->get_value()) {
                                                // tell it we've looped, so it can deal with the record state
                                                tr->transport_looped (_transport_frame);
                                        }
@@ -1293,7 +1367,9 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
        }
 
        _last_roll_location = _last_roll_or_reversal_location =  _transport_frame;
-       Located (); /* EMIT SIGNAL */
+       if (!synced_to_engine () || _transport_frame == _engine.transport_frame ()) {
+               Located (); /* EMIT SIGNAL */
+       }
 }
 
 /** Set the transport speed.
@@ -1346,6 +1422,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
                                   take care of it.
                                */
                                _play_range = false;
+                               _count_in_once = false;
                                unset_play_loop ();
                        }
                        _engine.transport_stop ();
@@ -1391,6 +1468,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
 
                if (synced_to_engine()) {
                        _engine.transport_start ();
+                       _count_in_once = false;
                } else {
                        start_transport ();
                }
@@ -1483,6 +1561,7 @@ Session::set_transport_speed (double speed, framepos_t destination_frame, bool a
 void
 Session::stop_transport (bool abort, bool clear_state)
 {
+       _count_in_once = false;
        if (_transport_speed == 0.0f) {
                return;
        }
@@ -1581,7 +1660,7 @@ Session::start_transport ()
 
        switch (record_status()) {
        case Enabled:
-               if (!config.get_punch_in()) {
+               if (!config.get_punch_in() && !preroll_record_punch_enabled()) {
                        enable_record ();
                }
                break;
@@ -1615,6 +1694,40 @@ Session::start_transport ()
                if (!dynamic_cast<MTC_Slave*>(_slave)) {
                        send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay));
                }
+
+               if (actively_recording() && click_data && (config.get_count_in () || _count_in_once)) {
+                       _count_in_once = false;
+                       /* calculate count-in duration (in audio samples)
+                        * - use [fixed] tempo/meter at _transport_frame
+                        * - calc duration of 1 bar + time-to-beat before or at transport_frame
+                        */
+                       const Tempo& tempo = _tempo_map->tempo_at_frame (_transport_frame);
+                       const Meter& meter = _tempo_map->meter_at_frame (_transport_frame);
+
+                       const double num = meter.divisions_per_bar ();
+                       const double den = meter.note_divisor ();
+                       const double barbeat = _tempo_map->exact_qn_at_frame (_transport_frame, 0) * den / (4. * num);
+                       const double bar_fract = fmod (barbeat, 1.0); // fraction of bar elapsed.
+
+                       _count_in_samples = meter.frames_per_bar (tempo, _current_frame_rate);
+
+                       double dt = _count_in_samples / num;
+                       if (bar_fract == 0) {
+                               /* at bar boundary, count-in 2 bars before start. */
+                               _count_in_samples *= 2;
+                       } else {
+                               /* beats left after full bar until roll position */
+                               _count_in_samples *= 1. + bar_fract;
+                       }
+
+                       int clickbeat = 0;
+                       framepos_t cf = _transport_frame - _count_in_samples;
+                       while (cf < _transport_frame) {
+                               add_click (cf - _worst_track_latency, clickbeat == 0);
+                               cf += dt;
+                               clickbeat = fmod (clickbeat + 1, num);
+                       }
+               }
        }
 
        DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));
@@ -1645,6 +1758,7 @@ Session::post_transport ()
        if (ptw & PostTransportLocate) {
 
                if (((!config.get_external_sync() && (auto_play_legal && config.get_auto_play())) && !_exporting) || (ptw & PostTransportRoll)) {
+                       _count_in_once = false;
                        start_transport ();
                } else {
                        transport_sub_state = 0;
@@ -1995,7 +2109,7 @@ Session::xrun_recovery ()
 void
 Session::route_processors_changed (RouteProcessorChange c)
 {
-       if (ignore_route_processor_changes) {
+       if (g_atomic_int_get (&_ignore_route_processor_changes) > 0) {
                return;
        }