PortAudio 对连续输入流的实时音频处理

PortAudio real-time audio processing for continuous input stream

我正在使用 PortAudio 来实现实时音频处理。

我的主要任务是连续从麦克风获取数据,并提供 100 个样本供其他处理线程处理 (each FRAME = 100 samples at a time)

这是我的 回调 每次连续收集 100 个样本 -

static int paStreamCallback( const void* input, void* output,
    unsigned long samplesPerFrame,
    const PaStreamCallbackTimeInfo* timeInfo,
    PaStreamCallbackFlags statusFlags,
    void* userData ) {

    paTestData *data = (paTestData*) userData;
    const SAMPLE *readPtr = (const SAMPLE*)input;   // Casting input read to valid input type SAMPLE (float)
    unsigned long totalSamples = TOTAL_NUM_OF_SAMPLES ; // totalSamples = 100 here

    (void) output;
    (void) timeInfo;
    (void) statusFlags;

    static int count = 1;

    if(data->sampleIndex < count * samplesPerFrame){
        data->recordedSample[data->sampleIndex] = *readPtr;
        data->sampleIndex++;
    }

    else if(data->sampleIndex ==  count * samplesPerFrame){

        processSampleFrame(data->recordedSample);
        count++;
        finished = paContinue;
    }

    return finished;
}

我的`main函数-

int main(void){

// Some Code here

data.sampleIndex = 0;
data.frameIndex = 1;

numBytes = TOTAL_NUM_OF_SAMPLES * sizeof(SAMPLE);
data.recordedSample = (SAMPLE*)malloc(numBytes);

for(i=0; i < TOTAL_NUM_OF_SAMPLES; i++)
    data.recordedSample[i] = 0;

// Open Stream Initialization

err = Pa_StartStream(stream);

/* Recording audio here..Speak into the MIC */
printf("\nRecording...\n");
fflush(stdout);

while((err = Pa_IsStreamActive(stream)) == 1)
    Pa_Sleep(10);

    if(err < 0)
            goto done;

    err = Pa_CloseStream(stream);

// Some more code here
}

将 100 个样本的每个帧发送到 processSampleFrame。

void processSampleFrame(SAMPLE *singleFrame){

    // Free buffer of this frame
    // Processing sample frame here
}

挑战在于我需要实现一种方法,其中时间 processSampleFrame 正在处理样本,我的 callBack 应该处于活动状态并继续获取下一个 Frame of 100 samples 和(可能更多取决于 processSampleFrame) 的处理时间。

此外,缓冲区应该能够在将帧传递给 processSampleFrame.

后尽快将其自身从帧中释放出来

编辑 2:

我尝试使用 PortAudio 提供的 PaUtilRingBuffer 来实现。这是我的 回调.

printf("Inside callback\n");
paTestData *data = (paTestData*) userData;

ring_buffer_size_t elementsWritable = PaUtil_GetRingBufferWriteAvailable(&data->ringBuffer);
ring_buffer_size_t elementsToWrite = rbs_min(elementsWritable, (ring_buffer_size_t)(samplesPerFrame * numChannels));

const SAMPLE *readPtr = (const SAMPLE*)input;
printf("Sample ReadPtr = %.8f\n", *readPtr);
(void) output;      // Preventing unused variable warnings
(void) timeInfo;
(void) statusFlags;

data->frameIndex += PaUtil_WriteRingBuffer(&data->ringBuffer, readPtr, elementsToWrite);

return paContinue;

主要

int main(void){

    paTestData data;    // Object of paTestData structure

    fflush(stdout);

    data.frameIndex = 1;

    long numBytes = TOTAL_NUM_OF_SAMPLES * LIMIT;
    data.ringBufferData = (SAMPLE*)PaUtil_AllocateMemory(numBytes);
    if(PaUtil_InitializeRingBuffer(&data.ringBuffer, sizeof(SAMPLE), ELEMENTS_TO_WRITE, data.ringBufferData) < 0){
        printf("Failed to initialise Ring Buffer.\n");
        goto done;

    err = Pa_StartStream(stream);

    /* Recording audio here..Speak into the MIC */
    printf("\nRecording samples\n");
    fflush(stdout);

    while((err = Pa_IsStreamActive(stream)) == 1)
        Pa_Sleep(10);

    if(err < 0)
                goto done;

        err = Pa_CloseStream(stream);

    // Error Handling here
}

PaTestData结构:

typedef struct{

    SAMPLE *ringBufferData;
    PaUtilRingBuffer ringBuffer;    
    unsigned int frameIndex;
}
paTestData;

成功获取分配的 space 后,我面临同样的段错误问题,因为无法按照 callback 中的建议使用任何 free =23=] 文档。

我在哪里可以释放分配给处理线程的帧的缓冲区。可能是一种获取线程同步的方法在这里真的很有用。感谢您的帮助。

处理音频输入的示例代码:

#define FRAME_SIZE                 1024
#define CIRCULAR_BUFFER_SIZE       (FRAME_SIZE * 4)

float buffer[CIRCULAR_BUFFER_SIZE];

typedef struct {
     int read, write;
     float vol;
} paData;

static int paStreamCallback(const void* input, void* output,
                            unsigned long samplesPerFrame,
                            const PaStreamCallbackTimeInfo* timeInfo,
                            PaStreamCallbackFlags statusFlags,
                            void* userData) {

    paData *data = (paData *)userData;
    // Write input buffer to our buffer: (memcpy function is fine, just a for loop of writing data
    memcpy(&buffer[write], input, samplesPerFrame); // Assuming samplesPerFrame = FRAME_SIZE

    // Increment write/wraparound
    write = (write + FRAME_SIZE) % CIRCULAR_BUFFER_SIZE;

    // dummy algorithm for processing blocks:
    processAlgorithm(&buffer[read]);

    // Write output
    float *dummy_buffer = &buffer[read]; // just for easy increment
    for (int i = 0; i < samplesPerFrame; i++) {
         // Mix audio input and processed input; 50% mix
         output[i] = input[i] * 0.5 + dummy_buffer[i] * 0.5;
    }

    // Increment read/wraparound
    read = (read + FRAME_SIZE) % CIRCULAR_BUFFER_SIZE;

    return paContinue;
}

int main(void) {
     // Initialize code here; any memory allocation needs to be done here! default buffers to 0 (silence)
     // initialize paData too; write = 0, read = 3072
     // read is 3072 because I'm thinking about this like a delay system.
}

对此持保留态度;这样做显然是更好的方法,但它可以用作起点。