3

I'm trying to implement simple delay/reverb described in this post https://stackoverflow.com/a/5319085/1562784 and I have a problem. On windows where I record 16bit/16khz samples and get 8k samples per recording callback call, it works fine. But on linux I get much smaller chunks from soundcard. Something around 150 samples. Because of that I modified delay/reverb code to buffer samples:

#define REVERB_BUFFER_LEN 8000

static void reverb( int16_t* Buffer, int N)
{
    int i;
    float decay = 0.5f;
    static int16_t sampleBuffer[REVERB_BUFFER_LEN] = {0};

    //Make room at the end of buffer to append new samples
    for (i = 0; i < REVERB_BUFFER_LEN - N; i++)
        sampleBuffer[ i ] = sampleBuffer[ i + N ] ;     

    //copy new chunk of audio samples at the end of buffer
    for (i = 0; i < N; i++)
        sampleBuffer[REVERB_BUFFER_LEN - N + i ] = Buffer[ i ] ;

    //perform effect
    for (i = 0; i < REVERB_BUFFER_LEN - 1600; i++)
    {
        sampleBuffer[i + 1600] += (int16_t)((float)sampleBuffer[i] * decay);
    }   

    //copy output sample
    for (i = 0; i < N; i++)
        Buffer[ i ] = sampleBuffer[REVERB_BUFFER_LEN - N + i ];


}

This results in white noise on output, so clearly I'm doing something wrong. On linux, I record in 16bit/16khz, same like on Windows and I'm running linux in VMWare.

Thank you!

Update:

As indicated in answered post, I was 'reverbing' old samples over and over again. Simple 'if' sovled a problem:

    for (i = 0; i < REVERB_BUFFER_LEN - 1600; i++)
    {
        if((i + 1600) >= REVERB_BUFFER_LEN - N)
            sampleBuffer[i + 1600] += (int16_t)((float)sampleBuffer[i] * decay);
    }
Community
  • 1
  • 1
Mike Jackson
  • 183
  • 1
  • 12

1 Answers1

2

Your loop that performs the actual reverb effect will be performed multiple times on the same samples, on different calls to the function. This is because you save old samples in the buffer, but you perform the reverb on all samples each time. This will likely cause them to overflow at some point.

You should only perform the reverb on the new samples, not on ones which have already been modified. I would also recommend checking for overflow and clipping to the min/max values instead of wrapping in that case.

A probably better way to perform reverb, which will work for any input buffer size, is to maintain a circular buffer of size REVERB_SAMPLES (1600 in your case), which contains the last samples.

void reverb( int16_t* buf, int len) {
    static int16_t reverb_buf[REVERB_SAMPLES] = {0};
    static int reverb_pos = 0;

    for (int i=0; i<len; i++) {
        int16_t new_value = buf[i] + reverb_buf[reverb_pos] * decay;
        reverb_buf[reverb_pos] = new_value;
        buf[i] = new_value;
        reverb_pos = (reverb_pos + 1) % REVERB_SAMPLES;
    }
}
interjay
  • 107,303
  • 21
  • 270
  • 254
  • Thank you very much, sir! That was exactly then problem! I put simple 'if check' inside reverb loop and that sovled problem. I'll try your implementation now. – Mike Jackson Sep 03 '15 at 13:41