@@ -740,30 +740,46 @@ impl AudioParamProcessor {
740
740
#[ cfg( test) ]
741
741
assert ! ( self . buffer. len( ) == 1 || self . buffer. len( ) == RENDER_QUANTUM_SIZE ) ;
742
742
743
- if self . buffer . len ( ) == 1 && input. is_silent ( ) {
743
+ // handle all k-rate and inactive a-rate processing
744
+ if self . buffer . len ( ) == 1 || !self . automation_rate . is_a_rate ( ) {
744
745
let mut value = self . buffer [ 0 ] ;
745
746
746
- if value. is_nan ( ) {
747
- value = self . default_value ;
748
- }
747
+ // we can return a 1-sized buffer if either
748
+ // - the input signal is zero, or
749
+ // - if this is k-rate processing
750
+ if input. is_silent ( ) || !self . automation_rate . is_a_rate ( ) {
751
+ output. set_single_valued ( true ) ;
752
+
753
+ value += input. channel_data ( 0 ) [ 0 ] ;
754
+
755
+ if value. is_nan ( ) {
756
+ value = self . default_value ;
757
+ }
758
+
759
+ output. channel_data_mut ( 0 ) [ 0 ] = value. clamp ( self . min_value , self . max_value ) ;
760
+ } else {
761
+ // a-rate processing and input non-zero
762
+ output. set_single_valued ( false ) ;
763
+ * output = input. clone ( ) ;
764
+ output. channel_data_mut ( 0 ) . iter_mut ( ) . for_each ( |o| {
765
+ * o += value;
749
766
750
- output. set_single_valued ( true ) ;
767
+ if o. is_nan ( ) {
768
+ * o = self . default_value ;
769
+ }
751
770
752
- let output_channel = output. channel_data_mut ( 0 ) ;
753
- output_channel[ 0 ] = value. clamp ( self . min_value , self . max_value ) ;
771
+ * o = o. clamp ( self . min_value , self . max_value )
772
+ } ) ;
773
+ }
754
774
} else {
755
- // @note: we could add two other optimizations here:
756
- // - when buffer.len() == 1 and buffer[0] == 0., then we don't need to
757
- // zip and add, but we still need to clamp
758
- // - when input.is_silent(), then we can copy_from_slice the buffer into
759
- // output and then just clamp
775
+ // a-rate processing
760
776
* output = input. clone ( ) ;
761
777
output. set_single_valued ( false ) ;
762
778
763
779
output
764
780
. channel_data_mut ( 0 )
765
781
. iter_mut ( )
766
- . zip ( self . buffer . iter ( ) . cycle ( ) )
782
+ . zip ( self . buffer . iter ( ) )
767
783
. for_each ( |( o, p) | {
768
784
* o += p;
769
785
@@ -3433,6 +3449,41 @@ mod tests {
3433
3449
}
3434
3450
}
3435
3451
3452
+ #[ test]
3453
+ fn test_k_rate_makes_input_single_valued ( ) {
3454
+ let alloc = Alloc :: with_capacity ( 1 ) ;
3455
+ let context = OfflineAudioContext :: new ( 1 , 0 , 48000. ) ;
3456
+
3457
+ let opts = AudioParamDescriptor {
3458
+ name : String :: new ( ) ,
3459
+ automation_rate : AutomationRate :: K ,
3460
+ default_value : 0. ,
3461
+ min_value : 0. ,
3462
+ max_value : 10. ,
3463
+ } ;
3464
+ let ( _param, mut render) = audio_param_pair ( opts, context. mock_registration ( ) ) ;
3465
+
3466
+ // no event in timeline, buffer length is 1
3467
+ let vs = render. compute_intrinsic_values ( 0. , 1. , 128 ) ;
3468
+ assert_float_eq ! ( vs, & [ 0. ; 1 ] [ ..] , abs_all <= 0. ) ;
3469
+
3470
+ // mix to output step, input is not silence
3471
+ let signal = alloc. silence ( ) ;
3472
+ let mut input = AudioRenderQuantum :: from ( signal) ;
3473
+ input. channel_data_mut ( 0 ) [ 0 ] = 1. ;
3474
+ input. channel_data_mut ( 0 ) [ 1 ] = 2. ;
3475
+ input. channel_data_mut ( 0 ) [ 2 ] = 3. ;
3476
+
3477
+ let signal = alloc. silence ( ) ;
3478
+ let mut output = AudioRenderQuantum :: from ( signal) ;
3479
+
3480
+ render. mix_to_output ( & input, & mut output) ;
3481
+
3482
+ // expect only 1, not the other values
3483
+ assert ! ( output. single_valued( ) ) ;
3484
+ assert_float_eq ! ( output. channel_data( 0 ) [ 0 ] , 1. , abs <= 0. ) ;
3485
+ }
3486
+
3436
3487
#[ test]
3437
3488
fn test_full_render_chain ( ) {
3438
3489
let alloc = Alloc :: with_capacity ( 1 ) ;
0 commit comments