2016-05-26 12 views
0

Ich mache Echtzeit-Datenverarbeitung Anwendung (Spektrumanalysator mit FFTW3 Lib) mit C und Linux. Meine eingehenden Daten werden derzeit von der Audioeingabe der h/w Audiozeile übernommen. Ich benutze PortAudio-Bibliotheken, um mit h/w zu sprechen. (I nicht verwenden PortAudio Callbacks derzeit). Ich wähle Portaudio, da viele Audio-Aufnahme-Beispiele dafür existieren. RtAudio, während möglicherweise niedrigere Latenzen bieten, leider auf CPP geschrieben, nicht C (so habe ich mehrere Portabilitätsprobleme). (Sollte ich einen anderen Wrapper ausprobieren? Gibt es einen direkten Weg, um Tonpuffer zu fangen, mit Beispielen?).Audioaufnahme mit PortAudio: Pa_GetStreamReadAvailable funktioniert nicht?

Ich habe fein funktionierende Setup, es sei denn, DFT-Berechnungen brauchen mehr Zeit als genug, um Audiopuffer mit neuen Daten zu füllen. So bleiben und sammeln sich Daten irgendwo im System, und es tritt eine Verzögerung zwischen der Audioeingabe und dem Bild auf und nimmt zu. In der Spektrumanalyse ist es nicht möglich, Daten zu "werfen". Also kann ich nur den Benutzer über niedrige CPU-Leistung warnen. Aber hier habe ich ein Problem.

Es gibt Pa_GetStreamReadAvailable Funktion vorhanden, um anzuzeigen, wie viele nicht freigegebene Daten verfügbar sind. Aber es funktioniert überhaupt nicht für mich. Ich bereite einfaches Beispiel, meist basierend auf Datei 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; 
} 

Ich erwarte, dass Zahlen in Ausdruck zu erhöhen, aber meine Ergebnisse sind eindeutig falsch:

598 44100 
3071 44100 
3071 44100 
3071 44100 
3071 44100 
3071 44100 
3071 44100 

Mit ‚Pa_OpenDefaultStream‘ anstelle von ‚Pa_OpenStream‘ gibt andere falsche Zahlen (8191). Wo liege ich falsch?

Oder es ist ein Fehler in der PA, aber um sicher zu sein, ich bevorzuge, zuerst zu fragen, bevor ein Bugreport file. Danke.

P.S. Eine Regression von PA-Bibliotheken zur Vorgängerversion (für Tests) ist nicht möglich, ich kann dieses Beispiel im modernen Ubuntu damit nicht kompilieren.

+0

Versuchen Sie, inputParameters.suggestedLatency zu erhöhen. Sie haben eine niedrige Latenz angegeben, die wahrscheinlich kürzer als 3071 Samples ist. Mit anderen Worten, Sie haben PA nicht aufgefordert, einen ausreichend großen Zwischenpuffer zu erstellen. Sie werden * immer * die Daten sammeln müssen, bevor der Puffer von PA überläuft. Es gibt keine Garantie, dass PA auch einen 1-Sekunden-Puffer unterstützt. –

Antwort

0

Es ist mir nicht klar, dass es hier einen Fehler gibt (Abgesehen davon, dass Sie eine FFT machen, die zu lange auf Ihrer Box dauert).

Normalerweise hat das Audio-Subsystem eine kleine Anzahl von Puffern (Sieht aus wie 3 in Ihrem Fall 3072 ist 3 * 1024, die Sie als FRAMES_PER_BUFFER setzen, 2 ist ein anderer allgemeiner Wert) und wenn Sie nicht mithalten können, verwirft er einfach Daten von der zuletzt gefüllte Puffer, es gibt keinen wachsenden Audio-Puffer mehr.

Es liegt in Ihrer Verantwortung, die Daten rechtzeitig aus diesen Puffern zu kopieren und diese in RAM oder auf Diskette zwischenzuspeichern, was Sie für Ihre Anwendung tun müssen.

Ich bin etwas überrascht, dass eine moderne Maschine Probleme mit einer 1024 Punkt FFT mit Audio-Rate hat.

Grüße, Dan.