annotate src/portaudio_20161030/examples/paex_record.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 284acf908dcd
children
rev   line source
Chris@4 1 /** @file paex_record.c
Chris@4 2 @ingroup examples_src
Chris@4 3 @brief Record input into an array; Save array to a file; Playback recorded data.
Chris@4 4 @author Phil Burk http://www.softsynth.com
Chris@4 5 */
Chris@4 6 /*
Chris@55 7 * $Id$
Chris@4 8 *
Chris@4 9 * This program uses the PortAudio Portable Audio Library.
Chris@4 10 * For more information see: http://www.portaudio.com
Chris@4 11 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
Chris@4 12 *
Chris@4 13 * Permission is hereby granted, free of charge, to any person obtaining
Chris@4 14 * a copy of this software and associated documentation files
Chris@4 15 * (the "Software"), to deal in the Software without restriction,
Chris@4 16 * including without limitation the rights to use, copy, modify, merge,
Chris@4 17 * publish, distribute, sublicense, and/or sell copies of the Software,
Chris@4 18 * and to permit persons to whom the Software is furnished to do so,
Chris@4 19 * subject to the following conditions:
Chris@4 20 *
Chris@4 21 * The above copyright notice and this permission notice shall be
Chris@4 22 * included in all copies or substantial portions of the Software.
Chris@4 23 *
Chris@4 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@4 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@4 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Chris@4 27 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
Chris@4 28 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@4 29 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@4 30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@4 31 */
Chris@4 32
Chris@4 33 /*
Chris@4 34 * The text above constitutes the entire PortAudio license; however,
Chris@4 35 * the PortAudio community also makes the following non-binding requests:
Chris@4 36 *
Chris@4 37 * Any person wishing to distribute modifications to the Software is
Chris@4 38 * requested to send the modifications to the original developer so that
Chris@4 39 * they can be incorporated into the canonical version. It is also
Chris@4 40 * requested that these non-binding requests be included along with the
Chris@4 41 * license above.
Chris@4 42 */
Chris@4 43
Chris@4 44 #include <stdio.h>
Chris@4 45 #include <stdlib.h>
Chris@4 46 #include "portaudio.h"
Chris@4 47
Chris@4 48 /* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
Chris@4 49 #define SAMPLE_RATE (44100)
Chris@4 50 #define FRAMES_PER_BUFFER (512)
Chris@4 51 #define NUM_SECONDS (5)
Chris@4 52 #define NUM_CHANNELS (2)
Chris@4 53 /* #define DITHER_FLAG (paDitherOff) */
Chris@4 54 #define DITHER_FLAG (0) /**/
Chris@4 55 /** Set to 1 if you want to capture the recording to a file. */
Chris@4 56 #define WRITE_TO_FILE (0)
Chris@4 57
Chris@4 58 /* Select sample format. */
Chris@4 59 #if 1
Chris@4 60 #define PA_SAMPLE_TYPE paFloat32
Chris@4 61 typedef float SAMPLE;
Chris@4 62 #define SAMPLE_SILENCE (0.0f)
Chris@4 63 #define PRINTF_S_FORMAT "%.8f"
Chris@4 64 #elif 1
Chris@4 65 #define PA_SAMPLE_TYPE paInt16
Chris@4 66 typedef short SAMPLE;
Chris@4 67 #define SAMPLE_SILENCE (0)
Chris@4 68 #define PRINTF_S_FORMAT "%d"
Chris@4 69 #elif 0
Chris@4 70 #define PA_SAMPLE_TYPE paInt8
Chris@4 71 typedef char SAMPLE;
Chris@4 72 #define SAMPLE_SILENCE (0)
Chris@4 73 #define PRINTF_S_FORMAT "%d"
Chris@4 74 #else
Chris@4 75 #define PA_SAMPLE_TYPE paUInt8
Chris@4 76 typedef unsigned char SAMPLE;
Chris@4 77 #define SAMPLE_SILENCE (128)
Chris@4 78 #define PRINTF_S_FORMAT "%d"
Chris@4 79 #endif
Chris@4 80
Chris@4 81 typedef struct
Chris@4 82 {
Chris@4 83 int frameIndex; /* Index into sample array. */
Chris@4 84 int maxFrameIndex;
Chris@4 85 SAMPLE *recordedSamples;
Chris@4 86 }
Chris@4 87 paTestData;
Chris@4 88
Chris@4 89 /* This routine will be called by the PortAudio engine when audio is needed.
Chris@4 90 ** It may be called at interrupt level on some machines so don't do anything
Chris@4 91 ** that could mess up the system like calling malloc() or free().
Chris@4 92 */
Chris@4 93 static int recordCallback( const void *inputBuffer, void *outputBuffer,
Chris@4 94 unsigned long framesPerBuffer,
Chris@4 95 const PaStreamCallbackTimeInfo* timeInfo,
Chris@4 96 PaStreamCallbackFlags statusFlags,
Chris@4 97 void *userData )
Chris@4 98 {
Chris@4 99 paTestData *data = (paTestData*)userData;
Chris@4 100 const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
Chris@4 101 SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
Chris@4 102 long framesToCalc;
Chris@4 103 long i;
Chris@4 104 int finished;
Chris@4 105 unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
Chris@4 106
Chris@4 107 (void) outputBuffer; /* Prevent unused variable warnings. */
Chris@4 108 (void) timeInfo;
Chris@4 109 (void) statusFlags;
Chris@4 110 (void) userData;
Chris@4 111
Chris@4 112 if( framesLeft < framesPerBuffer )
Chris@4 113 {
Chris@4 114 framesToCalc = framesLeft;
Chris@4 115 finished = paComplete;
Chris@4 116 }
Chris@4 117 else
Chris@4 118 {
Chris@4 119 framesToCalc = framesPerBuffer;
Chris@4 120 finished = paContinue;
Chris@4 121 }
Chris@4 122
Chris@4 123 if( inputBuffer == NULL )
Chris@4 124 {
Chris@4 125 for( i=0; i<framesToCalc; i++ )
Chris@4 126 {
Chris@4 127 *wptr++ = SAMPLE_SILENCE; /* left */
Chris@4 128 if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE; /* right */
Chris@4 129 }
Chris@4 130 }
Chris@4 131 else
Chris@4 132 {
Chris@4 133 for( i=0; i<framesToCalc; i++ )
Chris@4 134 {
Chris@4 135 *wptr++ = *rptr++; /* left */
Chris@4 136 if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
Chris@4 137 }
Chris@4 138 }
Chris@4 139 data->frameIndex += framesToCalc;
Chris@4 140 return finished;
Chris@4 141 }
Chris@4 142
Chris@4 143 /* This routine will be called by the PortAudio engine when audio is needed.
Chris@4 144 ** It may be called at interrupt level on some machines so don't do anything
Chris@4 145 ** that could mess up the system like calling malloc() or free().
Chris@4 146 */
Chris@4 147 static int playCallback( const void *inputBuffer, void *outputBuffer,
Chris@4 148 unsigned long framesPerBuffer,
Chris@4 149 const PaStreamCallbackTimeInfo* timeInfo,
Chris@4 150 PaStreamCallbackFlags statusFlags,
Chris@4 151 void *userData )
Chris@4 152 {
Chris@4 153 paTestData *data = (paTestData*)userData;
Chris@4 154 SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
Chris@4 155 SAMPLE *wptr = (SAMPLE*)outputBuffer;
Chris@4 156 unsigned int i;
Chris@4 157 int finished;
Chris@4 158 unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
Chris@4 159
Chris@4 160 (void) inputBuffer; /* Prevent unused variable warnings. */
Chris@4 161 (void) timeInfo;
Chris@4 162 (void) statusFlags;
Chris@4 163 (void) userData;
Chris@4 164
Chris@4 165 if( framesLeft < framesPerBuffer )
Chris@4 166 {
Chris@4 167 /* final buffer... */
Chris@4 168 for( i=0; i<framesLeft; i++ )
Chris@4 169 {
Chris@4 170 *wptr++ = *rptr++; /* left */
Chris@4 171 if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
Chris@4 172 }
Chris@4 173 for( ; i<framesPerBuffer; i++ )
Chris@4 174 {
Chris@4 175 *wptr++ = 0; /* left */
Chris@4 176 if( NUM_CHANNELS == 2 ) *wptr++ = 0; /* right */
Chris@4 177 }
Chris@4 178 data->frameIndex += framesLeft;
Chris@4 179 finished = paComplete;
Chris@4 180 }
Chris@4 181 else
Chris@4 182 {
Chris@4 183 for( i=0; i<framesPerBuffer; i++ )
Chris@4 184 {
Chris@4 185 *wptr++ = *rptr++; /* left */
Chris@4 186 if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
Chris@4 187 }
Chris@4 188 data->frameIndex += framesPerBuffer;
Chris@4 189 finished = paContinue;
Chris@4 190 }
Chris@4 191 return finished;
Chris@4 192 }
Chris@4 193
Chris@4 194 /*******************************************************************/
Chris@4 195 int main(void);
Chris@4 196 int main(void)
Chris@4 197 {
Chris@4 198 PaStreamParameters inputParameters,
Chris@4 199 outputParameters;
Chris@4 200 PaStream* stream;
Chris@4 201 PaError err = paNoError;
Chris@4 202 paTestData data;
Chris@4 203 int i;
Chris@4 204 int totalFrames;
Chris@4 205 int numSamples;
Chris@4 206 int numBytes;
Chris@4 207 SAMPLE max, val;
Chris@4 208 double average;
Chris@4 209
Chris@4 210 printf("patest_record.c\n"); fflush(stdout);
Chris@4 211
Chris@4 212 data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
Chris@4 213 data.frameIndex = 0;
Chris@4 214 numSamples = totalFrames * NUM_CHANNELS;
Chris@4 215 numBytes = numSamples * sizeof(SAMPLE);
Chris@4 216 data.recordedSamples = (SAMPLE *) malloc( numBytes ); /* From now on, recordedSamples is initialised. */
Chris@4 217 if( data.recordedSamples == NULL )
Chris@4 218 {
Chris@4 219 printf("Could not allocate record array.\n");
Chris@4 220 goto done;
Chris@4 221 }
Chris@4 222 for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
Chris@4 223
Chris@4 224 err = Pa_Initialize();
Chris@4 225 if( err != paNoError ) goto done;
Chris@4 226
Chris@4 227 inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
Chris@4 228 if (inputParameters.device == paNoDevice) {
Chris@4 229 fprintf(stderr,"Error: No default input device.\n");
Chris@4 230 goto done;
Chris@4 231 }
Chris@4 232 inputParameters.channelCount = 2; /* stereo input */
Chris@4 233 inputParameters.sampleFormat = PA_SAMPLE_TYPE;
Chris@4 234 inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
Chris@4 235 inputParameters.hostApiSpecificStreamInfo = NULL;
Chris@4 236
Chris@4 237 /* Record some audio. -------------------------------------------- */
Chris@4 238 err = Pa_OpenStream(
Chris@4 239 &stream,
Chris@4 240 &inputParameters,
Chris@4 241 NULL, /* &outputParameters, */
Chris@4 242 SAMPLE_RATE,
Chris@4 243 FRAMES_PER_BUFFER,
Chris@4 244 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 245 recordCallback,
Chris@4 246 &data );
Chris@4 247 if( err != paNoError ) goto done;
Chris@4 248
Chris@4 249 err = Pa_StartStream( stream );
Chris@4 250 if( err != paNoError ) goto done;
Chris@4 251 printf("\n=== Now recording!! Please speak into the microphone. ===\n"); fflush(stdout);
Chris@4 252
Chris@4 253 while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
Chris@4 254 {
Chris@4 255 Pa_Sleep(1000);
Chris@4 256 printf("index = %d\n", data.frameIndex ); fflush(stdout);
Chris@4 257 }
Chris@4 258 if( err < 0 ) goto done;
Chris@4 259
Chris@4 260 err = Pa_CloseStream( stream );
Chris@4 261 if( err != paNoError ) goto done;
Chris@4 262
Chris@4 263 /* Measure maximum peak amplitude. */
Chris@4 264 max = 0;
Chris@4 265 average = 0.0;
Chris@4 266 for( i=0; i<numSamples; i++ )
Chris@4 267 {
Chris@4 268 val = data.recordedSamples[i];
Chris@4 269 if( val < 0 ) val = -val; /* ABS */
Chris@4 270 if( val > max )
Chris@4 271 {
Chris@4 272 max = val;
Chris@4 273 }
Chris@4 274 average += val;
Chris@4 275 }
Chris@4 276
Chris@4 277 average = average / (double)numSamples;
Chris@4 278
Chris@4 279 printf("sample max amplitude = "PRINTF_S_FORMAT"\n", max );
Chris@4 280 printf("sample average = %lf\n", average );
Chris@4 281
Chris@4 282 /* Write recorded data to a file. */
Chris@4 283 #if WRITE_TO_FILE
Chris@4 284 {
Chris@4 285 FILE *fid;
Chris@4 286 fid = fopen("recorded.raw", "wb");
Chris@4 287 if( fid == NULL )
Chris@4 288 {
Chris@4 289 printf("Could not open file.");
Chris@4 290 }
Chris@4 291 else
Chris@4 292 {
Chris@4 293 fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
Chris@4 294 fclose( fid );
Chris@4 295 printf("Wrote data to 'recorded.raw'\n");
Chris@4 296 }
Chris@4 297 }
Chris@4 298 #endif
Chris@4 299
Chris@4 300 /* Playback recorded data. -------------------------------------------- */
Chris@4 301 data.frameIndex = 0;
Chris@4 302
Chris@4 303 outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
Chris@4 304 if (outputParameters.device == paNoDevice) {
Chris@4 305 fprintf(stderr,"Error: No default output device.\n");
Chris@4 306 goto done;
Chris@4 307 }
Chris@4 308 outputParameters.channelCount = 2; /* stereo output */
Chris@4 309 outputParameters.sampleFormat = PA_SAMPLE_TYPE;
Chris@4 310 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
Chris@4 311 outputParameters.hostApiSpecificStreamInfo = NULL;
Chris@4 312
Chris@4 313 printf("\n=== Now playing back. ===\n"); fflush(stdout);
Chris@4 314 err = Pa_OpenStream(
Chris@4 315 &stream,
Chris@4 316 NULL, /* no input */
Chris@4 317 &outputParameters,
Chris@4 318 SAMPLE_RATE,
Chris@4 319 FRAMES_PER_BUFFER,
Chris@4 320 paClipOff, /* we won't output out of range samples so don't bother clipping them */
Chris@4 321 playCallback,
Chris@4 322 &data );
Chris@4 323 if( err != paNoError ) goto done;
Chris@4 324
Chris@4 325 if( stream )
Chris@4 326 {
Chris@4 327 err = Pa_StartStream( stream );
Chris@4 328 if( err != paNoError ) goto done;
Chris@4 329
Chris@4 330 printf("Waiting for playback to finish.\n"); fflush(stdout);
Chris@4 331
Chris@4 332 while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(100);
Chris@4 333 if( err < 0 ) goto done;
Chris@4 334
Chris@4 335 err = Pa_CloseStream( stream );
Chris@4 336 if( err != paNoError ) goto done;
Chris@4 337
Chris@4 338 printf("Done.\n"); fflush(stdout);
Chris@4 339 }
Chris@4 340
Chris@4 341 done:
Chris@4 342 Pa_Terminate();
Chris@4 343 if( data.recordedSamples ) /* Sure it is NULL or valid. */
Chris@4 344 free( data.recordedSamples );
Chris@4 345 if( err != paNoError )
Chris@4 346 {
Chris@4 347 fprintf( stderr, "An error occured while using the portaudio stream\n" );
Chris@4 348 fprintf( stderr, "Error number: %d\n", err );
Chris@4 349 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
Chris@4 350 err = 1; /* Always return 0 or 1, but no other return codes. */
Chris@4 351 }
Chris@4 352 return err;
Chris@4 353 }
Chris@4 354