From 4bf3e65449864ee997ef88a5fdd24c16a963e47d Mon Sep 17 00:00:00 2001 From: b-ma Date: Wed, 18 Jan 2023 18:06:43 +0100 Subject: [PATCH 1/4] fix: add channel config to PannerOptions + cleaner defaults for generating node bindings --- src/node/panner.rs | 86 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/src/node/panner.rs b/src/node/panner.rs index 503b21e3..dd1053ef 100644 --- a/src/node/panner.rs +++ b/src/node/panner.rs @@ -32,6 +32,12 @@ impl From for PanningModelType { } } +impl Default for PanningModelType { + fn default() -> Self { + PanningModelType::EqualPower + } +} + /// Algorithm to reduce the volume of an audio source as it moves away from the listener #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum DistanceModelType { @@ -51,6 +57,12 @@ impl From for DistanceModelType { } } +impl Default for DistanceModelType { + fn default() -> Self { + DistanceModelType::Inverse + } +} + /// Options for constructing a [`PannerNode`] // dictionary PannerOptions : AudioNodeOptions { // PanningModelType panningModel = "equalpower"; @@ -84,13 +96,14 @@ pub struct PannerOptions { pub cone_inner_angle: f64, pub cone_outer_angle: f64, pub cone_outer_gain: f64, + pub channel_config: ChannelConfigOptions, } impl Default for PannerOptions { fn default() -> Self { PannerOptions { - panning_model: PanningModelType::EqualPower, - distance_model: DistanceModelType::Inverse, + panning_model: PanningModelType::default(), + distance_model: DistanceModelType::default(), position_x: 0., position_y: 0., position_z: 0., @@ -103,10 +116,45 @@ impl Default for PannerOptions { cone_inner_angle: 360., cone_outer_angle: 360., cone_outer_gain: 0., + channel_config: ChannelConfigOptions { + count: 2, + count_mode: ChannelCountMode::ClampedMax, + interpretation: ChannelInterpretation::Speakers, + }, } } } +/// Assert that the channel count is valid for the StereoPannerNode +/// see +/// +/// # Panics +/// +/// This function panics if given count is greater than 2 +/// +#[track_caller] +#[inline(always)] +fn assert_valid_channel_count(count: usize) { + if count > 2 { + panic!("NotSupportedError: PannerNode channel count cannot be greater than two"); + } +} + +/// Assert that the channel count is valid for the StereoPannerNode +/// see +/// +/// # Panics +/// +/// This function panics if given count mode is [`ChannelCountMode::Max`] +/// +#[track_caller] +#[inline(always)] +fn assert_valid_channel_count_mode(mode: ChannelCountMode) { + if mode == ChannelCountMode::Max { + panic!("NotSupportedError: PannerNode channel count mode cannot be set to max"); + } +} + /// Internal state of the HRTF renderer struct HrtfState { len: usize, @@ -262,23 +310,35 @@ impl AudioNode for PannerNode { 1 } - fn set_channel_count(&self, v: usize) { - if v > 2 { - panic!("NotSupportedError: PannerNode channel count cannot be greater than two"); - } - self.channel_config.set_count(v); + // same limitations as for the PannerNode + // see: https://webaudio.github.io/web-audio-api/#panner-channel-limitations + fn set_channel_count(&self, count: usize) { + assert_valid_channel_count(count); + self.channel_config.set_count(count); } - fn set_channel_count_mode(&self, v: ChannelCountMode) { - if v == ChannelCountMode::Max { - panic!("NotSupportedError: PannerNode channel count mode cannot be set to max"); - } - self.channel_config.set_count_mode(v); + fn set_channel_count_mode(&self, mode: ChannelCountMode) { + assert_valid_channel_count_mode(mode); + self.channel_config.set_count_mode(mode); } } impl PannerNode { - // can panic when loading HRIR-sphere + /// returns a `PannerNode` instance + /// + /// # Arguments + /// + /// * `context` - audio context in which the audio node will live. + /// * `options` - stereo panner options + /// + /// # Panics + /// + /// Will panic if: + /// + /// * `options.channel_config.count` is greater than 2 + /// * `options.channel_config.mode` is `ChannelCountMode::Max` + /// + /// Can panic when loading HRIR-sphere #[allow(clippy::missing_panics_doc)] pub fn new(context: &C, options: PannerOptions) -> Self { let node = context.register(move |registration| { From 6a2d2242abf436666e44cd0e7083fcb9a870b824 Mon Sep 17 00:00:00 2001 From: b-ma Date: Wed, 18 Jan 2023 18:11:55 +0100 Subject: [PATCH 2/4] doc: harmonize doc --- src/node/panner.rs | 2 +- src/node/stereo_panner.rs | 67 +++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/node/panner.rs b/src/node/panner.rs index dd1053ef..5d07acb9 100644 --- a/src/node/panner.rs +++ b/src/node/panner.rs @@ -225,7 +225,7 @@ impl HrtfState { } } -/// Node that positions / spatializes an incoming audio stream in three-dimensional space. +/// `PannerNode` positions / spatializes an incoming audio stream in three-dimensional space. /// /// - MDN documentation: /// - specification: and diff --git a/src/node/stereo_panner.rs b/src/node/stereo_panner.rs index 57c3b516..e3642ac6 100644 --- a/src/node/stereo_panner.rs +++ b/src/node/stereo_panner.rs @@ -78,6 +78,39 @@ fn get_stereo_gains(x: f32) -> [f32; 2] { } /// `StereoPannerNode` positions an incoming audio stream in a stereo image +/// +/// It is an audio-processing module that positions an incoming audio stream +/// in a stereo image using a low-cost panning algorithm. +/// +/// - MDN documentation: +/// - specification: +/// - see also: [`BaseAudioContext::create_stereo_panner`](crate::context::BaseAudioContext::create_stereo_panner) +/// +/// # Usage +/// +/// ```no_run +/// use web_audio_api::context::{BaseAudioContext, AudioContext}; +/// use web_audio_api::node::{AudioNode, AudioScheduledSourceNode}; +/// +/// // create an `AudioContext` +/// let context = AudioContext::default(); +/// // load and decode a soundfile +/// let panner = context.create_stereo_panner(); +/// panner.connect(&context.destination()); +/// // position source on the left +/// panner.pan().set_value(-1.); +/// +/// // pipe an oscillator into the stereo panner +/// let osc = context.create_oscillator(); +/// osc.frequency().set_value(200.); +/// osc.connect(&panner); +/// osc.start(); +/// ``` +/// +/// # Examples +/// +/// - `cargo run --release --example stereo_panner` +/// pub struct StereoPannerNode { /// Represents the node instance and its associated audio context registration: AudioContextRegistration, @@ -120,40 +153,6 @@ impl AudioNode for StereoPannerNode { } } -/// `StereoPannerNode` can be used to pan an audio stream left or right. -/// -/// It is an audio-processing module that positions an incoming audio stream -/// in a stereo image using a low-cost panning algorithm. -/// -/// - MDN documentation: -/// - specification: -/// - see also: [`BaseAudioContext::create_stereo_panner`](crate::context::BaseAudioContext::create_stereo_panner) -/// -/// # Usage -/// -/// ```no_run -/// use web_audio_api::context::{BaseAudioContext, AudioContext}; -/// use web_audio_api::node::{AudioNode, AudioScheduledSourceNode}; -/// -/// // create an `AudioContext` -/// let context = AudioContext::default(); -/// // load and decode a soundfile -/// let panner = context.create_stereo_panner(); -/// panner.connect(&context.destination()); -/// // position source on the left -/// panner.pan().set_value(-1.); -/// -/// // pipe an oscillator into the stereo panner -/// let osc = context.create_oscillator(); -/// osc.frequency().set_value(200.); -/// osc.connect(&panner); -/// osc.start(); -/// ``` -/// -/// # Examples -/// -/// - `cargo run --release --example stereo_panner` -/// impl StereoPannerNode { /// returns a `StereoPannerNode` instance /// From 5cf1356fefdb814ffbc9fafbf057f8c6fb1a1e15 Mon Sep 17 00:00:00 2001 From: b-ma Date: Wed, 18 Jan 2023 18:12:23 +0100 Subject: [PATCH 3/4] fix: complete options with channel_config --- examples/doppler.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/doppler.rs b/examples/doppler.rs index 5744b5eb..67aa1b55 100644 --- a/examples/doppler.rs +++ b/examples/doppler.rs @@ -42,6 +42,7 @@ fn main() { cone_inner_angle: 360., cone_outer_angle: 0., cone_outer_gain: 0., + ..PannerOptions::default() }; let panner = PannerNode::new(&context, opts); // move the siren in 10 seconds from y = 100 to y = -100 From 1cf57c6eefe6f84d9aa6ca0c6cb01423a60f5bea Mon Sep 17 00:00:00 2001 From: Otto Rottier Date: Wed, 18 Jan 2023 20:25:30 +0100 Subject: [PATCH 4/4] Fix some PannerNode comments --- src/node/panner.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/panner.rs b/src/node/panner.rs index 5d07acb9..60f6f111 100644 --- a/src/node/panner.rs +++ b/src/node/panner.rs @@ -125,7 +125,7 @@ impl Default for PannerOptions { } } -/// Assert that the channel count is valid for the StereoPannerNode +/// Assert that the channel count is valid for the PannerNode /// see /// /// # Panics @@ -140,7 +140,7 @@ fn assert_valid_channel_count(count: usize) { } } -/// Assert that the channel count is valid for the StereoPannerNode +/// Assert that the channel count is valid for the PannerNode /// see /// /// # Panics @@ -310,7 +310,7 @@ impl AudioNode for PannerNode { 1 } - // same limitations as for the PannerNode + // same limitations as for the StereoPannerNode // see: https://webaudio.github.io/web-audio-api/#panner-channel-limitations fn set_channel_count(&self, count: usize) { assert_valid_channel_count(count);