Skip to content

Commit a6913d1

Browse files
committed
make start time sticky to sample time when inside floating point error zone, cf. buffer stitching wpt test
make start time sticky to sample time when inside floating point error zone cf. buffer stitching from wpt
1 parent f4478ef commit a6913d1

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ include = [
1818
rust-version = "1.71"
1919

2020
[dependencies]
21+
almost = "0.2.0"
2122
arc-swap = "1.6"
2223
arrayvec = "0.7"
2324
cpal = { version = "0.15", optional = true }

src/node/audio_buffer_source.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,12 +633,20 @@ impl AudioProcessor for AudioBufferSourceRenderer {
633633
for (i, playback_info) in playback_infos.iter_mut().enumerate() {
634634
let current_time = block_time + i as f64 * dt;
635635

636+
// handle floating point errors due to start time computation
637+
// cf. test_subsample_buffer_stitching
638+
if !self.render_state.started {
639+
if almost::equal(current_time, self.start_time) {
640+
self.start_time = current_time;
641+
}
642+
}
643+
636644
// Handle following cases:
637645
// - we are before start time
638646
// - we are after stop time
639647
// - explicit duration (in buffer time reference) has been given and we have reached it
640648
// Note that checking against buffer duration is done below to handle looping
641-
if current_time < self.start_time
649+
if (current_time < self.start_time)
642650
|| current_time >= self.stop_time
643651
|| self.render_state.buffer_time_elapsed >= self.duration
644652
{
@@ -647,6 +655,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
647655

648656
// we have now reached start time
649657
if !self.render_state.started {
658+
// println!("start, {}, {}, {}", current_time, self.start_time, (current_time - self.start_time).abs());
650659
let delta = current_time - self.start_time;
651660
// handle that start time may be between last sample and this one
652661
self.offset += delta;
@@ -835,6 +844,7 @@ mod tests {
835844
use std::sync::{Arc, Mutex};
836845

837846
use crate::context::{BaseAudioContext, OfflineAudioContext};
847+
use crate::AudioBufferOptions;
838848
use crate::RENDER_QUANTUM_SIZE;
839849

840850
use super::*;
@@ -1817,6 +1827,49 @@ mod tests {
18171827
assert_float_eq!(channel[..], expected[..], abs_all <= 0.);
18181828
}
18191829

1830+
#[test]
1831+
// ported from wpt: the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html
1832+
fn test_subsample_buffer_stitching() {
1833+
let sample_rate = 44_100.;
1834+
let buffer_rate = 44_100.;
1835+
let buffer_length = 30;
1836+
let frequency = 440.;
1837+
1838+
let length = buffer_length * 15;
1839+
let mut context = OfflineAudioContext::new(1, length, sample_rate);
1840+
1841+
let mut wave_signal = vec![0.; context.length()];
1842+
let omega = 2. * PI / buffer_rate * frequency;
1843+
1844+
wave_signal.iter_mut().enumerate().for_each(|(i, s)| {
1845+
*s = (omega * i as f32).sin();
1846+
});
1847+
1848+
// Slice the sine wave into many little buffers to be assigned to ABSNs
1849+
// that are started at the appropriate times to produce a final sine
1850+
// wave.
1851+
for k in (0..context.length()).step_by(buffer_length) {
1852+
let mut buffer = AudioBuffer::new(AudioBufferOptions {
1853+
number_of_channels: 1,
1854+
length: buffer_length,
1855+
sample_rate,
1856+
});
1857+
buffer.copy_to_channel(&wave_signal[k..k + buffer_length], 0);
1858+
1859+
let mut src = AudioBufferSourceNode::new(&context, AudioBufferSourceOptions {
1860+
buffer: Some(buffer),
1861+
..Default::default()
1862+
});
1863+
src.connect(&context.destination());
1864+
src.start_at(k as f64 / buffer_rate as f64);
1865+
}
1866+
1867+
let result = context.start_rendering_sync();
1868+
let channel = result.get_channel_data(0);
1869+
1870+
assert_float_eq!(channel[..], wave_signal[..], abs_all <= 1e-9);
1871+
}
1872+
18201873
#[test]
18211874
fn test_onended_before_drop() {
18221875
let sample_rate = 48_000.;

0 commit comments

Comments
 (0)