1use crate::{
8 context::DistanceModel,
9 dsp::filters::Biquad,
10 effects::reverb::Reverb,
11 listener::Listener,
12 source::{SoundSource, Status},
13};
14use rg3d_core::{
15 math,
16 pool::{Handle, Pool},
17 visitor::{Visit, VisitResult, Visitor},
18};
19use std::ops::{Deref, DerefMut};
20
21pub mod reverb;
22
23#[derive(Default, Debug, Clone)]
25pub struct StubEffect {
26 base: BaseEffect,
27}
28
29impl Visit for StubEffect {
30 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
31 visitor.enter_region(name)?;
32
33 self.base.visit("Base", visitor)?;
34
35 visitor.leave_region()
36 }
37}
38
39impl EffectRenderTrait for StubEffect {
40 fn render(
41 &mut self,
42 _sources: &Pool<SoundSource>,
43 _listener: &Listener,
44 _distance_model: DistanceModel,
45 _mix_buf: &mut [(f32, f32)],
46 ) {
47 }
48}
49
50impl Deref for StubEffect {
51 type Target = BaseEffect;
52
53 fn deref(&self) -> &Self::Target {
54 &self.base
55 }
56}
57
58impl DerefMut for StubEffect {
59 fn deref_mut(&mut self) -> &mut Self::Target {
60 &mut self.base
61 }
62}
63
64#[derive(Debug, Clone)]
66pub enum Effect {
67 Stub(StubEffect),
69 Reverb(Reverb),
71}
72
73impl Default for Effect {
74 fn default() -> Self {
75 Effect::Stub(Default::default())
76 }
77}
78
79impl Effect {
80 fn id(&self) -> u32 {
81 match self {
82 Effect::Stub(_) => 0,
83 Effect::Reverb(_) => 1,
84 }
85 }
86
87 fn from_id(id: u32) -> Result<Self, String> {
88 match id {
89 0 => Ok(Effect::Stub(Default::default())),
90 1 => Ok(Effect::Reverb(Default::default())),
91 _ => Err(format!("Unknown effect id {}", id)),
92 }
93 }
94}
95
96impl Visit for Effect {
97 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
98 visitor.enter_region(name)?;
99
100 let mut id = self.id();
101 id.visit("Id", visitor)?;
102 if visitor.is_reading() {
103 *self = Self::from_id(id)?;
104 }
105
106 match self {
107 Effect::Stub(v) => v.visit("Data", visitor)?,
108 Effect::Reverb(v) => v.visit("Data", visitor)?,
109 }
110
111 visitor.leave_region()
112 }
113}
114
115pub(in crate) trait EffectRenderTrait {
116 fn render(
117 &mut self,
118 sources: &Pool<SoundSource>,
119 listener: &Listener,
120 distance_model: DistanceModel,
121 mix_buf: &mut [(f32, f32)],
122 );
123}
124
125#[derive(Debug, Clone)]
128pub struct BaseEffect {
129 gain: f32,
130 filters: Pool<InputFilter>,
131 inputs: Vec<EffectInput>,
132 frame_samples: Vec<(f32, f32)>,
133}
134
135impl Default for BaseEffect {
136 fn default() -> Self {
137 Self {
138 gain: 1.0,
139 filters: Default::default(),
140 inputs: Default::default(),
141 frame_samples: Default::default(),
142 }
143 }
144}
145
146impl BaseEffect {
147 pub(in crate) fn render(
148 &mut self,
149 sources: &Pool<SoundSource>,
150 listener: &Listener,
151 distance_model: DistanceModel,
152 amount: usize,
153 ) {
154 self.inputs
159 .retain(|input| sources.is_valid_handle(input.source));
160
161 if self.frame_samples.capacity() < amount {
163 self.frame_samples = Vec::with_capacity(amount)
164 }
165
166 self.frame_samples.clear();
167 for _ in 0..amount {
168 self.frame_samples.push((0.0, 0.0));
169 }
170
171 for input in self.inputs.iter_mut() {
172 let source = sources.borrow(input.source);
173
174 if source.status() != Status::Playing {
175 continue;
176 }
177
178 let distance_gain = match source {
179 SoundSource::Generic(_) => 1.0,
180 SoundSource::Spatial(spatial) => {
181 spatial.get_distance_gain(listener, distance_model)
182 }
183 };
184
185 let prev_distance_gain = input.last_distance_gain.unwrap_or(distance_gain);
186
187 input.last_distance_gain = Some(distance_gain);
188
189 let mut k = 0.0;
190 let step = 1.0 / amount as f32;
191
192 match self.filters.try_borrow_mut(input.filter) {
193 None => {
194 for ((accum_left, accum_right), &(input_left, input_right)) in
195 self.frame_samples.iter_mut().zip(source.frame_samples())
196 {
197 let g = math::lerpf(prev_distance_gain, distance_gain, k);
198 *accum_left += input_left * g;
199 *accum_right += input_right * g;
200 k += step;
201 }
202 }
203 Some(filter) => {
204 for ((accum_left, accum_right), &(input_left, input_right)) in
205 self.frame_samples.iter_mut().zip(source.frame_samples())
206 {
207 let (filtered_left, filtered_right) = filter.feed(input_left, input_right);
208 let g = math::lerpf(prev_distance_gain, distance_gain, k);
209 *accum_left += filtered_left * g;
210 *accum_right += filtered_right * g;
211 k += step;
212 }
213 }
214 }
215 }
216 }
217
218 pub fn gain(&self) -> f32 {
220 self.gain
221 }
222
223 pub fn set_gain(&mut self, gain: f32) {
227 self.gain = gain.max(0.0);
228 }
229
230 pub fn add_filter(&mut self, filter: InputFilter) -> Handle<InputFilter> {
233 self.filters.spawn(filter)
234 }
235
236 pub fn add_input(&mut self, input: EffectInput) {
238 self.inputs.push(input)
239 }
240
241 pub fn filter(&self, handle: Handle<InputFilter>) -> &InputFilter {
243 self.filters.borrow(handle)
244 }
245
246 pub fn filter_mut(&mut self, handle: Handle<InputFilter>) -> &mut InputFilter {
248 self.filters.borrow_mut(handle)
249 }
250}
251
252impl Visit for BaseEffect {
253 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
254 visitor.enter_region(name)?;
255
256 self.gain.visit("Gain", visitor)?;
257 self.filters.visit("Filters", visitor)?;
258 self.inputs.visit("Inputs", visitor)?;
259
260 visitor.leave_region()
261 }
262}
263
264#[derive(Default, Debug, Clone)]
267pub struct InputFilter {
268 left: Biquad,
269 right: Biquad,
270}
271
272impl InputFilter {
273 pub fn new(biquad: Biquad) -> Self {
275 Self {
276 left: biquad.clone(),
277 right: biquad,
278 }
279 }
280}
281
282impl InputFilter {
283 fn feed(&mut self, left_sample: f32, right_sample: f32) -> (f32, f32) {
284 (self.left.feed(left_sample), self.right.feed(right_sample))
285 }
286}
287
288impl Visit for InputFilter {
289 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
290 visitor.enter_region(name)?;
291
292 self.left.visit("Left", visitor)?;
293 self.right.visit("Right", visitor)?;
294
295 visitor.leave_region()
296 }
297}
298
299#[derive(Default, Debug, Clone)]
303pub struct EffectInput {
304 source: Handle<SoundSource>,
306
307 filter: Handle<InputFilter>,
310
311 last_distance_gain: Option<f32>,
314}
315
316impl EffectInput {
317 pub fn direct(source: Handle<SoundSource>) -> Self {
319 Self {
320 source,
321 filter: Handle::NONE,
322 last_distance_gain: None,
323 }
324 }
325
326 pub fn filtered(source: Handle<SoundSource>, filter: Handle<InputFilter>) -> Self {
333 Self {
334 source,
335 filter,
336 last_distance_gain: None,
337 }
338 }
339}
340
341impl Visit for EffectInput {
342 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
343 visitor.enter_region(name)?;
344
345 self.source.visit("Source", visitor)?;
346 self.filter.visit("Filter", visitor)?;
347
348 visitor.leave_region()
349 }
350}
351
352macro_rules! static_dispatch {
353 ($self:ident, $func:ident, $($args:expr),*) => {
354 match $self {
355 Effect::Stub(v) => v.$func($($args),*),
356 Effect::Reverb(v) => v.$func($($args),*),
357 }
358 };
359}
360
361impl EffectRenderTrait for Effect {
362 fn render(
363 &mut self,
364 sources: &Pool<SoundSource>,
365 listener: &Listener,
366 distance_model: DistanceModel,
367 mix_buf: &mut [(f32, f32)],
368 ) {
369 static_dispatch!(self, render, sources, listener, distance_model, mix_buf)
370 }
371}
372
373impl Deref for Effect {
374 type Target = BaseEffect;
375
376 fn deref(&self) -> &Self::Target {
377 match self {
378 Effect::Stub(v) => v,
379 Effect::Reverb(v) => v,
380 }
381 }
382}
383
384impl DerefMut for Effect {
385 fn deref_mut(&mut self) -> &mut Self::Target {
386 match self {
387 Effect::Stub(v) => v,
388 Effect::Reverb(v) => v,
389 }
390 }
391}