add license headers
This commit is contained in:
63
clip/clip.h
63
clip/clip.h
@@ -1,9 +1,40 @@
|
||||
/*
|
||||
* clip.h
|
||||
* Copyright (c) 2016 Chris Johnson
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
* Based on ClipOnly2 by Chris Johnson, 2016
|
||||
* This file is a derivative of the above module.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Changes:
|
||||
* - 2025-11-06 Christopher Herb:
|
||||
* - Templated audio buffer i/o
|
||||
* - Converted to procedural programming style
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace trnr {
|
||||
// clipper based on ClipOnly2 by Chris Johnson (MIT License)
|
||||
struct clip {
|
||||
double samplerate;
|
||||
|
||||
@@ -36,7 +67,8 @@ inline void clip_init(clip& c, double _samplerate)
|
||||
}
|
||||
|
||||
template <typename t_sample>
|
||||
inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, long sample_frames)
|
||||
inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs,
|
||||
long sample_frames)
|
||||
{
|
||||
t_sample* in1 = inputs[0];
|
||||
t_sample* in2 = inputs[1];
|
||||
@@ -47,7 +79,8 @@ inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, l
|
||||
overallscale /= 44100.0;
|
||||
overallscale *= c.samplerate;
|
||||
|
||||
int spacing = floor(overallscale); // should give us working basic scaling, usually 2 or 4
|
||||
int spacing =
|
||||
floor(overallscale); // should give us working basic scaling, usually 2 or 4
|
||||
if (spacing < 1) spacing = 1;
|
||||
if (spacing > 16) spacing = 16;
|
||||
|
||||
@@ -55,11 +88,13 @@ inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, l
|
||||
double input_l = *in1;
|
||||
double input_r = *in2;
|
||||
|
||||
// begin ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
|
||||
// begin ClipOnly2 stereo as a little, compressed chunk that can be dropped into
|
||||
// code
|
||||
if (input_l > 4.0) input_l = 4.0;
|
||||
if (input_l < -4.0) input_l = -4.0;
|
||||
if (c.was_pos_clip_l == true) { // current will be over
|
||||
if (input_l < c.last_sample_l) c.last_sample_l = 0.7058208 + (input_l * 0.2609148);
|
||||
if (input_l < c.last_sample_l)
|
||||
c.last_sample_l = 0.7058208 + (input_l * 0.2609148);
|
||||
else c.last_sample_l = 0.2491717 + (c.last_sample_l * 0.7390851);
|
||||
}
|
||||
c.was_pos_clip_l = false;
|
||||
@@ -68,7 +103,8 @@ inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, l
|
||||
input_l = 0.7058208 + (c.last_sample_l * 0.2609148);
|
||||
}
|
||||
if (c.was_neg_clip_l == true) { // current will be -over
|
||||
if (input_l > c.last_sample_l) c.last_sample_l = -0.7058208 + (input_l * 0.2609148);
|
||||
if (input_l > c.last_sample_l)
|
||||
c.last_sample_l = -0.7058208 + (input_l * 0.2609148);
|
||||
else c.last_sample_l = -0.2491717 + (c.last_sample_l * 0.7390851);
|
||||
}
|
||||
c.was_neg_clip_l = false;
|
||||
@@ -77,14 +113,16 @@ inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, l
|
||||
input_l = -0.7058208 + (c.last_sample_l * 0.2609148);
|
||||
}
|
||||
c.intermediate_l[spacing] = input_l;
|
||||
input_l = c.last_sample_l; // Latency is however many samples equals one 44.1k sample
|
||||
input_l =
|
||||
c.last_sample_l; // Latency is however many samples equals one 44.1k sample
|
||||
for (int x = spacing; x > 0; x--) c.intermediate_l[x - 1] = c.intermediate_l[x];
|
||||
c.last_sample_l = c.intermediate_l[0]; // run a little buffer to handle this
|
||||
|
||||
if (input_r > 4.0) input_r = 4.0;
|
||||
if (input_r < -4.0) input_r = -4.0;
|
||||
if (c.was_pos_clip_r == true) { // current will be over
|
||||
if (input_r < c.last_sample_r) c.last_sample_r = 0.7058208 + (input_r * 0.2609148);
|
||||
if (input_r < c.last_sample_r)
|
||||
c.last_sample_r = 0.7058208 + (input_r * 0.2609148);
|
||||
else c.last_sample_r = 0.2491717 + (c.last_sample_r * 0.7390851);
|
||||
}
|
||||
c.was_pos_clip_r = false;
|
||||
@@ -93,7 +131,8 @@ inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, l
|
||||
input_r = 0.7058208 + (c.last_sample_r * 0.2609148);
|
||||
}
|
||||
if (c.was_neg_clip_r == true) { // current will be -over
|
||||
if (input_r > c.last_sample_r) c.last_sample_r = -0.7058208 + (input_r * 0.2609148);
|
||||
if (input_r > c.last_sample_r)
|
||||
c.last_sample_r = -0.7058208 + (input_r * 0.2609148);
|
||||
else c.last_sample_r = -0.2491717 + (c.last_sample_r * 0.7390851);
|
||||
}
|
||||
c.was_neg_clip_r = false;
|
||||
@@ -102,10 +141,12 @@ inline void clip_process_block(clip& c, t_sample** inputs, t_sample** outputs, l
|
||||
input_r = -0.7058208 + (c.last_sample_r * 0.2609148);
|
||||
}
|
||||
c.intermediate_r[spacing] = input_r;
|
||||
input_r = c.last_sample_r; // Latency is however many samples equals one 44.1k sample
|
||||
input_r =
|
||||
c.last_sample_r; // Latency is however many samples equals one 44.1k sample
|
||||
for (int x = spacing; x > 0; x--) c.intermediate_r[x - 1] = c.intermediate_r[x];
|
||||
c.last_sample_r = c.intermediate_r[0]; // run a little buffer to handle this
|
||||
// end ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
|
||||
// end ClipOnly2 stereo as a little, compressed chunk that can be dropped into
|
||||
// code
|
||||
|
||||
*out1 = input_l;
|
||||
*out2 = input_r;
|
||||
|
||||
23
clip/fold.h
23
clip/fold.h
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* fold.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace trnr {
|
||||
|
||||
57
clip/tube.h
57
clip/tube.h
@@ -1,11 +1,45 @@
|
||||
/*
|
||||
* tube.h
|
||||
* Copyright (c) 2016 Chris Johnson
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
* Based on Tube2 by Chris Johnson, 2016
|
||||
* This file is a derivative/major refactor of the above module.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Changes:
|
||||
* - 2025-11-06 Christopher Herb:
|
||||
* - Templated audio buffer i/o
|
||||
* - Converted to procedural programming style
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace trnr {
|
||||
// modeled tube preamp based on tube2 by Chris Johnson (MIT License)
|
||||
|
||||
struct tube {
|
||||
double samplerate;
|
||||
|
||||
@@ -22,9 +56,9 @@ struct tube {
|
||||
float input_vol;
|
||||
float tube_amt;
|
||||
|
||||
void set_input(double value) { input_vol = std::clamp(value, 0.0, 1.0); }
|
||||
void set_input(double value) { input_vol = clamp(value, 0.0, 1.0); }
|
||||
|
||||
void set_tube(double value) { tube_amt = std::clamp(value, 0.0, 1.0); }
|
||||
void set_tube(double value) { tube_amt = clamp(value, 0.0, 1.0); }
|
||||
};
|
||||
|
||||
inline void tube_init(tube& t, double samplerate)
|
||||
@@ -46,7 +80,8 @@ inline void tube_init(tube& t, double samplerate)
|
||||
}
|
||||
|
||||
template <typename t_sample>
|
||||
inline void tube_process_block(tube& t, t_sample** inputs, t_sample** outputs, long sampleframes)
|
||||
inline void tube_process_block(tube& t, t_sample** inputs, t_sample** outputs,
|
||||
long sampleframes)
|
||||
{
|
||||
t_sample* in1 = inputs[0];
|
||||
t_sample* in2 = inputs[1];
|
||||
@@ -114,13 +149,15 @@ inline void tube_process_block(tube& t, t_sample** inputs, t_sample** outputs, l
|
||||
// original Tube algorithm: powerfactor widens the more linear region of the wave
|
||||
double factor = input_l; // Left channel
|
||||
for (int x = 0; x < powerfactor; x++) factor *= input_l;
|
||||
if ((powerfactor % 2 == 1) && (input_l != 0.0)) factor = (factor / input_l) * fabs(input_l);
|
||||
if ((powerfactor % 2 == 1) && (input_l != 0.0))
|
||||
factor = (factor / input_l) * fabs(input_l);
|
||||
factor *= gainscaling;
|
||||
input_l -= factor;
|
||||
input_l *= outputscaling;
|
||||
factor = input_r; // Right channel
|
||||
for (int x = 0; x < powerfactor; x++) factor *= input_r;
|
||||
if ((powerfactor % 2 == 1) && (input_r != 0.0)) factor = (factor / input_r) * fabs(input_r);
|
||||
if ((powerfactor % 2 == 1) && (input_r != 0.0))
|
||||
factor = (factor / input_r) * fabs(input_r);
|
||||
factor *= gainscaling;
|
||||
input_r -= factor;
|
||||
input_r *= outputscaling;
|
||||
@@ -174,13 +211,13 @@ inline void tube_process_block(tube& t, t_sample** inputs, t_sample** outputs, l
|
||||
t.fdp_l ^= t.fdp_l << 13;
|
||||
t.fdp_l ^= t.fdp_l >> 17;
|
||||
t.fdp_l ^= t.fdp_l << 5;
|
||||
// inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
|
||||
// frexp((double)inputSampleR, &expon);
|
||||
// inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l *
|
||||
// pow(2,expon+62)); frexp((double)inputSampleR, &expon);
|
||||
t.fdp_r ^= t.fdp_r << 13;
|
||||
t.fdp_r ^= t.fdp_r >> 17;
|
||||
t.fdp_r ^= t.fdp_r << 5;
|
||||
// inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
|
||||
// end 64 bit stereo floating point dither
|
||||
// inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l *
|
||||
// pow(2,expon+62)); end 64 bit stereo floating point dither
|
||||
|
||||
*out1 = input_l;
|
||||
*out2 = input_r;
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* fold.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
@@ -15,7 +38,8 @@ inline float alaw_encode(float input)
|
||||
if (abs_sample < (1.0f / A_LAW_A)) {
|
||||
output = sign * (A_LAW_A * abs_sample) / (1.0f + std::log(A_LAW_A));
|
||||
} else {
|
||||
output = sign * (1.0f + std::log(A_LAW_A * abs_sample)) / (1.0f + std::log(A_LAW_A));
|
||||
output =
|
||||
sign * (1.0f + std::log(A_LAW_A * abs_sample)) / (1.0f + std::log(A_LAW_A));
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
/*
|
||||
* oneknob.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "audio_math.h"
|
||||
|
||||
#include "../util/audio_math.h"
|
||||
#include "rms_detector.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -80,11 +104,13 @@ inline void oneknob_process_block(oneknob_comp& c, sample** audio, int frames)
|
||||
|
||||
// attack
|
||||
if (envelope_in > c.envelope_level) {
|
||||
c.envelope_level = envelope_in + c.attack_coef * (c.envelope_level - envelope_in);
|
||||
c.envelope_level =
|
||||
envelope_in + c.attack_coef * (c.envelope_level - envelope_in);
|
||||
}
|
||||
// release
|
||||
else {
|
||||
c.envelope_level = envelope_in + c.release_coef * (c.envelope_level - envelope_in);
|
||||
c.envelope_level =
|
||||
envelope_in + c.release_coef * (c.envelope_level - envelope_in);
|
||||
}
|
||||
|
||||
float x = c.envelope_level;
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
/*
|
||||
* pump.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio_math.h"
|
||||
#include "../util/audio_math.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace trnr {
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
/*
|
||||
* rms_detector.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace trnr {
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
/*
|
||||
* chebyshev.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <array>
|
||||
#include <math.h>
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
/*
|
||||
* spliteq.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "audio_math.h"
|
||||
#include "smoother.h"
|
||||
|
||||
#include "../util/audio_math.h"
|
||||
#include "../util/smoother.h"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
@@ -21,7 +45,8 @@ struct cascade_filter {
|
||||
std::vector<double> state; // State per stage
|
||||
};
|
||||
|
||||
inline void cascade_filter_setup(cascade_filter& f, filter_type _type, int _stages, double _cutoff, double _samplerate)
|
||||
inline void cascade_filter_setup(cascade_filter& f, filter_type _type, int _stages,
|
||||
double _cutoff, double _samplerate)
|
||||
{
|
||||
f.type = _type;
|
||||
f.stages = _stages;
|
||||
@@ -119,7 +144,8 @@ struct aw_filter {
|
||||
double samplerate;
|
||||
};
|
||||
|
||||
inline void aw_filter_init(aw_filter& f, filter_type type, float amount, double samplerate)
|
||||
inline void aw_filter_init(aw_filter& f, filter_type type, float amount,
|
||||
double samplerate)
|
||||
{
|
||||
f.type = type;
|
||||
f.amount = amount;
|
||||
@@ -269,7 +295,8 @@ struct spliteq {
|
||||
smoother transition_smoother;
|
||||
};
|
||||
|
||||
inline void spliteq_init(spliteq& eq, double samplerate, double low_mid_crossover, double mid_high_crossover)
|
||||
inline void spliteq_init(spliteq& eq, double samplerate, double low_mid_crossover,
|
||||
double mid_high_crossover)
|
||||
{
|
||||
low_mid_crossover /= 2.0;
|
||||
mid_high_crossover /= 2.0;
|
||||
@@ -495,8 +522,9 @@ inline void spliteq_process_block(spliteq& eq, float** audio, int frames)
|
||||
aw_filter_process_block(eq.lp_r, audio[1], frames);
|
||||
}
|
||||
|
||||
inline void spliteq_update(spliteq& eq, double hp_freq, double lp_freq, double low_mid_crossover,
|
||||
double mid_high_crossover, double bass_gain, double mid_gain, double treble_gain)
|
||||
inline void spliteq_update(spliteq& eq, double hp_freq, double lp_freq,
|
||||
double low_mid_crossover, double mid_high_crossover,
|
||||
double bass_gain, double mid_gain, double treble_gain)
|
||||
{
|
||||
low_mid_crossover /= 2.0;
|
||||
mid_high_crossover /= 2.0;
|
||||
@@ -534,8 +562,10 @@ inline void spliteq_update(spliteq& eq, double hp_freq, double lp_freq, double l
|
||||
|
||||
cascade_filter_setup(eq.bass_l, LOWPASS, 2, eq.low_mid_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.bass_r, LOWPASS, 2, eq.low_mid_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.treble_l, HIGHPASS, 2, eq.mid_high_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.treble_r, HIGHPASS, 2, eq.mid_high_crossover_adj, eq.samplerate);
|
||||
cascade_filter_setup(eq.treble_l, HIGHPASS, 2, eq.mid_high_crossover_adj,
|
||||
eq.samplerate);
|
||||
cascade_filter_setup(eq.treble_r, HIGHPASS, 2, eq.mid_high_crossover_adj,
|
||||
eq.samplerate);
|
||||
|
||||
eq.bass1_l.cutoff = low_mid_crossover;
|
||||
butterworth_biquad_coeffs(eq.bass1_l, eq.samplerate);
|
||||
@@ -574,9 +604,10 @@ inline void spliteq_update(spliteq& eq, double hp_freq, double lp_freq, double l
|
||||
butterworth_biquad_coeffs(eq.treble2_r, eq.samplerate);
|
||||
}
|
||||
|
||||
inline void spliteq_update(spliteq& eq, double bass_gain, double mid_gain, double treble_gain)
|
||||
inline void spliteq_update(spliteq& eq, double bass_gain, double mid_gain,
|
||||
double treble_gain)
|
||||
{
|
||||
trnr::spliteq_update(eq, eq.hp_l.amount, eq.lp_l.amount, eq.low_mid_crossover * 2.0, eq.mid_high_crossover * 2.0,
|
||||
bass_gain, mid_gain, treble_gain);
|
||||
trnr::spliteq_update(eq, eq.hp_l.amount, eq.lp_l.amount, eq.low_mid_crossover * 2.0,
|
||||
eq.mid_high_crossover * 2.0, bass_gain, mid_gain, treble_gain);
|
||||
}
|
||||
} // namespace trnr
|
||||
|
||||
@@ -1,3 +1,39 @@
|
||||
/*
|
||||
* ysfv.h
|
||||
* Copyright (c) 2016 Chris Johnson
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
* Based on work:
|
||||
* - YLowpass by Chris Johnson, 2016
|
||||
* - YHighpass by Chris Johnson, 2016
|
||||
* - YBandpass by Chris Johnson, 2016
|
||||
* - YNotch by Chris Johnson, 2016
|
||||
* This file is a derivative/major refactor consolidating the above modules.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Changes:
|
||||
* - 2025-11-06 Christopher Herb:
|
||||
* - Consolidated YLowpass, YHighpass, YBandpass, YNotch into one (state-variable) filter
|
||||
* - Templated audio buffer i/o
|
||||
* - Converted to procedural programming style
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
@@ -36,7 +72,7 @@ enum {
|
||||
Y_BIQ_S_R1,
|
||||
Y_BIQ_S_R2,
|
||||
Y_BIQ_TOTAL
|
||||
}; // coefnncient interpolating biquad filter, stereo
|
||||
};
|
||||
|
||||
enum {
|
||||
Y_FIX_FREQ,
|
||||
@@ -51,7 +87,7 @@ enum {
|
||||
Y_FIX_S_R1,
|
||||
Y_FIX_S_R2,
|
||||
Y_FIX_TOTAL
|
||||
}; // fixed frequency biquad filter for ultrasonics, stereo
|
||||
};
|
||||
|
||||
/////////////
|
||||
// LOWPASS //
|
||||
@@ -1104,7 +1140,7 @@ inline void ysvf_set_param(ysvf& y, ysvf_parameters param, float value)
|
||||
}
|
||||
|
||||
template <typename t_sample>
|
||||
inline void y_process_samples(ysvf& y, t_sample** inputs, t_sample** outputs,
|
||||
inline void ysvf_process_samples(ysvf& y, t_sample** inputs, t_sample** outputs,
|
||||
int block_size)
|
||||
{
|
||||
switch (y.filter_type) {
|
||||
|
||||
31
gfx/dice.h
31
gfx/dice.h
@@ -1,4 +1,28 @@
|
||||
/*
|
||||
* dice.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
using namespace std;
|
||||
@@ -28,6 +52,7 @@ struct dice {
|
||||
array<quad, 6> segments_left;
|
||||
};
|
||||
|
||||
// caclulates coordinates for an isometric dice control with bar segments
|
||||
inline void dice_init(dice& d, float width, float height)
|
||||
{
|
||||
const float shortening = 0.866f;
|
||||
@@ -66,7 +91,8 @@ inline void dice_init(dice& d, float width, float height)
|
||||
|
||||
// calculate segments of the left face
|
||||
for (int i = 0; i < d.segments_left.size(); i++) {
|
||||
const point base_p1 = point {mid_x - face_width + pad_x, face_half_height + pad_y};
|
||||
const point base_p1 =
|
||||
point {mid_x - face_width + pad_x, face_half_height + pad_y};
|
||||
const point base_p2 = point {mid_x - pad_x, face_height};
|
||||
float seg_y = i * (segment_height + gap_height);
|
||||
point p1 = {base_p1.x, base_p1.y + seg_y};
|
||||
@@ -80,7 +106,8 @@ inline void dice_init(dice& d, float width, float height)
|
||||
// correct center of the diamond face
|
||||
// the diamond spans from b_p1 (top) to the middle of the left face
|
||||
float diamond_center_x = mid_x;
|
||||
float diamond_center_y = face_half_height / 2.0f + face_half_height / 2.0f; // move down to actual center
|
||||
float diamond_center_y =
|
||||
face_half_height / 2.0f + face_half_height / 2.0f; // move down to actual center
|
||||
|
||||
// for 30-degree isometric, the grid directions are:
|
||||
float cos30 = 1.f; // cos(30°) = √3/2 ≈ 0.866
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* oversampler.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* combine_seq.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "simple_seq.h"
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* simple_seq.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
152
synth/triplex.h
152
synth/triplex.h
@@ -1,6 +1,30 @@
|
||||
/*
|
||||
* triplex.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "audio_buffer.h"
|
||||
#include "audio_math.h"
|
||||
|
||||
#include "../util/audio_buffer.h"
|
||||
#include "../util/audio_math.h"
|
||||
#include "voice_allocator.h"
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
@@ -45,7 +69,8 @@ inline float tx_wrap(float& phase)
|
||||
return phase;
|
||||
}
|
||||
|
||||
inline float tx_sineosc_process_sample(tx_sineosc& s, bool trigger, float frequency, float phase_modulation = 0.f)
|
||||
inline float tx_sineosc_process_sample(tx_sineosc& s, bool trigger, float frequency,
|
||||
float phase_modulation = 0.f)
|
||||
{
|
||||
if (trigger) {
|
||||
if (s.phase_reset) s.phase = 0.f;
|
||||
@@ -133,15 +158,18 @@ inline void tx_envelope_init(tx_envelope& e, double samplerate, bool retrigger =
|
||||
e.retrigger = retrigger;
|
||||
}
|
||||
|
||||
inline size_t tx_mtos(float ms, double samplerate) { return static_cast<size_t>(ms * samplerate / 1000.f); }
|
||||
inline size_t tx_mtos(float ms, double samplerate)
|
||||
{
|
||||
return static_cast<size_t>(ms * samplerate / 1000.f);
|
||||
}
|
||||
|
||||
inline float tx_lerp(float x1, float y1, float x2, float y2, float x)
|
||||
{
|
||||
return y1 + (((x - x1) * (y2 - y1)) / (x2 - x1));
|
||||
}
|
||||
|
||||
inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger, float _attack_mod = 0,
|
||||
float _decay_mod = 0)
|
||||
inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger,
|
||||
float _attack_mod = 0, float _decay_mod = 0)
|
||||
{
|
||||
size_t attack_mid_x1 = tx_mtos(e.attack1_rate + (float)_attack_mod, e.samplerate);
|
||||
size_t attack_mid_x2 = tx_mtos(e.attack2_rate + (float)_attack_mod, e.samplerate);
|
||||
@@ -162,7 +190,8 @@ inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger,
|
||||
if (e.state == attack1) {
|
||||
// while in attack phase
|
||||
if (e.phase < attack_mid_x1) {
|
||||
e.level = tx_lerp(0, e.start_level, (float)attack_mid_x1, e.attack1_level, (float)e.phase);
|
||||
e.level = tx_lerp(0, e.start_level, (float)attack_mid_x1, e.attack1_level,
|
||||
(float)e.phase);
|
||||
e.phase += 1;
|
||||
}
|
||||
// reset phase if parameter was changed
|
||||
@@ -177,7 +206,8 @@ inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger,
|
||||
if (e.state == attack2) {
|
||||
// while in attack phase
|
||||
if (e.phase < attack_mid_x2) {
|
||||
e.level = tx_lerp(0, e.attack1_level, (float)attack_mid_x2, 1, (float)e.phase);
|
||||
e.level =
|
||||
tx_lerp(0, e.attack1_level, (float)attack_mid_x2, 1, (float)e.phase);
|
||||
e.phase += 1;
|
||||
}
|
||||
// reset phase if parameter was changed
|
||||
@@ -219,7 +249,8 @@ inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger,
|
||||
if (e.state == decay2) {
|
||||
// while in decay phase
|
||||
if (e.phase < decay_mid_x2) {
|
||||
e.level = tx_lerp(0, e.decay1_level, (float)decay_mid_x2, e.sustain_level, (float)e.phase);
|
||||
e.level = tx_lerp(0, e.decay1_level, (float)decay_mid_x2, e.sustain_level,
|
||||
(float)e.phase);
|
||||
e.phase += 1;
|
||||
}
|
||||
// reset phase if parameter was changed
|
||||
@@ -240,7 +271,8 @@ inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger,
|
||||
if (e.state == release1) {
|
||||
// while in release phase
|
||||
if (e.phase < release_mid_x1) {
|
||||
e.level = tx_lerp(0, e.sustain_level, (float)release_mid_x1, e.release1_level, (float)e.phase);
|
||||
e.level = tx_lerp(0, e.sustain_level, (float)release_mid_x1, e.release1_level,
|
||||
(float)e.phase);
|
||||
e.phase += 1;
|
||||
}
|
||||
// reset phase if parameter was changed
|
||||
@@ -255,7 +287,8 @@ inline float tx_envelope_process_sample(tx_envelope& e, bool gate, bool trigger,
|
||||
if (e.state == release2) {
|
||||
// while in release phase
|
||||
if (e.phase < release_mid_x2) {
|
||||
e.level = tx_lerp(0, e.release1_level, (float)release_mid_x2, 0, (float)e.phase);
|
||||
e.level =
|
||||
tx_lerp(0, e.release1_level, (float)release_mid_x2, 0, (float)e.phase);
|
||||
e.phase += 1;
|
||||
}
|
||||
// reset phase if parameter was changed
|
||||
@@ -293,8 +326,8 @@ inline void tx_operator_init(tx_operator& op, double samplerate)
|
||||
tx_sineosc_init(op.oscillator, samplerate);
|
||||
}
|
||||
|
||||
inline float tx_operator_process_sample(tx_operator& op, bool gate, bool trigger, float frequency, float velocity,
|
||||
float pm = 0.f)
|
||||
inline float tx_operator_process_sample(tx_operator& op, bool gate, bool trigger,
|
||||
float frequency, float velocity, float pm = 0.f)
|
||||
{
|
||||
float env = tx_envelope_process_sample(op.envelope, gate, trigger);
|
||||
|
||||
@@ -336,16 +369,19 @@ inline void tx_voice_init(tx_state& s, double samplerate)
|
||||
tx_operator_init(s.op3, samplerate);
|
||||
}
|
||||
|
||||
inline void tx_voice_process_block(tx_state& t, voice_state& s, float** audio, size_t num_frames,
|
||||
inline void tx_voice_process_block(tx_state& t, voice_state& s, float** audio,
|
||||
size_t num_frames,
|
||||
const vector<audio_buffer<float>>& mods = {})
|
||||
{
|
||||
float frequency = midi_to_frequency(s.midi_note + t.pitch_mod + t.additional_pitch_mod);
|
||||
float frequency =
|
||||
midi_to_frequency(s.midi_note + t.pitch_mod + t.additional_pitch_mod);
|
||||
|
||||
for (int i = 0; i < num_frames; i++) {
|
||||
|
||||
voice_process_event_for_frame(s, i);
|
||||
|
||||
float pitch_env_signal = tx_envelope_process_sample(t.pitch_env, s.gate, s.trigger) * t.pitch_env_amt;
|
||||
float pitch_env_signal =
|
||||
tx_envelope_process_sample(t.pitch_env, s.gate, s.trigger) * t.pitch_env_amt;
|
||||
float pitched_freq = frequency + pitch_env_signal;
|
||||
|
||||
float output = 0.f;
|
||||
@@ -354,76 +390,101 @@ inline void tx_voice_process_block(tx_state& t, voice_state& s, float** audio, s
|
||||
if (t.algorithm == 0) {
|
||||
float fb_freq = frequency * t.op3.ratio;
|
||||
float fb_mod_index = (t.feedback_amt * MOD_INDEX_COEFF);
|
||||
float fb_signal = tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) * fb_mod_index;
|
||||
float fb_signal =
|
||||
tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) *
|
||||
fb_mod_index;
|
||||
|
||||
float op3_Freq = frequency * t.op3.ratio;
|
||||
float op3_mod_index = (t.op3.amplitude * MOD_INDEX_COEFF);
|
||||
float op3_signal =
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_Freq, s.velocity, fb_signal) * op3_mod_index;
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_Freq, s.velocity,
|
||||
fb_signal) *
|
||||
op3_mod_index;
|
||||
|
||||
float op2_freq = frequency * t.op2.ratio;
|
||||
float op2_mod_index = (t.op2.amplitude * MOD_INDEX_COEFF);
|
||||
float op2_signal =
|
||||
tx_operator_process_sample(t.op2, s.gate, s.trigger, op2_freq, s.velocity, op3_signal) * op2_mod_index;
|
||||
tx_operator_process_sample(t.op2, s.gate, s.trigger, op2_freq, s.velocity,
|
||||
op3_signal) *
|
||||
op2_mod_index;
|
||||
|
||||
float op1_freq = frequency * t.op1.ratio;
|
||||
output = tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq, s.velocity, op2_signal) *
|
||||
output = tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq,
|
||||
s.velocity, op2_signal) *
|
||||
t.op1.amplitude;
|
||||
} else if (t.algorithm == 1) {
|
||||
float fb_freq = frequency * t.op3.ratio;
|
||||
float fb_mod_index = (t.feedback_amt * MOD_INDEX_COEFF);
|
||||
float fb_signal = tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) * fb_mod_index;
|
||||
float fb_signal =
|
||||
tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) *
|
||||
fb_mod_index;
|
||||
|
||||
float op3_freq = frequency * t.op3.ratio;
|
||||
float op3_signal =
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_freq, s.velocity, fb_signal) * t.op3.amplitude;
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_freq, s.velocity,
|
||||
fb_signal) *
|
||||
t.op3.amplitude;
|
||||
|
||||
float op2_freq = frequency * t.op2.ratio;
|
||||
float op2_mod_index = (t.op2.amplitude * MOD_INDEX_COEFF);
|
||||
float op2_signal =
|
||||
tx_operator_process_sample(t.op2, s.gate, s.trigger, op2_freq, s.velocity) * op2_mod_index;
|
||||
float op2_signal = tx_operator_process_sample(t.op2, s.gate, s.trigger,
|
||||
op2_freq, s.velocity) *
|
||||
op2_mod_index;
|
||||
|
||||
float op1_freq = frequency * t.op1.ratio;
|
||||
float op1_signal = tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq, s.velocity, op2_signal) *
|
||||
float op1_signal =
|
||||
tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq, s.velocity,
|
||||
op2_signal) *
|
||||
t.op1.amplitude;
|
||||
|
||||
output = op1_signal + op3_signal;
|
||||
} else if (t.algorithm == 2) {
|
||||
float fb_freq = frequency * t.op3.ratio;
|
||||
float fb_mod_index = (t.feedback_amt * MOD_INDEX_COEFF);
|
||||
float fb_signal = tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) * fb_mod_index;
|
||||
float fb_signal =
|
||||
tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) *
|
||||
fb_mod_index;
|
||||
|
||||
float op3_freq = frequency * t.op3.ratio;
|
||||
float op3_signal =
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_freq, s.velocity, fb_signal) * t.op3.amplitude;
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_freq, s.velocity,
|
||||
fb_signal) *
|
||||
t.op3.amplitude;
|
||||
|
||||
float op2_freq = frequency * t.op2.ratio;
|
||||
float op2_signal =
|
||||
tx_operator_process_sample(t.op2, s.gate, s.trigger, op2_freq, s.velocity) * t.op2.amplitude;
|
||||
float op2_signal = tx_operator_process_sample(t.op2, s.gate, s.trigger,
|
||||
op2_freq, s.velocity) *
|
||||
t.op2.amplitude;
|
||||
|
||||
float op1_freq = frequency * t.op1.ratio;
|
||||
float op1_signal =
|
||||
tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq, s.velocity) * t.op1.amplitude;
|
||||
float op1_signal = tx_operator_process_sample(t.op1, s.gate, s.trigger,
|
||||
op1_freq, s.velocity) *
|
||||
t.op1.amplitude;
|
||||
|
||||
output = op1_signal + op2_signal + op3_signal;
|
||||
} else if (t.algorithm == 3) {
|
||||
float fb_freq = frequency * t.op3.ratio;
|
||||
float fb_mod_index = (t.feedback_amt * MOD_INDEX_COEFF);
|
||||
float fb_signal = tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) * fb_mod_index;
|
||||
float fb_signal =
|
||||
tx_sineosc_process_sample(t.feedback_osc, s.trigger, fb_freq) *
|
||||
fb_mod_index;
|
||||
|
||||
float op3_freq = frequency * t.op3.ratio;
|
||||
float op3_mod_index = (t.op3.amplitude * MOD_INDEX_COEFF);
|
||||
float op3_signal =
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_freq, s.velocity, fb_signal) * op3_mod_index;
|
||||
tx_operator_process_sample(t.op3, s.gate, s.trigger, op3_freq, s.velocity,
|
||||
fb_signal) *
|
||||
op3_mod_index;
|
||||
|
||||
float op2_freq = frequency * t.op2.ratio;
|
||||
float op2_mod_index = (t.op2.amplitude * MOD_INDEX_COEFF);
|
||||
float op2_signal =
|
||||
tx_operator_process_sample(t.op2, s.gate, s.trigger, op2_freq, s.velocity) * op2_mod_index;
|
||||
float op2_signal = tx_operator_process_sample(t.op2, s.gate, s.trigger,
|
||||
op2_freq, s.velocity) *
|
||||
op2_mod_index;
|
||||
|
||||
float op1_freq = frequency * t.op1.ratio;
|
||||
output =
|
||||
tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq, s.velocity, op2_signal + op3_signal) *
|
||||
output = tx_operator_process_sample(t.op1, s.gate, s.trigger, op1_freq,
|
||||
s.velocity, op2_signal + op3_signal) *
|
||||
t.op1.amplitude;
|
||||
}
|
||||
|
||||
@@ -532,19 +593,24 @@ inline void tx_synth_init(tx_synth& s, double samplerate)
|
||||
for (int i = 0; i < MAX_VOICES; i++) { tx_voice_init(s.voices[i], samplerate); }
|
||||
}
|
||||
|
||||
inline void tx_synth_process_block(tx_synth& s, float** audio, size_t num_frames, const vector<midi_event>& midi_events,
|
||||
inline void tx_synth_process_block(tx_synth& s, float** audio, size_t num_frames,
|
||||
const vector<midi_event>& midi_events,
|
||||
const vector<audio_buffer<float>>& mods = {})
|
||||
{
|
||||
for (int i = 0; i < num_frames; i++) { audio[0][i] = audio[1][i] = 0.f; } // clear audio buffers
|
||||
for (int i = 0; i < num_frames; i++) {
|
||||
audio[0][i] = audio[1][i] = 0.f;
|
||||
} // clear audio buffers
|
||||
|
||||
voice_allocator_process_block(s.allocator, midi_events);
|
||||
|
||||
for (int i = 0; i < s.allocator.active_voice_count; i++) {
|
||||
tx_voice_process_block(s.voices[i], s.allocator.voices[i], audio, num_frames, mods);
|
||||
tx_voice_process_block(s.voices[i], s.allocator.voices[i], audio, num_frames,
|
||||
mods);
|
||||
}
|
||||
}
|
||||
|
||||
inline void tx_apply_parameter_mapping(array<tx_state, MAX_VOICES>& v, tx_parameter_mapping& m, float value)
|
||||
inline void tx_apply_parameter_mapping(array<tx_state, MAX_VOICES>& v,
|
||||
tx_parameter_mapping& m, float value)
|
||||
{
|
||||
if (m.range_min != m.range_max || m.exponent != 1.f)
|
||||
value = powf(value, m.exponent) * (m.range_max - m.range_min) + m.range_min;
|
||||
@@ -743,8 +809,8 @@ inline void tx_apply_parameter_mapping(array<tx_state, MAX_VOICES>& v, tx_parame
|
||||
}
|
||||
}
|
||||
|
||||
inline void tx_apply_parameter_mappings(array<tx_state, MAX_VOICES>& v, std::vector<tx_parameter_mapping>& m,
|
||||
float value)
|
||||
inline void tx_apply_parameter_mappings(array<tx_state, MAX_VOICES>& v,
|
||||
std::vector<tx_parameter_mapping>& m, float value)
|
||||
{
|
||||
for (int i = 0; i < m.size(); i++) { tx_apply_parameter_mapping(v, m[i], value); }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* voice_allocator.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
@@ -31,7 +54,8 @@ inline void make_note_on(midi_event& ev, int _midi_note, float _velocity, int _o
|
||||
ev.offset = _offset;
|
||||
}
|
||||
|
||||
inline void make_note_off(midi_event& ev, int _midi_note, float _velocity, int _offset = 0)
|
||||
inline void make_note_off(midi_event& ev, int _midi_note, float _velocity,
|
||||
int _offset = 0)
|
||||
{
|
||||
ev.type = midi_event_type::NOTE_OFF;
|
||||
ev.midi_note = _midi_note;
|
||||
@@ -80,11 +104,14 @@ inline void voice_allocator_init(voice_allocator& va)
|
||||
for (size_t i = 0; i < MAX_VOICES; ++i) { va.voices[i].event_count = 0; }
|
||||
}
|
||||
|
||||
inline void voice_allocator_process_block(voice_allocator& va, const vector<midi_event>& midi_events)
|
||||
inline void voice_allocator_process_block(voice_allocator& va,
|
||||
const vector<midi_event>& midi_events)
|
||||
{
|
||||
// reset voice events and counts
|
||||
for (int i = 0; i < MAX_VOICES; i++) {
|
||||
for (int j = 0; j < MAX_EVENTS_PER_VOICE; j++) { va.voices[i].events[j] = midi_event {}; }
|
||||
for (int j = 0; j < MAX_EVENTS_PER_VOICE; j++) {
|
||||
va.voices[i].events[j] = midi_event {};
|
||||
}
|
||||
va.voices[i].event_count = 0;
|
||||
}
|
||||
|
||||
@@ -119,13 +146,16 @@ inline void voice_allocator_process_block(voice_allocator& va, const vector<midi
|
||||
}
|
||||
case NOTE_OFF: {
|
||||
for (size_t i = 0; i < va.active_voice_count; ++i) {
|
||||
if (va.voices[i].midi_note == ev.midi_note) va.voices[i].events[va.voices[i].event_count++] = ev;
|
||||
if (va.voices[i].midi_note == ev.midi_note)
|
||||
va.voices[i].events[va.voices[i].event_count++] = ev;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PITCH_WHEEL:
|
||||
case MOD_WHEEL: {
|
||||
for (size_t i = 0; i < va.active_voice_count; ++i) { va.voices[i].events[va.voices[i].event_count++] = ev; }
|
||||
for (size_t i = 0; i < va.active_voice_count; ++i) {
|
||||
va.voices[i].events[va.voices[i].event_count++] = ev;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* audio_buffer.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
@@ -27,6 +50,8 @@ void audio_buffer_init(audio_buffer<t_sample>& a, size_t channels, size_t frames
|
||||
template <typename t_sample>
|
||||
void audio_buffer_update_ptrs(audio_buffer<t_sample>& a)
|
||||
{
|
||||
for (int ch = 0; ch < a.channels; ++ch) { a.channel_ptrs[ch] = a.flat_data.data() + ch * a.frames; }
|
||||
for (int ch = 0; ch < a.channels; ++ch) {
|
||||
a.channel_ptrs[ch] = a.flat_data.data() + ch * a.frames;
|
||||
}
|
||||
}
|
||||
} // namespace trnr
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
/*
|
||||
* audio_math.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace trnr {
|
||||
|
||||
inline double lin_2_db(double lin)
|
||||
{
|
||||
if (lin <= 1e-20) lin = 1e-20; // avoid log(0)
|
||||
@@ -11,7 +35,13 @@ inline double lin_2_db(double lin)
|
||||
|
||||
inline double db_2_lin(double db) { return pow(10.0, db / 20.0); }
|
||||
|
||||
inline float midi_to_frequency(float midi_note) { return 440.0 * powf(2.0, ((float)midi_note - 69.0) / 12.0); }
|
||||
inline float midi_to_frequency(float midi_note)
|
||||
{
|
||||
return 440.0 * powf(2.0, ((float)midi_note - 69.0) / 12.0);
|
||||
}
|
||||
|
||||
inline float ms_to_samples(float ms, double sample_rate) { return (ms * 0.001f) * (float)sample_rate; }
|
||||
inline float ms_to_samples(float ms, double sample_rate)
|
||||
{
|
||||
return (ms * 0.001f) * (float)sample_rate;
|
||||
}
|
||||
} // namespace trnr
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* demo_noise.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
/*
|
||||
* format.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
@@ -46,7 +70,8 @@ inline string float_to_string_trimmed(float value)
|
||||
|
||||
inline string to_upper(string& str)
|
||||
{
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::toupper(c); });
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::toupper(c); });
|
||||
return str;
|
||||
}
|
||||
} // namespace trnr
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* retro_buf.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../companding/alaw.h"
|
||||
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* smoother.h
|
||||
* Copyright (c) 2025 Christopher Herb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio_math.h"
|
||||
@@ -14,7 +37,8 @@ struct smoother {
|
||||
int32_t remaining;
|
||||
};
|
||||
|
||||
inline void smoother_init(smoother& s, double samplerate, float time_ms, float initial_value = 0.0f)
|
||||
inline void smoother_init(smoother& s, double samplerate, float time_ms,
|
||||
float initial_value = 0.0f)
|
||||
{
|
||||
s.samplerate = fmax(0.0, samplerate);
|
||||
s.time_samples = ms_to_samples(time_ms, s.samplerate);
|
||||
|
||||
Reference in New Issue
Block a user