Implement Count-In (before recording), fixed BPM, up to 2 bars
authorRobin Gareus <robin@gareus.org>
Tue, 17 Jan 2017 19:43:55 +0000 (20:43 +0100)
committerRobin Gareus <robin@gareus.org>
Tue, 17 Jan 2017 19:43:55 +0000 (20:43 +0100)
libs/ardour/ardour/session.h
libs/ardour/ardour/session_configuration_vars.h
libs/ardour/session.cc
libs/ardour/session_process.cc
libs/ardour/session_transport.cc

index b62229a03c841962cba692a3c8a71aad76102186..f9172c5d6cbd7debdf4f23d51acfdd60b5a20272 100644 (file)
@@ -1898,6 +1898,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
        void   click (framepos_t start, framecnt_t nframes);
        void   run_click (framepos_t start, framecnt_t nframes);
        void   add_click (framepos_t pos, bool emphasis);
+       framecnt_t _count_in_samples;
 
        std::vector<Route*> master_outs;
 
index db789553cbc2a1f1f84c888a3df8c72c9cae707f..2f8d52b2b2f8b88a7c13955c1d0433bea91b7a59 100644 (file)
@@ -36,6 +36,7 @@ CONFIG_VARIABLE (bool, auto_return, "auto-return", false)
 CONFIG_VARIABLE (bool, auto_input, "auto-input", true)
 CONFIG_VARIABLE (bool, punch_in, "punch-in", false)
 CONFIG_VARIABLE (bool, punch_out, "punch-out", false)
+CONFIG_VARIABLE (bool, count_in, "count-in", false)
 CONFIG_VARIABLE (MonitorChoice, session_monitoring, "session-monitoring", MonitorAuto)
 CONFIG_VARIABLE (bool, layered_record_mode, "layered-record-mode", false)
 CONFIG_VARIABLE (uint32_t, subframes_per_frame, "subframes-per-frame", 100)
index f16324dca8863758e9a6d671efd1accb3759b89c..34e4c52e9fb2498ff584cab2d997d03a87c17d57 100644 (file)
@@ -300,6 +300,7 @@ Session::Session (AudioEngine &eng,
        , click_length (0)
        , click_emphasis_length (0)
        , _clicks_cleared (0)
+       , _count_in_samples (0)
        , _play_range (false)
        , _range_selection (-1,-1)
        , _object_selection (-1,-1)
index ad6ed1c16a94cf32ebe4a62d8cafa220b362b090..9be7007d194ed3905ee08ad130349a9d20f51aa4 100644 (file)
@@ -314,6 +314,47 @@ Session::process_with_events (pframes_t nframes)
                process_event (ev);
        }
 
+       /* count in */
+       if (_transport_speed != 1.0 && _count_in_samples > 0) {
+               _count_in_samples = 0;
+       }
+
+       if (_count_in_samples > 0) {
+               framecnt_t ns = std::min ((framecnt_t)nframes, _count_in_samples);
+
+               no_roll (ns);
+               run_click (_transport_frame - _count_in_samples, ns);
+
+               _count_in_samples -= ns;
+               nframes -= ns;
+
+               /* process events.. */
+               if (!events.empty() && next_event != events.end()) {
+                       SessionEvent* this_event = *next_event;
+                       Events::iterator the_next_one = next_event;
+                       ++the_next_one;
+
+                       while (this_event && this_event->action_frame == _transport_frame) {
+                               process_event (this_event);
+                               if (the_next_one == events.end()) {
+                                       this_event = 0;
+                               } else {
+                                       this_event = *the_next_one;
+                                       ++the_next_one;
+                               }
+                       }
+                       set_next_event ();
+               }
+
+               check_declick_out ();
+
+               if (nframes == 0) {
+                       return;
+               } else {
+                       _engine.split_cycle (ns);
+               }
+       }
+
        /* Decide on what to do with quarter-frame MTC during this cycle */
 
        bool const was_sending_qf_mtc = _send_qf_mtc;
index 5f1384d29218a6b70d25dceee60eb77826ba4d93..a6d25f05abf238e5cd7072aa838194d90a58e62a 100644 (file)
@@ -45,6 +45,7 @@
 #include "ardour/scene_changer.h"
 #include "ardour/session.h"
 #include "ardour/slave.h"
+#include "ardour/tempo.h"
 #include "ardour/operations.h"
 
 #include "pbd/i18n.h"
@@ -1616,6 +1617,38 @@ 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 ()) {
+                       /* 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);
+
+                       double div = meter.divisions_per_bar ();
+                       double pulses = _tempo_map->exact_qn_at_frame (_transport_frame, 0) * div / 4.0;
+                       double beats_left = fmod (pulses, div);
+
+                       _count_in_samples = meter.frames_per_bar (tempo, _current_frame_rate);
+
+                       double dt = _count_in_samples / div;
+                       if (beats_left == 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 += meter.frames_per_grid (tempo, _current_frame_rate) * beats_left;
+                       }
+
+                       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, div);
+                       }
+               }
        }
 
        DEBUG_TRACE (DEBUG::Transport, string_compose ("send TSC4 with speed = %1\n", _transport_speed));