Why is this RtAudio callback function generating a distorted sine wave?

102 Views Asked by At

I have an RtAudio callback function that fills a buffer with samples of a sine wave of a given frequency and amplitude and calculates the phase at which the sine wave written to the next buffer should begin. However, when these buffers are played, the sound generated is clearly not a sine wave.

I have printed the sample values filling the buffers and the phase between consecutive buffers is correct - there is no mismatch between consecutive buffers. I have timed the callback function and it takes less than a microsecond to fill the buffer. I am using a buffer size of 256 and a sample rate of 44110 so the time the buffer plays for is in the milliseconds.

Note that when I increase the buffer length to a large size so that playback is one the order of seconds, it sounds like a sine wave as intended. However, the latency is of course unacceptable for these buffer sizes.

Why is this RtAudio callback function generating a distorted sine wave? What is it I am not doing or what is it I am doing wrong?

int build_sound(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
               double streamTime, RtAudioStreamStatus status, void *userData) {
    
    double *buffer = (double *) outputBuffer;
    std::fill_n(buffer, nBufferFrames, 0.0);
    
    std::vector<pressedKey*> *data = static_cast<std::vector<pressedKey*>*>(userData);
    if (!data->empty()) { 
        for (auto it = data->begin(); it != data->end(); ) {
            pressedKey* trigger = *it;
            if (trigger->bufferphase.size()!=trigger->amps.size()) {
                trigger->bufferphase.resize(trigger->amps.size());
                for (int i=0; i<trigger->amps.size(); i++) {
                    trigger->bufferphase[i]=0;
                }
            }
            for (int i=0; i<trigger->amps.size(); i++) {
                for (int j=0; j<nBufferFrames; j=j+2)  {
                    double jdbl=static_cast<double>(j);
                    buffer[j]=buffer[j]+trigger->amps[i]*0.05*sin(2*PI*
                                                  trigger->freqs[i]*jdbl/SAMPLERATE
                                                  +trigger->bufferphase[i]);
                    buffer[j+1]=buffer[j+1]+trigger->amps[i]*0.05*sin(2*PI*
                                                    trigger->freqs[i]*jdbl/SAMPLERATE
                                                    +trigger->bufferphase[i]);
                }
                trigger->bufferphase[i]+=2*PI*(trigger->freqs[i]
                                              *(nBufferFrames-1)/SAMPLERATE); 
                if (i==0){
                    for (int j=0; j<nBufferFrames; j=j+2)  {
                        std::cout<<j<<" "<<buffer[j]<<std::endl;
                    }
                }  
            }
        ++it;       
        }
    }

    return 0;               
}

EDIT: Added output per Ted Lyngmo's suggestion. This clarifies the source of the problem: a buffer-sized gap in between buffers. I guess when interleaving is on RtAudio makes the buffer size nBufferSamples*2

rtaudio problem oscillogram

0

There are 0 best solutions below