Използвам микрофонен масив (playstation eye) с 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, трябва да картографира канали като напр
ПРИМЕР [ {Channel1} {Channel2} {Channel3} {Channel4} ]
Сега проблемът е, че когато духна в един микрофон на audacity (който използва основни аудио драйвери), получавам това. Очевидно един микрофон има пик от 1, а другите са почти безшумни.
Така че не разбирам какво правя погрешно, някакви насоки?