Implement Count-In (before recording), fixed BPM, up to 2 bars

This commit is contained in:
Robin Gareus 2017-01-17 20:43:55 +01:00
parent fcbed9c1dc
commit a6e02c0d71
5 changed files with 77 additions and 0 deletions

View 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;

View 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)

View 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)

View 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;

View 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));