So, I have been trying to make a WAV format file from scratch in C. The thing is, I can't wrap my head around as to why the sine tone is this noisy (see the screenshot below). I thought there's something wrong with my sine generating sequence, but I have seen a video in YouTube (https://www.youtube.com/watch?v=qqjvB_VxMRM) where the guy does exactly what I did and got a decent sine wave.
Here's the code:
int main() {
FILE *fptr;
char path[] ="sin400.wav";
fptr =fopen(path, "r+"); // Open the file
if (fptr == NULL) {
fclose(fptr);
printf("Creating new file %s\n", path);
fptr = fopen(path, "w+");
}
HEADER_t header={"RIFF", chunkSize, "WAVE"};
FMT_t format = { "fmt ", 16, 1, CHANNELS, SAMPLE_RATE, BYTE_RATE, BLOCK_ALIGN, 8 * bytes_per_sample };
fwrite(&header, sizeof(header), 1, fptr);
printf("test1\n");
fwrite(&format, sizeof(format), 1, fptr);
printf("test2\n");
// ==== Data ====
float amp = 0.5 * 32767;
int bufSize = SAMPLE_RATE * DURATION;
float T = (2.0 * M_PI) * freq / SAMPLE_RATE;
float angle = 0;
short buf[SAMPLE_RATE * DURATION];
printf("T: %f\n", T);
// Storing the sine wave to *buf
// Generating sine
for (int i = 0; i < bufSize; i++) {
buf[i] = (amp * sin(angle));
angle += T;
}
fclose(test);
DATA_t data = { "data", SUBCHUNK2_size, buf};
fwrite(&data, sizeof(data), 1, fptr); // Writing the data to the file
fclose(fptr); // Close the file
}
The structures:
// ======== Structures ========
// RIFF Header
typedef struct HEADER_s{
char chunkID[4];
uint32_t chunkSize;
char format[4];
}HEADER_t;
// FMT (Format) Subchunk
typedef struct FMT_s{
char subChunk1ID[4];
uint32_t subChunk1Size;
uint16_t format;
uint16_t channel;
uint32_t smplRate;
uint32_t byteRate;
uint16_t blockAlign;
uint16_t bitsPerSample;
}FMT_t;
// Data Subchunk
typedef struct DATA_s{
char subChunk2ID[4];
uint32_t subChunk2Size;
uint16_t *data;
}DATA_t;
Constants defined:
#define M_PI 3.14159265358979323846
const float freq = 440.f;
#define SUBCHUNK1_size 16 // It is 16 bytes for PCM
#define DURATION 2 // Duration of the audio in seconds
#define SAMPLE_RATE 44100 // This rate determines the quality of the sound, unit: Hz (44100 Hz is the sampling rate in CD)
#define CHANNELS 1 // Mono
#define bytes_per_sample 2 // It is 2 for PCM
#define SUBCHUNK2_size DURATION*SAMPLE_RATE*CHANNELS*bytes_per_sample
#define BYTE_RATE SAMPLE_RATE*CHANNELS*bytes_per_sample
#define BLOCK_ALIGN CHANNELS*bytes_per_sample
const int chunkSize=4+(8+SUBCHUNK1_size)+(8+SUBCHUNK2_size);
I have used (amp * sin(angle)) to get the sine values. Angle is offset in every iteration by T: angle += T
where T = (2 * M_PI) * freq / SAMPLE_RATE
The output waveform is:

I have no idea why this is happening. The wave is immaculate for certain sample ranges, and goes haywire everywhere else. :(
Now that I reviewed your comment about testing out the YouTube program and the "wav" file it created, I thought I would share the code version I derived from reviewing the C++ code, utilizing your code above. I did not have the information on your structures, so I decided to simplify things as the layout of the "wav" file is basically, header information followed by the data portion (in this case a sine wave).
Instead of structures, I just used string functionality to keep things simple. When I listened to the "wav" files created by both the YouTube C++ program and the C program I concocted, they sounded the same to my ear (I don't Audacity). When I compared the raw byte data in the two files, again they matched up.
The "waveform.wav" file was the YouTube file and "sin400.wav" was the file generated by the C program.
Go ahead and give that a try and see if it meets the spirit of your project.