13template <
typename SampleType =
float>
39 sample_rate_ = (std::isfinite(sample_rate) && sample_rate > 0.0) ? sample_rate
41 max_length_ms_ = std::isfinite(max_length_ms)
44 max_predelay_ms_ = std::isfinite(max_predelay_ms) ? std::max(0.0, max_predelay_ms)
47 const int max_len_samples =
static_cast<int>(std::ceil(
49 const int max_pre_samples =
static_cast<int>(std::ceil(
54 ring_mask_ =
static_cast<int>(next_pow2(
static_cast<std::size_t
>(
55 max_len_samples + max_pre_samples + 2))) - 1;
56 ring_.assign(
static_cast<std::size_t
>(ring_mask_) + 1u, SampleType{0});
62 tap_capacity_ =
static_cast<int>(std::ceil(
63 na::kNdMax * max_length_ms_ / 1000.0)) + na::kTapGuard;
64 for (
int bank = 0; bank < 2; ++bank)
65 for (
int ch = 0; ch < 2; ++ch) {
66 taps_[bank][ch].assign(
static_cast<std::size_t
>(tap_capacity_), Tap{});
67 tap_count_[bank][ch] = 0;
70 for (
int i = 0;
i < na::kNumAllpass; ++
i) {
71 allpass_len_[
i] = nearest_prime(std::max(2,
static_cast<int>(std::lround(
73 allpass_[
i].prepare(allpass_len_[
i] + 1);
76 swap_fade_len_ = std::max(1,
static_cast<int>(std::lround(
79 const auto smooth_s =
static_cast<SampleType
>(na::kParamSmoothMs / 1000.0);
80 const auto fs =
static_cast<SampleType
>(sample_rate_);
81 mix_.set_ramp_time(smooth_s, fs);
82 width_.set_ramp_time(smooth_s, fs);
83 output_gain_.set_ramp_time(smooth_s, fs);
84 converter_.set_ramp_time(smooth_s, fs);
86 for (
int ch = 0; ch < 2; ++ch) {
87 conv_hp_[ch].prepare(
static_cast<SampleType
>(sample_rate_));
88 conv_hp_[ch].set_cutoff(
static_cast<SampleType
>(na::kConverterFcLo));
89 conv_lp_[ch].prepare(
static_cast<SampleType
>(sample_rate_));
90 conv_lp_[ch].set_cutoff(
static_cast<SampleType
>(na::kConverterFcHi));
91 conv_dc_[ch].set_pole(
static_cast<SampleType
>(na::kConverterDcPole));
94 update_segment_coefficients();
102 std::fill(ring_.begin(), ring_.end(), SampleType{0});
105 for (
auto& bank : seg_state_)
106 for (
auto& ch : bank) ch.fill(SampleType{0});
107 for (
int ch = 0; ch < 2; ++ch) {
108 conv_hp_[ch].reset();
109 conv_lp_[ch].reset();
110 conv_dc_[ch].reset();
113 mix_.set_immediate(mix_.target());
114 width_.set_immediate(width_.target());
115 output_gain_.set_immediate(output_gain_.target());
116 converter_.set_immediate(converter_.target());
133 if (
program == program_)
return;
141 if (!std::isfinite(ms))
return;
143 if (v == length_ms_)
return;
149 if (!std::isfinite(ms))
return;
150 const double v = std::clamp(ms, 0.0, max_predelay_ms_);
151 if (v == predelay_ms_)
return;
159 if (!std::isfinite(pct))
return;
161 if (v == density_pct_)
return;
167 if (!std::isfinite(gamma))
return;
168 const double v = std::clamp(gamma, 0.0, 2.0);
169 if (v == density_growth_)
return;
176 if (!std::isfinite(pct))
return;
177 const double v = std::clamp(pct, 10.0, 95.0);
178 if (v == gate_hold_pct_)
return;
186 if (!std::isfinite(pct))
return;
187 const double v = std::clamp(pct, 5.0, 98.0);
188 if (v == attack_pct_)
return;
197 double density_pct,
double density_growth,
198 double gate_hold_pct,
double attack_pct) {
199 const double length = std::isfinite(
length_ms)
203 const double predelay = std::isfinite(predelay_ms)
204 ? std::clamp(predelay_ms, 0.0, max_predelay_ms_)
206 const double density = std::isfinite(density_pct)
207 ? std::clamp(density_pct,
210 const double growth = std::isfinite(density_growth)
211 ? std::clamp(density_growth, 0.0, 2.0)
213 const double hold = std::isfinite(gate_hold_pct)
214 ? std::clamp(gate_hold_pct, 10.0, 95.0)
216 const double attack = std::isfinite(attack_pct)
217 ? std::clamp(attack_pct, 5.0, 98.0)
219 if (
program == program_ && length == length_ms_ && predelay == predelay_ms_ &&
220 density == density_pct_ && growth == density_growth_ &&
221 hold == gate_hold_pct_ &&
attack == attack_pct_)
225 predelay_ms_ = predelay;
226 density_pct_ = density;
227 density_growth_ = growth;
228 gate_hold_pct_ =
hold;
237 double density_pct,
double density_growth,
238 double gate_hold_pct,
double attack_pct) {
239 const double length = std::isfinite(
length_ms)
243 const double predelay = std::isfinite(predelay_ms)
244 ? std::clamp(predelay_ms, 0.0, max_predelay_ms_)
246 const double density = std::isfinite(density_pct)
247 ? std::clamp(density_pct,
250 const double growth = std::isfinite(density_growth)
251 ? std::clamp(density_growth, 0.0, 2.0)
253 const double hold = std::isfinite(gate_hold_pct)
254 ? std::clamp(gate_hold_pct, 10.0, 95.0)
256 const double attack = std::isfinite(attack_pct)
257 ? std::clamp(attack_pct, 5.0, 98.0)
259 if (
program == program_ && length == length_ms_ && predelay == predelay_ms_ &&
260 density == density_pct_ && growth == density_growth_ &&
261 hold == gate_hold_pct_ &&
attack == attack_pct_)
265 predelay_ms_ = predelay;
266 density_pct_ = density;
267 density_growth_ = growth;
268 gate_hold_pct_ =
hold;
270 topology_dirty_ =
true;
271 topology_build_.active =
false;
280 if (seed == seed_)
return;
288 if (!std::isfinite(g))
return;
299 if (!std::isfinite(
tone))
return;
300 const double v = std::clamp(
tone, -1.0, 1.0);
301 if (v == tone_)
return;
303 update_segment_coefficients();
307 if (!std::isfinite(hz))
return;
308 const double v = std::clamp(hz, 1000.0, 18000.0);
309 if (v == hf_damp_hz_)
return;
311 update_segment_coefficients();
317 if (!std::isfinite(pct))
return;
318 width_.set_target(
static_cast<SampleType
>(std::clamp(pct, 0.0, 100.0) / 100.0));
323 if (!std::isfinite(amount))
return;
324 converter_.set_target(
static_cast<SampleType
>(std::clamp(amount, 0.0, 1.0)));
328 if (!std::isfinite(db))
return;
329 output_gain_.set_target(
335 if (!std::isfinite(pct))
return;
336 mix_.set_target(
static_cast<SampleType
>(std::clamp(pct, 0.0, 100.0) / 100.0));
343 if (!std::isfinite(
static_cast<double>(
left)) ||
344 !std::isfinite(
static_cast<double>(
right))) {
345 left = SampleType{0};
346 right = SampleType{0};
349 const SampleType dry_l =
left;
350 const SampleType dry_r =
right;
353 SampleType d = SampleType{0.5} * (dry_l + dry_r);
354 const auto g =
static_cast<SampleType
>(diffusion_);
356 const SampleType delayed = allpass_[
i].read(allpass_len_[
i] - 1);
358 d = -g * w + delayed;
362 ring_write_ = (ring_write_ + 1) & ring_mask_;
363 ring_[
static_cast<std::size_t
>(ring_write_)] = d;
365 SampleType wet_l = SampleType{0};
366 SampleType wet_r = SampleType{0};
369 wet_l = render_bank(front_, 0);
370 wet_r = render_bank(front_, 1);
372 SampleType old_gain{}, new_gain{};
373 const auto u =
static_cast<SampleType
>(fade_pos_) /
374 static_cast<SampleType
>(swap_fade_len_);
377 wet_l = old_gain * render_bank(front_, 0) + new_gain * render_bank(pending_, 0);
378 wet_r = old_gain * render_bank(front_, 1) + new_gain * render_bank(pending_, 1);
379 if (++fade_pos_ >= swap_fade_len_) {
382 seg_state_[front_][0].fill(SampleType{0});
383 seg_state_[front_][1].fill(SampleType{0});
390 const SampleType conv = converter_.next();
391 if (conv > SampleType{0}) {
392 wet_l = converter_stage(0, wet_l, conv);
393 wet_r = converter_stage(1, wet_r, conv);
397 const SampleType w = width_.next();
398 const SampleType mid = SampleType{0.5} * (wet_l + wet_r);
399 wet_l = mid + w * (wet_l - mid);
400 wet_r = mid + w * (wet_r - mid);
402 const SampleType trim = output_gain_.next();
406 SampleType dry_gain{}, wet_gain{};
408 left = dry_gain * dry_l + wet_gain * wet_l;
409 right = dry_gain * dry_r + wet_gain * wet_r;
410 advance_topology_rebuild();
426 int tap_count(
int channel)
const {
return tap_count_[front_][channel & 1]; }
430 const Tap&
tap(
int channel,
int index)
const {
431 return taps_[front_][channel & 1][
static_cast<std::size_t
>(index)];
436 double tap_norm(
int channel)
const {
return tap_norm_[front_][channel & 1]; }
453 diffusion_, converter_.target() > SampleType{0});
458 double tone()
const {
return tone_; }
466 attack_pct_ / 100.0);
472 SampleType render_bank(
int bank,
int channel) {
473 std::array<SampleType, nonlin_ambience::kSegments> acc{};
474 const Tap* taps = taps_[bank][channel].data();
475 const int count = tap_count_[bank][channel];
476 const SampleType* ring = ring_.data();
477 const int write = ring_write_;
478 const int mask = ring_mask_;
479 for (
int k = 0; k < count; ++k)
480 acc[
static_cast<std::size_t
>(taps[k].segment)] +=
481 static_cast<SampleType
>(taps[k].gain) *
482 ring[
static_cast<std::size_t
>((write - taps[k].
delay) & mask)];
485 auto& state = seg_state_[bank][channel];
487 const SampleType
a = seg_pole_[
static_cast<std::size_t
>(s)];
489 a * state[
static_cast<std::size_t
>(s)] +
490 (SampleType{1} -
a) * acc[
static_cast<std::size_t
>(
s)]);
491 out += state[
static_cast<std::size_t
>(
s)];
498 SampleType converter_stage(
int channel, SampleType x, SampleType amount) {
499 namespace na = nonlin_ambience;
500 SampleType
y = conv_hp_[channel].process_highpass(x);
501 y = conv_lp_[channel].process_lowpass(y);
503 const int bits = na::kConverterBitsMax -
504 static_cast<int>(std::lround(
505 static_cast<double>(amount) * na::kConverterBitSweep));
506 const auto step =
static_cast<SampleType
>(
507 1.0 /
static_cast<double>(1 << (std::max(2, bits) - 1)));
510 dither_.next_unit<SampleType>()) * step;
511 y = std::round((y + d) / step) * step;
513 return conv_dc_[channel].process(y);
518 void rebuild_immediate() {
519 topology_dirty_ =
false;
520 topology_build_.active =
false;
526 void rebuild_and_swap() {
527 if (ring_.empty())
return;
528 topology_dirty_ =
false;
529 topology_build_.active =
false;
539 const int back = 1 - front_;
541 ++topology_rebuild_count_;
542 seg_state_[
back][0].fill(SampleType{0});
543 seg_state_[
back][1].fill(SampleType{0});
549 void build_bank(
int bank) {
550 namespace na = nonlin_ambience;
552 const int window_samples = std::max(1,
static_cast<int>(std::lround(
559 const double gate_hold = gate_hold_pct_ / 100.0;
560 const double attack = attack_pct_ / 100.0;
561 for (
int ch = 0; ch < 2; ++ch) {
562 const std::uint32_t seed = ch == 0 ? seed_ : (seed_ ^ na::kSeedRodd);
563 Tap* out = taps_[bank][ch].data();
569 while (t <
static_cast<double>(
window_samples) && count < tap_capacity_) {
571 const double nd = na::pulse_density(
u, density_pct_, density_growth_);
572 const double grid = sample_rate_ / nd;
574 const auto design = na::design_velvet_tap(
583 if (design.audible) {
587 const double magnitude = design.magnitude;
588 out[
count].delay = design.delay;
589 out[
count].gain =
static_cast<float>(design.gain);
590 out[
count].segment = design.segment;
601 const double norm = l1 > na::kNormFloor ? na::kL1Budget / l1 : 0.0;
602 for (
int k = 0;
k <
count; ++
k)
603 out[k].gain =
static_cast<float>(
static_cast<double>(out[k].gain) * norm);
605 tap_count_[bank][ch] =
count;
606 tap_norm_[bank][ch] = norm;
610 struct IncrementalTopologyBuild {
614 bool normalizing =
false;
615 int window_samples = 1;
616 int predelay_samples = 0;
619 int normalize_index = 0;
630 void begin_incremental_topology_rebuild() {
631 auto&
b = topology_build_;
635 b.window_samples = std::max(1,
static_cast<int>(std::lround(
637 b.predelay_samples = std::max(0,
static_cast<int>(std::lround(
639 b.program = program_;
640 b.density_pct = density_pct_;
641 b.density_growth = density_growth_;
642 b.gate_hold = gate_hold_pct_ / 100.0;
643 b.attack = attack_pct_ / 100.0;
644 bank_window_[
b.bank] =
b.window_samples;
645 bank_predelay_[
b.bank] =
b.predelay_samples;
648 void finish_incremental_channel() {
649 auto&
b = topology_build_;
650 tap_count_[
b.bank][
b.channel] =
b.count;
651 tap_norm_[
b.bank][
b.channel] =
b.norm;
652 if (++
b.channel < 2) {
653 b.normalizing =
false;
656 b.normalize_index = 0;
662 seg_state_[
b.bank][0].fill(SampleType{0});
663 seg_state_[
b.bank][1].fill(SampleType{0});
668 topology_dirty_ =
false;
669 ++topology_rebuild_count_;
672 void advance_incremental_topology_unit() {
673 namespace na = nonlin_ambience;
674 auto&
b = topology_build_;
675 Tap* out = taps_[
b.bank][
b.channel].data();
677 if (
b.normalize_index <
b.count) {
678 auto& gain = out[
b.normalize_index++].gain;
679 gain =
static_cast<float>(
static_cast<double>(gain) *
b.norm);
681 finish_incremental_channel();
685 if (
b.t >=
static_cast<double>(
b.window_samples) ||
b.count >= tap_capacity_) {
686 b.norm =
b.l1 > na::kNormFloor ? na::kL1Budget /
b.l1 : 0.0;
687 b.normalizing =
true;
688 b.normalize_index = 0;
691 const double u =
b.t /
static_cast<double>(
b.window_samples);
692 const double nd = na::pulse_density(
u,
b.density_pct,
b.density_growth);
693 const double grid = sample_rate_ / nd;
694 const std::uint32_t channel_seed =
695 b.channel == 0 ? seed_ : (seed_ ^ na::kSeedRodd);
696 const auto design = na::design_velvet_tap(
697 b.program,
b.t, grid,
b.window_samples,
b.predelay_samples,
698 b.gate_hold,
b.attack,
700 if (design.audible) {
701 const double magnitude = design.magnitude;
702 out[
b.count].delay = design.delay;
703 out[
b.count].gain =
static_cast<float>(design.gain);
704 out[
b.count].segment = design.segment;
712 void advance_topology_rebuild() {
713 topology_work_units_last_sample_ = 0;
715 if (!topology_build_.active) {
716 if (!topology_dirty_)
return;
717 begin_incremental_topology_rebuild();
720 advance_incremental_topology_unit();
721 ++topology_work_units_last_sample_;
727 void update_segment_coefficients() {
728 namespace na = nonlin_ambience;
729 constexpr double kTwoPi = 6.283185307179586476925286766559;
730 const double bright = na::kFcBright;
731 const double dark = hf_damp_hz_;
732 for (
int s = 0;
s < na::kSegments; ++
s) {
733 const double q = std::clamp(
734 static_cast<double>(s) /
static_cast<double>(na::kSegments - 1) -
737 const double fc = bright * std::pow(dark / bright, q);
739 seg_pole_[
static_cast<std::size_t
>(
s)] =
static_cast<SampleType
>(
740 std::exp(-kTwoPi * fc / sample_rate_));
746 static std::size_t next_pow2(std::size_t n) {
748 while (p < n)
p <<= 1;
752 static bool is_prime(
int n) {
753 if (n < 2)
return false;
754 if (n % 2 == 0)
return n == 2;
755 for (
int d = 3;
d *
d <=
n;
d += 2)
756 if (n % d == 0)
return false;
762 static int nearest_prime(
int n) {
763 for (
int offset = 0; offset < 64; ++offset) {
764 if (is_prime(n + offset))
return n + offset;
765 if (n - offset > 1 && is_prime(n - offset))
return n - offset;
772 double sample_rate_ = 48000.0;
777 double length_ms_ = 350.0;
778 double predelay_ms_ = 0.0;
788 int tap_capacity_ = 0;
790 std::vector<Tap> taps_[2][2];
791 int tap_count_[2][2] = {{0, 0}, {0, 0}};
792 double tap_norm_[2][2] = {{0.0, 0.0}, {0.0, 0.0}};
795 int bank_window_[2] = {0, 0};
796 int bank_predelay_[2] = {0, 0};
798 std::vector<SampleType> ring_;
805 std::array<SampleType, nonlin_ambience::kSegments> seg_pole_{};
806 std::array<std::array<SampleType, nonlin_ambience::kSegments>, 2> seg_state_[2]{};
810 bool fading_ =
false;
812 std::uint64_t topology_rebuild_count_ = 0;
813 bool topology_dirty_ =
false;
814 IncrementalTopologyBuild topology_build_{};
815 int topology_work_units_last_sample_ = 0;
816 int swap_fade_len_ = 1;
818 SmoothedValue<SampleType> mix_{SampleType{1}};
819 SmoothedValue<SampleType> width_{SampleType{1}};
820 SmoothedValue<SampleType> output_gain_{SampleType{1}};
821 SmoothedValue<SampleType> converter_{SampleType{0}};
823 TptFilterT<SampleType> conv_hp_[2];
824 TptFilterT<SampleType> conv_lp_[2];
825 DcBlocker<SampleType> conv_dc_[2];
826 Xorshift32 dither_{0x2C1B3A5Du};
The nonlin / gated ambience engine. Stereo, processed in place.
Definition nonlin_ambience.hpp:14
double tap_norm(int channel) const
The L1 normalization scalar solved for channel's live tap table, so a caller can predict |g_k| withou...
Definition nonlin_ambience.hpp:436
void set_width_pct(double pct)
0 % is mono (both channels exactly the mid signal), 100 % is the two independent velvet realizations.
Definition nonlin_ambience.hpp:316
double envelope(double tau) const
The normalized envelope this instance's current settings ask for.
Definition nonlin_ambience.hpp:464
void set_seed(std::uint32_t seed)
Seed for the L channel; R derives as seed ⊕ kSeedRodd.
Definition nonlin_ambience.hpp:279
void set_converter_amount(double amount)
0 disables the converter stage entirely.
Definition nonlin_ambience.hpp:322
int predelay_samples() const
Definition nonlin_ambience.hpp:446
void set_length_ms(double ms)
Window length in ms — the absolute time the dimensionless envelope is stretched across.
Definition nonlin_ambience.hpp:140
double worst_case_gain() const
The worst-case gain for the current settings, as a closed form of the shipped constants (series law 8...
Definition nonlin_ambience.hpp:451
void set_mix_pct(double pct)
Dry/wet, 0 .. 100 %. The default is 100 (send style).
Definition nonlin_ambience.hpp:334
int allpass_length(int index) const
Definition nonlin_ambience.hpp:447
int window_samples() const
Window length in samples — the denominator of every τ.
Definition nonlin_ambience.hpp:445
void process_sample(SampleType &left, SampleType &right)
One stereo frame, in place. Allocation-free, lock-free, branch-light.
Definition nonlin_ambience.hpp:342
void set_program(NonlinProgram program)
Definition nonlin_ambience.hpp:132
void request_topology(NonlinProgram program, double length_ms, double predelay_ms, double density_pct, double density_growth, double gate_hold_pct, double attack_pct)
RT-bounded counterpart used by hosted automation.
Definition nonlin_ambience.hpp:236
static constexpr int kTopologyWorkPerSample
Definition nonlin_ambience.hpp:19
void reset()
Clears every state.
Definition nonlin_ambience.hpp:101
void set_gate_hold_pct(double pct)
The Gated program's hold point, as a percent of the window.
Definition nonlin_ambience.hpp:175
NonlinProgram program() const
Definition nonlin_ambience.hpp:456
void set_topology(NonlinProgram program, double length_ms, double predelay_ms, double density_pct, double density_growth, double gate_hold_pct, double attack_pct)
Atomically applies the complete topology snapshot and regenerates the inactive tap bank at most once.
Definition nonlin_ambience.hpp:196
void set_attack_pct(double pct)
The Reverse program's rise point and the NonLin2 program's gate point, as a percent of the window.
Definition nonlin_ambience.hpp:185
void set_output_gain_db(double db)
Definition nonlin_ambience.hpp:327
void set_density_growth(double gamma)
Definition nonlin_ambience.hpp:166
void set_diffusion(double g)
Allpass coefficient.
Definition nonlin_ambience.hpp:287
double length_ms() const
Definition nonlin_ambience.hpp:457
std::uint64_t topology_rebuild_count() const
Definition nonlin_ambience.hpp:274
void set_hf_damp_hz(double hz)
Definition nonlin_ambience.hpp:306
const Tap & tap(int channel, int index) const
Tap index on channel.
Definition nonlin_ambience.hpp:430
int tap_count(int channel) const
Number of taps currently live on channel (0 = L, 1 = R).
Definition nonlin_ambience.hpp:426
int topology_work_units_last_sample() const
Definition nonlin_ambience.hpp:275
void set_predelay_ms(double ms)
Definition nonlin_ambience.hpp:148
void set_density_pct(double pct)
Scales Nd_min only; Nd_max is fixed so the late field stays above the smoothness floor no matter how ...
Definition nonlin_ambience.hpp:158
void process(SampleType *left, SampleType *right, int num_samples)
A block of stereo frames, in place.
Definition nonlin_ambience.hpp:414
bool swap_in_progress() const
Definition nonlin_ambience.hpp:459
void prepare(double sample_rate, double max_length_ms=nonlin_ambience::kMaxLengthMs, double max_predelay_ms=nonlin_ambience::kMaxPredelayMs)
Allocates the tap ring and both tap banks.
Definition nonlin_ambience.hpp:34
double tone() const
Definition nonlin_ambience.hpp:458
static constexpr int latency_samples()
Series law 5: exactly zero.
Definition nonlin_ambience.hpp:128
void set_tone(double tone)
Spectral tilt T ∈ [−1, +1]: positive keeps highs later (brighter), negative darkens.
Definition nonlin_ambience.hpp:298
Deterministic TPDF dither and bounded error-feedback quantization.
@ count
sentinel: number of real capabilities (keep LAST)
Definition canvas_capability.hpp:38
@ d
Definition pitch.hpp:22
@ b
Definition pitch.hpp:31
@ index
Definition gpu_pass.hpp:140
@ back
Definition gpu_pass.hpp:283
constexpr double kTwoPi
Definition lfo_sampling.hpp:77
The calibration register: every number this module ships that is not cited to the literature lives he...
Definition nonlin_ambience_design.hpp:253
constexpr double kRevRise
Reverse program: normalized rise point r and swell exponent p (p < 1 concave, p > 1 convex).
Definition nonlin_ambience_design.hpp:305
constexpr double kMinDensityPct
Lower bound of the density control's documented 10 .. 100 % range.
Definition nonlin_ambience_design.hpp:379
constexpr double kMaxLengthMs
Definition nonlin_ambience_design.hpp:375
constexpr double kFcDark
Definition nonlin_ambience_design.hpp:328
double worst_case_gain(double diffusion=kDiffusionDefault, bool converter_on=false)
The shipped worst-case gain as a closed form of the shipped constants: Π_i (1 + 2·g_i) · G_L1,...
Definition nonlin_ambience_design.hpp:400
constexpr double kDensityRefPct
The density_pct value at which Nd_min equals kNdMin exactly, so the shipped default reproduces the sh...
Definition nonlin_ambience_design.hpp:280
constexpr double kGammaDefault
Density growth exponent γ.
Definition nonlin_ambience_design.hpp:286
constexpr double kGateHold
Gated program: normalized hold point h and fall width w.
Definition nonlin_ambience_design.hpp:299
constexpr double kMinLengthMs
Largest window and pre-delay prepare() sizes storage for, in ms.
Definition nonlin_ambience_design.hpp:374
constexpr double kMaxPredelayMs
Definition nonlin_ambience_design.hpp:376
constexpr std::uint32_t kDefaultSeed
Default seed_L.
Definition nonlin_ambience_design.hpp:348
constexpr double kDiffusionMax
Definition nonlin_ambience_design.hpp:267
constexpr int kNumAllpass
Number of pre-diffusion Schroeder allpasses.
Definition nonlin_ambience_design.hpp:257
double program_envelope(NonlinProgram program, double tau, double gate_hold=kGateHold, double attack=kRevRise)
The dimensionless program envelope E(τ), τ ∈ [0, 1] (series law 7 — scale invariant,...
Definition nonlin_ambience_design.hpp:413
constexpr int kSegments
Number of time segments the tap range is split into for spectral tilt.
Definition nonlin_ambience_design.hpp:323
constexpr double kDiffusionDefault
Allpass coefficient, exposed as diffusion.
Definition nonlin_ambience_design.hpp:266
T ms_to_samples(T ms, T sample_rate)
Milliseconds → samples at sample_rate Hz.
Definition units.hpp:147
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
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
@ delay
Definition envelope.hpp:57
@ hold
Definition envelope.hpp:59
@ attack
Definition envelope.hpp:58
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ EqualPower
(cos(u·π/2), sin(u·π/2)) — power sum == 1.
Definition crossfade.hpp:43
@ EqualGain
(1−u, u) — amplitude sum == 1.
Definition crossfade.hpp:42
constexpr T crossfade_smoothstep(T t) noexcept
Smoothstep progress shaping: cubic 3u²−2u³ with zero slope at both ends, clamped to [0,...
Definition crossfade.hpp:50
@ a
Definition formant_filter_bank.hpp:20
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
NonlinAmbienceT< double > NonlinAmbience64
Definition nonlin_ambience.hpp:830
void crossfade_gains(T u, CrossfadeGainLaw law, T &old_gain, T &new_gain) noexcept
Old/new blend gains for an ALREADY-SHAPED progress u (the caller applies any smoothstep/clamp first).
Definition crossfade.hpp:61
NonlinProgram
The four programs.
Definition nonlin_ambience_design.hpp:243
@ ambience
Short falling cloud — the "natural" one.
Definition nonlin_ambience_design.hpp:244
VelvetNoiseDrawT< SampleType > velvet_noise_draw(std::uint64_t seed, std::uint64_t index) noexcept
Pure draw for one velvet grid cell.
Definition velvet_noise.hpp:26
NonlinAmbienceT< float > NonlinAmbience
Definition nonlin_ambience.hpp:829
constexpr SampleType tpdf_difference(SampleType first, SampleType second) noexcept
Converts two independent uniform draws in [0, 1) to unit-peak TPDF noise.
Definition dither.hpp:32
@ grid
Definition geometry.hpp:348
@ s
Definition input_events.hpp:41
@ y
Definition input_events.hpp:42
@ q
Definition input_events.hpp:41
@ n
Definition input_events.hpp:40
@ p
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40
@ t
Definition input_events.hpp:41
The nonlin / gated ambience engine — a reverb whose envelope is DESIGNED rather than decayed.
One velvet tap: where to read, how much to scale it, and which spectral segment it belongs to.
Definition nonlin_ambience.hpp:23
float gain
Definition nonlin_ambience.hpp:25
int delay
Definition nonlin_ambience.hpp:24
int segment
Definition nonlin_ambience.hpp:26