Skip to content

Commit

Permalink
Merge pull request #252 from b-ma/feat/panner-api
Browse files Browse the repository at this point in the history
Clean panner API
  • Loading branch information
orottier authored Jan 18, 2023
2 parents b598e84 + 1cf57c6 commit aaf9180
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 48 deletions.
1 change: 1 addition & 0 deletions examples/doppler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
88 changes: 74 additions & 14 deletions src/node/panner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ impl From<u8> 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 {
Expand All @@ -51,6 +57,12 @@ impl From<u8> for DistanceModelType {
}
}

impl Default for DistanceModelType {
fn default() -> Self {
DistanceModelType::Inverse
}
}

/// Options for constructing a [`PannerNode`]
// dictionary PannerOptions : AudioNodeOptions {
// PanningModelType panningModel = "equalpower";
Expand Down Expand Up @@ -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.,
Expand All @@ -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 PannerNode
/// see <https://webaudio.github.io/web-audio-api/#audionode-channelcount-constraints>
///
/// # 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 PannerNode
/// see <https://webaudio.github.io/web-audio-api/#audionode-channelcountmode-constraints>
///
/// # 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,
Expand Down Expand Up @@ -177,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: <https://developer.mozilla.org/en-US/docs/Web/API/PannerNode>
/// - specification: <https://www.w3.org/TR/webaudio/#pannernode> and
Expand Down Expand Up @@ -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 StereoPannerNode
// 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<C: BaseAudioContext>(context: &C, options: PannerOptions) -> Self {
let node = context.register(move |registration| {
Expand Down
67 changes: 33 additions & 34 deletions src/node/stereo_panner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: <https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode>
/// - specification: <https://webaudio.github.io/web-audio-api/#stereopannernode>
/// - 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,
Expand Down Expand Up @@ -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: <https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode>
/// - specification: <https://webaudio.github.io/web-audio-api/#stereopannernode>
/// - 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
///
Expand Down

0 comments on commit aaf9180

Please sign in to comment.