Запись звука с помощью PortAudio: Pa_GetStreamReadAvailable не работает?

I make realtime data processing application (spectrum analyzer using fftw3 lib) using C and Linux. Мои входящие данные в настоящее время берутся из h/w audio line input. Я использую portaudio libs, чтобы поговорить с h / w. (В настоящее время я не использую обратные вызовы PortAudio). Я выбираю Portaudio, потому что для него существует много примеров записи аудио. RtAudio, в то время как может предложить более низкие задержки, к сожалению, написано на CPP, а не C (так что у меня есть несколько проблем с переносимостью). (Должен ли я попробовать другую обертку? Есть ли прямой способ поймать звуковой буфер, с примерами?).

У меня есть прекрасная рабочая настройка, если расчеты 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!nn");

    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 %dn", 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 streamn" );
    fprintf( stderr, "Error number: %dn", err );
    fprintf( stderr, "Error message: %sn", 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, но, чтобы быть уверенным, я предпочитаю сначала спросить, прежде чем файл bugreport.
Спасибо.

P.S. регрессия PA libs к предыдущей версии (для тестов) невозможна, я не могу скомпилировать этот пример в современной Ubuntu с ним.

1 ответ

  1. Мне не ясно, что здесь есть ошибка (кроме того, что вы делаете FFT, который занимает слишком много времени на вашей коробке).

    Обычно аудиосистема имеет небольшое количество буферов (похоже, что 3 в вашем случае 3072-это 3 * 1024, которые вы устанавливаете в качестве FRAMES_PER_BUFFER, 2-Еще одно общее значение), и если вы не можете поддерживать его, он просто отбрасывает данные из наименее недавно заполненного буфера, нет никогда растущего буфера звука.

    Это ваша ответственность, чтобы скопировать данные из этих буферов во времени и буферизации в оперативной памяти или на диске, что вам нужно сделать для вашего приложения.

    Я несколько удивлен, что у современной машины есть какие-то проблемы с 1024 point FFT при скорости звука.

    С Уважением, Дэн.