Deluge Firmware 1.3.0
Build date: 2025.06.05
Loading...
Searching...
No Matches
util.hpp
1/*
2 * Copyright © 2015-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19#include "deluge/util/fixedpoint.h"
20#include "deluge/util/functions.h"
21#include "dsp/stereo_sample.h"
22#include <cmath>
23#include <span>
24
25namespace deluge::dsp {
29constexpr q31_t FOLD_MIN = 0.1 * ONE_Q31;
30constexpr q31_t THREE_FOURTHS = 0.75 * ONE_Q31;
31inline q31_t fold(q31_t input, q31_t level) {
32 // no folding occurs if max is 0 or if max is greater than input
33 // to keep the knob range consistent fold starts from 0 and
34 // increases, decreasing would lead to a large deadspace until
35 // suddenly clipping occured
36 // note 9db loss
37 q31_t extra = 0;
38 q31_t max = level >> 8;
39 if (input > max) {
40 extra = input - max;
41 }
42 else if (input < -max) {
43 extra = input + max;
44 }
45 // this avoids inverting the wave
46 return 2 * extra - input;
47}
52inline q31_t polynomialOscillatorApproximation(q31_t x) {
53 // requires 1 to be ONE_Q31
54
55 q31_t x2 = 2 * multiply_32x32_rshift32(x, x);
56 q31_t x3 = 2 * multiply_32x32_rshift32(x2, x);
57 // this is 4(3*x/4 - x^3) which is a nice shape
58 q31_t r1 = 8 * (multiply_32x32_rshift32(THREE_FOURTHS, x) - x3);
59
60 q31_t r2 = 2 * multiply_32x32_rshift32(r1, r1);
61 q31_t r3 = 2 * multiply_32x32_rshift32(r2, r1);
62 // at this point we've applied the polynomial twice
63 q31_t out = 8 * (multiply_32x32_rshift32(THREE_FOURTHS, r1) - r3);
64
65 return out;
66}
67
68inline void foldBufferPolyApproximation(std::span<q31_t> buffer, q31_t level) {
69 q31_t fold_level = add_saturate(level, FOLD_MIN);
70 for (auto& sample : buffer) {
71 q31_t x = lshiftAndSaturateUnknown(multiply_32x32_rshift32(fold_level, sample), 8);
72 // volume compensation
73 sample = polynomialOscillatorApproximation(x) >> 7;
74 }
75}
76
77inline void foldBufferPolyApproximation(std::span<StereoSample> buffer, q31_t level) {
78 foldBufferPolyApproximation(std::span<q31_t>{reinterpret_cast<q31_t*>(buffer.data()), buffer.size() * 2}, level);
79}
80
84inline void foldBuffer(std::span<q31_t> buffer, q31_t foldLevel) {
85 for (auto& sample : buffer) {
86 auto out = fold(sample, foldLevel);
87 // volume compensation
88 sample = out + 4 * multiply_32x32_rshift32(out, foldLevel);
89 }
90}
91} // namespace deluge::dsp