aboutsummaryrefslogtreecommitdiffstats
path: root/source/device_formula.cpp
blob: a70f4652ca60f3b3834ecd72d7ae0450be548c53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * @file device_formula.cpp
 * @brief Function for filling generator buffer using a mathematical formula.
 * This is kept in its own file as exprtk.hpp takes forever to compile.
 *
 * Copyright (C) 2021 Clyne Sullivan
 *
 * Distributed under the GNU GPL v3 or later. You should have received a copy of
 * the GNU General Public License along with this program.
 * If not, see <https://www.gnu.org/licenses/>.
 */

#include "stmdsp.hpp"
#include "exprtk.hpp"

#include <algorithm>
#include <random>
#include <string_view>
#include <vector>

static std::random_device randomDevice;

std::vector<stmdsp::dacsample_t> deviceGenLoadFormulaEval(const std::string& formulaString)
{
    double x = 0;

    exprtk::symbol_table<double> symbol_table;
    exprtk::function_compositor<double> compositor (symbol_table);
    exprtk::expression<double> expression;
    exprtk::parser<double> parser;

    symbol_table.add_constants();
    symbol_table.add_variable("x", x);
    symbol_table.add_function("random",
        [](double l, double h) -> double {
            return std::uniform_real_distribution<double>(l, h)(randomDevice);
        });
    compositor.add(exprtk::function_compositor<double>::function()
                       .name("square")
                       .var("X")
                       .expression("ceil(sin(pi*X))"));
    compositor.add(exprtk::function_compositor<double>::function()
                       .name("triangle")
                       .var("X")
                       .expression("ceil(sin(pi*X))*(X-floor(X))+ceil(-sin(pi*X))*(-X-floor(-X))"));
    compositor.add(exprtk::function_compositor<double>::function()
                       .name("pulse")
                       .var("L")
                       .var("X")
                       .expression("if(X<=L,1,0)"));
    expression.register_symbol_table(symbol_table);
    parser.compile(formulaString, expression);

    const auto genFun = [&x, &expression] {
        const auto s = std::clamp(expression.value(), -1., 1.) * 2048. + 2048.;
        ++x;
        return static_cast<stmdsp::dacsample_t>(std::min(s, 4095.));
    };

    std::vector<stmdsp::dacsample_t> samples (stmdsp::SAMPLES_MAX);
    std::generate(samples.begin(), samples.end(), genFun);
    return samples;
}