47 #include "pa_ringbuffer.h"
55 static ring_buffer_size_t rbs_min(ring_buffer_size_t a, ring_buffer_size_t b)
57 return (a < b) ? a : b;
61 #define FILE_NAME "audio_data.raw"
62 #define SAMPLE_RATE (44100)
63 #define FRAMES_PER_BUFFER (512)
64 #define NUM_SECONDS (10)
65 #define NUM_CHANNELS (2)
66 #define NUM_WRITES_PER_BUFFER (4)
68 #define DITHER_FLAG (0)
73 #define PA_SAMPLE_TYPE paFloat32
75 #define SAMPLE_SILENCE (0.0f)
76 #define PRINTF_S_FORMAT "%.8f"
78 #define PA_SAMPLE_TYPE paInt16
80 #define SAMPLE_SILENCE (0)
81 #define PRINTF_S_FORMAT "%d"
83 #define PA_SAMPLE_TYPE paInt8
85 #define SAMPLE_SILENCE (0)
86 #define PRINTF_S_FORMAT "%d"
88 #define PA_SAMPLE_TYPE paUInt8
89 typedef unsigned char SAMPLE;
90 #define SAMPLE_SILENCE (128)
91 #define PRINTF_S_FORMAT "%d"
98 SAMPLE *ringBufferData;
99 PaUtilRingBuffer ringBuffer;
106 static int threadFunctionWriteToRawFile(
void* ptr)
111 pData->threadSyncFlag = 0;
115 ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferReadAvailable(&pData->ringBuffer);
116 if ( (elementsInBuffer >= pData->ringBuffer.bufferSize / NUM_WRITES_PER_BUFFER) ||
117 pData->threadSyncFlag )
120 ring_buffer_size_t sizes[2] = {0};
123 ring_buffer_size_t elementsRead = PaUtil_GetRingBufferReadRegions(&pData->ringBuffer, elementsInBuffer, ptr + 0, sizes + 0, ptr + 1, sizes + 1);
124 if (elementsRead > 0)
127 for (i = 0; i < 2 && ptr[i] != NULL; ++i)
129 fwrite(ptr[i], pData->ringBuffer.elementSizeBytes, sizes[i], pData->file);
131 PaUtil_AdvanceRingBufferReadIndex(&pData->ringBuffer, elementsRead);
134 if (pData->threadSyncFlag)
144 pData->threadSyncFlag = 0;
151 static int threadFunctionReadFromRawFile(
void* ptr)
157 ring_buffer_size_t elementsInBuffer = PaUtil_GetRingBufferWriteAvailable(&pData->ringBuffer);
159 if (elementsInBuffer >= pData->ringBuffer.bufferSize / NUM_WRITES_PER_BUFFER)
162 ring_buffer_size_t sizes[2] = {0};
165 PaUtil_GetRingBufferWriteRegions(&pData->ringBuffer, elementsInBuffer, ptr + 0, sizes + 0, ptr + 1, sizes + 1);
167 if (!feof(pData->file))
169 ring_buffer_size_t itemsReadFromFile = 0;
171 for (i = 0; i < 2 && ptr[i] != NULL; ++i)
173 itemsReadFromFile += (ring_buffer_size_t)fread(ptr[i], pData->ringBuffer.elementSizeBytes, sizes[i], pData->file);
175 PaUtil_AdvanceRingBufferWriteIndex(&pData->ringBuffer, itemsReadFromFile);
178 pData->threadSyncFlag = 0;
183 pData->threadSyncFlag = 1;
195 typedef int (*ThreadFunctionType)(
void*);
202 typedef unsigned (__stdcall* WinThreadFunctionType)(
void*);
203 pData->threadHandle = (
void*)_beginthreadex(NULL, 0, (WinThreadFunctionType)fn, pData, CREATE_SUSPENDED, NULL);
204 if (pData->threadHandle == NULL)
return paUnanticipatedHostError;
207 SetThreadPriority(pData->threadHandle, THREAD_PRIORITY_ABOVE_NORMAL);
210 pData->threadSyncFlag = 1;
211 ResumeThread(pData->threadHandle);
216 while (pData->threadSyncFlag) {
225 pData->threadSyncFlag = 1;
227 while (pData->threadSyncFlag) {
231 CloseHandle(pData->threadHandle);
232 pData->threadHandle = 0;
243 static int recordCallback(
const void *inputBuffer,
void *outputBuffer,
244 unsigned long framesPerBuffer,
250 ring_buffer_size_t elementsWriteable = PaUtil_GetRingBufferWriteAvailable(&data->ringBuffer);
251 ring_buffer_size_t elementsToWrite = rbs_min(elementsWriteable, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS));
252 const SAMPLE *rptr = (
const SAMPLE*)inputBuffer;
259 data->frameIndex += PaUtil_WriteRingBuffer(&data->ringBuffer, rptr, elementsToWrite);
268 static int playCallback(
const void *inputBuffer,
void *outputBuffer,
269 unsigned long framesPerBuffer,
275 ring_buffer_size_t elementsToPlay = PaUtil_GetRingBufferReadAvailable(&data->ringBuffer);
276 ring_buffer_size_t elementsToRead = rbs_min(elementsToPlay, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS));
277 SAMPLE* wptr = (SAMPLE*)outputBuffer;
284 data->frameIndex += PaUtil_ReadRingBuffer(&data->ringBuffer, wptr, elementsToRead);
289 static unsigned NextPowerOf2(
unsigned val)
292 val = (val >> 1) | val;
293 val = (val >> 2) | val;
294 val = (val >> 4) | val;
295 val = (val >> 8) | val;
296 val = (val >> 16) | val;
313 printf(
"patest_record.c\n"); fflush(stdout);
316 numSamples = NextPowerOf2((
unsigned)(SAMPLE_RATE * 0.5 * NUM_CHANNELS));
317 numBytes = numSamples *
sizeof(SAMPLE);
318 data.ringBufferData = (SAMPLE *) PaUtil_AllocateMemory( numBytes );
319 if( data.ringBufferData == NULL )
321 printf(
"Could not allocate ring buffer data.\n");
325 if (PaUtil_InitializeRingBuffer(&data.ringBuffer,
sizeof(SAMPLE), numSamples, data.ringBufferData) < 0)
327 printf(
"Failed to initialize ring buffer. Size is not power of 2 ??\n");
332 if( err != paNoError )
goto done;
336 fprintf(stderr,
"Error: No default input device.\n");
354 if( err != paNoError )
goto done;
357 data.file = fopen(FILE_NAME,
"wb");
358 if (data.file == 0)
goto done;
361 err = startThread(&data, threadFunctionWriteToRawFile);
362 if( err != paNoError )
goto done;
365 if( err != paNoError )
goto done;
366 printf(
"\n=== Now recording to '" FILE_NAME
"' for %d seconds!! Please speak into the microphone. ===\n", NUM_SECONDS); fflush(stdout);
371 while( delayCntr++ < NUM_SECONDS )
373 printf(
"index = %d\n", data.frameIndex ); fflush(stdout);
376 if( err < 0 )
goto done;
379 if( err != paNoError )
goto done;
382 err = stopThread(&data);
383 if( err != paNoError )
goto done;
394 fprintf(stderr,
"Error: No default output device.\n");
402 printf(
"\n=== Now playing back from file '" FILE_NAME
"' until end-of-file is reached ===\n"); fflush(stdout);
412 if( err != paNoError )
goto done;
417 data.file = fopen(FILE_NAME,
"rb");
421 err = startThread(&data, threadFunctionReadFromRawFile);
422 if( err != paNoError )
goto done;
425 if( err != paNoError )
goto done;
427 printf(
"Waiting for playback to finish.\n"); fflush(stdout);
431 printf(
"index = %d\n", data.frameIndex ); fflush(stdout);
434 if( err < 0 )
goto done;
438 if( err != paNoError )
goto done;
442 printf(
"Done.\n"); fflush(stdout);
447 if( data.ringBufferData )
448 PaUtil_FreeMemory( data.ringBufferData );
449 if( err != paNoError )
451 fprintf( stderr,
"An error occured while using the portaudio stream\n" );
452 fprintf( stderr,
"Error number: %d\n", err );
PaError Pa_Initialize(void)
PaDeviceIndex Pa_GetDefaultInputDevice(void)
PaError Pa_OpenStream(PaStream **stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData)
PaTime defaultLowInputLatency
PaError Pa_StartStream(PaStream *stream)
void * hostApiSpecificStreamInfo
The portable PortAudio API.
PaSampleFormat sampleFormat
PaError Pa_IsStreamActive(PaStream *stream)
unsigned long PaStreamCallbackFlags
const PaDeviceInfo * Pa_GetDeviceInfo(PaDeviceIndex device)
PaDeviceIndex Pa_GetDefaultOutputDevice(void)
const char * Pa_GetErrorText(PaError errorCode)
PaError Pa_CloseStream(PaStream *stream)
PaError Pa_Terminate(void)