PortAudio麦克风捕获,分离通道值

时间:2014-03-20 17:57:31

标签: c audio core-audio microphone portaudio

我使用带有PortAudio的麦克风阵列(Playstation eye)。我正在尝试麦克风阵列处理,在那里我可以知道每个麦克风的电平并使用波束成形或耳间时间延迟来指定声音的方向。我无法确定每个频道的声级。

以下是一些代码片段,第一个是recordCallback。

static int recordCallback( const void *inputBuffer, void *outputBuffer,
                          unsigned long framesPerBuffer,
                          const PaStreamCallbackTimeInfo* timeInfo,
                          PaStreamCallbackFlags statusFlags,
                          void *userData )
{

    paTestData *data = (paTestData*)userData;


    const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
    SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
    long framesToCalc;
    long i;
    int finished;
    unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;

    (void) outputBuffer; /* Prevent unused variable warnings. */
    (void) timeInfo;
    (void) statusFlags;
    (void) userData;

    if( framesLeft < framesPerBuffer )
    {
        framesToCalc = framesLeft;
        finished = paComplete;
    }
    else
    {
        framesToCalc = framesPerBuffer;
        finished = paContinue;
    }

    if( inputBuffer == NULL )
    {
        for( i=0; i<framesToCalc; i++ )
        {
            *wptr++ = SAMPLE_SILENCE;  /* 1 */
            if( NUM_CHANNELS =>= 2 ) *wptr++ = SAMPLE_SILENCE;  /* 2 */
            if( NUM_CHANNELS =>= 3 ) *wptr++ = SAMPLE_SILENCE;  /* 3 */
            if( NUM_CHANNELS >= 4 ) *wptr++ = SAMPLE_SILENCE;  /* 4 */
        }
    }
    else
    {
        for( i=0; i<framesToCalc; i++ )
        {
            *wptr++ = *rptr++;  /* 1 */
            if( NUM_CHANNELS >= 2 ) *wptr++ = *rptr++;  /* 2 */
            if( NUM_CHANNELS >= 3 ) *wptr++ = *rptr++;  /* 3 */
            if( NUM_CHANNELS >= 4 ) *wptr++ = *rptr++;  /* 4 */
        }
    }
    data->frameIndex += framesToCalc;
    return finished;
}

以下是我播放音频并试图显示频道平均值的主要方法。

int main(void)
{
    PaStreamParameters  inputParameters,
    outputParameters;
    PaStream*           stream;
    PaError             err = paNoError;
    paTestData          data;
    int                 i;
    int                 totalFrames;
    int                 numSamples;
    int                 numBytes;
    SAMPLE              max, val;
    double              average;

    printf("patest_record.c\n"); fflush(stdout);

    data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
    data.frameIndex = 0;
    numSamples = totalFrames * NUM_CHANNELS;
    numBytes = numSamples * sizeof(SAMPLE);
    data.recordedSamples = (SAMPLE *) malloc( numBytes ); /* From now on, recordedSamples is initialised. */
    if( data.recordedSamples == NULL )
    {
        printf("Could not allocate record array.\n");
        goto done;
    }
    for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;

    err = Pa_Initialize();
    if( err != paNoError ) goto done;

    inputParameters.device = 2; /* default input device */
    if (inputParameters.device == paNoDevice) {
        fprintf(stderr,"Error: No default input device.\n");
        goto done;
    }
    inputParameters.channelCount = 2;                    /* stereo input */
    inputParameters.sampleFormat = PA_SAMPLE_TYPE;
    inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
    inputParameters.hostApiSpecificStreamInfo = NULL;

    /* Record some audio. -------------------------------------------- */
    err = Pa_OpenStream(
                        &stream,
                        &inputParameters,
                        NULL,                  /* &outputParameters, */
                        SAMPLE_RATE,
                        FRAMES_PER_BUFFER,
                        paClipOff,      /* we won't output out of range samples so don't bother clipping them */
                        recordCallback,
                        &data );
    if( err != paNoError ) goto done;

    err = Pa_StartStream( stream );
    if( err != paNoError ) goto done;
    printf("\n=== Now recording!! Please speak into the microphone. ===\n"); fflush(stdout);

    while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
    {
        Pa_Sleep(1000);

        printf("index = %d\n", data.frameIndex ); fflush(stdout);
        printf("Channel = %d\n", data.currentChannel ); fflush(stdout);
    }
    if( err < 0 ) goto done;

    err = Pa_CloseStream( stream );
    if( err != paNoError ) goto done;

    /* Measure maximum peak amplitude. */

    /*  average for each channel */

    SAMPLE channel1val =0;
    SAMPLE channel2val = 0;
    SAMPLE channel3val =0;
    SAMPLE channel4val = 0;

    long channel1avg = 0.0;
    long channel2avg =0.0;
    long channel3avg =0.0;
    long channel4avg =0.0;

    SAMPLE channel1max = 0;
    SAMPLE channel2max =0;
    SAMPLE channel3max =0;
    SAMPLE channel4max =0;

    i = 0;
    do
    {

        channel1val = data.recordedSamples[i];
        if (channel1val < 0)
        {
            channel1val = -channel1val;
        }

        if (channel1val > channel1max)
        {
            channel1max = channel1val;
        }
        channel1avg  += channel1val;

        i = i + 4;
    }
    while (i<numSamples);

    i = 1;
    do
    {
        channel2val = data.recordedSamples[i];
        if (channel2val < 0)
        {
            channel2val = -channel2val;
        }

        if (channel2val > channel2max)
        {
            channel2max = channel2val;
        }
        channel2avg  += channel2val;

        i = i + 4;
    }
    while (i<numSamples);

    i = 2;
    do
    {
        channel3val = data.recordedSamples[i];
        if (channel3val < 0)
        {
            channel3val = -channel3val;
        }

        if (channel3val > channel3max)
        {
            channel3max = channel3val;
        }
        channel3avg  += channel3val;

        i = i + 4;
    }
    while (i<numSamples);

    i = 3;
    do
    {
        channel4val = data.recordedSamples[i];
        if (channel4val < 0)
        {
            channel4val = -channel4val;
        }

        if (channel4val > channel4max)
        {
            channel4max = channel4val;
        }
        channel4avg  += channel4val;

        i = i + 4;
    }
    while (i<numSamples);






    channel1avg = channel1avg / (double)numSamples;
    channel2avg = channel2avg / (double)numSamples;
    channel3avg = channel3avg / (double)numSamples;
    channel4avg = channel4avg / (double)numSamples;

  // printf("sample max amplitude = "PRINTF_S_FORMAT"\n", max );
  //  printf("sample average = %lf\n", average );


    printf("channel1 max amplitude = "PRINTF_S_FORMAT"\n", channel1max);
    printf("sample average = %lf\n", channel1avg);

    printf("channel2 max amplitude = "PRINTF_S_FORMAT"\n", channel2max);
    printf("sample average = %lf\n", channel2avg);

    printf("channel3 max amplitude = "PRINTF_S_FORMAT"\n", channel3max);
    printf("sample average = %lf\n", channel3avg);

    printf("channel4 max amplitude = "PRINTF_S_FORMAT"\n", channel4max);
    printf("sample average = %lf\n", channel4avg);


    printf("/nPrinting out values/n");

    for (int j=0; j<8; j++)
    {
        printf("Value: %lf\n", data.recordedSamples[j]);
    }


    /* Write recorded data to a file. */
#if WRITE_TO_FILE
    {
        FILE  *fid;
        fid = fopen("recorded.raw", "wb");
        if( fid == NULL )
        {
            printf("Could not open file.");
        }
        else
        {
            fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
            fclose( fid );
            printf("Wrote data to 'recorded.raw'\n");
        }
    }
#endif

    /* Playback recorded data.  -------------------------------------------- */
    data.frameIndex = 0;

    outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
    if (outputParameters.device == paNoDevice) {
        fprintf(stderr,"Error: No default output device.\n");
        goto done;
    }
    outputParameters.channelCount = 2;                     /* stereo output */
    outputParameters.sampleFormat =  PA_SAMPLE_TYPE;
    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
    outputParameters.hostApiSpecificStreamInfo = NULL;

    printf("\n=== Now playing back. ===\n"); fflush(stdout);
    err = Pa_OpenStream(
                        &stream,
                        NULL, /* no input */
                        &outputParameters,
                        SAMPLE_RATE,
                        FRAMES_PER_BUFFER,
                        paClipOff,      /* we won't output out of range samples so don't bother clipping them */
                        playCallback,
                        &data );
    if( err != paNoError ) goto done;

    if( stream )
    {
        err = Pa_StartStream( stream );
        if( err != paNoError ) goto done;

        printf("Waiting for playback to finish.\n"); fflush(stdout);

        while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
        if( err < 0 ) goto done;

        err = Pa_CloseStream( stream );
        if( err != paNoError ) goto done;

        printf("Done.\n"); fflush(stdout);
    }

done:
    Pa_Terminate();
    if( data.recordedSamples )       /* Sure it is NULL or valid. */
        free( data.recordedSamples );
    if( err != paNoError )
    {
        fprintf( stderr, "An error occured while using the portaudio stream\n" );
        fprintf( stderr, "Error number: %d\n", err );
        fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
        err = 1;          /* Always return 0 or 1, but no other return codes. */
    }
    return err;
}

如果我运行我的代码并吹入一个麦克风,我就会得到这个。当我使用我的代码播放声音时,它工作正常,声音是正确的,但查看输出的值:

channel1 max amplitude = 1.00000000
sample average = 1.000000
channel2 max amplitude = 0.02542114
sample average = 0.025421
channel3 max amplitude = 1.00000000
sample average = 1.000000
channel4 max amplitude = 0.02627563
sample average = 0.026276

这显然不正确。因为它显示两个通道几乎相同。根据我的理解,因为它捕获线性PCM,它应该是映射通道,如

样品 [ {}通道1 {}通道2 {}通道3 {}通道4 ]

现在的问题是,当我在audacity(使用核心音频驱动程序)上吹入一个麦克风时,我得到了这个。显然,一个麦克风的峰值为1,其他麦克风的峰值接近静音。

Audacity Levels

所以我不明白我做错了什么,有什么指示?

1 个答案:

答案 0 :(得分:0)

看起来你只录制了2个频道

inputParameters.channelCount = 2;                    /* stereo input */

这可以解释为什么ch 1和3以及ch 2和4测量相同的水平,因为你只是从同一个频道跳过其他每个样本。