You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
6.7 KiB
204 lines
6.7 KiB
#include "input/portaudio.h" |
|
#include "input/common.h" |
|
|
|
#include <portaudio.h> |
|
#define PORTBUFSIZE 512 |
|
|
|
#define SAMPLE_SILENCE -32767 |
|
#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; |
|
SAMPLE *rptr = (SAMPLE *)inputBuffer; |
|
long framesToCalc; |
|
// long i; |
|
int finished; |
|
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; |
|
int16_t silence_buffer[PORTBUFSIZE] = {SAMPLE_SILENCE}; |
|
(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) { |
|
write_to_fftw_input_buffers(silence_buffer, framesToCalc, audio); |
|
/* |
|
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 == PORTBUFSIZE-1) n = 0; |
|
} |
|
*/ |
|
} else { |
|
write_to_fftw_input_buffers(rptr, framesToCalc, audio); |
|
/* |
|
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 == PORTBUFSIZE-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 = PORTBUFSIZE; |
|
data.recordedSamples = (SAMPLE *)malloc(2 * PORTBUFSIZE * sizeof(SAMPLE)); |
|
if (data.recordedSamples == NULL) { |
|
fprintf(stderr, "Error: failure in memory allocation!\n"); |
|
exit(EXIT_FAILURE); |
|
} else |
|
memset(data.recordedSamples, 0x00, 2 * PORTBUFSIZE); |
|
|
|
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, PORTBUFSIZE, 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; |
|
}
|
|
|