#include <math.h>
#include <portaudio.h>
#include <stdio.h>

#define TABLE_SIZE 800
#define SAMPLES 44100

typedef struct {
	float sine[TABLE_SIZE];
	int left_phase;
	int right_phase;
	char message[20];
} testData;

static int callback(const void *input, void *output, unsigned long fpb,
		const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags sFlags,
		void *userdata) {
	testData *data = (testData*)userdata;
	float *out = (float*)output;
	unsigned long i;

	for (i = 0; i < fpb; ++i) {
		*out++ = data->sine[data->left_phase];
		*out++ = data->sine[data->right_phase];

		data->left_phase += 2;
		data->right_phase += 2;

		if (data->left_phase >= TABLE_SIZE)
			data->left_phase -= TABLE_SIZE;
		else if (data->right_phase >= TABLE_SIZE)
			data->right_phase -= TABLE_SIZE;
	}

	return paContinue;
}

static void StreamFinished (void *userdata) {
	testData *data = (testData*)userdata;

	printf("Stream completed: %s\n", data->message);
}

int main(void) {
	PaStreamParameters outputParameters;
	PaStream *stream;
	PaError error;
	testData data;

	for (int i = 0; i < TABLE_SIZE; ++i) {
		data.sine[i] = (float) sin(((double)i/TABLE_SIZE) * M_PI * 4.);
	}

	data.left_phase = data.right_phase = 0;

	error = Pa_Initialize();

	outputParameters.device = Pa_GetDefaultOutputDevice();
	if (outputParameters.device == paNoDevice) {
		fprintf(stderr, "Error: no default output device available\n");
		return 1;
	}

	outputParameters.channelCount = 2;
	outputParameters.sampleFormat = paFloat32;
	outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)\
										->defaultLowOutputLatency;

	outputParameters.hostApiSpecificStreamInfo = NULL;

	error = Pa_OpenStream(&stream, NULL,
			&outputParameters,
			SAMPLES,
			32, // frames per buffer
			paClipOff,
			callback,
			&data);

	if (error != paNoError) goto error;

	Pa_SetStreamFinishedCallback(stream, &StreamFinished);
	Pa_StartStream(stream);
	Pa_Sleep(5000);
	Pa_StopStream(stream);
	Pa_CloseStream(stream);
	Pa_Terminate();

	return error;
error:
	Pa_Terminate();
	fprintf(stderr, "An error occurred while using PortAudio.\n");
	fprintf(stderr, "%d: %s\n", error, Pa_GetErrorText(error));
	return error;
}
