Avoid audible clicks when rapidly chaning panning

This commit is contained in:
derselbst 2021-02-06 15:26:25 +01:00 committed by Tom M
parent e2d67ea772
commit 25b0503ba7
3 changed files with 30 additions and 7 deletions

View file

@ -493,7 +493,8 @@ fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t *buffers, unsigned int
for(i = buffers->count; i <= bufnum; i++)
{
buffers->bufs[i].amp = 0.0f;
buffers->bufs[i].target_amp = 0.0f;
buffers->bufs[i].current_amp = 0.0f;
}
buffers->count = bufnum + 1;
@ -512,7 +513,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp)
return;
}
buffers->bufs[bufnum].amp = value;
buffers->bufs[bufnum].target_amp = value;
}
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping)

View file

@ -143,8 +143,14 @@ struct _fluid_rvoice_buffers_t
unsigned int count; /* Number of records in "bufs" */
struct
{
fluid_real_t amp;
int mapping; /* Mapping to mixdown buffer index */
/* the actual, linearly interpolated amplitude with which the dsp sample should be mixed into the buf */
fluid_real_t current_amp;
/* the desired amplitude [...] mixed into the buf (directly set by e.g. rapidly changing PAN events) */
fluid_real_t target_amp;
/* Mapping to mixdown buffer index */
int mapping;
} bufs[FLUID_RVOICE_MAX_BUFS];
};

View file

@ -392,13 +392,17 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
for(i = 0; i < bufcount; i++)
{
fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
fluid_real_t amp = buffers->bufs[i].amp;
fluid_real_t target_amp = buffers->bufs[i].target_amp;
fluid_real_t current_amp = buffers->bufs[i].current_amp;
fluid_real_t amp_incr;
if(buf == NULL || amp == 0.0f)
if(buf == NULL || (current_amp == 0.0f && target_amp == 0.0f))
{
continue;
}
amp_incr = (target_amp - current_amp) / FLUID_BUFSIZE;
FLUID_ASSERT((uintptr_t)buf % FLUID_DEFAULT_ALIGNMENT == 0);
/* mixdown sample_count samples in the current buffer buf
@ -406,13 +410,25 @@ fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers,
#pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT)
for(dsp_i = 0; dsp_i < sample_count; dsp_i++)
{
fluid_real_t samp;
if(dsp_i < FLUID_BUFSIZE)
{
samp = (current_amp + amp_incr * dsp_i) * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
}
else
{
samp = target_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
}
// Index by blocks (not by samples) to let the compiler know that we always start accessing
// buf and dsp_buf at the FLUID_BUFSIZE*sizeof(fluid_real_t) byte boundary and never somewhere
// in between.
// A good compiler should understand: Aha, so I don't need to add a peel loop when vectorizing
// this loop. Great.
buf[start_block * FLUID_BUFSIZE + dsp_i] += amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i];
buf[start_block * FLUID_BUFSIZE + dsp_i] += samp;
}
buffers->bufs[i].current_amp = target_amp;
}
}