parent
80c4064fb1
commit
24c872936f
6 changed files with 243 additions and 0 deletions
@ -0,0 +1,196 @@ |
|||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <portaudio.h> |
||||||
|
#include "portaudio.h" |
||||||
|
#include "fifo.h" |
||||||
|
#define BUFFERSIZE 4096 |
||||||
|
|
||||||
|
#define SAMPLE_SILENCE 32768 |
||||||
|
#define PA_SAMPLE_TYPE paInt16 |
||||||
|
typedef short SAMPLE; |
||||||
|
|
||||||
|
typedef struct { |
||||||
|
int frameIndex; /* Index into sample array. */ |
||||||
|
int maxFrameIndex; |
||||||
|
SAMPLE *recordedSamples; |
||||||
|
} paTestData; |
||||||
|
|
||||||
|
static struct audio_data *audio; |
||||||
|
static int n = 0; |
||||||
|
|
||||||
|
static int recordCallback(const void *inputBuffer, void *outputBuffer, |
||||||
|
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, |
||||||
|
PaStreamCallbackFlags statusFlags, void *userData) { |
||||||
|
paTestData *data = (paTestData*)userData; |
||||||
|
const SAMPLE *rptr = (const SAMPLE*)inputBuffer; |
||||||
|
long framesToCalc; |
||||||
|
long i; |
||||||
|
int finished; |
||||||
|
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; |
||||||
|
|
||||||
|
(void) outputBuffer; // Prevent unused variable warnings.
|
||||||
|
(void) timeInfo; |
||||||
|
(void) statusFlags; |
||||||
|
(void) userData; |
||||||
|
|
||||||
|
if( framesLeft < framesPerBuffer ) { |
||||||
|
framesToCalc = framesLeft; |
||||||
|
finished = paComplete; |
||||||
|
} else { |
||||||
|
framesToCalc = framesPerBuffer; |
||||||
|
finished = paContinue; |
||||||
|
} |
||||||
|
|
||||||
|
if(inputBuffer == NULL) { |
||||||
|
for(i=0; i<framesToCalc; i++) { |
||||||
|
if(audio->channels == 1) audio->audio_out_l[n] = SAMPLE_SILENCE; |
||||||
|
if(audio->channels == 2) { |
||||||
|
audio->audio_out_l[n] = SAMPLE_SILENCE; |
||||||
|
audio->audio_out_r[n] = SAMPLE_SILENCE; |
||||||
|
} |
||||||
|
if(n == BUFSIZE-1) n = 0; |
||||||
|
} |
||||||
|
} else { |
||||||
|
for(i=0; i<framesToCalc; i++) { |
||||||
|
if(audio->channels == 1) { |
||||||
|
audio->audio_out_l[n] = (rptr[0] + rptr[1]) / 2; |
||||||
|
rptr += 2; |
||||||
|
} |
||||||
|
if(audio->channels == 2) { |
||||||
|
audio->audio_out_l[n] = *rptr++; |
||||||
|
audio->audio_out_r[n] = *rptr++; |
||||||
|
} |
||||||
|
n++; |
||||||
|
if(n == BUFSIZE-1) n = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
data->frameIndex += framesToCalc; |
||||||
|
if(finished == paComplete) { |
||||||
|
data->frameIndex = 0; |
||||||
|
finished = paContinue; |
||||||
|
} |
||||||
|
return finished; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void portaudio_simple_free(paTestData data) { |
||||||
|
Pa_Terminate(); |
||||||
|
free(data.recordedSamples); |
||||||
|
} |
||||||
|
|
||||||
|
void* input_portaudio(void *audiodata) { |
||||||
|
audio = (struct audio_data *)audiodata; |
||||||
|
|
||||||
|
PaStreamParameters inputParameters; |
||||||
|
PaStream* stream; |
||||||
|
PaError err = paNoError; |
||||||
|
paTestData data; |
||||||
|
|
||||||
|
// start portaudio
|
||||||
|
err = Pa_Initialize(); |
||||||
|
if(err != paNoError) { |
||||||
|
fprintf(stderr, "Error: unable to initilize portaudio - %s\n", Pa_GetErrorText(err)); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
// get portaudio device
|
||||||
|
int deviceNum = -1, numOfDevices = Pa_GetDeviceCount(); |
||||||
|
if(!strcmp(audio->source, "list")) { |
||||||
|
if(numOfDevices < 0) { |
||||||
|
fprintf(stderr, "Error: portaudio was unable to find a audio device! Code: 0x%x\n", numOfDevices); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
for(int i = 0; i < numOfDevices; i++) { |
||||||
|
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); |
||||||
|
printf("Device #%d: %s\n" |
||||||
|
"\tInput Channels: %d\n" |
||||||
|
"\tOutput Channels: %d\n" |
||||||
|
"\tDefault SampleRate: %lf\n", |
||||||
|
i+1, deviceInfo->name, deviceInfo->maxInputChannels, |
||||||
|
deviceInfo->maxOutputChannels, deviceInfo->defaultSampleRate); |
||||||
|
} |
||||||
|
exit(EXIT_SUCCESS); |
||||||
|
} else if(!strcmp(audio->source, "auto")) { |
||||||
|
deviceNum = Pa_GetDefaultInputDevice(); |
||||||
|
|
||||||
|
if(deviceNum == paNoDevice) { |
||||||
|
fprintf(stderr, "Error: no portaudio input device found\n"); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
} else if(sscanf(audio->source,"%d", &deviceNum)) { |
||||||
|
if(deviceNum > numOfDevices) { |
||||||
|
fprintf(stderr, "Error: Invalid input device!\n"); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
deviceNum--; |
||||||
|
} else { |
||||||
|
for(int i = 0; i < numOfDevices; i++) { |
||||||
|
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); |
||||||
|
if(!strcmp(audio->source, deviceInfo->name)) { |
||||||
|
deviceNum=i; |
||||||
|
break; |
||||||
|
}
|
||||||
|
} |
||||||
|
if(deviceNum==-1) { |
||||||
|
fprintf(stderr, "Error: No such device '%s'!\n", audio->source); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
} |
||||||
|
inputParameters.device = deviceNum; |
||||||
|
|
||||||
|
// set parameters
|
||||||
|
data.maxFrameIndex = BUFSIZE; |
||||||
|
data.recordedSamples = (SAMPLE *)malloc(2*BUFSIZE*sizeof(SAMPLE)); |
||||||
|
if(data.recordedSamples == NULL) { |
||||||
|
fprintf(stderr, "Error: failure in memory allocation!\n"); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} else memset(data.recordedSamples, 0x00, 2*BUFSIZE); |
||||||
|
|
||||||
|
inputParameters.channelCount = 2; |
||||||
|
inputParameters.sampleFormat = PA_SAMPLE_TYPE; |
||||||
|
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency; |
||||||
|
inputParameters.hostApiSpecificStreamInfo = NULL; |
||||||
|
|
||||||
|
// set it to work
|
||||||
|
err = Pa_OpenStream(&stream, &inputParameters, NULL, audio->rate, BUFSIZE, |
||||||
|
paClipOff, recordCallback, &data); |
||||||
|
if(err != paNoError) { |
||||||
|
fprintf(stderr, "Error: failure in opening stream (%x)\n", err); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
// main loop
|
||||||
|
while(1){ |
||||||
|
// start recording
|
||||||
|
data.frameIndex = 0; |
||||||
|
err = Pa_StartStream(stream); |
||||||
|
if(err != paNoError) { |
||||||
|
fprintf(stderr, "Error: failure in starting stream (%x)\n", err); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
// record
|
||||||
|
while((err = Pa_IsStreamActive(stream)) == 1) { |
||||||
|
Pa_Sleep(5); |
||||||
|
if(audio->terminate == 1) break; |
||||||
|
} |
||||||
|
// check for errors
|
||||||
|
if(err < 0) { |
||||||
|
fprintf(stderr, "Error: failure in recording audio (%x)\n", err); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
// check if it bailed
|
||||||
|
if(audio->terminate == 1) break; |
||||||
|
} |
||||||
|
// close stream
|
||||||
|
if((err = Pa_CloseStream(stream)) != paNoError) { |
||||||
|
fprintf(stderr, "Error: failure in closing stream (%x)\n", err); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
portaudio_simple_free(data); |
||||||
|
return 0; |
||||||
|
}
|
||||||
@ -0,0 +1 @@ |
|||||||
|
void* input_portaudio(void *audiodata); |
||||||
Loading…
Reference in new issue