Skip to content

Instantly share code, notes, and snippets.

@nkorth
Last active November 20, 2017 21:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nkorth/f6682895b06373f6320a to your computer and use it in GitHub Desktop.
Save nkorth/f6682895b06373f6320a to your computer and use it in GitHub Desktop.
Wave generator
/*
* Wave generator
* by Nathan Korth
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <getopt.h>
#define PI 3.14159
#define DEFAULT_LENGTH 1
void writeWAV16(int16_t* samples, uint16_t numChannels, uint32_t numSamples, uint32_t sampleRate, FILE* stream){
uint32_t formatChunkSize = 16;
uint32_t dataChunkSize = 4 * numChannels * numSamples;
uint32_t totalChunkSize = 4 + 8 + formatChunkSize + 8 + dataChunkSize;
uint16_t waveFormat = 1; // WAVE_FORMAT_PCM
uint32_t bytesPerSecond = sampleRate * 4 * numChannels;
uint16_t blockAlign = 4 * numChannels;
uint16_t bitsPerSample = 8 * 2;
fputs("RIFF", stream);
fwrite(&totalChunkSize, 4, 1, stream);
fputs("WAVE", stream);
// format chunk
fputs("fmt ", stream);
fwrite(&formatChunkSize, 4, 1, stream);
fwrite(&waveFormat, 2, 1, stream);
fwrite(&numChannels, 2, 1, stream);
fwrite(&sampleRate, 4, 1, stream);
fwrite(&bytesPerSecond, 4, 1, stream);
fwrite(&blockAlign, 2, 1, stream);
fwrite(&bitsPerSample, 2, 1, stream);
// data chunk
fputs("data", stream);
fwrite(&dataChunkSize, 4, 1, stream);
fwrite(samples, sizeof(int16_t), numSamples, stream);
}
void usage(char* invocation){
fprintf(stderr,
"Usage: %s -f FREQUENCY [options] > filename.wav\n"
"Options:\n"
" -f FREQUENCY, --frequency=FREQUENCY Set frequency in Hz.\n"
" -h, --help Print this message and exit.\n"
" -l SECONDS, --length=SECONDS Set length in seconds. (default %d)\n"
" -w NAME, --waveform=NAME Set waveform to sine, saw, or square.\n",
invocation, DEFAULT_LENGTH);
}
double waveform_sine(double t){
return sin(2 * PI * t);
}
double waveform_saw(double t){
double intpart; // discarded
return -1 + 2 * modf(t, &intpart);
}
double waveform_square(double t){
double intpart;
return modf(t, &intpart) > 0.5 ? -1 : 1;
}
int main(int argc, char* argv[]){
int frequency = 0;
int length = DEFAULT_LENGTH;
double (*waveform)(double) = waveform_sine;
static struct option longopts[] = {
{"frequency", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"length", required_argument, NULL, 'l'},
{"waveform", required_argument, NULL, 'w'}
};
char flag;
while((flag = getopt_long(argc, argv, "f:hl:w:", longopts, NULL)) != -1){
switch(flag){
case 'f':
frequency = atoi(optarg);
break;
case 'h':
usage(argv[0]);
return 0;
case 'l':
length = atoi(optarg);
break;
case 'w':
if(strcmp(optarg, "sine") == 0){
waveform = waveform_sine;
} else if(strcmp(optarg, "saw") == 0){
waveform = waveform_saw;
} else if(strcmp(optarg, "square") == 0){
waveform = waveform_square;
} else{
fputs("Unrecognized waveform.\n", stderr);
return 1;
}
break;
}
}
if(frequency == 0 || length == 0){
usage(argv[0]);
return 1;
}
int sampleRate = 44100;
uint32_t numSamples = sampleRate * length;
int16_t samples[numSamples];
for(uint32_t i = 0; i < numSamples; ++i){
double t = ((double) i) / sampleRate * frequency;
double sample_float = waveform(t);
samples[i] = sample_float * INT16_MAX;
}
writeWAV16(samples, 1, numSamples, sampleRate, stdout);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment