added fifo buffering to account for mysterious change in framesPerBuf from portaudio
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 15 Oct 2012 02:51:56 +0000 (02:51 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Mon, 15 Oct 2012 02:51:56 +0000 (02:51 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@749 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/portaudio/Makefile
codec2-dev/portaudio/pa_rec.c
codec2-dev/portaudio/pa_recplay.c

index a1876de9e64a1645b22bd633510d965f601f5925..39255b6ce5c8c2102f2ff04849e74239f27374ff 100644 (file)
@@ -3,7 +3,7 @@
 
 CFLAGS =  -g -Wall -I../src
 LIBS = -lm -lportaudio -pthread
-SRC  = ../src/fdmdv.c ../src/kiss_fft.c
+SRC  = ../src/fdmdv.c ../src/kiss_fft.c ../src/fifo.c
 
 all: pa_rec pa_play pa_recplay pa_impresp
 
index 79366621cdd0c9294dc392390e5ba3246848676e..00023b02bd60ee8759116380408d105856d6bcc2 100644 (file)
@@ -81,7 +81,7 @@ static int recordCallback( const void *inputBuffer, void *outputBuffer,
     paTestData *data = (paTestData*)userData;
     FILE       *fout = data->fout;
     int         framesToCopy;
-    int         i, n8;
+    int         i;
     int         finished;
     short      *rptr = (short*)inputBuffer;
     float       out8k[N8];
@@ -130,8 +130,7 @@ static int recordCallback( const void *inputBuffer, void *outputBuffer,
 
 int main(int argc, char *argv[])
 {
-    PaStreamParameters  inputParameters,
-                        outputParameters;
+    PaStreamParameters  inputParameters;
     PaStream*           stream;
     PaError             err = paNoError;
     paTestData          data;
@@ -158,6 +157,9 @@ int main(int argc, char *argv[])
     err = Pa_Initialize();
     if( err != paNoError ) goto done;
 
+    printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
+            Pa_GetVersion(), Pa_GetVersionText() );
+
     inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
     if (inputParameters.device == paNoDevice) {
         fprintf(stderr,"Error: No default input device.\n");
index f745396f498b5ff60da0f0c46ee74e3b83b77617..6bfcd08b09bcaa09d75c6d17f4cfbe365e3295cc 100644 (file)
@@ -44,6 +44,7 @@
 #include <stdlib.h>
 #include "portaudio.h"
 #include "fdmdv.h"
+#include "fifo.h"
 
 #define SAMPLE_RATE  48000         /* 48 kHz sampling rate rec. as we
                                      can trust accuracy of sound
 #define NUM_CHANNELS 2             /* I think most sound cards prefer
                                      stereo, we will convert to mono
                                      as we sample */
+#define MAX_FPB      2048          /* maximum value of framesPerBuffer */
 
 /* state information passed to call back */
 
 typedef struct {
     float               in48k[FDMDV_OS_TAPS + N48];
     float               in8k[MEM8 + N8];
+    struct FIFO        *infifo;
+    struct FIFO        *outfifo;
 } paTestData;
 
 
@@ -85,43 +89,95 @@ static int callback( const void *inputBuffer, void *outputBuffer,
     float       out8k[N8];
     float       out48k[N48];
     short       out48k_short[N48];
+    short       in48k_short[N48];
+    short       indata[MAX_FPB];
+    short       outdata[MAX_FPB];
 
     (void) timeInfo;
     (void) statusFlags;
 
     assert(inputBuffer != NULL);
+    assert(outputBuffer != NULL);
+
+    /* 
+       framesPerBuffer is portaudio-speak for number of samples we
+       actually get from the record side and need to provide to the
+       play side. On Linux (at least) it was found that
+       framesPerBuffer may not always be what we ask for in the
+       framesPerBuffer field of Pa_OpenStream.  For example a request
+       for 960 sample buffers lead to framesPerBuffer = 1024.
+
+       To perform the 48 to 8 kHz conversion we need an integer
+       multiple of FDMDV_OS samples to support the interpolation and
+       decimation.  As we can't guarantee the size of framesPerBuffer
+       we do a little FIFO buffering.
+    */
 
-    /* just use left channel */
+    //printf("framesPerBuffer: %d N48 %d\n", framesPerBuffer, N48);
 
+    /* assemble a mono buffer (just use left channel) and write to FIFO */
+
+    assert(framesPerBuffer < MAX_FPB);
     for(i=0; i<framesPerBuffer; i++,rptr+=2)
-       data->in48k[i+FDMDV_OS_TAPS] = *rptr; 
+       indata[i] = *rptr;
+    fifo_write(data->infifo, indata, framesPerBuffer);
 
-    /* downsample and update filter memory */
+    /* while we have enough samples available ... */
 
-    fdmdv_48_to_8(out8k, &in48k[FDMDV_OS_TAPS], N8);
-    for(i=0; i<FDMDV_OS_TAPS; i++)
-       in48k[i] = in48k[i+framesPerBuffer];
+    //printf("infifo before: %d\n", fifo_n(data->infifo));
+    while (fifo_read(data->infifo, in48k_short, N48) == 0) {
 
-    /* play side, back up to 8k */
+       /* convert to float */
 
-    for(i=0; i<N8; i++)
-       in8k[MEM8+i] = out8k[i];
+       for(i=0; i<N48; i++)
+           in48k[FDMDV_OS_TAPS + i] = in48k_short[i];
 
-    /* upsample and update filter memory */
+       /* downsample and update filter memory */
 
-    fdmdv_8_to_48(out48k, &in8k[MEM8], N8);
-    for(i=0; i<MEM8; i++)
-       in8k[i] = in8k[i+N8];
+       fdmdv_48_to_8(out8k, &in48k[FDMDV_OS_TAPS], N8);
+       for(i=0; i<FDMDV_OS_TAPS; i++)
+           in48k[i] = in48k[i+N48];
 
-    assert(outputBuffer != NULL);
+       /* play side, back up to 8k */
+
+       for(i=0; i<N8; i++)
+           in8k[MEM8+i] = out8k[i];
+
+       /* upsample and update filter memory */
 
-    /* write signal to both channels */
+       fdmdv_8_to_48(out48k, &in8k[MEM8], N8);
+       for(i=0; i<MEM8; i++)
+           in8k[i] = in8k[i+N8];
 
-    for(i=0; i<N48; i++)
-       out48k_short[i] = (short)out48k[i];
-    for(i=0; i<framesPerBuffer; i++,wptr+=2) {
-       wptr[0] = out48k_short[i]; 
-       wptr[1] = out48k_short[i]; 
+       /* write signal to both channels */
+
+       for(i=0; i<N48; i++)
+           out48k_short[i] = (short)out48k[i];
+
+       fifo_write(data->outfifo, out48k_short, N48);
+    }
+    //printf("infifo after: %d\n", fifo_n(data->infifo));
+    //printf("outfifo     : %d\n", fifo_n(data->outfifo));
+
+
+    /* OK now set up output samples */
+
+    if (fifo_read(data->outfifo, outdata, framesPerBuffer) == 0) {
+
+       /* write signal to both channels */
+
+       for(i=0; i<framesPerBuffer; i++,wptr+=2) {
+           wptr[0] = outdata[i]; 
+           wptr[1] = outdata[i]; 
+       }
+    }
+    else {
+       //printf("no data\n");
+       /* zero output if no data available */
+       for(i=0; i<framesPerBuffer; i++,wptr+=2) {
+           wptr[0] = 0; 
+           wptr[1] = 0; 
+       }
     }
 
     return paContinue;
@@ -135,11 +191,18 @@ int main(int argc, char *argv[])
     paTestData          data;
     int                 i;
 
+    /* init callback data */
+
     for(i=0; i<MEM8; i++)
        data.in8k[i] = 0.0;
     for(i=0; i<FDMDV_OS_TAPS; i++)
        data.in48k[i] = 0.0;
 
+    data.infifo = fifo_create(2*N48);
+    data.outfifo = fifo_create(2*N48);
+
+    /* init port audio */
+
     err = Pa_Initialize();
     if( err != paNoError ) goto done;
 
@@ -170,7 +233,7 @@ int main(int argc, char *argv[])
              &inputParameters,
               &outputParameters,
               SAMPLE_RATE,
-              N48,
+              512,
               paClipOff,      
               callback,
               &data );
@@ -198,6 +261,10 @@ done:
         fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
         err = 1;          /* Always return 0 or 1, but no other return codes. */
     }
+
+    fifo_destroy(data.infifo);
+    fifo_destroy(data.outfifo);
+
     return err;
 }