1
$\begingroup$

I have implemented an oversampling algorithm for an audio signal in C++ which is producing a distortion of the signal at the start of a buffer. The algorithm is wrapped in a class with methods for up and down sampling by a factor of 4, with a 256 tap linear phase FIR filter performing the "interpolation" of the upsampled signal. The distortion occurs after convolving the input signal with the filter coefficients so I think that is the source of the problem.

Here is the function I am using to apply the upsampling (where the distortion is first noticed):

// Upsample a signal four times
std::vector<double> oversample::upsample4x(double* inBuffer, size_t inLength)
{
    // Output length is 4 times the length of the input
    size_t outLength = 4*inLength;

    // Create vectors for the upsampled signal, pre and post filtering.
    std::vector<double> upSampled(outLength);
    std::vector<double> upFiltered(outLength);

    // Pad the signal with zeros
    for(size_t i=0; i<inLength; i++)
    {
        size_t j = i*4;
        upSampled[j] = inBuffer[i];
        upSampled[j+1] = 0;
        upSampled[j+2] = 0;
        upSampled[j+3] = 0;
    }

    // Use FIR filter to remove aliased images
    // accumulator for each sample
    double acc;
    for(size_t k=0; k<outLength; k++)
    {
        // Put the current sample into the buffer.
        upHistory[upIndex] = upSampled[k];

        // Create a local copy of the current index for calculating the output.
        size_t outIndex = upIndex;

        // Zero the accumulator.
        acc = 0;

        // For the zero-indexed array of length QTAPS (length of FIR+1).
        for(size_t i=0; i<QTAPS; i++)
        {
            // Convolve the buffer with the filter.
            acc += upHistory[outIndex] * quarterTaps[i];

            // If the index is above zero, decrement, otherwise set it to the filter length.
            outIndex = (outIndex > 0) ? --outIndex : QTAPS;
        }
        // Assign accumulator to the output vector.
        upFiltered[k] = 2*acc;

        // Check to see if we have reached the end of buffer.
        upIndex = (upIndex < QTAPS) ? ++upIndex : 0;
    }

    // Return the upsampled and filtered signal.
    return upFiltered;
}

The size_t upIndex is a member of th class oversample as well as the buffer upHistory which is the past signal used for the convolution. The algorithm is implemented as a ring buffer. QTAPS is the number of taps used for the filter (at a quarter of the sampling rate hence qtaps).

An illustration of the problem can be seen in this MATLAB figure:

Upsampled Signal

The input signal is 1500 samples long (so upsampled is 6000), after which I put the same signal through again. The real problem with this is that when I implement it for audio it gives an audible buzz every buffer, making the audio unusable. I've looked through the algorithm too many times and can no longer see any issues, so any help would be greatly appreciated.

EDIT: There was a discontinuity in the sine wave which is causing the visible distortion in the previous figure. This new figure illustrates a zoomed time domain shot of a guitar chord, where there are two very clear discontinuities which were not present in the original signal.

Up and downsampled signal

There are 30 samples between each peak, and the two peaks are periodic with a period of the length of the filter. I think the two peaks are caused by the two convolution processes from the up and down sampling (same filter, same code, just one pads and one decimates). I still can't figure out where this jump is coming from.

$\endgroup$

closed as off-topic by Jason R, Gilles, Peter K. May 31 '16 at 18:34

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions requesting working code written to a specification are off-topic as they are unlikely to benefit anyone else. Instead, describe the problem you're solving and where you're stuck." – Jason R, Gilles, Peter K.
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    $\begingroup$ have you checked the initial conditions ? block based audio processing requires you to supply correct initial conditions at the beginning of every frame. $\endgroup$ – Fat32 May 30 '16 at 0:25
  • $\begingroup$ I presume this is the problem but I can't see it anywhere. The variables upIndex and upHistory are persistent as they are members of the class. $\endgroup$ – loudnoises May 30 '16 at 7:38
  • $\begingroup$ I've looked at your code... it seems to me that at the beginning of the convolution computation by flip&drag method, where the input signal portion is shorter than the filter length, is causing the problem... Those index variables are out of yoru control... That's all I can say without further information. You better write your own method. it will be a mere copy of the above code with a few lines of added. $\endgroup$ – Fat32 May 31 '16 at 0:36
  • 3
    $\begingroup$ I'm wondering about the line outIndex = (outIndex > 0) ? --outIndex : QTAPS; Should outIndex really ever by set to QTAPS? Shouldn't that be QTAPS-1? $\endgroup$ – Peter K. May 31 '16 at 12:22
  • 1
    $\begingroup$ That was it, two off-by-one errors in two locations (also for the upIndex condition). Thanks for your time @PeterK. $\endgroup$ – loudnoises May 31 '16 at 19:28