Skip to content

Commit 75096f1

Browse files
authored
Merge pull request #482 from b-ma/fix/channel_splitter_options
Fix: more compliant option checks for ChannelSplitterNode
2 parents 8c520b1 + 495d59c commit 75096f1

File tree

3 files changed

+105
-15
lines changed

3 files changed

+105
-15
lines changed

src/node/channel_merger.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ impl AudioNode for ChannelMergerNode {
101101

102102
fn set_channel_count(&self, count: usize) {
103103
assert_valid_channel_count(count);
104-
self.channel_config.set_count(count, self.registration());
105104
}
106105

107106
fn set_channel_count_mode(&self, mode: ChannelCountMode) {
@@ -174,10 +173,35 @@ impl AudioProcessor for ChannelMergerRenderer {
174173

175174
#[cfg(test)]
176175
mod tests {
176+
use float_eq::assert_float_eq;
177+
177178
use crate::context::{BaseAudioContext, OfflineAudioContext};
178179
use crate::node::{AudioNode, AudioScheduledSourceNode};
179180

180-
use float_eq::assert_float_eq;
181+
use super::*;
182+
183+
#[test]
184+
#[should_panic]
185+
fn test_invalid_constructor_options() {
186+
let sample_rate = 48000.;
187+
let context = OfflineAudioContext::new(1, 128, sample_rate);
188+
189+
let mut options = ChannelMergerOptions::default();
190+
options.audio_node_options.channel_count = 2;
191+
192+
let _merger = ChannelMergerNode::new(&context, options);
193+
}
194+
195+
#[test]
196+
#[should_panic]
197+
fn test_invalid_set_channel_count() {
198+
let sample_rate = 48000.;
199+
let context = OfflineAudioContext::new(1, 128, sample_rate);
200+
201+
let options = ChannelMergerOptions::default();
202+
let merger = ChannelMergerNode::new(&context, options);
203+
merger.set_channel_count(3);
204+
}
181205

182206
#[test]
183207
fn test_merge() {

src/node/channel_splitter.rs

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::MAX_CHANNELS;
88

99
use super::{AudioNode, AudioNodeOptions, ChannelConfig, ChannelCountMode, ChannelInterpretation};
1010

11+
const DEFAULT_NUMBER_OF_OUTPUTS: usize = 6;
12+
1113
/// Assert that the given number of channels is valid for a ChannelMergerNode
1214
///
1315
/// # Panics
@@ -27,6 +29,22 @@ pub(crate) fn assert_valid_number_of_channels(number_of_channels: usize) {
2729
);
2830
}
2931

32+
/// Assert that the channel count is valid for the ChannelSplitterNode
33+
/// see <https://webaudio.github.io/web-audio-api/#audionode-channelcount-constraints>
34+
///
35+
/// # Panics
36+
///
37+
/// This function panics if given count is not equal to number of outputs
38+
///
39+
#[track_caller]
40+
#[inline(always)]
41+
fn assert_valid_channel_count(count: usize, number_of_outputs: usize) {
42+
assert!(
43+
count == number_of_outputs,
44+
"InvalidStateError - channel count of ChannelSplitterNode must be equal to number of outputs"
45+
);
46+
}
47+
3048
/// Assert that the channel count mode is valid for the ChannelSplitterNode
3149
/// see <https://webaudio.github.io/web-audio-api/#audionode-channelcountmode-constraints>
3250
///
@@ -72,9 +90,9 @@ pub struct ChannelSplitterOptions {
7290
impl Default for ChannelSplitterOptions {
7391
fn default() -> Self {
7492
Self {
75-
number_of_outputs: 6,
93+
number_of_outputs: DEFAULT_NUMBER_OF_OUTPUTS,
7694
audio_node_options: AudioNodeOptions {
77-
channel_count: 6, // must be same as number_of_outputs
95+
channel_count: DEFAULT_NUMBER_OF_OUTPUTS, // must be same as number_of_outputs
7896
channel_count_mode: ChannelCountMode::Explicit,
7997
channel_interpretation: ChannelInterpretation::Discrete,
8098
},
@@ -87,6 +105,7 @@ impl Default for ChannelSplitterOptions {
87105
pub struct ChannelSplitterNode {
88106
registration: AudioContextRegistration,
89107
channel_config: ChannelConfig,
108+
number_of_outputs: usize,
90109
}
91110

92111
impl AudioNode for ChannelSplitterNode {
@@ -99,11 +118,7 @@ impl AudioNode for ChannelSplitterNode {
99118
}
100119

101120
fn set_channel_count(&self, count: usize) {
102-
assert_eq!(
103-
count,
104-
self.channel_count(),
105-
"InvalidStateError - Cannot edit channel count of ChannelSplitterNode"
106-
);
121+
assert_valid_channel_count(count, self.number_of_outputs);
107122
}
108123

109124
fn set_channel_count_mode(&self, mode: ChannelCountMode) {
@@ -123,14 +138,23 @@ impl AudioNode for ChannelSplitterNode {
123138
}
124139

125140
fn number_of_outputs(&self) -> usize {
126-
self.channel_count()
141+
self.number_of_outputs
127142
}
128143
}
129144

130145
impl ChannelSplitterNode {
131146
pub fn new<C: BaseAudioContext>(context: &C, mut options: ChannelSplitterOptions) -> Self {
132147
context.base().register(move |registration| {
133148
assert_valid_number_of_channels(options.number_of_outputs);
149+
150+
// if channel count has been explicitly set, we need to check
151+
// its value against number of outputs
152+
if options.audio_node_options.channel_count != DEFAULT_NUMBER_OF_OUTPUTS {
153+
assert_valid_channel_count(
154+
options.audio_node_options.channel_count,
155+
options.number_of_outputs,
156+
);
157+
}
134158
options.audio_node_options.channel_count = options.number_of_outputs;
135159

136160
assert_valid_channel_count_mode(options.audio_node_options.channel_count_mode);
@@ -139,10 +163,11 @@ impl ChannelSplitterNode {
139163
let node = ChannelSplitterNode {
140164
registration,
141165
channel_config: options.audio_node_options.into(),
166+
number_of_outputs: options.number_of_outputs,
142167
};
143168

144169
let render = ChannelSplitterRenderer {
145-
number_of_outputs: node.channel_count(),
170+
number_of_outputs: options.number_of_outputs,
146171
};
147172

148173
(node, Box::new(render))
@@ -186,18 +211,59 @@ impl AudioProcessor for ChannelSplitterRenderer {
186211

187212
#[cfg(test)]
188213
mod tests {
214+
use float_eq::assert_float_eq;
215+
189216
use crate::context::{BaseAudioContext, OfflineAudioContext};
190217
use crate::node::{AudioNode, AudioScheduledSourceNode};
191218
use crate::AudioBuffer;
192219

193-
use float_eq::assert_float_eq;
220+
use super::*;
221+
222+
#[test]
223+
fn test_valid_constructor_options() {
224+
let sample_rate = 48000.;
225+
let context = OfflineAudioContext::new(1, 128, sample_rate);
226+
227+
let options = ChannelSplitterOptions {
228+
number_of_outputs: 2,
229+
..Default::default()
230+
};
231+
232+
let splitter = ChannelSplitterNode::new(&context, options);
233+
assert_eq!(splitter.number_of_outputs(), 2);
234+
assert_eq!(splitter.channel_count(), 2);
235+
}
236+
237+
#[test]
238+
#[should_panic]
239+
fn test_invalid_constructor_options() {
240+
let sample_rate = 48000.;
241+
let context = OfflineAudioContext::new(1, 128, sample_rate);
242+
243+
let mut options = ChannelSplitterOptions::default();
244+
options.audio_node_options.channel_count = 7;
245+
246+
let _splitter = ChannelSplitterNode::new(&context, options);
247+
}
248+
249+
#[test]
250+
#[should_panic]
251+
fn test_set_channel_count() {
252+
let sample_rate = 48000.;
253+
let context = OfflineAudioContext::new(1, 128, sample_rate);
254+
255+
let options = ChannelSplitterOptions::default();
256+
let splitter = ChannelSplitterNode::new(&context, options);
257+
splitter.set_channel_count(3);
258+
}
194259

195260
#[test]
196261
fn test_splitter() {
197262
let sample_rate = 48000.;
198263
let mut context = OfflineAudioContext::new(1, 128, sample_rate);
199264

200265
let splitter = context.create_channel_splitter(2);
266+
201267
// connect the 2nd output to the destination
202268
splitter.connect_at(&context.destination(), 1, 0);
203269

src/node/oscillator.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use super::{
1414
TABLE_LENGTH_USIZE,
1515
};
1616

17-
fn get_fase_incr(freq: f32, detune: f32, sample_rate: f64) -> f64 {
17+
fn get_phase_incr(freq: f32, detune: f32, sample_rate: f64) -> f64 {
1818
let computed_freq = freq as f64 * (detune as f64 / 1200.).exp2();
1919
let clamped = computed_freq.clamp(-sample_rate / 2., sample_rate / 2.);
2020
clamped / sample_rate
@@ -411,7 +411,7 @@ impl AudioProcessor for OscillatorRenderer {
411411
}
412412

413413
if frequency_values.len() == 1 && detune_values.len() == 1 {
414-
let phase_incr = get_fase_incr(frequency_values[0], detune_values[0], sample_rate);
414+
let phase_incr = get_phase_incr(frequency_values[0], detune_values[0], sample_rate);
415415
channel_data
416416
.iter_mut()
417417
.for_each(|output| self.generate_sample(output, phase_incr, &mut current_time, dt));
@@ -421,7 +421,7 @@ impl AudioProcessor for OscillatorRenderer {
421421
.zip(frequency_values.iter().cycle())
422422
.zip(detune_values.iter().cycle())
423423
.for_each(|((output, &f), &d)| {
424-
let phase_incr = get_fase_incr(f, d, sample_rate);
424+
let phase_incr = get_phase_incr(f, d, sample_rate);
425425
self.generate_sample(output, phase_incr, &mut current_time, dt)
426426
});
427427
}

0 commit comments

Comments
 (0)