@@ -401,23 +401,24 @@ impl AudioBufferSourceRenderer {
401401 ControlMessage :: LoopEnd ( loop_end) => self . loop_state . end = * loop_end,
402402 }
403403
404+ // @todo -
404405 self . clamp_loop_boundaries ( ) ;
405406 }
406407
407408 fn clamp_loop_boundaries ( & mut self ) {
408409 if let Some ( buffer) = & self . buffer {
409410 let duration = buffer. duration ( ) ;
410411
412+ // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopstart
411413 if self . loop_state . start < 0. {
412414 self . loop_state . start = 0. ;
413- }
414-
415- if self . loop_state . start > duration {
415+ } else if self . loop_state . start > duration {
416416 self . loop_state . start = duration;
417417 }
418418
419+ // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopend
419420 if self . loop_state . end <= 0. || self . loop_state . end > duration {
420- self . loop_state . end = 0. ;
421+ self . loop_state . end = duration ;
421422 }
422423 }
423424 }
@@ -469,8 +470,6 @@ impl AudioProcessor for AudioBufferSourceRenderer {
469470 end : loop_end,
470471 } = self . loop_state ;
471472
472- println ! ( "infos: {loop_start}, {loop_end}" ) ;
473-
474473 // these will only be used if `loop_` is true, so no need for `Option`
475474 let mut actual_loop_start = 0. ;
476475 let mut actual_loop_end = 0. ;
@@ -526,9 +525,11 @@ impl AudioProcessor for AudioBufferSourceRenderer {
526525 // For now we just consider that we can go fast track if loop points are
527526 // bound to the buffer boundaries.
528527 //
529- // by default loop_end is 0., see AudioBufferSourceOptions
530- // but loop_start = 0 && loop_end = buffer.duration should go to fast track
531- if loop_start != 0. || ( loop_end != 0. && loop_end != self . duration ) {
528+ // by default loop_end is equal to buffer_duration, so loop_start = 0 &&
529+ // loop_end = buffer.duration should go to fast track
530+
531+ // @todo - test loop_end against 0 too, semantics is loop_end as not been changed
532+ if loop_start != 0. || loop_end != buffer_duration {
532533 self . render_state . is_aligned = false ;
533534 }
534535
@@ -556,9 +557,8 @@ impl AudioProcessor for AudioBufferSourceRenderer {
556557 buffer. length ( )
557558 } ;
558559
559- // in case of a loop point in the middle of the block, this value
560- // will be used to recompute `buffer_time` according
561- // to the actual loop point.
560+ // In case of a loop point in the middle of the block, this value will
561+ // be used to recompute `buffer_time` according to the actual loop point.
562562 let mut loop_point_index: Option < usize > = None ;
563563
564564 buffer
@@ -624,6 +624,7 @@ impl AudioProcessor for AudioBufferSourceRenderer {
624624 if is_looping {
625625 if loop_start >= 0. && loop_end > 0. && loop_start < loop_end {
626626 actual_loop_start = loop_start;
627+ // @todo - min is not required loop_end is already clamped
627628 actual_loop_end = loop_end. min ( buffer_duration) ;
628629 } else {
629630 actual_loop_start = 0. ;
@@ -740,25 +741,22 @@ impl AudioProcessor for AudioBufferSourceRenderer {
740741 } ) => {
741742 // `prev_frame_index` cannot be out of bounds
742743 let prev_sample = buffer_channel[ * prev_frame_index] ;
743-
744- // @todo - stiching between loop points
745744 let next_sample = match buffer_channel. get ( prev_frame_index + 1 )
746745 {
747746 Some ( val) => * val,
748747 None => {
749- // @todo - this works only in "normal" case
750- // - check invalid loop points
751- // - playback_rate < 0.
748+ // @todo - handle playback_rate < 0.
752749 //
753750 // find first sample >= to start loop point
754751 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}" ) ;
752+ let start_playhead =
753+ actual_loop_start * sample_rate;
754+ let start_index =
755+ if start_playhead. floor ( ) == start_playhead {
756+ start_playhead as usize
757+ } else {
758+ start_playhead as usize + 1
759+ } ;
762760
763761 buffer_channel[ start_index]
764762 } else {
@@ -1426,7 +1424,7 @@ mod tests {
14261424 expected[ i] = 1. ;
14271425 }
14281426
1429- assert_float_eq ! ( channel[ ..] , expected[ ..] , abs_all <= 0. ) ;
1427+ assert_float_eq ! ( channel[ ..] , expected[ ..] , abs_all <= 1e-10 ) ;
14301428 }
14311429 }
14321430
@@ -1511,12 +1509,12 @@ mod tests {
15111509 assert_float_eq ! (
15121510 result. get_channel_data( 0 ) [ ..] ,
15131511 expected_left[ ..] ,
1514- abs_all <= 0.
1512+ abs_all <= 1e-10
15151513 ) ;
15161514 assert_float_eq ! (
15171515 result. get_channel_data( 1 ) [ ..] ,
15181516 expected_right[ ..] ,
1519- abs_all <= 0.
1517+ abs_all <= 1e-10
15201518 ) ;
15211519 }
15221520 }
@@ -1574,12 +1572,14 @@ mod tests {
15741572 }
15751573
15761574 #[ test]
1577- fn test_loop_hangs ( ) {
1575+ // @todo - test all conditions
1576+ fn test_loop_out_of_bounds ( ) {
15781577 let sample_rate = 48_000. ;
15791578 let length = sample_rate as usize / 10 ;
15801579 let mut context = OfflineAudioContext :: new ( 1 , length, sample_rate) ;
15811580
1582- let mut buffer = context. create_buffer ( 1 , 500 , sample_rate) ;
1581+ let buffer_size = 500 ;
1582+ let mut buffer = context. create_buffer ( 1 , buffer_size, sample_rate) ;
15831583 let data = vec ! [ 1. ; 1 ] ;
15841584 buffer. copy_to_channel ( & data, 0 ) ;
15851585
@@ -1590,14 +1590,25 @@ mod tests {
15901590 src. set_loop ( true ) ;
15911591 src. set_loop_start ( 0.5 ) ; // outside of buffer duration
15921592 src. set_loop_end ( 1.5 ) ; // outside of buffer duration
1593-
15941593 src. start ( ) ;
15951594
15961595 let result = context. start_rendering_sync ( ) ; // should terminate
15971596 let channel = result. get_channel_data ( 0 ) ;
15981597
1599- assert_float_eq ! ( channel[ 0 ] , 1.0 , abs_all <= 0. ) ;
1600- assert_float_eq ! ( channel[ 1 ..] , vec![ 0. ; length - 1 ] [ ..] , abs_all <= 0. ) ;
1598+ // Both loop points will be clamped to buffer duration due to rules defined at
1599+ // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopstart
1600+ // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopend
1601+ // Thus it violates the rule defined in
1602+ // https://webaudio.github.io/web-audio-api/#playback-AudioBufferSourceNode
1603+ // `loopStart >= 0 && loopEnd > 0 && loopStart < loopEnd`
1604+ // Hence the whole buffer should be looped
1605+
1606+ let mut expected = vec ! [ 0. ; length] ;
1607+ for i in ( 0 ..length) . step_by ( buffer_size) {
1608+ expected[ i] = 1. ;
1609+ }
1610+
1611+ assert_float_eq ! ( channel[ ..] , expected[ ..] , abs_all <= 0. ) ;
16011612 }
16021613
16031614 #[ test]
0 commit comments