Я использую массив микрофонов (игровой глаз) с PortAudio. Я пытаюсь обработать массив микрофонов, где я могу узнать уровень каждого микрофона и указать направление звука, используя формирование луча или интерауральные временные задержки. У меня возникли проблемы с определением того, какие уровни звука исходят от каждого канала.
Вот несколько фрагментов кода, первым из которых является 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, а другие почти бесшумны.
Так что я не понимаю, что я делаю неправильно, какие-либо указатели?