#define _USE_MATH_DEFINES

#include <array>
#include <cmath>
#include <fstream>
#include <functional>
#include <iostream>
#include <string>

double square_wave(int i)
{
    return (i < 128) ? 1 : -1;
}

double sawtooth_wave(int i)
{
    return (static_cast<double>(i) - 127.5) / 127.5;
}

double triangle_wave(int i)
{
    if (i > 128)
        i = 256 - i;

    return (static_cast<double>(i) - 64) / 64;
}

double sine_wave(int i)
{
    return std::sin(static_cast<double>(i) / 256 * 2 * M_PI);
}

int main()
{
    std::fstream fs;

    fs.open("waveforms.bin", std::ios::out | std::ios::binary);

    // 4 waveforms of 4K each (16 volumes)
    // so 16K total

    std::array<std::function<double(int)>, 4> funcs = {square_wave, sawtooth_wave, triangle_wave, sine_wave};

    for (auto func : funcs)
    {
        for (int vol {0}; vol != 16; ++vol)
        {
            for (int i {0}; i != 256; ++i)
            {
                auto val = static_cast<uint8_t>(std::round(func(i) * 127.5 * (static_cast<double>(vol) / 15) + 127.5));

                std::cout << "f(" << vol << ", " << i << ") = " << static_cast<int>(val) << '\n';

                fs << val;
            }
        }
    }

    std::cout << "Press a key..." << std::endl;
    std::string s;
    std::cin >> s;
}
