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:
Paul Davis 2011-03-18 20:21:51 +00:00
parent 065b5ce8e7
commit ca84e02b48
10 changed files with 140 additions and 70 deletions

View File

@ -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 ();

View File

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

View File

@ -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 {

View File

@ -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
{

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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 {

View File

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