2024-10-30 19:51:40 +00:00
|
|
|
#include <ranges>
|
|
|
|
|
2024-10-02 17:16:34 +01:00
|
|
|
#include <Gamma/scl.h>
|
|
|
|
|
2024-10-06 23:26:13 +01:00
|
|
|
#include "Senior.hpp"
|
2024-09-30 18:50:58 +01:00
|
|
|
|
2024-10-30 20:59:17 +00:00
|
|
|
#define BITS 16
|
|
|
|
#define RATE 64
|
|
|
|
|
2024-11-12 11:39:02 +00:00
|
|
|
namespace Ottobit
|
|
|
|
{
|
2024-10-21 16:38:25 +01:00
|
|
|
void Senior::prepare(setup info)
|
|
|
|
{
|
|
|
|
// Initialization, this method will be called with buffer size, etc.
|
|
|
|
set_bit_factor();
|
|
|
|
lfo.set_sample_rate(info.rate);
|
|
|
|
lfo.freq(5);
|
|
|
|
|
2024-10-30 20:59:17 +00:00
|
|
|
skipped_frames.resize(info.output_channels);
|
|
|
|
fms.resize(info.output_channels);
|
|
|
|
lpfs.resize(info.output_channels);
|
|
|
|
phases.resize(info.output_channels);
|
|
|
|
|
|
|
|
float init_phase{0};
|
|
|
|
const float phase_frac{1.f / info.output_channels};
|
2024-10-21 16:38:25 +01:00
|
|
|
|
2024-10-30 20:59:17 +00:00
|
|
|
for (auto [fm, lpf, ph] : std::views::zip(fms, lpfs, phases))
|
2024-10-21 16:38:25 +01:00
|
|
|
{
|
|
|
|
fm.set_sample_rate(info.rate);
|
|
|
|
fm.maxDelay(0.1);
|
2024-10-30 19:51:40 +00:00
|
|
|
|
|
|
|
lpf.set_sample_rate(info.rate);
|
|
|
|
lpf.type(gam::LOW_PASS);
|
2024-10-21 16:38:25 +01:00
|
|
|
|
2024-10-30 20:59:17 +00:00
|
|
|
ph = init_phase;
|
|
|
|
init_phase += phase_frac;
|
2024-10-21 16:38:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-06 23:26:13 +01:00
|
|
|
void Senior::operator()(tick t)
|
2024-09-30 18:50:58 +01:00
|
|
|
{
|
2024-10-20 23:37:37 +01:00
|
|
|
// Only compute skipped_frames when control changes
|
2024-10-07 22:53:11 +01:00
|
|
|
if (inputs.s_rate != previous_rate)
|
2024-10-01 00:43:19 +01:00
|
|
|
{
|
2024-10-07 22:53:11 +01:00
|
|
|
step_size = (1. - inputs.s_rate) * RATE;
|
|
|
|
previous_rate = inputs.s_rate;
|
2024-10-01 00:43:19 +01:00
|
|
|
}
|
|
|
|
|
2024-10-14 21:41:27 +01:00
|
|
|
if (inputs.bits != previous_bits)
|
|
|
|
{
|
|
|
|
set_bit_factor();
|
|
|
|
previous_bits = inputs.bits;
|
|
|
|
}
|
|
|
|
|
2024-10-20 23:37:37 +01:00
|
|
|
if (inputs.depth != previous_depth ||
|
|
|
|
inputs.am_fm != previous_am_fm)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (inputs.am_fm < 1.f)
|
|
|
|
am_amp = (inputs.am_fm * 0.5) + (inputs.depth * 0.5);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
am_amp = 2 - inputs.am_fm;
|
|
|
|
fm_amp = inputs.am_fm - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
previous_depth = inputs.depth;
|
|
|
|
previous_am_fm = inputs.am_fm;
|
|
|
|
}
|
|
|
|
|
2024-10-30 20:59:17 +00:00
|
|
|
// Process the input buffer for each ouput channels
|
|
|
|
for(int i{0}; i < outputs.audio.channels; i++)
|
2024-09-30 18:50:58 +01:00
|
|
|
{
|
2024-10-30 20:59:17 +00:00
|
|
|
auto* out{outputs.audio[i]};
|
|
|
|
auto* in{inputs.audio[i % inputs.audio.channels]};
|
2024-09-30 18:50:58 +01:00
|
|
|
|
2024-10-20 23:37:37 +01:00
|
|
|
// Init current_frame and out_frame for each channel
|
|
|
|
double current_frame{crush(in[0])};
|
|
|
|
double out_frame{current_frame};
|
2024-10-01 00:43:19 +01:00
|
|
|
|
2024-10-02 17:16:34 +01:00
|
|
|
for(int j{0}; j < t.frames; j++)
|
2024-09-30 18:50:58 +01:00
|
|
|
{
|
2024-10-02 17:16:34 +01:00
|
|
|
if (skipped_frames[i] <= step_size)
|
|
|
|
skipped_frames[i]++;
|
2024-10-01 00:43:19 +01:00
|
|
|
else
|
2024-09-30 22:30:26 +01:00
|
|
|
{
|
2024-10-02 17:16:34 +01:00
|
|
|
skipped_frames[i] = 0;
|
2024-10-07 22:53:11 +01:00
|
|
|
current_frame = crush(in[j]);
|
2024-09-30 22:30:26 +01:00
|
|
|
}
|
|
|
|
|
2024-10-20 23:37:37 +01:00
|
|
|
if (inputs.depth)
|
2024-10-07 22:53:11 +01:00
|
|
|
{
|
|
|
|
lfo.set(inputs.freq, phases[i], 0);
|
2024-10-14 21:41:27 +01:00
|
|
|
|
|
|
|
if (inputs.am_fm < 1.f)
|
2024-10-20 23:37:37 +01:00
|
|
|
out_frame = current_frame * (lfo.cos() * am_amp + (1 - am_amp));
|
2024-10-14 21:41:27 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
double amp = lfo.cos() * inputs.depth;
|
|
|
|
fms[i].delay(amp * .0025 + 1);
|
2024-10-20 23:37:37 +01:00
|
|
|
double am = current_frame * (amp + 1 - inputs.depth);
|
2024-10-14 21:41:27 +01:00
|
|
|
double fm = fms[i](current_frame);
|
2024-10-20 23:37:37 +01:00
|
|
|
out_frame = am * am_amp + fm * fm_amp;
|
2024-10-14 21:41:27 +01:00
|
|
|
}
|
|
|
|
|
2024-10-07 22:53:11 +01:00
|
|
|
phases[i] = lfo.phase();
|
|
|
|
}
|
2024-10-30 19:51:40 +00:00
|
|
|
else
|
|
|
|
out_frame = current_frame;
|
2024-10-20 23:37:37 +01:00
|
|
|
|
2024-10-30 19:51:40 +00:00
|
|
|
if (inputs.filter < 1.f)
|
|
|
|
{
|
2024-10-30 20:59:17 +00:00
|
|
|
lpfs[i].freq(inputs.filter * 3000.);
|
2024-10-30 19:51:40 +00:00
|
|
|
out[j] = lpfs[i](out_frame);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
out[j] = out_frame;
|
2024-09-30 18:50:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-30 22:30:26 +01:00
|
|
|
|
2024-10-06 23:26:13 +01:00
|
|
|
void Senior::set_bit_factor()
|
2024-09-30 22:30:26 +01:00
|
|
|
{
|
2024-10-30 20:59:17 +00:00
|
|
|
bit_factor = pow(2, inputs.bits * BITS) - 1;
|
2024-09-30 22:30:26 +01:00
|
|
|
}
|
2024-10-02 17:16:34 +01:00
|
|
|
|
2024-10-07 22:53:11 +01:00
|
|
|
double Senior::crush(const double& f)
|
2024-10-02 17:16:34 +01:00
|
|
|
{
|
2024-10-30 20:59:17 +00:00
|
|
|
if (inputs.bits < 1.f)
|
2024-10-02 17:16:34 +01:00
|
|
|
// Rounding using static_cast
|
|
|
|
// return static_cast<double>(static_cast<int>(f * bit_factor)) / bit_factor;
|
2024-10-06 23:26:13 +01:00
|
|
|
// Close, but prefer the use of roundMagic from Lance Putnam's Gama
|
2024-10-02 17:16:34 +01:00
|
|
|
return gam::scl::round<double>(f * bit_factor) / bit_factor;
|
2024-10-30 20:59:17 +00:00
|
|
|
else
|
|
|
|
return f;
|
2024-10-02 17:16:34 +01:00
|
|
|
}
|
2024-10-07 22:53:11 +01:00
|
|
|
|
|
|
|
} // namespace Ottobit
|