@@ -740,30 +740,46 @@ impl AudioParamProcessor {
740740 #[ cfg( test) ]
741741 assert ! ( self . buffer. len( ) == 1 || self . buffer. len( ) == RENDER_QUANTUM_SIZE ) ;
742742
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 ( ) {
744745 let mut value = self . buffer [ 0 ] ;
745746
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;
749766
750- output. set_single_valued ( true ) ;
767+ if o. is_nan ( ) {
768+ * o = self . default_value ;
769+ }
751770
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+ }
754774 } 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
760776 * output = input. clone ( ) ;
761777 output. set_single_valued ( false ) ;
762778
763779 output
764780 . channel_data_mut ( 0 )
765781 . iter_mut ( )
766- . zip ( self . buffer . iter ( ) . cycle ( ) )
782+ . zip ( self . buffer . iter ( ) )
767783 . for_each ( |( o, p) | {
768784 * o += p;
769785
@@ -3433,6 +3449,41 @@ mod tests {
34333449 }
34343450 }
34353451
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+
34363487 #[ test]
34373488 fn test_full_render_chain ( ) {
34383489 let alloc = Alloc :: with_capacity ( 1 ) ;
0 commit comments