Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Created April 5, 2018 03:28
Show Gist options
  • Save MCJack123/02ef260f5a742dca7df2d902ce05c7ec to your computer and use it in GitHub Desktop.
Save MCJack123/02ef260f5a742dca7df2d902ce05c7ec to your computer and use it in GitHub Desktop.
Equation to WAV converter (requires exprtk)
#include <iostream>
#include <fstream>
#include <string>
#include <cstdint>
#include "exprtk.hpp"
typedef struct {
char sGroupID[4];
uint32_t dwFileLength;
char sRiffType[4];
} wav_header_t;
typedef struct {
char sGroupID[4];
uint32_t dwChunkSize;
uint16_t wFormatTag;
uint16_t wChannels;
uint32_t dwSamplesPerSec;
uint32_t dwAvgBytesPerSec;
uint16_t wBlockAlign;
uint16_t dwBitsPerSample;
} wav_fmt_t;
typedef struct {
char sGroupID[4];
uint32_t dwChunkSize;
int16_t * sampleData;
} wav_data_t;
typedef struct {
int size;
char * data;
} wav_t;
int length = 15;
int samplerate = 44100;
double x = 0.0;
double y;
wav_header_t wav_header;
wav_fmt_t wav_format;
wav_data_t wav_data;
double cutoff(double num) {
if (num > 1.0) return 1.0;
else if (num < -1.0) return -1.0;
else return num;
}
void pushValue(char * a, uint16_t data, int off) {
//std::cout << "Pushing value " << data << " at offset " << off << "\n";
*((uint16_t*)(&a[off])) = data;
}
void pushValue(char * a, uint32_t data, int off) {
//std::cout << "Pushing value " << data << " at offset " << off << "\n";
*((uint32_t*)(&a[off])) = data;
}
void pushArray(char * a, int16_t data[], int length, int off) {
//std::cout << "Pushing array at offset " << off << "\n";
for (int i = 0; i < length; i++) {
//std::cout << i << " to offset " << off+(i*2) << "\n";
*((int16_t*)(&a[off+(i*2)])) = data[i];
}
}
void pushString(char * a, char * data, int off) {
//std::cout << "Pushing string " << data << " at offset " << off << "\n";
for (int i = 0; i < 4; i++) {
*(&a[off+i]) = data[i];
}
}
wav_t prepareWav(wav_header_t header, wav_fmt_t format, wav_data_t datav) {
wav_t wave;
wave.size = header.dwFileLength + 8;
char * data = (char*)malloc(wave.size);
//std::cout << wave.size << "\n";
pushString(data, header.sGroupID, 0);
pushValue(data, header.dwFileLength, 4);
pushString(data, header.sRiffType, 8);
pushString(data, format.sGroupID, 12);
pushValue(data, format.dwChunkSize, 16);
pushValue(data, format.wFormatTag, 20);
pushValue(data, format.wChannels, 22);
pushValue(data, format.dwSamplesPerSec, 24);
pushValue(data, format.dwAvgBytesPerSec, 28);
pushValue(data, format.wBlockAlign, 32);
pushValue(data, format.dwBitsPerSample, 34);
pushString(data, datav.sGroupID, 36);
pushValue(data, datav.dwChunkSize, 40);
pushArray(data, datav.sampleData, datav.dwChunkSize / 2, 44);
wave.data = data;
return wave;
}
int main(int argc, const char * argv[]) {
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <file.wav> [-t time] [-s samplerate]\n";
return 1;
}
std::cout << "Enter an equation (example: \"y := sin(440 * x)\"): ";
std::string equation;
std::getline(std::cin, equation);
for (int i = 2; i < argc; i++) {
if (std::string(argv[i]) == "-t") {
length = std::stoi(std::string(argv[i]));
} else if (std::string(argv[i]) == "-s") {
samplerate = std::stoi(std::string(argv[i]));
}
}
int samplenum = samplerate * length;
int16_t * samples = (int16_t*)malloc(samplenum*2);
double sampletable[samplenum];
// Calculate samples
std::cout << "Calculating...\n";
exprtk::symbol_table<double> symbol_table;
symbol_table.add_variable("x", x);
symbol_table.add_variable("y", y);
exprtk::expression<double> expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<double> parser;
parser.compile(equation, expression);
//std::cout << "Getting values...\n";
double greatest = 0.0;
for (int i = 0; i < samplenum; i++) {
//std::cout << x;
//std::cout.flush();
x = (M_PI / samplerate) * i * (440 / 217);
y = expression.value();
//std::cout << " = " << y << " = " << (cutoff(y) * 32767) << "\n";
sampletable[i] = y;
if (y > greatest) greatest = y;
}
//std::cout << "Reducing...\n";
for (int i = 0; i < samplenum; i++) {
samples[i] = (int16_t)(cutoff(sampletable[i] / greatest) * 32767);
}
// Write WAV
std::cout << "Creating WAV...\n";
memcpy(wav_header.sGroupID, "RIFF", 4);
memcpy(wav_header.sRiffType, "WAVE", 4);
memcpy(wav_format.sGroupID, "fmt ", 4);
wav_format.dwChunkSize = 16;
wav_format.wFormatTag = 1;
wav_format.wChannels = 1;
wav_format.dwSamplesPerSec = samplerate;
wav_format.dwBitsPerSample = 16;
wav_format.wBlockAlign = wav_format.wChannels * (wav_format.dwBitsPerSample / 8);
wav_format.dwAvgBytesPerSec = wav_format.dwSamplesPerSec * wav_format.wBlockAlign;
memcpy(wav_data.sGroupID, "data", 4);
wav_data.dwChunkSize = samplenum * 2;
wav_data.sampleData = samples;
wav_header.dwFileLength = wav_format.dwChunkSize + 16 + wav_data.dwChunkSize;
//std::cout << "Writing WAV...\n";
wav_t waveout = prepareWav(wav_header, wav_format, wav_data);
//std::cout << waveout.size << "\n";
std::ofstream out;
out.open(argv[1]);
out.write(waveout.data, waveout.size);
out.close();
std::cout << "Written to " << argv[1] << "\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment