servo_media_audio/
stereo_panner.rs1use std::f32::consts::PI;
6
7use malloc_size_of_derive::MallocSizeOf;
8
9use crate::block::{Chunk, FRAMES_PER_BLOCK, Tick};
10use crate::node::{AudioNodeEngine, AudioNodeType, BlockInfo, ChannelInfo};
11use crate::param::{Param, ParamType};
12
13#[derive(Copy, Clone, Debug, MallocSizeOf)]
14pub struct StereoPannerOptions {
15 pub pan: f32,
16}
17
18impl Default for StereoPannerOptions {
19 fn default() -> Self {
20 StereoPannerOptions { pan: 0. }
21 }
22}
23
24#[derive(AudioNodeCommon)]
25pub(crate) struct StereoPannerNode {
26 channel_info: ChannelInfo,
27 pan: Param,
28}
29
30impl StereoPannerNode {
31 pub fn new(options: StereoPannerOptions, channel_info: ChannelInfo) -> Self {
32 Self {
33 channel_info,
34 pan: Param::new(options.pan),
35 }
36 }
37
38 pub fn update_parameters(&mut self, info: &BlockInfo, tick: Tick) -> bool {
39 self.pan.update(info, tick)
40 }
41}
42
43impl AudioNodeEngine for StereoPannerNode {
44 fn node_type(&self) -> AudioNodeType {
45 AudioNodeType::StereoPannerNode
46 }
47
48 fn process(&mut self, mut inputs: Chunk, info: &BlockInfo) -> Chunk {
49 debug_assert!(inputs.len() == 1);
50
51 {
52 let block = &mut inputs.blocks[0];
53
54 block.explicit_repeat();
55
56 let mono = if block.chan_count() == 1 {
57 block.resize_silence(2);
58 true
59 } else {
60 debug_assert!(block.chan_count() == 2);
61 false
62 };
63
64 let (l, r) = block.data_mut().split_at_mut(FRAMES_PER_BLOCK.0 as usize);
65 let mut pan = self.pan.value();
66 for frame in 0..FRAMES_PER_BLOCK.0 {
67 let frame = Tick(frame);
68 if self.update_parameters(info, frame) {
69 pan = self.pan.value();
70 }
71
72 pan = pan.clamp(-1., 1.);
76
77 let x = if mono {
78 (pan + 1.) / 2.
79 } else if pan <= 0. {
80 pan + 1.
81 } else {
82 pan
83 };
84 let x = x * PI / 2.;
85
86 let mut gain_l = x.cos();
87 let mut gain_r = x.sin();
88 if gain_l <= 0. {
90 gain_l = 0.
91 }
92 if gain_r <= 0. {
93 gain_r = 0.;
94 }
95
96 let index = frame.0 as usize;
97 if mono {
98 let input = l[index];
99 l[index] = input * gain_l;
100 r[index] = input * gain_r;
101 } else if pan <= 0. {
102 l[index] += r[index] * gain_l;
103 r[index] *= gain_r;
104 } else {
105 r[index] += l[index] * gain_r;
106 l[index] *= gain_l;
107 }
108 }
109 }
110
111 inputs
112 }
113
114 fn input_count(&self) -> u32 {
115 1
116 }
117
118 fn get_param(&mut self, id: ParamType) -> &mut Param {
119 match id {
120 ParamType::Pan => &mut self.pan,
121 _ => panic!("Unknown param {:?} for PannerNode", id),
122 }
123 }
124}