#include #include "Senior.hpp" namespace Ottobit { 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); skipped_frames.resize(info.input_channels); fms.resize(info.input_channels); for (auto& fm : fms) { fm.set_sample_rate(info.rate); fm.maxDelay(0.1); } phases.resize(info.output_channels); float phase_frac{1.f / info.output_channels}; for (int i{0}; i < info.output_channels; i++) { phases[i] = i * phase_frac; } } void Senior::operator()(tick t) { // Only compute skipped_frames when control changes if (inputs.s_rate != previous_rate) { step_size = (1. - inputs.s_rate) * RATE; previous_rate = inputs.s_rate; } if (inputs.bits != previous_bits) { set_bit_factor(); previous_bits = inputs.bits; } 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; } // Process the input buffer for(int i{0}; i < inputs.audio.channels; i++) { auto* in = inputs.audio[i]; auto* out = outputs.audio[i % outputs.audio.channels]; // Init current_frame and out_frame for each channel double current_frame{crush(in[0])}; double out_frame{current_frame}; for(int j{0}; j < t.frames; j++) { if (skipped_frames[i] <= step_size) skipped_frames[i]++; else { skipped_frames[i] = 0; current_frame = crush(in[j]); } if (inputs.depth) { lfo.set(inputs.freq, phases[i], 0); if (inputs.am_fm < 1.f) out_frame = current_frame * (lfo.cos() * am_amp + (1 - am_amp)); else { double amp = lfo.cos() * inputs.depth; fms[i].delay(amp * .0025 + 1); double am = current_frame * (amp + 1 - inputs.depth); double fm = fms[i](current_frame); out_frame = am * am_amp + fm * fm_amp; } phases[i] = lfo.phase(); } out[j] = out_frame; } } } void Senior::set_bit_factor() { bit_factor = pow(2, inputs.bits) - 1; } double Senior::crush(const double& f) { if (inputs.bits == BITS) return f; else // Rounding using static_cast // return static_cast(static_cast(f * bit_factor)) / bit_factor; // Close, but prefer the use of roundMagic from Lance Putnam's Gama return gam::scl::round(f * bit_factor) / bit_factor; } } // namespace Ottobit