Fix metronome when looping

This commit is contained in:
Robin Gareus 2019-11-08 17:16:04 +01:00
parent 08fdb98262
commit 804f9c9bde
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04

View file

@ -58,8 +58,6 @@ Session::add_click (samplepos_t pos, bool emphasis)
void
Session::click (samplepos_t cycle_start, samplecnt_t nframes)
{
vector<TempoMap::BBTPoint> 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<TempoMap::BBTPoint>::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<TempoMap::BBTPoint> 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<TempoMap::BBTPoint>::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<Click*>::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) {