00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include "portaudio.h"
00047 #include "pa_ringbuffer.h"
00048 #include "pa_util.h"
00049
00050 #ifdef _WIN32
00051 #include <windows.h>
00052 #include <process.h>
00053 #endif
00054
00055
00056 #define FILE_NAME "audio_data.raw"
00057 #define SAMPLE_RATE (44100)
00058 #define FRAMES_PER_BUFFER (512)
00059 #define NUM_SECONDS (10)
00060 #define NUM_CHANNELS (2)
00061 #define NUM_WRITES_PER_BUFFER (4)
00062
00063 #define DITHER_FLAG (0)
00064
00065
00066
00067 #if 1
00068 #define PA_SAMPLE_TYPE paFloat32
00069 typedef float SAMPLE;
00070 #define SAMPLE_SILENCE (0.0f)
00071 #define PRINTF_S_FORMAT "%.8f"
00072 #elif 1
00073 #define PA_SAMPLE_TYPE paInt16
00074 typedef short SAMPLE;
00075 #define SAMPLE_SILENCE (0)
00076 #define PRINTF_S_FORMAT "%d"
00077 #elif 0
00078 #define PA_SAMPLE_TYPE paInt8
00079 typedef char SAMPLE;
00080 #define SAMPLE_SILENCE (0)
00081 #define PRINTF_S_FORMAT "%d"
00082 #else
00083 #define PA_SAMPLE_TYPE paUInt8
00084 typedef unsigned char SAMPLE;
00085 #define SAMPLE_SILENCE (128)
00086 #define PRINTF_S_FORMAT "%d"
00087 #endif
00088
00089 typedef struct
00090 {
00091 unsigned frameIndex;
00092 int threadSyncFlag;
00093 SAMPLE *ringBufferData;
00094 PaUtilRingBuffer ringBuffer;
00095 FILE *file;
00096 void *threadHandle;
00097 }
00098 paTestData;
00099
00100
00101 static int threadFunctionWriteToRawFile(void* ptr)
00102 {
00103 paTestData* pData = (paTestData*)ptr;
00104
00105
00106 pData->threadSyncFlag = 0;
00107
00108 while (1)
00109 {
00110 ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferReadAvailable(&pData->ringBuffer);
00111 if ( (elementsInBuffer >= pData->ringBuffer.bufferSize / NUM_WRITES_PER_BUFFER) ||
00112 pData->threadSyncFlag )
00113 {
00114 void* ptr[2] = {0};
00115 ring_buffer_size_t sizes[2] = {0};
00116
00117
00118 ring_buffer_size_t elementsRead = PaUtil_GetRingBufferReadRegions(&pData->ringBuffer, elementsInBuffer, ptr + 0, sizes + 0, ptr + 1, sizes + 1);
00119 if (elementsRead > 0)
00120 {
00121 int i;
00122 for (i = 0; i < 2 && ptr[i] != NULL; ++i)
00123 {
00124 fwrite(ptr[i], pData->ringBuffer.elementSizeBytes, sizes[i], pData->file);
00125 }
00126 PaUtil_AdvanceRingBufferReadIndex(&pData->ringBuffer, elementsRead);
00127 }
00128
00129 if (pData->threadSyncFlag)
00130 {
00131 break;
00132 }
00133 }
00134
00135
00136 Pa_Sleep(20);
00137 }
00138
00139 pData->threadSyncFlag = 0;
00140
00141 return 0;
00142 }
00143
00144
00145
00146 static int threadFunctionReadFromRawFile(void* ptr)
00147 {
00148 paTestData* pData = (paTestData*)ptr;
00149
00150 while (1)
00151 {
00152 ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferWriteAvailable(&pData->ringBuffer);
00153
00154 if (elementsInBuffer >= pData->ringBuffer.bufferSize / NUM_WRITES_PER_BUFFER)
00155 {
00156 void* ptr[2] = {0};
00157 ring_buffer_size_t sizes[2] = {0};
00158
00159
00160 PaUtil_GetRingBufferWriteRegions(&pData->ringBuffer, elementsInBuffer, ptr + 0, sizes + 0, ptr + 1, sizes + 1);
00161
00162 if (!feof(pData->file))
00163 {
00164 ring_buffer_size_t itemsReadFromFile = 0;
00165 int i;
00166 for (i = 0; i < 2 && ptr[i] != NULL; ++i)
00167 {
00168 itemsReadFromFile += (ring_buffer_size_t)fread(ptr[i], pData->ringBuffer.elementSizeBytes, sizes[i], pData->file);
00169 }
00170 PaUtil_AdvanceRingBufferWriteIndex(&pData->ringBuffer, itemsReadFromFile);
00171
00172
00173 pData->threadSyncFlag = 0;
00174 }
00175 else
00176 {
00177
00178 pData->threadSyncFlag = 1;
00179 break;
00180 }
00181 }
00182
00183
00184 Pa_Sleep(20);
00185 }
00186
00187 return 0;
00188 }
00189
00190 typedef int (*ThreadFunctionType)(void*);
00191
00192
00193
00194 static PaError startThread( paTestData* pData, ThreadFunctionType fn )
00195 {
00196 #ifdef _WIN32
00197 typedef unsigned (__stdcall* WinThreadFunctionType)(void*);
00198 pData->threadHandle = (void*)_beginthreadex(NULL, 0, (WinThreadFunctionType)fn, pData, CREATE_SUSPENDED, NULL);
00199 if (pData->threadHandle == NULL) return paUnanticipatedHostError;
00200
00201
00202 SetThreadPriority(pData->threadHandle, THREAD_PRIORITY_ABOVE_NORMAL);
00203
00204
00205 pData->threadSyncFlag = 1;
00206 ResumeThread(pData->threadHandle);
00207
00208 #endif
00209
00210
00211 while (pData->threadSyncFlag) {
00212 Pa_Sleep(10);
00213 }
00214
00215 return paNoError;
00216 }
00217
00218 static int stopThread( paTestData* pData )
00219 {
00220 pData->threadSyncFlag = 1;
00221
00222 while (pData->threadSyncFlag) {
00223 Pa_Sleep(10);
00224 }
00225 #ifdef _WIN32
00226 CloseHandle(pData->threadHandle);
00227 pData->threadHandle = 0;
00228 #endif
00229
00230 return paNoError;
00231 }
00232
00233
00234
00235
00236
00237
00238 static int recordCallback( const void *inputBuffer, void *outputBuffer,
00239 unsigned long framesPerBuffer,
00240 const PaStreamCallbackTimeInfo* timeInfo,
00241 PaStreamCallbackFlags statusFlags,
00242 void *userData )
00243 {
00244 paTestData *data = (paTestData*)userData;
00245 ring_buffer_size_t elementsWriteable = PaUtil_GetRingBufferWriteAvailable(&data->ringBuffer);
00246 ring_buffer_size_t elementsToWrite = min(elementsWriteable, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS));
00247 const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
00248
00249 (void) outputBuffer;
00250 (void) timeInfo;
00251 (void) statusFlags;
00252 (void) userData;
00253
00254 data->frameIndex += PaUtil_WriteRingBuffer(&data->ringBuffer, rptr, elementsToWrite);
00255
00256 return paContinue;
00257 }
00258
00259
00260
00261
00262
00263 static int playCallback( const void *inputBuffer, void *outputBuffer,
00264 unsigned long framesPerBuffer,
00265 const PaStreamCallbackTimeInfo* timeInfo,
00266 PaStreamCallbackFlags statusFlags,
00267 void *userData )
00268 {
00269 paTestData *data = (paTestData*)userData;
00270 ring_buffer_size_t elementsToPlay = PaUtil_GetRingBufferReadAvailable(&data->ringBuffer);
00271 ring_buffer_size_t elementsToRead = min(elementsToPlay, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS));
00272 SAMPLE* wptr = (SAMPLE*)outputBuffer;
00273
00274 (void) inputBuffer;
00275 (void) timeInfo;
00276 (void) statusFlags;
00277 (void) userData;
00278
00279 data->frameIndex += PaUtil_ReadRingBuffer(&data->ringBuffer, wptr, elementsToRead);
00280
00281 return data->threadSyncFlag ? paComplete : paContinue;
00282 }
00283
00284 static unsigned NextPowerOf2(unsigned val)
00285 {
00286 val--;
00287 val = (val >> 1) | val;
00288 val = (val >> 2) | val;
00289 val = (val >> 4) | val;
00290 val = (val >> 8) | val;
00291 val = (val >> 16) | val;
00292 return ++val;
00293 }
00294
00295
00296 int main(void);
00297 int main(void)
00298 {
00299 PaStreamParameters inputParameters,
00300 outputParameters;
00301 PaStream* stream;
00302 PaError err = paNoError;
00303 paTestData data = {0};
00304 unsigned delayCntr;
00305 unsigned numSamples;
00306 unsigned numBytes;
00307
00308 printf("patest_record.c\n"); fflush(stdout);
00309
00310
00311 numSamples = NextPowerOf2((unsigned)(SAMPLE_RATE * 0.5 * NUM_CHANNELS));
00312 numBytes = numSamples * sizeof(SAMPLE);
00313 data.ringBufferData = (SAMPLE *) PaUtil_AllocateMemory( numBytes );
00314 if( data.ringBufferData == NULL )
00315 {
00316 printf("Could not allocate ring buffer data.\n");
00317 goto done;
00318 }
00319
00320 if (PaUtil_InitializeRingBuffer(&data.ringBuffer, sizeof(SAMPLE), numSamples, data.ringBufferData) < 0)
00321 {
00322 printf("Failed to initialize ring buffer. Size is not power of 2 ??\n");
00323 goto done;
00324 }
00325
00326 err = Pa_Initialize();
00327 if( err != paNoError ) goto done;
00328
00329 inputParameters.device = Pa_GetDefaultInputDevice();
00330 if (inputParameters.device == paNoDevice) {
00331 fprintf(stderr,"Error: No default input device.\n");
00332 goto done;
00333 }
00334 inputParameters.channelCount = 2;
00335 inputParameters.sampleFormat = PA_SAMPLE_TYPE;
00336 inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
00337 inputParameters.hostApiSpecificStreamInfo = NULL;
00338
00339
00340 err = Pa_OpenStream(
00341 &stream,
00342 &inputParameters,
00343 NULL,
00344 SAMPLE_RATE,
00345 FRAMES_PER_BUFFER,
00346 paClipOff,
00347 recordCallback,
00348 &data );
00349 if( err != paNoError ) goto done;
00350
00351
00352 data.file = fopen(FILE_NAME, "wb");
00353 if (data.file == 0) goto done;
00354
00355
00356 err = startThread(&data, threadFunctionWriteToRawFile);
00357 if( err != paNoError ) goto done;
00358
00359 err = Pa_StartStream( stream );
00360 if( err != paNoError ) goto done;
00361 printf("\n=== Now recording to '" FILE_NAME "' for %d seconds!! Please speak into the microphone. ===\n", NUM_SECONDS); fflush(stdout);
00362
00363
00364
00365 delayCntr = 0;
00366 while( delayCntr++ < NUM_SECONDS )
00367 {
00368 printf("index = %d\n", data.frameIndex ); fflush(stdout);
00369 Pa_Sleep(1000);
00370 }
00371 if( err < 0 ) goto done;
00372
00373 err = Pa_CloseStream( stream );
00374 if( err != paNoError ) goto done;
00375
00376
00377 err = stopThread(&data);
00378 if( err != paNoError ) goto done;
00379
00380
00381 fclose(data.file);
00382 data.file = 0;
00383
00384
00385 data.frameIndex = 0;
00386
00387 outputParameters.device = Pa_GetDefaultOutputDevice();
00388 if (outputParameters.device == paNoDevice) {
00389 fprintf(stderr,"Error: No default output device.\n");
00390 goto done;
00391 }
00392 outputParameters.channelCount = 2;
00393 outputParameters.sampleFormat = PA_SAMPLE_TYPE;
00394 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
00395 outputParameters.hostApiSpecificStreamInfo = NULL;
00396
00397 printf("\n=== Now playing back from file '" FILE_NAME "' until end-of-file is reached ===\n"); fflush(stdout);
00398 err = Pa_OpenStream(
00399 &stream,
00400 NULL,
00401 &outputParameters,
00402 SAMPLE_RATE,
00403 FRAMES_PER_BUFFER,
00404 paClipOff,
00405 playCallback,
00406 &data );
00407 if( err != paNoError ) goto done;
00408
00409 if( stream )
00410 {
00411
00412 data.file = fopen(FILE_NAME, "rb");
00413 if (data.file != 0)
00414 {
00415
00416 err = startThread(&data, threadFunctionReadFromRawFile);
00417 if( err != paNoError ) goto done;
00418
00419 err = Pa_StartStream( stream );
00420 if( err != paNoError ) goto done;
00421
00422 printf("Waiting for playback to finish.\n"); fflush(stdout);
00423
00424
00425 while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) {
00426 printf("index = %d\n", data.frameIndex ); fflush(stdout);
00427 Pa_Sleep(1000);
00428 }
00429 if( err < 0 ) goto done;
00430 }
00431
00432 err = Pa_CloseStream( stream );
00433 if( err != paNoError ) goto done;
00434
00435 fclose(data.file);
00436
00437 printf("Done.\n"); fflush(stdout);
00438 }
00439
00440 done:
00441 Pa_Terminate();
00442 if( data.ringBufferData )
00443 PaUtil_FreeMemory( data.ringBufferData );
00444 if( err != paNoError )
00445 {
00446 fprintf( stderr, "An error occured while using the portaudio stream\n" );
00447 fprintf( stderr, "Error number: %d\n", err );
00448 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
00449 err = 1;
00450 }
00451 return err;
00452 }
00453