Я делаю приложение обработки данных в реальном времени (анализатор спектра с использованием fftw3 lib) с использованием C и Linux. В настоящее время мои входящие данные берутся из h/w аудиоввода. Я использую библиотеки PortAudio для общения с h/w. (I не использовать PortAudio обратные вызовы). Я выбираю Portaudio, из-за того, что для него существует множество примеров аудиозаписи. RtAudio, хотя может предложить более низкие задержки, к сожалению, написанные на CPP, а не C (поэтому у меня много проблем с переносимостью). (Должен ли я попробовать другую оболочку? Есть ли прямой способ захвата звукового буфера с примерами?).Запись звука с использованием PortAudio: Pa_GetStreamReadAvailable не работает?
У меня прекрасная рабочая настройка, если расчеты DFT не занимают больше времени, чем достаточно для заполнения буфера аудиоданных новыми данными. Таким образом, данные остаются и накапливаются где-то в системе, и задержка между аудиовходом и изображением происходит и увеличивается. В спектральном анализе невозможно «выбросить» часть данных. Поэтому я могу только предупредить пользователя о низкой мощности процессора. Но здесь у меня проблема.
Существует Pa_GetStreamReadAvailable Функция существует, чтобы показать, сколько еще не прочитанных данных. Но для меня это вообще не работает. Я готовлю простой пример, в основном на основе файла www.kfr.co.il/files/speed_photo/complete.c
#include <sys/ioctl.h>
#include <linux/parport.h>
#include <linux/ppdev.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <portaudio.h>
/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (1024)
#define NUM_SECONDS (5)
#define NUM_CHANNELS (2)
/* #define DITHER_FLAG (paDitherOff) */
#define DITHER_FLAG (0) /**/
/* Select sample format. */
#if 1
#define PA_SAMPLE_TYPE paFloat32
typedef float SAMPLE;
#define SAMPLE_SILENCE (0.0f)
#define PRINTF_S_FORMAT "%.8f"
#elif 1
#define PA_SAMPLE_TYPE paInt16
typedef short SAMPLE;
#define SAMPLE_SILENCE (0)
#define PRINTF_S_FORMAT "%d"
#elif 0
#define PA_SAMPLE_TYPE paInt8
typedef char SAMPLE;
#define SAMPLE_SILENCE (0)
#define PRINTF_S_FORMAT "%d"
#else
#define PA_SAMPLE_TYPE paUInt8
typedef unsigned char SAMPLE;
#define SAMPLE_SILENCE (128)
#define PRINTF_S_FORMAT "%d"
#endif
int running = 1;
void signalHandler(int sig)
{
running = 0;
}
/*******************************************************************/
int main(void);
int main(void)
{
printf("Initializing PortAudio...\n");
PaStreamParameters inputParameters, outputParameters;
PaStream *stream;
PaError err;
SAMPLE *recordedSamples;
int i;
int maxFrames;
int numSamples;
int numBytes;
SAMPLE max, average, val;
// Set ctrl-c handler
signal(SIGINT, signalHandler);
//totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
maxFrames = SAMPLE_RATE*1;
numSamples = maxFrames * NUM_CHANNELS;
numBytes = numSamples * sizeof(SAMPLE);
recordedSamples = (SAMPLE *) malloc(numBytes);
if(recordedSamples == NULL)
{
printf("Could not allocate record array.\n");
exit(1);
}
for(i=0; i<numSamples; i++) recordedSamples[i] = 0;
err = Pa_Initialize();
if(err != paNoError) goto error;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto error;
}
inputParameters.channelCount = NUM_CHANNELS;
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 */
NULL, /* no callback, use blocking API */
NULL); /* no callback, so no callback userData */
if(err != paNoError) goto error;
printf("Starting!\n\n");
printf("Numbers should increasing:\n");
err = Pa_StartStream(stream);
if(err != paNoError) goto error;
Pa_ReadStream(stream, recordedSamples, maxFrames);
i = 1;
while (i<8)
{
long toRead = Pa_GetStreamReadAvailable(stream);
printf("%ld %d\n", toRead, maxFrames);
if (toRead > maxFrames)
toRead = maxFrames;
err = Pa_ReadStream(stream, recordedSamples, toRead);
if(err != paNoError) goto error;
// Here is place for heavy calculations,
// they can be longer than time needed for filling one buffer.
// (So data, awaiting for processing, should be (and really is)
// accumulated somewhere in system/OS buffer.)
// Emulate big delays:
usleep(i*1000000);
i++;
}
printf("Stopping PortAudio...\n");
err = Pa_CloseStream(stream);
if(err != paNoError) goto error;
free(recordedSamples);
Pa_Terminate();
return 0;
error:
Pa_Terminate();
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));
return -1;
}
Я ожидаю, что все большее число в распечатке, но мои результаты явно не так:
598 44100
3071 44100
3071 44100
3071 44100
3071 44100
3071 44100
3071 44100
Использование «Pa_OpenDefaultStream» вместо «Pa_OpenStream» дает другое неправильные числа (8191). Где я ошибаюсь?
Или это ошибка в PA, но, конечно, я предпочитаю сначала спросить, прежде чем файл будет опубликован. Спасибо.
P.S. Регрессия PA libs к предыдущей версии (для тестов) невозможна, я не могу скомпилировать этот пример в современном Ubuntu с ней.
Попробуйте увеличить входные параметры. вы указали низкую задержку, которая, вероятно, будет меньше 3071 образцов. Другими словами, вы не просили PA создать достаточно большой промежуточный буфер. Вы всегда будете иметь возможность собирать данные до переполнения буфера PA. Нет гарантии, что PA поддерживает 1-секундный буфер. –