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));
258 data->frameIndex += PaUtil_WriteRingBuffer(&data->ringBuffer, inputBuffer, elementsToWrite);
267 static int playCallback(
const void *inputBuffer,
void *outputBuffer,
268 unsigned long framesPerBuffer,
274 ring_buffer_size_t elementsToPlay = PaUtil_GetRingBufferReadAvailable(&data->ringBuffer);
275 ring_buffer_size_t elementsToRead = rbs_min(elementsToPlay, (ring_buffer_size_t)(framesPerBuffer * NUM_CHANNELS));
282 data->frameIndex += PaUtil_ReadRingBuffer(&data->ringBuffer, outputBuffer, elementsToRead);
287 static unsigned NextPowerOf2(
unsigned val)
290 val = (val >> 1) | val;
291 val = (val >> 2) | val;
292 val = (val >> 4) | val;
293 val = (val >> 8) | val;
294 val = (val >> 16) | val;
311 printf(
"patest_record.c\n"); fflush(stdout);
314 numSamples = NextPowerOf2((
unsigned)(SAMPLE_RATE * 0.5 * NUM_CHANNELS));
315 numBytes = numSamples *
sizeof(SAMPLE);
316 data.ringBufferData = (SAMPLE *) PaUtil_AllocateZeroInitializedMemory( numBytes );
317 if( data.ringBufferData == NULL )
319 printf(
"Could not allocate ring buffer data.\n");
323 if (PaUtil_InitializeRingBuffer(&data.ringBuffer,
sizeof(SAMPLE), numSamples, data.ringBufferData) < 0)
325 printf(
"Failed to initialize ring buffer. Size is not power of 2 ??\n");
330 if( err != paNoError )
goto done;
334 fprintf(stderr,
"Error: No default input device.\n");
352 if( err != paNoError )
goto done;
355 data.file = fopen(FILE_NAME,
"wb");
356 if (data.file == 0)
goto done;
359 err = startThread(&data, threadFunctionWriteToRawFile);
360 if( err != paNoError )
goto done;
363 if( err != paNoError )
goto done;
364 printf(
"\n=== Now recording to '" FILE_NAME
"' for %d seconds!! Please speak into the microphone. ===\n", NUM_SECONDS); fflush(stdout);
369 while( delayCntr++ < NUM_SECONDS )
371 printf(
"index = %d\n", data.frameIndex ); fflush(stdout);
374 if( err < 0 )
goto done;
377 if( err != paNoError )
goto done;
380 err = stopThread(&data);
381 if( err != paNoError )
goto done;
392 fprintf(stderr,
"Error: No default output device.\n");
400 printf(
"\n=== Now playing back from file '" FILE_NAME
"' until end-of-file is reached ===\n"); fflush(stdout);
410 if( err != paNoError )
goto done;
415 data.file = fopen(FILE_NAME,
"rb");
419 err = startThread(&data, threadFunctionReadFromRawFile);
420 if( err != paNoError )
goto done;
423 if( err != paNoError )
goto done;
425 printf(
"Waiting for playback to finish.\n"); fflush(stdout);
429 printf(
"index = %d\n", data.frameIndex ); fflush(stdout);
432 if( err < 0 )
goto done;
436 if( err != paNoError )
goto done;
440 printf(
"Done.\n"); fflush(stdout);
445 if( data.ringBufferData )
446 PaUtil_FreeMemory( data.ringBufferData );
447 if( err != paNoError )
449 fprintf( stderr,
"An error occurred while using the portaudio stream\n" );
450 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)