diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc index 87444686a3..557e1c1d12 100644 --- a/libs/ardour/session_click.cc +++ b/libs/ardour/session_click.cc @@ -58,8 +58,6 @@ Session::add_click (samplepos_t pos, bool emphasis) void Session::click (samplepos_t cycle_start, samplecnt_t nframes) { - vector points; // TODO use mempool allocator - if (_click_io == 0) { return; } @@ -87,32 +85,64 @@ Session::click (samplepos_t cycle_start, samplecnt_t nframes) /* range to check for clicks */ samplepos_t start = cycle_start + offset; - const samplepos_t end = start + nframes; /* correct start, potentially */ start = max (start, (samplepos_t) 0); - if (end > start) { - _tempo_map->get_grid (points, start, end); - } + samplecnt_t remain = nframes; - if (distance (points.begin(), points.end()) == 0) { - goto run_clicks; - } + while (remain > 0) { + samplecnt_t move = remain; - for (vector::iterator i = points.begin(); i != points.end(); ++i) { - switch ((*i).beat) { - case 1: - add_click ((*i).sample, true); - break; - default: - if (click_emphasis_data == 0 || (Config->get_use_click_emphasis () == false) || (click_emphasis_data && (*i).beat != 1)) { // XXX why is this check needed ?? (*i).beat !=1 must be true here - add_click ((*i).sample, false); + Location* loop_location = locations()->auto_loop_location (); + if (loop_location) { + const samplepos_t loop_start = loop_location->start (); + const samplepos_t loop_end = loop_location->end (); + if (start >= loop_end) { + samplecnt_t off = (start - loop_end) % (loop_end - loop_start); + start = loop_start + off; + move = std::min (remain, loop_end - start); + } else if (start + move >= loop_end) { + move = std::min (remain, loop_end - start); + } + if (move == 0) { + start = loop_start; + const samplecnt_t looplen = loop_end - loop_start; + move = std::min (remain, looplen); } - break; } + + const samplepos_t end = start + move; + + vector points; // TODO use mempool allocator + _tempo_map->get_grid (points, start, end); + + if (distance (points.begin(), points.end()) == 0) { + start += move; + remain -= move; + continue; + } + + for (vector::iterator i = points.begin(); i != points.end(); ++i) { + if ((*i).sample < start || (*i).sample >= end) { + // FIXME: TempoMap::get_grid() returns duplicates and out of range points + continue; + } + switch ((*i).beat) { + case 1: + add_click ((*i).sample, true); + break; + default: + if (click_emphasis_data == 0 || (Config->get_use_click_emphasis () == false) || (click_emphasis_data && (*i).beat != 1)) { // XXX why is this check needed ?? (*i).beat !=1 must be true here + add_click ((*i).sample, false); + } + break; + } + } + + start += move; + remain -= move; } - run_clicks: clickm.release (); run_click (cycle_start, nframes); } @@ -135,31 +165,59 @@ Session::run_click (samplepos_t start, samplepos_t nframes) buf = bufs.get_audio(0).data(); memset (buf, 0, sizeof (Sample) * nframes); + /* given a large output latency, `start' can be offset by by > 1 cycle. + * and needs to be mapped back into the loop-range */ + Location* loop_location = locations()->auto_loop_location (); + bool crossloop = false; + samplecnt_t span = nframes; + if (loop_location) { + const samplepos_t loop_start = loop_location->start (); + const samplepos_t loop_end = loop_location->end (); + if (start >= loop_end) { + samplecnt_t off = (start - loop_end) % (loop_end - loop_start); + start = loop_start + off; + span = std::min (nframes, loop_end - start); + } else if (start + nframes >= loop_end) { + crossloop = true; + span = std::min (nframes, loop_end - start); + } + } + for (list::iterator i = clicks.begin(); i != clicks.end(); ) { - samplecnt_t copy; + Click *clk = *i; + + if (loop_location) { + const samplepos_t loop_start = loop_location->start (); + const samplepos_t loop_end = loop_location->end (); + /* remove any clicks that are outside loop location, and not currently playing */ + if ((clk->start < loop_start || clk->start >= loop_end) && clk->offset == 0) { + delete clk; + i = clicks.erase (i); + continue; + } + } + samplecnt_t internal_offset; - Click *clk; - clk = *i; - - if (clk->start < start) { + if (clk->start <= start || clk->offset > 0) { internal_offset = 0; - } else { + } else if (clk->start < start + span) { + /* queue click at offset in current cycle */ internal_offset = clk->start - start; + } else if (crossloop) { + /* When loop wraps around in current cycle, take + * clicks at loop-start into account */ + const samplepos_t loop_start = loop_location->start (); + internal_offset = clk->start - loop_start + span; } - if (nframes < internal_offset) { - /* we've just located or something.. - effectively going backwards. - lets get the flock out of here */ - break; + if (internal_offset >= nframes) { + break; } - copy = min (clk->duration - clk->offset, nframes - internal_offset); - + samplecnt_t copy = min (clk->duration - clk->offset, nframes - internal_offset); memcpy (buf + internal_offset, &clk->data[clk->offset], copy * sizeof (Sample)); - clk->offset += copy; if (clk->offset >= clk->duration) {