scratch/audiovisual/sound_synthesis.c
2024-12-26 14:02:40 -03:00

122 lines
3.5 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
const double PI = 3.141592653589793;
const double SECONDS = 0.5;
const size_t CHANNELS = 1;
const size_t SAMPLE_RATE = 44100;
const size_t BITS_PER_SAMPLE = 16;
const size_t TOTAL_SAMPLES = (SECONDS * CHANNELS * SAMPLE_RATE);
// http://soundfile.sapp.org/doc/WaveFormat/ (https://archive.is/069fj)
struct wav_header
{
char chunk_id[4];
uint32_t chunk_size;
char format[4];
char subchunk_id[4];
uint32_t subchunk1_size;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
char subchunk2_id[4];
uint32_t subchunk2_size;
};
static void *xcalloc(const size_t num, const size_t size)
{
void *ptr = calloc(num, size);
if (ptr == NULL) {
perror("calloc");
exit(1);
}
return ptr;
}
void wav_populate_header(struct wav_header *const wavh, const size_t total_samples, const size_t channels)
{
memcpy(wavh->chunk_id, "RIFF", 4);
memcpy(wavh->format, "WAVE", 4);
memcpy(wavh->subchunk_id, "fmt ", 4);
wavh->chunk_size = (sizeof(struct wav_header) + total_samples) - 8;
wavh->subchunk1_size = 16;
wavh->audio_format = 1;
wavh->num_channels = 1;
wavh->sample_rate = SAMPLE_RATE;
wavh->byte_rate = (SAMPLE_RATE * channels * BITS_PER_SAMPLE) / 8;
wavh->block_align = (channels * BITS_PER_SAMPLE) / 8;
wavh->bits_per_sample = BITS_PER_SAMPLE;
memcpy(wavh->subchunk2_id, "data", 4);
wavh->subchunk2_size = (total_samples * channels * BITS_PER_SAMPLE) / 8;
}
void wav_create_file(const struct wav_header *wavh, FILE *wav_fp, const int16_t *data, const size_t total_samples)
{
fwrite(wavh, sizeof(struct wav_header), 1, wav_fp); // write WAV header to file
fwrite(data, sizeof(int16_t), total_samples, wav_fp); // ...and finally the audio data
}
int16_t sinewave(const size_t time, const size_t sample_rate, const double freq)
{
const double rad = (2 * PI) * (time / (sample_rate / freq)); // get radian frequency
const double t_amplitude = (32767 * 0.9);
return t_amplitude * sin(rad);
}
int16_t squarewave(const size_t time, const size_t sample_rate, const double freq)
{
const double t_amplitude = (32767 * 0.9);
const size_t period = (sample_rate / freq);
if ((time % period) < (period / 2))
return t_amplitude;
return 0;
//const double rad = (2 * PI) * (time / (sample_rate / freq)); // get radian frequency
//return ((sin(rad) >= 0) ? t_amplitude : 0); // -1 * t_amplitude for peak to peak amp.
//32767 * (2 * fabs(2 * (((time / period) - floor((time / period) + (1 / 2)))) ) * -1);
}
int16_t trianglewave(const size_t time, const size_t sample_rate, const double freq)
{
// a triangle wave can be expressed in terms of sine and arcsine
const double t_amplitude = (32767 * 0.9);
const double period = sin((2 * PI) * (time / (sample_rate / freq)));
return (2 * t_amplitude / PI) * asin(period);
}
int main(int argc, char **argv)
{
FILE *fp = stdout;
if (argc > 1) {
if ((fp = fopen(argv[1], "wb")) == NULL) {
perror("fopen");
return 1;
}
}
int16_t buffer[TOTAL_SAMPLES];
const double freq = 220;
for (int i = 0; i < TOTAL_SAMPLES; ++i) {
buffer[i] = sinewave(i, SAMPLE_RATE, freq);
//buffer[i] = squarewave(i, SAMPLE_RATE, freq);
//buffer[i] = trianglewave(i, SAMPLE_RATE, freq);
}
struct wav_header *wavh = xcalloc(1, sizeof(struct wav_header));
wav_populate_header(wavh, TOTAL_SAMPLES, CHANNELS);
wav_create_file(wavh, fp, buffer, TOTAL_SAMPLES);
free(wavh);
fclose(fp);
return 0;
}