Skip to content

Commit d62bdfe

Browse files
committed
fix: ring buffer size + add previously failling tests from wpt
1 parent 86c1a5c commit d62bdfe

File tree

1 file changed

+147
-99
lines changed

1 file changed

+147
-99
lines changed

src/node/delay.rs

Lines changed: 147 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -197,24 +197,20 @@ impl DelayNode {
197197
"NotSupportedError - maxDelayTime MUST be greater than zero and less than three minutes",
198198
);
199199

200-
// we internally clamp max delay to quantum duration because the current
201-
// implementation doesn't allow sub-quantum delays. Later, this will
202-
// ensure that even if the declared max_delay_time and max_delay are smaller
200+
// wW internally clamp max delay to quantum duration. This ensure
201+
// that even if the declared max_delay_time and max_delay are smaller
203202
// than quantum duration, the node, if found in a loop, will gracefully
204-
// fallback to the clamped behavior. (e.g. we ensure that ring buffer size
205-
// is always >= 2)
203+
// fallback to the clamped behavior. (e.g. we ensure that ring buffer
204+
// size is always >= 2)
206205
let quantum_duration = 1. / sample_rate * RENDER_QUANTUM_SIZE as f64;
207206
let max_delay_time = options.max_delay_time.max(quantum_duration);
208207

209-
// allocate large enough buffer to store all delayed samples
210-
//
211-
// we add 1 here so that in edge cases where num_samples is a multiple of
212-
// RENDER_QUANTUM_SIZE and delay_time == max_delay_time we are sure to
213-
// enough room for history. (see. test_max_delay_multiple_of_quantum_size)
214-
let num_samples = max_delay_time * sample_rate + 1.;
215-
let num_quanta =
216-
(num_samples.ceil() as usize + RENDER_QUANTUM_SIZE - 1) / RENDER_QUANTUM_SIZE;
217-
let ring_buffer = Vec::with_capacity(num_quanta);
208+
// Allocate large enough buffer to store all delayed samples.
209+
// We add one extra buffer in the ring buffer so that reader never read the
210+
// same entry in history as the writer, even if `delay_time === max_delay_time`
211+
// cf. test_max_delay_multiple_of_quantum_size and test_max_delay
212+
let num_quanta = (max_delay_time * sample_rate / RENDER_QUANTUM_SIZE as f64).ceil() as usize;
213+
let ring_buffer = Vec::with_capacity(num_quanta + 1);
218214

219215
let shared_ring_buffer = Rc::new(RefCell::new(ring_buffer));
220216
let shared_ring_buffer_clone = Rc::clone(&shared_ring_buffer);
@@ -707,60 +703,59 @@ mod tests {
707703
}
708704

709705
#[test]
710-
fn test_sub_sample_accurate() {
711-
{
712-
let delay_in_samples = 128.5;
713-
let sample_rate = 48000.;
714-
let mut context = OfflineAudioContext::new(1, 256, sample_rate);
706+
fn test_sub_sample_accurate_1() {
707+
let delay_in_samples = 128.5;
708+
let sample_rate = 48000.;
709+
let mut context = OfflineAudioContext::new(1, 256, sample_rate);
715710

716-
let delay = context.create_delay(2.);
717-
delay.delay_time.set_value(delay_in_samples / sample_rate);
718-
delay.connect(&context.destination());
711+
let delay = context.create_delay(2.);
712+
delay.delay_time.set_value(delay_in_samples / sample_rate);
713+
delay.connect(&context.destination());
719714

720-
let mut dirac = context.create_buffer(1, 1, sample_rate);
721-
dirac.copy_to_channel(&[1.], 0);
715+
let mut dirac = context.create_buffer(1, 1, sample_rate);
716+
dirac.copy_to_channel(&[1.], 0);
722717

723-
let mut src = context.create_buffer_source();
724-
src.connect(&delay);
725-
src.set_buffer(dirac);
726-
src.start_at(0.);
718+
let mut src = context.create_buffer_source();
719+
src.connect(&delay);
720+
src.set_buffer(dirac);
721+
src.start_at(0.);
727722

728-
let result = context.start_rendering_sync();
729-
let channel = result.get_channel_data(0);
723+
let result = context.start_rendering_sync();
724+
let channel = result.get_channel_data(0);
730725

731-
let mut expected = vec![0.; 256];
732-
expected[128] = 0.5;
733-
expected[129] = 0.5;
726+
let mut expected = vec![0.; 256];
727+
expected[128] = 0.5;
728+
expected[129] = 0.5;
734729

735-
assert_float_eq!(channel[..], expected[..], abs_all <= 0.00001);
736-
}
730+
assert_float_eq!(channel[..], expected[..], abs_all <= 0.00001);
731+
}
737732

738-
{
739-
let delay_in_samples = 128.8;
740-
let sample_rate = 48000.;
741-
let mut context = OfflineAudioContext::new(1, 256, sample_rate);
733+
#[test]
734+
fn test_sub_sample_accurate_2() {
735+
let delay_in_samples = 128.8;
736+
let sample_rate = 48000.;
737+
let mut context = OfflineAudioContext::new(1, 256, sample_rate);
742738

743-
let delay = context.create_delay(2.);
744-
delay.delay_time.set_value(delay_in_samples / sample_rate);
745-
delay.connect(&context.destination());
739+
let delay = context.create_delay(2.);
740+
delay.delay_time.set_value(delay_in_samples / sample_rate);
741+
delay.connect(&context.destination());
746742

747-
let mut dirac = context.create_buffer(1, 1, sample_rate);
748-
dirac.copy_to_channel(&[1.], 0);
743+
let mut dirac = context.create_buffer(1, 1, sample_rate);
744+
dirac.copy_to_channel(&[1.], 0);
749745

750-
let mut src = context.create_buffer_source();
751-
src.connect(&delay);
752-
src.set_buffer(dirac);
753-
src.start_at(0.);
746+
let mut src = context.create_buffer_source();
747+
src.connect(&delay);
748+
src.set_buffer(dirac);
749+
src.start_at(0.);
754750

755-
let result = context.start_rendering_sync();
756-
let channel = result.get_channel_data(0);
751+
let result = context.start_rendering_sync();
752+
let channel = result.get_channel_data(0);
757753

758-
let mut expected = vec![0.; 256];
759-
expected[128] = 0.2;
760-
expected[129] = 0.8;
754+
let mut expected = vec![0.; 256];
755+
expected[128] = 0.2;
756+
expected[129] = 0.8;
761757

762-
assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
763-
}
758+
assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
764759
}
765760

766761
#[test]
@@ -935,6 +930,60 @@ mod tests {
935930
assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
936931
}
937932

933+
// reproduce wpt tests from
934+
// - the-delaynode-interface/delaynode-max-default-delay.html
935+
// - the-delaynode-interface/delaynode-max-nondefault-delay.html
936+
#[test]
937+
fn test_max_delay() {
938+
use std::f32::consts::PI;
939+
940+
for &delay_time_seconds in [1., 1.5].iter() {
941+
let sample_rate = 44100.0;
942+
let render_length = 4 * sample_rate as usize;
943+
944+
let mut context = OfflineAudioContext::new(1, render_length, sample_rate);
945+
946+
// create 2 seconds tone buffer at 20Hz
947+
let tone_frequency = 20.;
948+
let tone_length_seconds = 2.;
949+
let tone_length = tone_length_seconds as usize * sample_rate as usize;
950+
let mut tone_buffer = context.create_buffer(1, tone_length, sample_rate);
951+
let tone_data = tone_buffer.get_channel_data_mut(0);
952+
953+
for i in 0..tone_data.len() {
954+
tone_data[i] = (tone_frequency * 2.0 * PI * i as f32 / sample_rate).sin();
955+
}
956+
957+
let mut buffer_source = context.create_buffer_source();
958+
buffer_source.set_buffer(tone_buffer.clone());
959+
960+
let delay = context.create_delay(delay_time_seconds); // max delay defaults to 1 second
961+
delay.delay_time.set_value(delay_time_seconds as f32);
962+
963+
buffer_source.connect(&delay);
964+
delay.connect(&context.destination());
965+
buffer_source.start_at(0.);
966+
967+
let output = context.start_rendering_sync();
968+
let source = tone_buffer.get_channel_data(0);
969+
let rendered = output.get_channel_data(0);
970+
971+
let delay_time_frames = (delay_time_seconds * sample_rate as f64) as usize;
972+
let tone_length_frames = (tone_length_seconds * sample_rate as f64) as usize;
973+
974+
for i in 0..rendered.len() {
975+
if i < delay_time_frames {
976+
assert_eq!(rendered[i], 0.);
977+
} else if i >= delay_time_frames && i < delay_time_frames + tone_length_frames {
978+
let j = i - delay_time_frames;
979+
assert_eq!(rendered[i], source[j]);
980+
} else {
981+
assert_eq!(rendered[i], 0.);
982+
}
983+
}
984+
}
985+
}
986+
938987
#[test]
939988
fn test_max_delay_smaller_than_quantum_size() {
940989
// regression test that even if the declared max_delay_time is smaller than
@@ -975,66 +1024,65 @@ mod tests {
9751024
}
9761025
}
9771026

1027+
// test_max_delay_multiple_of_quantum_size_x
1028+
// are regression test that delay node has always enough internal buffer size
1029+
// when max_delay is a multiple of quantum size and delay == max_delay.
1030+
// This bug only occurs when the Writer is called before than the Reader,
1031+
// which is the case when not in a loop
9781032
#[test]
979-
fn test_max_delay_multiple_of_quantum_size() {
980-
// regression test that delay node has always enough internal buffer size
981-
// when max_delay is a multiple of quantum size and delay == max_delay.
982-
// This bug only occurs when the Writer is called before than the Reader,
983-
// which is the case when not in a loop
984-
1033+
fn test_max_delay_multiple_of_quantum_size_1() {
9851034
// set delay and max delay time exactly 1 render quantum
986-
{
987-
let sample_rate = 48000.;
988-
let mut context = OfflineAudioContext::new(1, 256, sample_rate);
1035+
let sample_rate = 48000.;
1036+
let mut context = OfflineAudioContext::new(1, 256, sample_rate);
9891037

990-
let max_delay = 128. / sample_rate;
991-
let delay = context.create_delay(max_delay.into());
992-
delay.delay_time.set_value(max_delay);
993-
delay.connect(&context.destination());
1038+
let max_delay = 128. / sample_rate;
1039+
let delay = context.create_delay(max_delay.into());
1040+
delay.delay_time.set_value(max_delay);
1041+
delay.connect(&context.destination());
9941042

995-
let mut dirac = context.create_buffer(1, 1, sample_rate);
996-
dirac.copy_to_channel(&[1.], 0);
1043+
let mut dirac = context.create_buffer(1, 1, sample_rate);
1044+
dirac.copy_to_channel(&[1.], 0);
9971045

998-
let mut src = context.create_buffer_source();
999-
src.connect(&delay);
1000-
src.set_buffer(dirac);
1001-
src.start_at(0.);
1046+
let mut src = context.create_buffer_source();
1047+
src.connect(&delay);
1048+
src.set_buffer(dirac);
1049+
src.start_at(0.);
10021050

1003-
let result = context.start_rendering_sync();
1004-
let channel = result.get_channel_data(0);
1051+
let result = context.start_rendering_sync();
1052+
let channel = result.get_channel_data(0);
10051053

1006-
let mut expected = vec![0.; 256];
1007-
expected[128] = 1.;
1054+
let mut expected = vec![0.; 256];
1055+
expected[128] = 1.;
10081056

1009-
assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
1010-
}
1057+
assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
1058+
}
10111059

1060+
#[test]
1061+
fn test_max_delay_multiple_of_quantum_size_2() {
10121062
// set delay and max delay time exactly 2 render quantum
1013-
{
1014-
let sample_rate = 48_000.;
1015-
let mut context = OfflineAudioContext::new(1, 3 * 128, sample_rate);
1063+
let sample_rate = 48_000.;
1064+
let mut context = OfflineAudioContext::new(1, 3 * 128, sample_rate);
10161065

1017-
let max_delay = 128. * 2. / sample_rate;
1018-
let delay = context.create_delay(max_delay.into());
1019-
delay.delay_time.set_value(max_delay);
1020-
delay.connect(&context.destination());
1066+
let max_delay = 128. * 2. / sample_rate;
1067+
let delay = context.create_delay(max_delay.into());
1068+
delay.delay_time.set_value(max_delay);
1069+
delay.connect(&context.destination());
10211070

1022-
let mut dirac = context.create_buffer(1, 1, sample_rate);
1023-
dirac.copy_to_channel(&[1.], 0);
1071+
let mut dirac = context.create_buffer(1, 1, sample_rate);
1072+
dirac.copy_to_channel(&[1.], 0);
10241073

1025-
let mut src = context.create_buffer_source();
1026-
src.connect(&delay);
1027-
src.set_buffer(dirac);
1028-
src.start_at(0.);
1074+
let mut src = context.create_buffer_source();
1075+
src.connect(&delay);
1076+
src.set_buffer(dirac);
1077+
src.start_at(0.);
10291078

1030-
let result = context.start_rendering_sync();
1031-
let channel = result.get_channel_data(0);
1079+
let result = context.start_rendering_sync();
1080+
let channel = result.get_channel_data(0);
10321081

1033-
let mut expected = vec![0.; 3 * 128];
1034-
expected[256] = 1.;
1082+
let mut expected = vec![0.; 3 * 128];
1083+
expected[256] = 1.;
10351084

1036-
assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
1037-
}
1085+
assert_float_eq!(channel[..], expected[..], abs_all <= 1e-5);
10381086
}
10391087

10401088
#[test]

0 commit comments

Comments
 (0)