fix (?) capture alignment by making sure we use non-public latency information for playback latency, thus avoiding counting plugin latency twice
git-svn-id: svn://localhost/ardour2/branches/3.0@9168 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
065b5ce8e7
commit
ca84e02b48
@ -253,8 +253,9 @@ _ the regular process() call to session->process() is not made.
|
||||
*/
|
||||
PBD::Signal3<void, Port *, Port *, bool> PortConnectedOrDisconnected;
|
||||
|
||||
std::string make_port_name_relative (std::string);
|
||||
std::string make_port_name_non_relative (std::string);
|
||||
std::string make_port_name_relative (std::string) const;
|
||||
std::string make_port_name_non_relative (std::string) const;
|
||||
bool port_is_mine (const std::string&) const;
|
||||
|
||||
static AudioEngine* instance() { return _instance; }
|
||||
void died ();
|
||||
|
@ -108,6 +108,7 @@ public:
|
||||
boost::shared_ptr<MuteMaster> _mute_master;
|
||||
bool no_panner_reset;
|
||||
boost::shared_ptr<PannerShell> _panshell;
|
||||
framecnt_t scnt;
|
||||
|
||||
static bool panners_legal;
|
||||
static PBD::Signal0<int> PannersLegal;
|
||||
|
@ -441,16 +441,6 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
|
||||
(*chan)->current_playback_buffer = 0;
|
||||
}
|
||||
|
||||
/* two conditions to test for here:
|
||||
|
||||
A: this track is rec-enabled, and the session has confirmed that we can record
|
||||
B: this track is rec-enabled, has been recording, and we are set up for auto-punch-in
|
||||
|
||||
The second test is necessary to capture the extra material that arrives AFTER the transport
|
||||
frame has left the punch range (which will cause the "can_record" argument to be false).
|
||||
*/
|
||||
|
||||
|
||||
// Safeguard against situations where process() goes haywire when autopunching
|
||||
// and last_recordable_frame < first_recordable_frame
|
||||
|
||||
@ -458,14 +448,16 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
|
||||
last_recordable_frame = max_framepos;
|
||||
}
|
||||
|
||||
OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
|
||||
if (record_enabled()) {
|
||||
|
||||
calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
|
||||
|
||||
if (rec_nframes && !was_recording) {
|
||||
capture_captured = 0;
|
||||
was_recording = true;
|
||||
}
|
||||
OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
|
||||
calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
|
||||
|
||||
if (rec_nframes && !was_recording) {
|
||||
capture_captured = 0;
|
||||
was_recording = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_record && !_last_capture_sources.empty()) {
|
||||
_last_capture_sources.clear ();
|
||||
@ -1479,8 +1471,9 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
|
||||
string region_name;
|
||||
|
||||
RegionFactory::region_name (region_name, whole_file_region_name, false);
|
||||
|
||||
// cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add region " << region_name << endl;
|
||||
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n",
|
||||
_name, (*ci)->start, (*ci)->frames, region_name));
|
||||
|
||||
try {
|
||||
|
||||
|
@ -993,12 +993,10 @@ AudioEngine::get_port_by_name (const string& portname)
|
||||
}
|
||||
}
|
||||
|
||||
if (portname.find_first_of (':') != string::npos) {
|
||||
if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
|
||||
/* not an ardour: port */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!port_is_mine (portname)) {
|
||||
/* not an ardour port */
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string const rel = make_port_name_relative (portname);
|
||||
|
||||
@ -1416,7 +1414,7 @@ AudioEngine::update_total_latencies ()
|
||||
}
|
||||
|
||||
string
|
||||
AudioEngine::make_port_name_relative (string portname)
|
||||
AudioEngine::make_port_name_relative (string portname) const
|
||||
{
|
||||
string::size_type len;
|
||||
string::size_type n;
|
||||
@ -1437,7 +1435,7 @@ AudioEngine::make_port_name_relative (string portname)
|
||||
}
|
||||
|
||||
string
|
||||
AudioEngine::make_port_name_non_relative (string portname)
|
||||
AudioEngine::make_port_name_non_relative (string portname) const
|
||||
{
|
||||
string str;
|
||||
|
||||
@ -1452,6 +1450,17 @@ AudioEngine::make_port_name_non_relative (string portname)
|
||||
return str;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioEngine::port_is_mine (const string& portname) const
|
||||
{
|
||||
if (portname.find_first_of (':') != string::npos) {
|
||||
if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioEngine::is_realtime () const
|
||||
{
|
||||
|
@ -62,6 +62,7 @@ Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pann
|
||||
, _no_outs_cuz_we_no_monitor (false)
|
||||
, _mute_master (mm)
|
||||
, no_panner_reset (false)
|
||||
, scnt (0)
|
||||
{
|
||||
_panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable));
|
||||
_display_to_user = false;
|
||||
@ -83,6 +84,7 @@ Delivery::Delivery (Session& s, boost::shared_ptr<Pannable> pannable, boost::sha
|
||||
, _no_outs_cuz_we_no_monitor (false)
|
||||
, _mute_master (mm)
|
||||
, no_panner_reset (false)
|
||||
, scnt (0)
|
||||
{
|
||||
_panshell = boost::shared_ptr<PannerShell>(new PannerShell (_name, _session, pannable));
|
||||
_display_to_user = false;
|
||||
@ -280,6 +282,21 @@ Delivery::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pf
|
||||
|
||||
panner = _panshell->panner();
|
||||
|
||||
#if 0
|
||||
if (_session.transport_rolling()) {
|
||||
cerr << name() << " first value written : " << scnt << endl;
|
||||
for (BufferSet::audio_iterator b = bufs.audio_begin(); b != bufs.audio_end(); ++b) {
|
||||
Sample* p = b->data ();
|
||||
float s = (float) scnt;
|
||||
for (pframes_t n = 0; n < nframes; ++n) {
|
||||
p[n] = s * 0.001;
|
||||
s += 1.0;
|
||||
}
|
||||
}
|
||||
scnt += nframes;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (panner && !panner->bypassed()) {
|
||||
|
||||
// Use the panner to distribute audio to output port buffers
|
||||
|
@ -655,35 +655,26 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
|
||||
return;
|
||||
}
|
||||
|
||||
/* we transitioned to recording. lets see if its transport based or a punch */
|
||||
|
||||
first_recordable_frame = transport_frame + _capture_offset;
|
||||
last_recordable_frame = max_framepos;
|
||||
capture_start_frame = _session.transport_frame();
|
||||
first_recordable_frame = capture_start_frame + _capture_offset;
|
||||
last_recordable_frame = max_framepos;
|
||||
|
||||
/* in theory, we should be offsetting by _session.worst_playback_latency() when we adjust
|
||||
for ExistingMaterial alignment. But that number includes the worst processor latency
|
||||
across all routes, and each track will already be roll-delay adjusted to handle that.
|
||||
so don't use worst_playback_latency(), just worst_output_latency() which covers
|
||||
only downstream latency from IO ports.
|
||||
*/
|
||||
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 basic FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8\n",
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 (%9) FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8 WOL %10 WTL %11\n",
|
||||
name(), first_recordable_frame, last_recordable_frame, capture_start_frame,
|
||||
_capture_offset,
|
||||
existing_material_offset,
|
||||
transport_frame,
|
||||
_roll_delay));
|
||||
_roll_delay,
|
||||
_session.transport_frame(),
|
||||
_session.worst_output_latency(),
|
||||
_session.worst_track_latency()));
|
||||
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
first_recordable_frame += existing_material_offset;
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n",
|
||||
first_recordable_frame));
|
||||
} else {
|
||||
capture_start_frame += _roll_delay;
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift CFS by roll delay of %1 to %2\n",
|
||||
_roll_delay, capture_start_frame));
|
||||
}
|
||||
}
|
||||
|
||||
prepare_record_status (capture_start_frame);
|
||||
|
||||
@ -703,13 +694,11 @@ Diskstream::check_record_status (framepos_t transport_frame, bool can_record)
|
||||
} else {
|
||||
/* punch out */
|
||||
|
||||
last_recordable_frame = transport_frame + _capture_offset;
|
||||
last_recordable_frame = _session.transport_frame() + _capture_offset;
|
||||
|
||||
if (_alignment_style == ExistingMaterial) {
|
||||
last_recordable_frame += existing_material_offset;
|
||||
} else {
|
||||
last_recordable_frame += _roll_delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -766,6 +755,10 @@ Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, f
|
||||
rec_offset = first_recordable_frame - transport_frame;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
|
||||
_name, enum_2_string (ot), transport_frame, nframes,
|
||||
first_recordable_frame, last_recordable_frame, rec_nframes, rec_offset));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -113,12 +113,16 @@ Graph::reset_thread_list ()
|
||||
drop_threads ();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* XXX this only makes sense when we can use just the AudioEngine thread
|
||||
and still keep the graph current with the route list
|
||||
*/
|
||||
if (num_threads <= 1) {
|
||||
/* no point creating 1 thread - the AudioEngine already gives us one
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), &a_thread, 100000) == 0) {
|
||||
_thread_list.push_back (a_thread);
|
||||
}
|
||||
|
@ -1156,6 +1156,10 @@ IO::latency () const
|
||||
|
||||
for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
|
||||
if ((latency = i->private_latency_range (_direction == Output).max) > max_latency) {
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose ("port %1 has %2 latency of %3 - use\n",
|
||||
name(),
|
||||
((_direction == Output) ? "PLAYBACK" : "CAPTURE"),
|
||||
latency));
|
||||
max_latency = latency;
|
||||
}
|
||||
}
|
||||
|
@ -346,21 +346,50 @@ Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) c
|
||||
for (vector<string>::const_iterator c = connections.begin();
|
||||
c != connections.end(); ++c) {
|
||||
|
||||
jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str());
|
||||
jack_latency_range_t lr;
|
||||
jack_latency_range_t lr;
|
||||
|
||||
if (!AudioEngine::instance()->port_is_mine (*c)) {
|
||||
|
||||
if (remote_port) {
|
||||
jack_port_get_latency_range (
|
||||
remote_port,
|
||||
(playback ? JackPlaybackLatency : JackCaptureLatency),
|
||||
&lr);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose (
|
||||
"\t%1 <-> %2 : latter has latency range %3 .. %4\n",
|
||||
name(), *c, lr.min, lr.max));
|
||||
range.min = min (range.min, lr.min);
|
||||
range.max = max (range.max, lr.max);
|
||||
}
|
||||
/* port belongs to some other JACK client, use
|
||||
* JACK to lookup its latency information.
|
||||
*/
|
||||
|
||||
jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str());
|
||||
|
||||
if (remote_port) {
|
||||
jack_port_get_latency_range (
|
||||
remote_port,
|
||||
(playback ? JackPlaybackLatency : JackCaptureLatency),
|
||||
&lr);
|
||||
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose (
|
||||
"\t%1 <-> %2 : latter has latency range %3 .. %4\n",
|
||||
name(), *c, lr.min, lr.max));
|
||||
|
||||
range.min = min (range.min, lr.min);
|
||||
range.max = max (range.max, lr.max);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* port belongs to this instance of ardour,
|
||||
so look up its latency information
|
||||
internally, because our published/public
|
||||
values already contain our plugin
|
||||
latency compensation.
|
||||
*/
|
||||
|
||||
Port* remote_port = AudioEngine::instance()->get_port_by_name (*c);
|
||||
if (remote_port) {
|
||||
lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
|
||||
DEBUG_TRACE (DEBUG::Latency, string_compose (
|
||||
"\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
|
||||
name(), *c, lr.min, lr.max));
|
||||
|
||||
range.min = min (range.min, lr.min);
|
||||
range.max = max (range.max, lr.max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1200,6 +1200,26 @@ Session::set_block_size (pframes_t nframes)
|
||||
|
||||
struct RouteSorter {
|
||||
/** @return true to run r1 before r2, otherwise false */
|
||||
bool sort_by_rec_enabled (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2) {
|
||||
if (r1->record_enabled()) {
|
||||
if (r2->record_enabled()) {
|
||||
/* both rec-enabled, just use signal order */
|
||||
return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
|
||||
} else {
|
||||
/* r1 rec-enabled, r2 not rec-enabled, run r2 early */
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (r2->record_enabled()) {
|
||||
/* r2 rec-enabled, r1 not rec-enabled, run r1 early */
|
||||
return true;
|
||||
} else {
|
||||
/* neither rec-enabled, use signal order */
|
||||
return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool operator() (boost::shared_ptr<Route> r1, boost::shared_ptr<Route> r2) {
|
||||
if (r2->feeds (r1)) {
|
||||
/* r1 fed by r2; run r2 early */
|
||||
@ -1210,8 +1230,8 @@ struct RouteSorter {
|
||||
} else {
|
||||
if (r1->not_fed ()) {
|
||||
if (r2->not_fed ()) {
|
||||
/* no ardour-based connections inbound to either route. just use signal order */
|
||||
return r1->order_key(N_("signal")) < r2->order_key(N_("signal"));
|
||||
/* no ardour-based connections inbound to either route. */
|
||||
return sort_by_rec_enabled (r1, r2);
|
||||
} else {
|
||||
/* r2 has connections, r1 does not; run r1 early */
|
||||
return true;
|
||||
@ -1497,8 +1517,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
|
||||
|
||||
failed:
|
||||
if (!new_routes.empty()) {
|
||||
add_routes (new_routes, true, false);
|
||||
save_state (_current_snapshot_name);
|
||||
add_routes (new_routes, true, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user