mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 16:46:35 +01:00
compensate for processor latency during bounce
This commit is contained in:
parent
1e3a955fc0
commit
5b2da3caf7
4 changed files with 109 additions and 40 deletions
|
|
@ -470,6 +470,13 @@ class LIBARDOUR_API Route : public SessionObject, public Automatable, public Rou
|
||||||
pframes_t nframes, int declick,
|
pframes_t nframes, int declick,
|
||||||
bool gain_automation_ok);
|
bool gain_automation_ok);
|
||||||
|
|
||||||
|
virtual void bounce_process (BufferSet& bufs,
|
||||||
|
framepos_t start_frame, framecnt_t nframes,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint,
|
||||||
|
bool for_export);
|
||||||
|
|
||||||
|
framecnt_t bounce_get_latency (boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export) const;
|
||||||
|
|
||||||
boost::shared_ptr<IO> _input;
|
boost::shared_ptr<IO> _input;
|
||||||
boost::shared_ptr<IO> _output;
|
boost::shared_ptr<IO> _output;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -417,38 +417,7 @@ AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nfram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no processing is required, there's no need to go any further.
|
bounce_process (buffers, start, nframes, endpoint, include_endpoint, for_export);
|
||||||
|
|
||||||
if (!endpoint && !include_endpoint) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
|
||||||
|
|
||||||
if (!include_endpoint && (*i) == endpoint) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we're not exporting, stop processing if we come across a routing processor.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!for_export && (*i)->does_routing()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* even for export, don't run any processor that does routing.
|
|
||||||
|
|
||||||
oh, and don't bother with the peak meter either.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
|
||||||
(*i)->run (buffers, start, start+nframes, nframes, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*i) == endpoint) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,68 @@ Route::process_output_buffers (BufferSet& bufs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Route::bounce_process (BufferSet& buffers, framepos_t start, framecnt_t nframes,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export)
|
||||||
|
{
|
||||||
|
/* If no processing is required, there's no need to go any further. */
|
||||||
|
if (!endpoint && !include_endpoint) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
|
|
||||||
|
if (!include_endpoint && (*i) == endpoint) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we're not exporting, stop processing if we come across a routing processor. */
|
||||||
|
|
||||||
|
if (!for_export && (*i)->does_routing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't run any processors that does routing.
|
||||||
|
* oh, and don't bother with the peak meter either.
|
||||||
|
*/
|
||||||
|
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
||||||
|
(*i)->run (buffers, start, start+nframes, nframes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//buffers.set_count ((*i)->output_streams());
|
||||||
|
|
||||||
|
if ((*i) == endpoint) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
framecnt_t
|
||||||
|
Route::bounce_get_latency (boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export) const
|
||||||
|
{
|
||||||
|
framecnt_t latency = 0;
|
||||||
|
if (!endpoint && !include_endpoint) {
|
||||||
|
return latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
|
|
||||||
|
if (!include_endpoint && (*i) == endpoint) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!for_export && (*i)->does_routing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
||||||
|
latency += (*i)->signal_latency ();
|
||||||
|
}
|
||||||
|
if ((*i) == endpoint) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return latency;
|
||||||
|
}
|
||||||
|
|
||||||
ChanCount
|
ChanCount
|
||||||
Route::n_process_buffers ()
|
Route::n_process_buffers ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4133,6 +4133,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||||
framepos_t position;
|
framepos_t position;
|
||||||
framecnt_t this_chunk;
|
framecnt_t this_chunk;
|
||||||
framepos_t to_do;
|
framepos_t to_do;
|
||||||
|
framepos_t latency_skip;
|
||||||
BufferSet buffers;
|
BufferSet buffers;
|
||||||
SessionDirectory sdir(get_best_session_directory_for_new_source ());
|
SessionDirectory sdir(get_best_session_directory_for_new_source ());
|
||||||
const string sound_dir = sdir.sound_path();
|
const string sound_dir = sdir.sound_path();
|
||||||
|
|
@ -4208,10 +4209,12 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||||
|
|
||||||
position = start;
|
position = start;
|
||||||
to_do = len;
|
to_do = len;
|
||||||
|
latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export);
|
||||||
|
|
||||||
/* create a set of reasonably-sized buffers */
|
/* create a set of reasonably-sized buffers */
|
||||||
buffers.ensure_buffers (DataType::AUDIO, max_proc.n_audio(), chunk_size);
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
||||||
buffers.ensure_buffers (DataType::MIDI, max_proc.n_midi(), chunk_size);
|
buffers.ensure_buffers(*t, max_proc.get(*t), chunk_size);
|
||||||
|
}
|
||||||
buffers.set_count (max_proc);
|
buffers.set_count (max_proc);
|
||||||
|
|
||||||
for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
|
for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
|
||||||
|
|
@ -4228,6 +4231,40 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start += this_chunk;
|
||||||
|
to_do -= this_chunk;
|
||||||
|
itt.progress = (float) (1.0 - ((double) to_do / len));
|
||||||
|
|
||||||
|
if (latency_skip >= chunk_size) {
|
||||||
|
latency_skip -= chunk_size;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const framecnt_t current_chunk = this_chunk - latency_skip;
|
||||||
|
|
||||||
|
uint32_t n = 0;
|
||||||
|
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
|
||||||
|
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
|
||||||
|
|
||||||
|
if (afs) {
|
||||||
|
if (afs->write (buffers.get_audio(n).data(latency_skip), current_chunk) != current_chunk) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
latency_skip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* post-roll, pick up delayed processor output */
|
||||||
|
latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export);
|
||||||
|
|
||||||
|
while (latency_skip && !itt.cancel) {
|
||||||
|
this_chunk = min (latency_skip, chunk_size);
|
||||||
|
latency_skip -= this_chunk;
|
||||||
|
|
||||||
|
buffers.silence (this_chunk, 0);
|
||||||
|
track.bounce_process (buffers, start, this_chunk, endpoint, include_endpoint, for_export);
|
||||||
|
|
||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
|
for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
|
||||||
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
|
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
|
||||||
|
|
@ -4238,12 +4275,6 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start += this_chunk;
|
|
||||||
to_do -= this_chunk;
|
|
||||||
|
|
||||||
itt.progress = (float) (1.0 - ((double) to_do / len));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!itt.cancel) {
|
if (!itt.cancel) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue