Skip to main content

servo_media_audio/delay_node/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::collections::VecDeque;
6use std::sync::Arc;
7
8use f32;
9use log::error;
10use malloc_size_of_derive::MallocSizeOf;
11use parking_lot::RwLock;
12
13use crate::audio_node::{
14    AudioNodeEngine, AudioNodeType, BlockInfo, ChannelInfo, ChannelInterpretation,
15};
16use crate::block::{Block, Chunk};
17use crate::param::{Param, ParamType};
18
19mod delay_reader;
20mod delay_writer;
21pub(crate) use delay_reader::DelayReader;
22pub(crate) use delay_writer::DelayWriter;
23
24// Share with internal nodes. Use Arc because AudioNodeEngine requires Send
25type DelayBuffer = Arc<RwLock<VecDeque<Block>>>;
26type CachedUpmixedBlock = Arc<RwLock<Option<UpmixedBlock>>>;
27
28#[derive(Copy, Clone, Debug, MallocSizeOf)]
29pub struct DelayNodeOptions {
30    pub max_delay_time: f64,
31    pub delay_time: f64,
32}
33
34impl Default for DelayNodeOptions {
35    fn default() -> Self {
36        DelayNodeOptions {
37            max_delay_time: 1.,
38            delay_time: 0.,
39        }
40    }
41}
42
43#[derive(AudioNodeCommon)]
44pub(crate) struct DelayNode {
45    channel_info: ChannelInfo,
46    delay_writer: Option<Box<DelayWriter>>,
47    delay_reader: Option<Box<DelayReader>>,
48}
49
50/// UpmixedBlock is a Block that has been upmixed to the output channel count of the DelayReader
51#[derive(Debug)]
52struct UpmixedBlock {
53    // The index of the upmixed block in the delay line
54    index: usize,
55    block: Block,
56}
57
58impl UpmixedBlock {
59    fn new(
60        index: usize,
61        channel_count: u8,
62        channel_interpretation: ChannelInterpretation,
63        block: &Block,
64    ) -> Self {
65        let mut block = block.clone();
66        block.mix(channel_count, channel_interpretation);
67        UpmixedBlock { index, block }
68    }
69
70    fn index(&self) -> usize {
71        self.index
72    }
73
74    fn block(&self) -> &Block {
75        &self.block
76    }
77
78    fn increment_index(&mut self) {
79        self.index += 1;
80    }
81}
82
83impl DelayNode {
84    pub fn new(options: DelayNodeOptions, channel_info: ChannelInfo) -> Self {
85        let delay_line = Arc::new(RwLock::new(VecDeque::with_capacity(0)));
86        let upmixed_block = Arc::new(RwLock::new(None));
87        DelayNode {
88            channel_info,
89            delay_writer: Some(Box::new(DelayWriter::new(
90                delay_line.clone(),
91                upmixed_block.clone(),
92                channel_info,
93                options.max_delay_time,
94            ))),
95            delay_reader: Some(Box::new(DelayReader::new(
96                delay_line,
97                upmixed_block,
98                Param::new(options.delay_time as f32),
99                channel_info,
100            ))),
101        }
102    }
103}
104
105impl AudioNodeEngine for DelayNode {
106    fn node_type(&self) -> AudioNodeType {
107        AudioNodeType::DelayNode
108    }
109
110    fn process(&mut self, inputs: Chunk, info: &BlockInfo) -> Chunk {
111        let Some(delay_writer) = &mut self.delay_writer else {
112            error!("No DelayWriter initialized!");
113            return Chunk::explicit_silence();
114        };
115        delay_writer.process(inputs, info);
116
117        // Read from the internal buffer
118        let Some(delay_reader) = &mut self.delay_reader else {
119            error!("No DelayReader initialized!");
120            return Chunk::explicit_silence();
121        };
122        delay_reader.process(Chunk::default(), info)
123    }
124
125    fn get_param(&mut self, id: ParamType) -> &mut Param {
126        // DelayReader should not be None when `get_param` is called.
127        // The only time DelayNode gives up ownership of its DelayReader is within a render quantum
128        // processing loop, when it gives ownership to the graph. In this case it has removed itself
129        // from the graph so it will not be processed, and therefore never call `get_param` within the
130        // processing loop.
131        self.delay_reader
132            .as_mut()
133            .expect("Tried to get delay_time Param without an owned DelayReader.")
134            .get_param(id)
135    }
136}