I wrote a very basic C program to play a sine of a user-specified frequency. In the interest of portability, I have it spit values directly to stdout, so hopefully you can reproduce my problem on your own machine. This is the code I wrote:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define RATE 48000
#define TWOPI (3.14159 * 2.0)
int main(int argc, char** argv) {
float frequency = atof(argv[1]);
float phase = 0.0;
float increment = TWOPI/RATE;
int16_t sample;
while (1) {
sample = sin(phase) * 32767;
putchar(sample & 255);
putchar(sample >> 8);
phase += increment * frequency;
}
return 0;
}
It can be compiled with:
cc sine.c -lm
and played with
./a.out 440.0 | sox -r 48000 -c 1 -t s16 - -d
That is: 16 bit mono audio at a sampling rate of 48,000 Hz.
I've tested this on both OpenBSD and MacOS and have noticed the same behavior: at around 6 seconds, the pitch of the wave jumps slightly. This happens again around 12 seconds. Further changes will take place as the wave continues to play. I have also replaced the sin() while loop with a prebuilt wavetable of a sine accessed through linear interpolation, only to notice the same problems.
Any ideas what might be off here?
argv[0]
without first checkingargc
to assure the desired command line parameter actually exists $\endgroup$double
unless the value contains a trailingf
. Then it is afloat
value. The posted code contains several such literals, and is dividing adouble
value by afloat
value, which results in the compiler displaying a warning about this conversion between types $\endgroup$argc
, so when the user does not enter a command line parameter, the program seg faults at the call toatof()
$\endgroup$atof()
has misleading name It actually returns adouble
, not afloat
$\endgroup$