paex_record.c

Go to the documentation of this file.
00001 
00006 /*
00007  * $Id: paex_record.c 1752 2011-09-08 03:21:55Z philburk $
00008  *
00009  * This program uses the PortAudio Portable Audio Library.
00010  * For more information see: http://www.portaudio.com
00011  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
00012  *
00013  * Permission is hereby granted, free of charge, to any person obtaining
00014  * a copy of this software and associated documentation files
00015  * (the "Software"), to deal in the Software without restriction,
00016  * including without limitation the rights to use, copy, modify, merge,
00017  * publish, distribute, sublicense, and/or sell copies of the Software,
00018  * and to permit persons to whom the Software is furnished to do so,
00019  * subject to the following conditions:
00020  *
00021  * The above copyright notice and this permission notice shall be
00022  * included in all copies or substantial portions of the Software.
00023  *
00024  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00026  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00027  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
00028  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00029  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00030  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00031  */
00032 
00033 /*
00034  * The text above constitutes the entire PortAudio license; however, 
00035  * the PortAudio community also makes the following non-binding requests:
00036  *
00037  * Any person wishing to distribute modifications to the Software is
00038  * requested to send the modifications to the original developer so that
00039  * they can be incorporated into the canonical version. It is also 
00040  * requested that these non-binding requests be included along with the 
00041  * license above.
00042  */
00043 
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include "portaudio.h"
00047 
00048 /* #define SAMPLE_RATE  (17932) // Test failure to open with this value. */
00049 #define SAMPLE_RATE  (44100)
00050 #define FRAMES_PER_BUFFER (512)
00051 #define NUM_SECONDS     (5)
00052 #define NUM_CHANNELS    (2)
00053 /* #define DITHER_FLAG     (paDitherOff) */
00054 #define DITHER_FLAG     (0) 
00055 
00056 #define WRITE_TO_FILE   (0)
00057 
00058 /* Select sample format. */
00059 #if 1
00060 #define PA_SAMPLE_TYPE  paFloat32
00061 typedef float SAMPLE;
00062 #define SAMPLE_SILENCE  (0.0f)
00063 #define PRINTF_S_FORMAT "%.8f"
00064 #elif 1
00065 #define PA_SAMPLE_TYPE  paInt16
00066 typedef short SAMPLE;
00067 #define SAMPLE_SILENCE  (0)
00068 #define PRINTF_S_FORMAT "%d"
00069 #elif 0
00070 #define PA_SAMPLE_TYPE  paInt8
00071 typedef char SAMPLE;
00072 #define SAMPLE_SILENCE  (0)
00073 #define PRINTF_S_FORMAT "%d"
00074 #else
00075 #define PA_SAMPLE_TYPE  paUInt8
00076 typedef unsigned char SAMPLE;
00077 #define SAMPLE_SILENCE  (128)
00078 #define PRINTF_S_FORMAT "%d"
00079 #endif
00080 
00081 typedef struct
00082 {
00083     int          frameIndex;  /* Index into sample array. */
00084     int          maxFrameIndex;
00085     SAMPLE      *recordedSamples;
00086 }
00087 paTestData;
00088 
00089 /* This routine will be called by the PortAudio engine when audio is needed.
00090 ** It may be called at interrupt level on some machines so don't do anything
00091 ** that could mess up the system like calling malloc() or free().
00092 */
00093 static int recordCallback( const void *inputBuffer, void *outputBuffer,
00094                            unsigned long framesPerBuffer,
00095                            const PaStreamCallbackTimeInfo* timeInfo,
00096                            PaStreamCallbackFlags statusFlags,
00097                            void *userData )
00098 {
00099     paTestData *data = (paTestData*)userData;
00100     const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
00101     SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
00102     long framesToCalc;
00103     long i;
00104     int finished;
00105     unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
00106 
00107     (void) outputBuffer; /* Prevent unused variable warnings. */
00108     (void) timeInfo;
00109     (void) statusFlags;
00110     (void) userData;
00111 
00112     if( framesLeft < framesPerBuffer )
00113     {
00114         framesToCalc = framesLeft;
00115         finished = paComplete;
00116     }
00117     else
00118     {
00119         framesToCalc = framesPerBuffer;
00120         finished = paContinue;
00121     }
00122 
00123     if( inputBuffer == NULL )
00124     {
00125         for( i=0; i<framesToCalc; i++ )
00126         {
00127             *wptr++ = SAMPLE_SILENCE;  /* left */
00128             if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE;  /* right */
00129         }
00130     }
00131     else
00132     {
00133         for( i=0; i<framesToCalc; i++ )
00134         {
00135             *wptr++ = *rptr++;  /* left */
00136             if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++;  /* right */
00137         }
00138     }
00139     data->frameIndex += framesToCalc;
00140     return finished;
00141 }
00142 
00143 /* This routine will be called by the PortAudio engine when audio is needed.
00144 ** It may be called at interrupt level on some machines so don't do anything
00145 ** that could mess up the system like calling malloc() or free().
00146 */
00147 static int playCallback( const void *inputBuffer, void *outputBuffer,
00148                          unsigned long framesPerBuffer,
00149                          const PaStreamCallbackTimeInfo* timeInfo,
00150                          PaStreamCallbackFlags statusFlags,
00151                          void *userData )
00152 {
00153     paTestData *data = (paTestData*)userData;
00154     SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
00155     SAMPLE *wptr = (SAMPLE*)outputBuffer;
00156     unsigned int i;
00157     int finished;
00158     unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
00159 
00160     (void) inputBuffer; /* Prevent unused variable warnings. */
00161     (void) timeInfo;
00162     (void) statusFlags;
00163     (void) userData;
00164 
00165     if( framesLeft < framesPerBuffer )
00166     {
00167         /* final buffer... */
00168         for( i=0; i<framesLeft; i++ )
00169         {
00170             *wptr++ = *rptr++;  /* left */
00171             if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++;  /* right */
00172         }
00173         for( ; i<framesPerBuffer; i++ )
00174         {
00175             *wptr++ = 0;  /* left */
00176             if( NUM_CHANNELS == 2 ) *wptr++ = 0;  /* right */
00177         }
00178         data->frameIndex += framesLeft;
00179         finished = paComplete;
00180     }
00181     else
00182     {
00183         for( i=0; i<framesPerBuffer; i++ )
00184         {
00185             *wptr++ = *rptr++;  /* left */
00186             if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++;  /* right */
00187         }
00188         data->frameIndex += framesPerBuffer;
00189         finished = paContinue;
00190     }
00191     return finished;
00192 }
00193 
00194 /*******************************************************************/
00195 int main(void);
00196 int main(void)
00197 {
00198     PaStreamParameters  inputParameters,
00199                         outputParameters;
00200     PaStream*           stream;
00201     PaError             err = paNoError;
00202     paTestData          data;
00203     int                 i;
00204     int                 totalFrames;
00205     int                 numSamples;
00206     int                 numBytes;
00207     SAMPLE              max, val;
00208     double              average;
00209 
00210     printf("patest_record.c\n"); fflush(stdout);
00211 
00212     data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
00213     data.frameIndex = 0;
00214     numSamples = totalFrames * NUM_CHANNELS;
00215     numBytes = numSamples * sizeof(SAMPLE);
00216     data.recordedSamples = (SAMPLE *) malloc( numBytes ); /* From now on, recordedSamples is initialised. */
00217     if( data.recordedSamples == NULL )
00218     {
00219         printf("Could not allocate record array.\n");
00220         goto done;
00221     }
00222     for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
00223 
00224     err = Pa_Initialize();
00225     if( err != paNoError ) goto done;
00226 
00227     inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
00228     if (inputParameters.device == paNoDevice) {
00229         fprintf(stderr,"Error: No default input device.\n");
00230         goto done;
00231     }
00232     inputParameters.channelCount = 2;                    /* stereo input */
00233     inputParameters.sampleFormat = PA_SAMPLE_TYPE;
00234     inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
00235     inputParameters.hostApiSpecificStreamInfo = NULL;
00236 
00237     /* Record some audio. -------------------------------------------- */
00238     err = Pa_OpenStream(
00239               &stream,
00240               &inputParameters,
00241               NULL,                  /* &outputParameters, */
00242               SAMPLE_RATE,
00243               FRAMES_PER_BUFFER,
00244               paClipOff,      /* we won't output out of range samples so don't bother clipping them */
00245               recordCallback,
00246               &data );
00247     if( err != paNoError ) goto done;
00248 
00249     err = Pa_StartStream( stream );
00250     if( err != paNoError ) goto done;
00251     printf("\n=== Now recording!! Please speak into the microphone. ===\n"); fflush(stdout);
00252 
00253     while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
00254     {
00255         Pa_Sleep(1000);
00256         printf("index = %d\n", data.frameIndex ); fflush(stdout);
00257     }
00258     if( err < 0 ) goto done;
00259 
00260     err = Pa_CloseStream( stream );
00261     if( err != paNoError ) goto done;
00262 
00263     /* Measure maximum peak amplitude. */
00264     max = 0;
00265     average = 0.0;
00266     for( i=0; i<numSamples; i++ )
00267     {
00268         val = data.recordedSamples[i];
00269         if( val < 0 ) val = -val; /* ABS */
00270         if( val > max )
00271         {
00272             max = val;
00273         }
00274         average += val;
00275     }
00276 
00277     average = average / (double)numSamples;
00278 
00279     printf("sample max amplitude = "PRINTF_S_FORMAT"\n", max );
00280     printf("sample average = %lf\n", average );
00281 
00282     /* Write recorded data to a file. */
00283 #if WRITE_TO_FILE
00284     {
00285         FILE  *fid;
00286         fid = fopen("recorded.raw", "wb");
00287         if( fid == NULL )
00288         {
00289             printf("Could not open file.");
00290         }
00291         else
00292         {
00293             fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
00294             fclose( fid );
00295             printf("Wrote data to 'recorded.raw'\n");
00296         }
00297     }
00298 #endif
00299 
00300     /* Playback recorded data.  -------------------------------------------- */
00301     data.frameIndex = 0;
00302 
00303     outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
00304     if (outputParameters.device == paNoDevice) {
00305         fprintf(stderr,"Error: No default output device.\n");
00306         goto done;
00307     }
00308     outputParameters.channelCount = 2;                     /* stereo output */
00309     outputParameters.sampleFormat =  PA_SAMPLE_TYPE;
00310     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
00311     outputParameters.hostApiSpecificStreamInfo = NULL;
00312 
00313     printf("\n=== Now playing back. ===\n"); fflush(stdout);
00314     err = Pa_OpenStream(
00315               &stream,
00316               NULL, /* no input */
00317               &outputParameters,
00318               SAMPLE_RATE,
00319               FRAMES_PER_BUFFER,
00320               paClipOff,      /* we won't output out of range samples so don't bother clipping them */
00321               playCallback,
00322               &data );
00323     if( err != paNoError ) goto done;
00324 
00325     if( stream )
00326     {
00327         err = Pa_StartStream( stream );
00328         if( err != paNoError ) goto done;
00329         
00330         printf("Waiting for playback to finish.\n"); fflush(stdout);
00331 
00332         while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
00333         if( err < 0 ) goto done;
00334         
00335         err = Pa_CloseStream( stream );
00336         if( err != paNoError ) goto done;
00337         
00338         printf("Done.\n"); fflush(stdout);
00339     }
00340 
00341 done:
00342     Pa_Terminate();
00343     if( data.recordedSamples )       /* Sure it is NULL or valid. */
00344         free( data.recordedSamples );
00345     if( err != paNoError )
00346     {
00347         fprintf( stderr, "An error occured while using the portaudio stream\n" );
00348         fprintf( stderr, "Error number: %d\n", err );
00349         fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
00350         err = 1;          /* Always return 0 or 1, but no other return codes. */
00351     }
00352     return err;
00353 }
00354 

Generated on Sat Aug 6 19:33:25 2016 for PortAudio by  doxygen 1.5.6