Trouble Generating a Sine Wave in C/Matlab from Basics

this is a crosspost from stackoverflow as I figured there may be more who can help me here...

I've been writing a basic C program to generate a sine wave and write it out to STDOUT for piping into a filter which I am also going to write but I'm having issues.

I am able to generate what sounds like a good clean sine wave, but the frequency is off. When I listen to the output I am generating and compare to a true signal generators output, the frequency of mine is slightly too high.

The C code should generate raw 16 bit signed stereo wav @ 44100Hz for a frequency passed as an argument to the program, or 500Hz as default.

A matlab version of the code is here, (modded very slightly for 1 indexing in Matlab, WHY MATHWORKS WHY!?) minus the passing to STDOUT etc as I know that works fine

CHANNELS = 2; SAMPLING_RATE = 44100; NUM_SAMPLES = 512;

frequency = 1000;

%% BEGIN WHILE(1) LOOP HERE

output_buff = zeros(1,CHANNELS*NUM_SAMPLES);

for i = 1:2:CHANNELS*NUM_SAMPLES
output_buff(i) = 30000 * sin(frequency * pi * (i-1)/NUM_SAMPLES);
output_buff(i+1) = output_buff(i);
end

%% OUTPUT TO STDOUT AND REPEAT


I should add that this code runs (in the C version) inside a while true loop, generating a full output_buff of values, then pushing the buffer to STDOUT.

I have written some further testing code to see what's actually being generated as follows:

plot(1:CHANNELS*NUM_SAMPLES, output_buff)

output_buff = output_buff .* hanning(length(output_buff))';
Y = fft(output_buff);
Mag=abs(Y(1:length(output_buff)/2)).^2;
[a,b]=max(Mag);
% Result
SAMPLING_RATE*b/length(output_buff)


When I run this script, I can see at the end the frequency of the generated signal is actually 1.0767e+03Hz... Close but no cigar...

I've tried tweaking some of the parameters but I have no idea what's wrong or how to make the generated frequency more accurate.

The C code is as follows:

#include <sys/types.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <unistd.h>

#define M_PI 3.1415926535897932384626433832795L
#define NUM_CHANNELS 2
#define NUM_SAMPLES 1024
#define SAMPLE_RATE 44100

double frequency = 500.0;

int main(int argc, char *argv[])
{
if (argc >= 2){
frequency = atof(argv[1]);
}

int16_t samples[NUM_CHANNELS * NUM_SAMPLES];
unsigned cbBuffer=sizeof(samples);

while(1){
for (int i = 0; i < cbBuffer; i+=NUM_CHANNELS){
samples[i] = (int16_t) 30000 * sin(frequency * M_PI * (double)i /(double)(NUM_SAMPLES));
samples[i+1] = samples[i];
}

int done=write(STDOUT_FILENO, samples, cbBuffer);
if(done<0){
fprintf(stderr, "%s : Write to stdout failed, error=%s.", argv[0], strerror(errno));
exit(1);
}else if(done!=cbBuffer){
fprintf(stderr, "%s : Could not read requested number of bytes from stream.\n", argv[0]);
}
}

return 0;
}


UPDATE:

I changed the C code as follows and I now get a nice smooth sine wave but the frequency is way too low

int main(int argc, char *argv[])
{
if (argc >= 2){
frequency = atof(argv[1]);
}

int16_t samples[NUM_CHANNELS * NUM_SAMPLES];
unsigned cbBuffer=sizeof(samples);
int counter = 0;

while(1){
for (int i = 0; i < NUM_CHANNELS * NUM_SAMPLES; i+=NUM_CHANNELS){
samples[i] = (int16_t) 3000 * sin(frequency * M_PI * (double)counter /(double)(SAMPLE_RATE));
samples[i+1] = samples[i];
counter++;
}

int done=write(STDOUT_FILENO, samples, cbBuffer);
if(done<0){
fprintf(stderr, "%s : Write to stdout failed, error=%s.", argv[0], strerror(errno));
exit(1);
}else if(done!=cbBuffer){
fprintf(stderr, "%s : Could not read requested number of bytes from stream.\n", argv[0]);
}
}

return 0;
}

• you need to reference the sample rate during sine wave creation. Try x = 30000*sin(frequency*2*pi*(0:NUM_SAMPLES-1)'/SAMPLING_RATE) – Hilmar Feb 5 '14 at 14:26
• Thanks for the advice, however when I do this the end result is a sine wave with a strange sort of buzz noise over the top... Difficult thing to describe in text! – o0rebelious0o Feb 5 '14 at 14:31
• A raw sample generated can be found at sharesend.com/k5nfklyn and played with sox --no-show-progress -t raw -e signed -b 16 -c 2 -r 44100 – o0rebelious0o Feb 5 '14 at 14:36

So I've managed to fix it. My problem was I wasn't properly taking into account the Sampling Rate of the produced raw wav file, and that by using the loop variable, there is a discontinuity for each iteration of the loop.

The final working code is as follows:

#include <sys/types.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <unistd.h>

#define M_PI 3.1415926535897932384626433832795L
#define NUM_CHANNELS 2
#define NUM_SAMPLES 512
#define SAMPLE_RATE 44100

double frequency = 500.0;

int main(int argc, char *argv[])
{
if (argc >= 2){
frequency = atof(argv[1]);
}

int16_t samples[NUM_CHANNELS * NUM_SAMPLES];
unsigned cbBuffer=sizeof(samples);
int counter = 0;

while(1){
for (int i = 0; i < NUM_CHANNELS * NUM_SAMPLES; i+=NUM_CHANNELS){
samples[i] = (int16_t) 3000 * sin(frequency * 2 * M_PI * (double)counter /(double)(SAMPLE_RATE));
samples[i+1] = samples[i];
counter++;
}

int done=write(STDOUT_FILENO, samples, cbBuffer);
if(done<0){
fprintf(stderr, "%s : Write to stdout failed, error=%s.", argv[0], strerror(errno));
exit(1);
}else if(done!=cbBuffer){
fprintf(stderr, "%s : Could not read requested number of bytes from stream.\n", argv[0]);
}
}

return 0;
}

• You could also have used in your original version samples[2*i]=samples[2*i+1]=... to get the index right. If NUM_CHANNELS could ever be different from 2, you would need an inner loop to account for that variability. – Lutz Lehmann Feb 5 '14 at 19:43