@@ -411,6 +411,7 @@ impl AudioBufferSourceRenderer {
411411 if self . loop_state . start < 0. {
412412 self . loop_state . start = 0. ;
413413 }
414+
414415 if self . loop_state . start > duration {
415416 self . loop_state . start = duration;
416417 }
@@ -455,8 +456,8 @@ impl AudioProcessor for AudioBufferSourceRenderer {
455456 let buffer = match & self . buffer {
456457 None => {
457458 output. make_silent ( ) ;
458- // #462 like the above arm, we can safely return tail_time false if this node has
459- // no buffer set.
459+ // #462 like the above arm, we can safely return tail_time false
460+ // if this node has no buffer set.
460461 return false ;
461462 }
462463 Some ( b) => b,
@@ -468,6 +469,8 @@ impl AudioProcessor for AudioBufferSourceRenderer {
468469 end : loop_end,
469470 } = self . loop_state ;
470471
472+ println ! ( "infos: {loop_start}, {loop_end}" ) ;
473+
471474 // these will only be used if `loop_` is true, so no need for `Option`
472475 let mut actual_loop_start = 0. ;
473476 let mut actual_loop_end = 0. ;
@@ -479,6 +482,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
479482 let computed_playback_rate = ( playback_rate * ( detune / 1200. ) . exp2 ( ) ) as f64 ;
480483
481484 let buffer_duration = buffer. duration ( ) ;
485+ let buffer_length = buffer. length ( ) ;
482486 // multiplier to be applied on `position` to tackle possible difference
483487 // between the context and buffer sample rates. As this is an edge case,
484488 // we just linearly interpolate, thus favoring performance vs quality
@@ -637,6 +641,11 @@ impl AudioProcessor for AudioBufferSourceRenderer {
637641 for ( i, playback_info) in playback_infos. iter_mut ( ) . enumerate ( ) {
638642 let current_time = block_time + i as f64 * dt;
639643
644+ // Handle following cases:
645+ // - we are before start time
646+ // - we are after stop time
647+ // - explicit duration (in buffer time reference) has been given and we have reached it
648+ // Note that checking against buffer duration is done below to handle looping
640649 if current_time < self . start_time
641650 || current_time >= self . stop_time
642651 || self . render_state . buffer_time_elapsed >= self . duration
@@ -696,10 +705,15 @@ impl AudioProcessor for AudioBufferSourceRenderer {
696705 let prev_frame_index = playhead_floored as usize ; // can't be < 0.
697706 let k = ( playhead - playhead_floored) as f32 ;
698707
699- * playback_info = Some ( PlaybackInfo {
700- prev_frame_index,
701- k,
702- } ) ;
708+ // Due to how buffer_time is computed, we can still run into
709+ // floating point errors and try to access a non existing index
710+ // cf. test_end_of_file_slow_track_2
711+ if prev_frame_index < buffer_length {
712+ * playback_info = Some ( PlaybackInfo {
713+ prev_frame_index,
714+ k,
715+ } ) ;
716+ }
703717 }
704718
705719 let time_incr = dt * computed_playback_rate;
@@ -726,10 +740,31 @@ impl AudioProcessor for AudioBufferSourceRenderer {
726740 } ) => {
727741 // `prev_frame_index` cannot be out of bounds
728742 let prev_sample = buffer_channel[ * prev_frame_index] ;
743+
744+ // @todo - stiching between loop points
729745 let next_sample = match buffer_channel. get ( prev_frame_index + 1 )
730746 {
731747 Some ( val) => * val,
732- None => 0. ,
748+ None => {
749+ // @todo - this works only in "normal" case
750+ // - check invalid loop points
751+ // - playback_rate < 0.
752+ //
753+ // find first sample >= to start loop point
754+ if is_looping {
755+ let start_playhead = actual_loop_start * sample_rate;
756+ let start_index = if start_playhead. floor ( ) == start_playhead {
757+ start_playhead as usize
758+ } else {
759+ start_playhead as usize + 1
760+ } ;
761+ println ! ( "{actual_loop_start}, {actual_loop_end}" ) ;
762+
763+ buffer_channel[ start_index]
764+ } else {
765+ 0.
766+ }
767+ }
733768 } ;
734769
735770 ( 1. - k) . mul_add ( prev_sample, k * next_sample)
@@ -1395,6 +1430,45 @@ mod tests {
13951430 }
13961431 }
13971432
1433+ #[ test]
1434+ fn test_slow_track_loop_mono ( ) {
1435+ let sample_rate = 48_000. ;
1436+ let len = RENDER_QUANTUM_SIZE * 4 ;
1437+
1438+ for buffer_len in [
1439+ RENDER_QUANTUM_SIZE / 2 - 1 ,
1440+ RENDER_QUANTUM_SIZE / 2 ,
1441+ RENDER_QUANTUM_SIZE / 2 + 1 ,
1442+ RENDER_QUANTUM_SIZE - 1 ,
1443+ RENDER_QUANTUM_SIZE ,
1444+ RENDER_QUANTUM_SIZE + 1 ,
1445+ RENDER_QUANTUM_SIZE * 2 - 1 ,
1446+ RENDER_QUANTUM_SIZE * 2 ,
1447+ RENDER_QUANTUM_SIZE * 2 + 1 ,
1448+ ] {
1449+ let mut context = OfflineAudioContext :: new ( 1 , len, sample_rate) ;
1450+
1451+ let mut dirac = context. create_buffer ( 1 , buffer_len, sample_rate) ;
1452+ dirac. copy_to_channel ( & [ 1. ] , 0 ) ;
1453+
1454+ let mut src = context. create_buffer_source ( ) ;
1455+ src. connect ( & context. destination ( ) ) ;
1456+ src. set_loop ( true ) ;
1457+ src. set_buffer ( dirac) ;
1458+ src. start_at ( 1. / sample_rate as f64 ) ;
1459+
1460+ let result = context. start_rendering_sync ( ) ;
1461+ let channel = result. get_channel_data ( 0 ) ;
1462+
1463+ let mut expected = vec ! [ 0. ; len] ;
1464+ for i in ( 1 ..len) . step_by ( buffer_len) {
1465+ expected[ i] = 1. ;
1466+ }
1467+
1468+ assert_float_eq ! ( channel[ ..] , expected[ ..] , abs_all <= 1e-9 ) ;
1469+ }
1470+ }
1471+
13981472 #[ test]
13991473 fn test_fast_track_loop_stereo ( ) {
14001474 let sample_rate = 48_000. ;
@@ -1426,9 +1500,12 @@ mod tests {
14261500
14271501 let mut expected_left: Vec < f32 > = vec ! [ 0. ; len] ;
14281502 let mut expected_right = vec ! [ 0. ; len] ;
1429- for i in ( 0 ..len - 1 ) . step_by ( buffer_len) {
1503+ for i in ( 0 ..len) . step_by ( buffer_len) {
14301504 expected_left[ i] = 1. ;
1431- expected_right[ i + 1 ] = 1. ;
1505+
1506+ if i < expected_right. len ( ) - 1 {
1507+ expected_right[ i + 1 ] = 1. ;
1508+ }
14321509 }
14331510
14341511 assert_float_eq ! (
@@ -1444,10 +1521,62 @@ mod tests {
14441521 }
14451522 }
14461523
1524+ #[ test]
1525+ fn test_slow_track_loop_stereo ( ) {
1526+ let sample_rate = 48_000. ;
1527+ let len = RENDER_QUANTUM_SIZE * 4 ;
1528+
1529+ for buffer_len in [
1530+ RENDER_QUANTUM_SIZE / 2 - 1 ,
1531+ RENDER_QUANTUM_SIZE / 2 ,
1532+ RENDER_QUANTUM_SIZE / 2 + 1 ,
1533+ RENDER_QUANTUM_SIZE - 1 ,
1534+ RENDER_QUANTUM_SIZE ,
1535+ RENDER_QUANTUM_SIZE + 1 ,
1536+ RENDER_QUANTUM_SIZE * 2 - 1 ,
1537+ RENDER_QUANTUM_SIZE * 2 ,
1538+ RENDER_QUANTUM_SIZE * 2 + 1 ,
1539+ ] {
1540+ let mut context = OfflineAudioContext :: new ( 2 , len, sample_rate) ;
1541+ let mut dirac = context. create_buffer ( 2 , buffer_len, sample_rate) ;
1542+ dirac. copy_to_channel ( & [ 1. ] , 0 ) ;
1543+ dirac. copy_to_channel ( & [ 0. , 1. ] , 1 ) ;
1544+
1545+ let mut src = context. create_buffer_source ( ) ;
1546+ src. connect ( & context. destination ( ) ) ;
1547+ src. set_loop ( true ) ;
1548+ src. set_buffer ( dirac) ;
1549+ src. start_at ( 1. / sample_rate as f64 ) ;
1550+
1551+ let result = context. start_rendering_sync ( ) ;
1552+
1553+ let mut expected_left: Vec < f32 > = vec ! [ 0. ; len] ;
1554+ let mut expected_right = vec ! [ 0. ; len] ;
1555+ for i in ( 1 ..len) . step_by ( buffer_len) {
1556+ expected_left[ i] = 1. ;
1557+
1558+ if i < expected_right. len ( ) - 1 {
1559+ expected_right[ i + 1 ] = 1. ;
1560+ }
1561+ }
1562+
1563+ assert_float_eq ! (
1564+ result. get_channel_data( 0 ) [ ..] ,
1565+ expected_left[ ..] ,
1566+ abs_all <= 1e-9
1567+ ) ;
1568+ assert_float_eq ! (
1569+ result. get_channel_data( 1 ) [ ..] ,
1570+ expected_right[ ..] ,
1571+ abs_all <= 1e-9
1572+ ) ;
1573+ }
1574+ }
1575+
14471576 #[ test]
14481577 fn test_loop_hangs ( ) {
14491578 let sample_rate = 48_000. ;
1450- let length = sample_rate as usize ;
1579+ let length = sample_rate as usize / 10 ;
14511580 let mut context = OfflineAudioContext :: new ( 1 , length, sample_rate) ;
14521581
14531582 let mut buffer = context. create_buffer ( 1 , 500 , sample_rate) ;
@@ -1468,7 +1597,7 @@ mod tests {
14681597 let channel = result. get_channel_data ( 0 ) ;
14691598
14701599 assert_float_eq ! ( channel[ 0 ] , 1.0 , abs_all <= 0. ) ;
1471- assert_float_eq ! ( channel[ 1 ..] , [ 0. ; 48_000 - 1 ] [ ..] , abs_all <= 0. ) ;
1600+ assert_float_eq ! ( channel[ 1 ..] , vec! [ 0. ; length - 1 ] [ ..] , abs_all <= 0. ) ;
14721601 }
14731602
14741603 #[ test]
@@ -1501,6 +1630,36 @@ mod tests {
15011630 assert_float_eq ! ( channel[ ..] , expected[ ..] , abs_all <= 0. ) ;
15021631 }
15031632
1633+ #[ test]
1634+ // regression test for #452
1635+ // - fals track
1636+ // - duration not set so `self.duration` is `f64::MAX`
1637+ // - stop time is > buffer length
1638+ fn test_end_of_file_slow_track_2 ( ) {
1639+ let sample_rate = 48_000. ;
1640+ let mut context = OfflineAudioContext :: new ( 1 , RENDER_QUANTUM_SIZE , sample_rate) ;
1641+
1642+ let mut buffer = context. create_buffer ( 1 , 5 , sample_rate) ;
1643+ let data = vec ! [ 1. ; 1 ] ;
1644+ buffer. copy_to_channel ( & data, 0 ) ;
1645+
1646+ let mut src = context. create_buffer_source ( ) ;
1647+ src. connect ( & context. destination ( ) ) ;
1648+ src. set_buffer ( buffer) ;
1649+ // play in fast track
1650+ src. start_at ( 1. / sample_rate as f64 ) ;
1651+ // stop after end of buffer but before the end of render quantum
1652+ src. stop_at ( 125. / sample_rate as f64 ) ;
1653+
1654+ let result = context. start_rendering_sync ( ) ;
1655+ let channel = result. get_channel_data ( 0 ) ;
1656+
1657+ let mut expected = vec ! [ 0. ; 128 ] ;
1658+ expected[ 1 ] = 1. ;
1659+
1660+ assert_float_eq ! ( channel[ ..] , expected[ ..] , abs_all <= 0. ) ;
1661+ }
1662+
15041663 #[ test]
15051664 fn test_loop_no_restart_suspend ( ) {
15061665 let sample_rate = 48_000. ;
0 commit comments