This program is intended continuously to feed a sine wave of 425 Hz to the default output device. At first it seems to work correctly, but after about 12 seconds, the pitch seems to change. This doesn't happen if the second argument and return value of fillbuf is changed to double; but why does it happen with float; and will it happen with double too, at a later time?
PS. I should also ask: since this is happening, this is clearly an incorrect way of doing what I'm trying to do; what is the correct way? Should I simply switch to double, or is there a more reliable solution (if switching to double does in fact just delay the problem)?
#include <stdio.h>
#include <string.h> /* memset */
#include <math.h>
#include <portaudio.h>
/*
* Write a sinusoid to the sound card. --
*
* Example of basic usage of the BLOCKING technique (as opposed to the
* callback technique).
*
*/
#define SR 44100 /* sample rate */
#define FREQ 425
#define BUFSIZE 512
FILE *fp = NULL;
float delta = 2 * M_PI * FREQ / SR;
float fillbuf(float *buffer, float initarg);
int play();
int main()
{
/* for gnuplot */
/* fp = fopen("/tmp/sine", "w"); */
play();
}
float fillbuf(float *buf, float arg)
{
int i;
for (i = 0; i < BUFSIZE; i++) {
buf[i] = sin(arg);
/* for gnuplot */
if (fp)
fprintf(fp, "%f\t%f\n", arg, buf[i]);
arg += delta;
}
/* print the time */
printf("%f\n", arg/FREQ/2/M_PI);
return arg;
}
int play()
{
PaError err;
int i, odev, arg = 0;
PaStreamParameters oparam;
PaStream *stream;
float buf[BUFSIZE];
err = Pa_Initialize();
if (err != paNoError) {
printf("%s\n", Pa_GetErrorText(err));
return 1;
}
odev=Pa_GetDefaultOutputDevice();
/* set all of oparam to zero */
memset(&oparam, 0, sizeof(PaStreamParameters));
oparam.device = odev;
oparam.channelCount = 1;
oparam.sampleFormat = paFloat32;
/* takes care of underflow errors and clicks */
oparam.suggestedLatency = 0.05;
Pa_OpenStream(&stream, NULL, &oparam, SR, BUFSIZE, paNoFlag,
/* only for asynchronous mode */
NULL, NULL);
err = Pa_StartStream(stream);
if (err != paNoError) {
printf("%s\n", Pa_GetErrorText(err));
return 1;
}
while (1) {
arg = fillbuf(buf, arg);
err = Pa_WriteStream(stream, buf, BUFSIZE);
if (err != paNoError)
printf("%s\n", Pa_GetErrorText(err));
}
Pa_StopStream(stream);
Pa_CloseStream(stream);
Pa_Terminate();
}