215#include <type_traits>
265 static constexpr double kDrawbarRatio[9] = {0.5, 1.0, 1.5, 2.0, 3.0,
267 static constexpr double kDrawbarAmp[9] = {0.50, 1.00, 0.35, 0.70, 0.45,
268 0.55, 0.25, 0.20, 0.30};
271 constexpr double kTailLevel = 0.30;
276 for (
int p = 0; p < n; ++p) {
279 row.ratio = kDrawbarRatio[p];
280 row.amp = kDrawbarAmp[p];
285 row.ratio =
static_cast<double>(p + 1);
286 row.amp = kTailLevel / (row.ratio * row.ratio);
310 static constexpr double kModeRatio[10] = {0.50, 1.00, 1.19, 1.50, 2.00,
311 2.50, 2.66, 3.00, 4.00, 5.00};
312 static constexpr double kModeAmp[10] = {0.60, 1.00, 0.70, 0.55, 0.80,
313 0.35, 0.30, 0.40, 0.30, 0.20};
314 static constexpr double kModeDecayMs[10] = {8000, 6000, 4000, 3000, 2500,
315 1500, 1400, 1200, 800, 500};
318 constexpr double kClusterRatioStep = 1.14;
322 constexpr double kClusterLevel = 0.20;
323 constexpr double kClusterAmpExponent = 1.5;
324 constexpr double kClusterDecayScaleMs = 3000.0;
329 for (
int p = 0; p < n; ++p) {
332 row.ratio = kModeRatio[p];
333 row.amp = kModeAmp[p];
334 row.decay_ms = kModeDecayMs[p];
336 row.ratio = 5.0 * std::pow(kClusterRatioStep,
337 static_cast<double>(p - 9));
338 row.amp = kClusterLevel * std::pow(1.0 / row.ratio,
339 kClusterAmpExponent);
340 row.decay_ms = kClusterDecayScaleMs / row.ratio;
349template <
typename SampleType =
float>
434 static constexpr double kTwoPi = 6.283185307179586476925286766559;
447 return f0_hz *
ratio *
455 const double nyquist = 0.5 * sample_rate;
457 if (f_hz <= taper_start)
return 1.0;
458 if (f_hz >= nyquist)
return 0.0;
460 return 0.5 * (1.0 + std::cos(kPi() * t));
482 if (std::isfinite(sample_rate) && sample_rate > 0.0) sample_rate_ = sample_rate;
484 partial_count_ = std::min(partial_count_, max_partials_);
490 const auto slots =
static_cast<std::size_t
>(2 * max_partials_);
491 phase_.resize(slots);
492 gain_.assign(slots, 0.0);
493 gain_step_.assign(slots, 0.0);
494 increment_.assign(slots, 0.0);
495 increment_step_.assign(slots, 0.0);
496 decay_env_.assign(slots, 1.0);
497 decay_coef_.assign(slots, 1.0);
498 slot_detune_.assign(slots, 1.0);
499 render_slots_.assign(slots, 0);
501 onset_.prepare(sample_rate_);
512 for (
auto& p : phase_) p.reset(0.0);
513 std::fill(decay_env_.begin(), decay_env_.end(), 1.0);
514 std::fill(gain_.begin(), gain_.end(), 0.0);
515 std::fill(gain_step_.begin(), gain_step_.end(), 0.0);
516 std::fill(increment_step_.begin(), increment_step_.end(), 0.0);
517 draw_doublet_jitter();
518 apply_stored_phases();
519 cadence_countdown_ = 0;
520 update_control_block(
true);
526 if (!std::isfinite(f0))
return;
535 std::clamp(n, 1, std::max(1, std::min(max_partials_, voice_.count)));
543 if (!std::isfinite(b))
return;
549 if (!std::isfinite(s))
return;
555 if (!std::isfinite(g))
return;
568 if constexpr (!std::is_same_v<SampleType, float>) {
571 trig_profile_ = profile;
577#if defined(__APPLE__) && defined(__clang__) && defined(__aarch64__)
578 return std::is_same_v<SampleType, float> &&
590 for (
int p = 0; p < v.count; ++p) {
591 const auto& row = v.partials[
static_cast<std::size_t
>(p)];
592 if (!std::isfinite(row.ratio) || !std::isfinite(row.amp) ||
593 !std::isfinite(row.phase01) || !std::isfinite(row.decay_ms))
597 partial_count_ = std::clamp(partial_count_, 1,
598 std::max(1, std::min(max_partials_, voice_.count)));
607 if (!std::isfinite(
ratio) || !std::isfinite(amp_lin) ||
608 !std::isfinite(phase01) || !std::isfinite(decay_ms))
610 voice_.partials[
static_cast<std::size_t
>(p)] = {
ratio, amp_lin, phase01,
612 voice_.count = std::max(voice_.count, p + 1);
625 if (!std::isfinite(
static_cast<double>(m)))
return;
626 morph_ = std::clamp(
static_cast<double>(m), 0.0, 1.0);
628 double morph()
const {
return morph_; }
639 : f_hz / fundamental_hz_;
640 const double a = envelope_a_.gain_db_at(abscissa);
641 const double b = envelope_b_.gain_db_at(abscissa);
642 return (1.0 - morph_) *
a + morph_ * b +
643 tilt_db_oct_ * std::log2(f_hz / fundamental_hz_);
652 if (!std::isfinite(ms))
return;
660 if (!std::isfinite(ms))
return;
670 if (!std::isfinite(cents))
return;
680 if (!std::isfinite(start_cents) || !std::isfinite(time_ms))
return;
681 glide_start_cents_ = start_cents;
682 glide_time_ms_ = std::max(time_ms, 0.0);
692 draw_doublet_jitter();
698 switch (retrig_phase_) {
700 apply_stored_phases();
705 for (
int p = 0; p < partial_count_; ++p)
706 for (
int k = 0; k < 2; ++k)
707 phase_[slot(p, k)].reset(rng_.next_unit<
double>());
710 std::fill(decay_env_.begin(), decay_env_.end(), 1.0);
711 glide_position_ = 0.0;
713 update_control_block(
true);
721 bool active()
const {
return onset_.active(); }
728 if (p < 0 || p >= partial_count_)
return 0.0;
729 return increment_[slot(p, 0)] * sample_rate_;
741 switch (trig_profile_) {
743 process_with_trig<FastTrigProfile::realtime_precise>(out, n);
747 process_with_trig<FastTrigProfile::reference>(out, n);
753 template <FastTrigProfile Profile>
754 void process_with_trig(SampleType* out,
int n) {
755 for (
int i = 0;
i < n; ++
i) {
756 if (cadence_countdown_ <= 0) update_control_block(
false);
757 --cadence_countdown_;
760#if defined(__APPLE__) && defined(__clang__) && defined(__aarch64__)
761 if constexpr (std::is_same_v<SampleType, float> &&
763 sum = render_precise_simd_sample();
765 constexpr bool rendered_simd =
766#if defined(__APPLE__) && defined(__clang__) && defined(__aarch64__)
767 std::is_same_v<SampleType, float> &&
772 for (
int r = rendered_simd ? render_count_ : 0; r < render_count_; ++r) {
773 const auto s =
static_cast<std::size_t
>(render_slots_[
774 static_cast<std::size_t
>(r)]);
782 const double sine = [&] {
784 return std::sin(
kTwoPi * phase_[s].phase());
786 return static_cast<double>(
788 static_cast<float>(phase_[s].phase())));
790 sum += gain_[s] * decay_env_[s] *
sine;
791 phase_[s].advance(increment_[s]);
792 gain_[s] += gain_step_[s];
793 increment_[s] += increment_step_[s];
794 decay_env_[s] *= decay_coef_[s];
797 const double env =
static_cast<double>(onset_.
next());
801 out[
i] =
static_cast<SampleType
>(
805 static constexpr double kPi() {
return 3.14159265358979323846; }
810 static constexpr std::size_t slot(
int p,
int k) {
811 return static_cast<std::size_t
>(2 *
p +
k);
814#if defined(__APPLE__) && defined(__clang__) && defined(__aarch64__)
816 double render_precise_simd_sample() {
817 simd_float4 accumulated = simd_make_float4(0.0f);
819 for (;
r + 3 < render_count_;
r += 4) {
820 const auto s0 =
static_cast<std::size_t
>(render_slots_[
r]);
821 const auto s1 =
static_cast<std::size_t
>(render_slots_[
r + 1]);
822 const auto s2 =
static_cast<std::size_t
>(render_slots_[
r + 2]);
823 const auto s3 =
static_cast<std::size_t
>(render_slots_[
r + 3]);
824 const simd_float4 phase = simd_make_float4(
825 static_cast<float>(phase_[s0].phase()),
826 static_cast<float>(phase_[s1].phase()),
827 static_cast<float>(phase_[s2].phase()),
828 static_cast<float>(phase_[s3].phase()));
829 const simd_float4
sine = FastMath::sin_cycles_precise(phase);
830 const simd_float4 amplitude = simd_make_float4(
831 static_cast<float>(gain_[s0] * decay_env_[s0]),
832 static_cast<float>(gain_[s1] * decay_env_[s1]),
833 static_cast<float>(gain_[s2] * decay_env_[s2]),
834 static_cast<float>(gain_[s3] * decay_env_[s3]));
835 accumulated += amplitude *
sine;
837 const std::array<std::size_t, 4> slots{s0, s1, s2, s3};
838 for (
const auto s : slots) {
839 phase_[
s].advance(increment_[s]);
840 gain_[
s] += gain_step_[
s];
841 increment_[
s] += increment_step_[
s];
842 decay_env_[
s] *= decay_coef_[
s];
846 for (;
r < render_count_; ++
r) {
847 const auto s =
static_cast<std::size_t
>(render_slots_[
r]);
848 sum += gain_[
s] * decay_env_[
s] *
851 static_cast<float>(phase_[
s].phase())));
852 phase_[
s].advance(increment_[s]);
853 gain_[
s] += gain_step_[
s];
854 increment_[
s] += increment_step_[
s];
855 decay_env_[
s] *= decay_coef_[
s];
867 void refresh_onset() {
868 onset_.set_attack_ms(attack_ms_);
869 onset_.set_release_ms(release_ms_);
872 void apply_stored_phases() {
873 for (
int p = 0;
p < std::max(partial_count_, 1); ++
p) {
874 const double stored =
875 voice_.partials[
static_cast<std::size_t
>(
p)].phase01;
876 for (
int k = 0;
k < 2; ++
k) {
877 const auto s = slot(p, k);
878 if (s < phase_.size()) phase_[
s].reset(stored);
886 void draw_doublet_jitter() {
887 for (std::size_t s = 0;
s < slot_detune_.size(); ++
s)
889 rng_.next_bipolar<
double>();
896 void update_control_block(
bool immediate) {
899 const double glide = glide_ratio();
903 const int sub_slots = pair ? 2 : 1;
904 const double pair_scale = pair ? 0.5 : 1.0;
909 double magnitude_sum = 0.0;
911 for (
int p = 0;
p < partial_count_; ++
p) {
912 const auto&
row = voice_.partials[
static_cast<std::size_t
>(
p)];
913 const double base_hz =
919 for (
int k = 0;
k < sub_slots; ++
k) {
920 const auto s = slot(p, k);
927 pair ? (
k == 0 ? -0.5 : 0.5) * detune_cents_ *
928 slot_detune_[slot(p, 0)]
936 const double signed_gain =
939 target_gain_[
s] = signed_gain;
940 target_increment_[
s] = f_hz / sample_rate_;
941 magnitude_sum += std::abs(signed_gain);
951 ? decay_coefficient(
row.decay_ms)
953 render_slots_[
static_cast<std::size_t
>(render_count_++)] =
962 normaliser_ = 1.0 / std::max(1.0, magnitude_sum);
964 for (
int r = 0;
r < render_count_; ++
r) {
965 const auto s =
static_cast<std::size_t
>(
966 render_slots_[
static_cast<std::size_t
>(
r)]);
967 const double g = target_gain_[
s] * normaliser_;
970 increment_[
s] = target_increment_[
s];
972 increment_step_[
s] = 0.0;
974 gain_step_[
s] = (
g - gain_[
s]) * step;
975 increment_step_[
s] = (target_increment_[
s] - increment_[
s]) * step;
983 double decay_coefficient(
double decay_ms)
const {
984 if (!(decay_ms > 0.0))
return 1.0;
985 const double tau_samples = decay_ms * 0.001 * sample_rate_;
986 return tau_samples > 0.0 ? std::exp(-1.0 / tau_samples) : 0.0;
989 double glide_ratio()
const {
990 if (glide_time_ms_ <= 0.0 || glide_start_cents_ == 0.0)
return 1.0;
991 const double t = std::min(glide_position_, 1.0);
995 void advance_glide() {
996 if (glide_time_ms_ <= 0.0) {
997 glide_position_ = 1.0;
1000 const double block_ms = 1000.0 *
1004 std::min(1.0, glide_position_ + block_ms / glide_time_ms_);
1007 double sample_rate_ = 44100.0;
1016 double morph_ = 0.0;
1020 double glide_start_cents_ = 0.0;
1021 double glide_time_ms_ = 0.0;
1022 double glide_position_ = 1.0;
1023 double normaliser_ = 1.0;
1031 SpectralEnvelope envelope_a_{};
1032 SpectralEnvelope envelope_b_{};
1034 ArT<double> onset_{};
1035 Xorshift32 rng_{0x9E3779B9u};
1037 std::vector<osc::PhaseAccumulator> phase_{};
1038 std::vector<double> gain_{}, gain_step_{};
1039 std::vector<double> increment_{}, increment_step_{};
1040 std::vector<double> decay_env_{}, decay_coef_{};
1041 std::vector<double> slot_detune_{};
1042 std::vector<int> render_slots_{};
1043 std::array<double, 2 * VoiceTable::kMaxPartials> target_gain_{};
1044 std::array<double, 2 * VoiceTable::kMaxPartials> target_increment_{};
1046 int render_count_ = 0;
1047 int cadence_countdown_ = 0;
Public spectral-envelope value types used by the additive bank.
A sinusoidal-bank additive synthesizer.
Definition additive_bank.hpp:350
double detune_cents() const
Definition additive_bank.hpp:673
static constexpr double kAttackMaxMs
Definition additive_bank.hpp:407
void set_seed(std::uint32_t seed)
Seeds the initial-phase and doublet-jitter generator.
Definition additive_bank.hpp:690
void process(SampleType *out, int n)
Definition additive_bank.hpp:740
AdditiveBankT()
Definition additive_bank.hpp:476
static constexpr double kDoubletJitterSpread
Definition additive_bank.hpp:419
EnvelopeMode
How a partial's amplitude evolves.
Definition additive_bank.hpp:365
@ shared_ar
One onset/release shape for every partial.
Definition additive_bank.hpp:366
@ per_partial_decay
The shared onset times each partial's own exp(−t/τ_p).
Definition additive_bank.hpp:369
static constexpr double kBElectricPianoTine
Definition additive_bank.hpp:395
bool active() const
Definition additive_bank.hpp:721
void set_retrig_phase(RetrigPhase p)
Definition additive_bank.hpp:685
RetrigPhase
Phase treatment on retrigger().
Definition additive_bank.hpp:353
@ seeded_random
Phases drawn from the Xorshift32 seeded at reset().
Definition additive_bank.hpp:359
@ free_run
Phases keep running.
Definition additive_bank.hpp:357
@ reset_stored
Every phase returns to its table phase01.
Definition additive_bank.hpp:354
const VoiceTable & voice() const
Definition additive_bank.hpp:600
static constexpr double kInharmonicityMax
Definition additive_bank.hpp:390
static constexpr double kMasterGainDefaultDb
Definition additive_bank.hpp:403
static constexpr double kInharmonicityDefault
Definition additive_bank.hpp:385
bool set_trig_profile(FastTrigProfile profile) noexcept
Selects the bounded-cycle sine implementation used by the float bank.
Definition additive_bank.hpp:564
static double worst_case_gain()
The worst-case output magnitude over the entire legal parameter space.
Definition additive_bank.hpp:467
void set_fundamental_hz(double f0)
Definition additive_bank.hpp:525
static constexpr double kMasterGainMinDb
Definition additive_bank.hpp:401
static double nyquist_guard_gain(double f_hz, double sample_rate)
The Nyquist guard: unity below fs/2 − kNyquistGuardBandHz, a raised cosine to exactly zero at fs/2,...
Definition additive_bank.hpp:454
static constexpr double kInharmonicityCitedMax
Definition additive_bank.hpp:387
void prepare(double sample_rate, int max_partials=kMaxPartialsDefault)
Sizes the per-partial arrays and returns the bank to a fresh state.
Definition additive_bank.hpp:481
void release()
Note-off.
Definition additive_bank.hpp:719
void set_pitch_glide(double start_cents, double time_ms)
A shared initial pitch glide: every partial is scaled by 2^(cents(t)/1200), starting at start_cents a...
Definition additive_bank.hpp:679
static constexpr double kFundamentalMinHz
Definition additive_bank.hpp:381
void set_master_gain_db(double g)
Definition additive_bank.hpp:554
void set_partial(int p, double ratio, double amp_lin, double phase01, double decay_ms)
Sets one row of the active table.
Definition additive_bank.hpp:604
double envelope_db_at(double f_hz) const
The live morphed envelope in dB at a partial frequency — the exact quantity the render applies,...
Definition additive_bank.hpp:636
static constexpr double kReleaseMinMs
Definition additive_bank.hpp:409
static constexpr double kNyquistGuardBandHz
Definition additive_bank.hpp:428
void set_envelope_a(const SpectralEnvelope &e)
Definition additive_bank.hpp:617
static constexpr double kSpectralTiltMaxDbOct
Definition additive_bank.hpp:398
RetrigPhase retrig_phase() const
Definition additive_bank.hpp:686
void load_voice(const VoiceTable &v)
Definition additive_bank.hpp:588
static constexpr int kAmpUpdateCadenceSamples
Definition additive_bank.hpp:424
SpectralDomain spectral_domain() const
Definition additive_bank.hpp:631
double spectral_tilt_db_oct() const
Definition additive_bank.hpp:552
void set_release_ms(double ms)
Definition additive_bank.hpp:659
static constexpr int kMaxPartialsDefault
Definition additive_bank.hpp:378
static constexpr double kTwoPi
Definition additive_bank.hpp:434
static constexpr double kSpectralTiltMinDbOct
Definition additive_bank.hpp:397
void set_attack_ms(double ms)
Definition additive_bank.hpp:651
double inharmonicity_b() const
Definition additive_bank.hpp:546
static constexpr double kFundamentalMaxHz
Definition additive_bank.hpp:382
static constexpr double kMasterGainMaxDb
Definition additive_bank.hpp:402
static constexpr double kEnvelopeCurve
Definition additive_bank.hpp:432
bool doublet_active() const
Definition additive_bank.hpp:674
void set_partial_count(int n)
Definition additive_bank.hpp:531
static constexpr int latency_samples()
Zero. Direct time-domain oscillators; nothing is buffered.
Definition additive_bank.hpp:472
static constexpr double kSpectralTiltDefaultDbOct
Definition additive_bank.hpp:399
SampleType next()
Definition additive_bank.hpp:734
static constexpr double kAttackMinMs
Definition additive_bank.hpp:406
int max_partials() const
Definition additive_bank.hpp:538
static constexpr double kBUpperTreble
Definition additive_bank.hpp:394
void set_inharmonicity_b(double b)
Stiff-string coefficient.
Definition additive_bank.hpp:542
void set_envelope_b(const SpectralEnvelope &e)
Definition additive_bank.hpp:618
static double partial_frequency_hz(double f0_hz, double ratio, double inharmonicity_b)
The published stiff-string law: f = f0 · ratio · √(1 + B·ratio²).
Definition additive_bank.hpp:445
double partial_frequency(int p) const
The current swept frequency of one partial's primary oscillator, in Hz — the quantity the inharmonici...
Definition additive_bank.hpp:727
EnvelopeMode envelope_mode() const
Definition additive_bank.hpp:649
void reset()
Clears every phase, envelope, and ramp, and rewinds the generator, so a render from here is bit-ident...
Definition additive_bank.hpp:509
static constexpr int kMaxPartialsCeiling
Definition additive_bank.hpp:377
void set_envelope_mode(EnvelopeMode mode)
Definition additive_bank.hpp:648
double master_gain_db() const
Definition additive_bank.hpp:559
static constexpr double kDetuneMaxCents
Definition additive_bank.hpp:413
static constexpr double kFundamentalDefaultHz
Definition additive_bank.hpp:383
static constexpr double kReleaseMaxMs
Definition additive_bank.hpp:410
int partial_count() const
Definition additive_bank.hpp:537
void retrigger()
Note-on.
Definition additive_bank.hpp:697
void set_morph(float m)
Crossfade A↔B.
Definition additive_bank.hpp:624
void set_spectral_domain(SpectralDomain d)
Definition additive_bank.hpp:630
double morph() const
Definition additive_bank.hpp:628
void set_spectral_tilt_db_oct(double s)
Definition additive_bank.hpp:548
static constexpr bool trig_profile_has_vector_path(FastTrigProfile profile)
Definition additive_bank.hpp:576
static constexpr int kPartialCountDefault
Definition additive_bank.hpp:379
double fundamental_hz() const
Definition additive_bank.hpp:529
static constexpr double kDetuneDefaultCents
Definition additive_bank.hpp:412
static constexpr double kBPianoTenor
Definition additive_bank.hpp:392
static constexpr double kBPianoMid
Definition additive_bank.hpp:393
static constexpr double kReleaseDefaultMs
Definition additive_bank.hpp:408
static constexpr double kAttackDefaultMs
Definition additive_bank.hpp:405
void set_detune_cents(double cents)
Doublet spread in cents.
Definition additive_bank.hpp:669
FastTrigProfile trig_profile() const noexcept
Definition additive_bank.hpp:574
SampleType next()
Definition envelope.hpp:404
A break-point spectral envelope: gain in dB as a function of frequency, interpolated linearly in the ...
Definition additive_spectral_envelope.hpp:44
The envelope family — AR, AD, AHD, DAHDSR, and a trigger-driven modulation envelope — plus a level-in...
Scalar math helpers for real-time audio DSP.
@ g
Definition pitch.hpp:27
float simd_reduce_add(const float *data, std::size_t count)
Definition simd.hpp:67
T cents_to_ratio(T cents)
Cents → frequency ratio. +100 → 2^(1/12), +1200 → 2.
Definition units.hpp:118
T db_to_linear(T db)
Amplitude dB → linear gain. 0 dB → 1, −6.0206 dB → 0.5.
Definition units.hpp:71
Definition additive_bank.hpp:218
VoiceTable make_organ_voice(int count=64)
The drawbar organ voice (§10a): nine tonewheel footages over a −12 dB/oct harmonic tail.
Definition additive_bank.hpp:264
FastTrigProfile
Semantic accuracy choices for bounded-cycle real-time trigonometry.
Definition fast_math.hpp:38
@ reference
Platform sine; the compatibility default.
Definition fast_math.hpp:40
@ realtime_precise
Float-precision path with maximum absolute error at most 2.5e-7 over one bounded cycle.
Definition fast_math.hpp:46
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
@ a
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
@ linear
2-point. Cheapest; audible imaging when pitching up.
Definition granular.hpp:133
@ sine
Definition lfo_sampling.hpp:54
@ immediate
Replace the output with the hold from the adopting frame onward.
Definition freeze_hold.hpp:155
SpectralDomain
This enum exists because "sampling a spectral envelope makes timbrepitch-independent" is only true un...
Definition additive_spectral_envelope.hpp:36
@ absolute_hz
Definition additive_spectral_envelope.hpp:36
AdditiveBankT< float > AdditiveBank
Definition additive_bank.hpp:1050
VoiceTable make_bell_voice(int count=64)
The bell voice (§10b): a modal body whose partials each decay at their own rate.
Definition additive_bank.hpp:309
AdditiveBankT< double > AdditiveBank64
Definition additive_bank.hpp:1051
float sum(const float *data, std::size_t count) noexcept
@ s
Definition input_events.hpp:41
@ r
Definition input_events.hpp:41
@ p
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40
@ t
Definition input_events.hpp:41
@ row
Definition design_ir.hpp:53
Deterministic randomness for modulation: a counter-free PRNG, a Gaussian draw, a stateless purpose-ke...
static float sin_cycles(float phase_cycles) noexcept
Computes sine for a normalized phase in [0, 1).
Definition fast_math.hpp:102
Which abscissa a SpectralEnvelope's break-points are measured along.
Definition additive_bank.hpp:222
double ratio
Frequency as a multiple of f0.
Definition additive_bank.hpp:223
double phase01
Stored initial phase in cycles, [0, 1).
Definition additive_bank.hpp:225
double decay_ms
Exponential τ.
Definition additive_bank.hpp:226
double amp
Unit-referenced amplitude, pre-normaliser.
Definition additive_bank.hpp:224
A partial set. Fixed capacity; copying one is a memcpy, never an allocation.
Definition additive_bank.hpp:231
bool add(const VoicePartial &p)
Definition additive_bank.hpp:244
bool harmonic
Whether inharmonicity_B applies.
Definition additive_bank.hpp:239
void clear()
Definition additive_bank.hpp:243
std::array< VoicePartial, kMaxPartials > partials
Definition additive_bank.hpp:241
static constexpr int kMaxPartials
Definition additive_bank.hpp:232
int count
Definition additive_bank.hpp:240
The real-unit vocabulary shared by every DSP block in the catalog.