Skip to content

Commit 400900f

Browse files
committed
Apply limits of compound AudioParam values (osc, biquad)
For the BiquadFilterNode: The nominal range for the frequency compound parameter is [0, Nyquist frequency]. For the OscillatorNode: The nominal range for the frequency compound parameter is [-Nyquist frequency, Nyquist frequency]. Fixes #461
1 parent f7ff7c9 commit 400900f

File tree

2 files changed

+12
-7
lines changed

2 files changed

+12
-7
lines changed

src/node/biquad_filter.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::{MAX_CHANNELS, RENDER_QUANTUM_SIZE};
1414

1515
use super::{AudioNode, ChannelConfig, ChannelConfigOptions};
1616

17-
fn get_computed_freq(freq: f32, detune: f32) -> f32 {
18-
freq * (detune / 1200.).exp2()
17+
fn get_computed_freq(freq: f32, detune: f32, sample_rate: f32) -> f32 {
18+
freq * (detune / 1200.).exp2().clamp(0., sample_rate / 2.)
1919
}
2020

2121
/// Biquad filter coefficients normalized against a0
@@ -490,7 +490,8 @@ impl BiquadFilterNode {
490490
let q = self.q().value();
491491

492492
// get coefs
493-
let computed_freq = get_computed_freq(frequency, detune);
493+
let computed_freq = get_computed_freq(frequency, detune, sample_rate);
494+
494495
let Coefficients { b0, b1, b2, a1, a2 } = calculate_coefs(
495496
type_,
496497
sample_rate as f64,
@@ -614,7 +615,7 @@ impl AudioProcessor for BiquadFilterRenderer {
614615
let gain = params.get(&self.gain);
615616
let sample_rate_f64 = f64::from(sample_rate);
616617
// compute first coef and fill the coef list with this value
617-
let computed_freq = get_computed_freq(frequency[0], detune[0]);
618+
let computed_freq = get_computed_freq(frequency[0], detune[0], sample_rate);
618619
let coef = calculate_coefs(
619620
type_,
620621
sample_rate_f64,
@@ -635,7 +636,7 @@ impl AudioProcessor for BiquadFilterRenderer {
635636
.zip(gain.iter().cycle())
636637
.skip(1)
637638
.for_each(|((((coefs, &f), &d), &q), &g)| {
638-
let computed_freq = get_computed_freq(f, d);
639+
let computed_freq = get_computed_freq(f, d, sample_rate);
639640
*coefs = calculate_coefs(
640641
type_,
641642
sample_rate_f64,
@@ -703,15 +704,16 @@ mod tests {
703704

704705
#[test]
705706
fn test_computed_freq() {
707+
let sample_rate = 48000.;
706708
let g_sharp = 415.3;
707709
let a = 440.;
708710
let b_flat = 466.16;
709711

710712
// 100 cents is 1 semi tone up
711-
let res = get_computed_freq(a, 100.);
713+
let res = get_computed_freq(a, 100., sample_rate);
712714
assert_float_eq!(res, b_flat, abs <= 0.01);
713715
// -100 cents is 1 semi tone below
714-
let res = get_computed_freq(a, -100.);
716+
let res = get_computed_freq(a, -100., sample_rate);
715717
assert_float_eq!(res, g_sharp, abs <= 0.01);
716718
}
717719

src/node/oscillator.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,8 @@ impl AudioProcessor for OscillatorRenderer {
404404
self.start_time = current_time;
405405
}
406406

407+
let nyquist = scope.sample_rate / 2.;
408+
407409
channel_data
408410
.iter_mut()
409411
.zip(frequency_values.iter().cycle())
@@ -418,6 +420,7 @@ impl AudioProcessor for OscillatorRenderer {
418420

419421
// @todo: we could avoid recompute that if both param lengths are 1
420422
let computed_frequency = frequency * (detune / 1200.).exp2();
423+
let computed_frequency = computed_frequency.clamp(-nyquist, nyquist);
421424

422425
// first sample to render
423426
if !self.started {

0 commit comments

Comments
 (0)