@@ -125,6 +125,7 @@ pub struct AudioBlock<'a> {
125125 pub sample_rate : f32 ,
126126 pub positions : [ ChannelPosition ; MAX_AUDIO_CHANNELS ] ,
127127 stereo : [ [ f32 ; 2 ] ; MAX_AUDIO_CHANNELS ] ,
128+ stereo_channels : usize ,
128129}
129130
130131fn stereo_indices ( channels : usize , positions : [ ChannelPosition ; MAX_AUDIO_CHANNELS ] ) -> [ usize ; 2 ] {
@@ -207,17 +208,26 @@ impl<'a> AudioBlock<'a> {
207208 positions : [ ChannelPosition ; MAX_AUDIO_CHANNELS ] ,
208209 ) -> Self {
209210 let channels = channels. clamp ( 1 , MAX_AUDIO_CHANNELS ) ;
211+ let stereo_channels = ( 2 ..channels. min ( samples. len ( ) ) )
212+ . rfind ( |& channel| {
213+ samples[ channel..]
214+ . iter ( )
215+ . step_by ( channels)
216+ . any ( |sample| sample. to_bits ( ) != 0 )
217+ } )
218+ . map_or ( channels. min ( 2 ) , |channel| channel + 1 ) ;
210219 Self {
211220 samples,
212221 channels,
213222 sample_rate : sanitize_sample_rate ( sample_rate) ,
214223 positions,
215224 stereo : stereo_matrix ( channels, positions) ,
225+ stereo_channels,
216226 }
217227 }
218228
219- pub fn stereo_matrix ( & self ) -> & [ [ f32 ; 2 ] ; MAX_AUDIO_CHANNELS ] {
220- & self . stereo
229+ pub fn stereo_matrix ( & self ) -> & [ [ f32 ; 2 ] ] {
230+ & self . stereo [ .. self . stereo_channels ]
221231 }
222232
223233 pub fn frame_count ( & self ) -> usize {
@@ -230,83 +240,96 @@ impl<'a> AudioBlock<'a> {
230240}
231241
232242#[ derive( Debug , Clone , Copy ) ]
233- struct CompensatedSum {
234- sum : f64 ,
235- correction : f64 ,
243+ struct CompensatedPair {
244+ sums : [ f64 ; 2 ] ,
245+ corrections : [ f64 ; 2 ] ,
236246}
237247
238- impl CompensatedSum {
248+ impl CompensatedPair {
239249 const ZERO : Self = Self {
240- sum : 0.0 ,
241- correction : 0.0 ,
250+ sums : [ 0.0 ; 2 ] ,
251+ corrections : [ 0.0 ; 2 ] ,
242252 } ;
243253
244254 // Kahan-Babuska-Neumaier compensated addition.
245- fn add ( & mut self , value : f64 ) {
246- let next = self . sum + value;
247- self . correction += if self . sum . abs ( ) >= value. abs ( ) {
248- ( self . sum - next) + value
255+ fn add ( & mut self , index : usize , value : f64 ) {
256+ let next = self . sums [ index ] + value;
257+ self . corrections [ index ] += if self . sums [ index ] . abs ( ) >= value. abs ( ) {
258+ ( self . sums [ index ] - next) + value
249259 } else {
250- ( value - next) + self . sum
260+ ( value - next) + self . sums [ index ]
251261 } ;
252- self . sum = next;
262+ self . sums [ index] = next;
263+ }
264+
265+ fn add_both ( & mut self , value : f64 ) {
266+ ( 0 ..2 ) . for_each ( |index| self . add ( index, value) ) ;
267+ }
268+
269+ fn refresh ( & mut self ) {
270+ ( self . sums , self . corrections ) = ( [ self . sums [ 1 ] , 0.0 ] , [ self . corrections [ 1 ] , 0.0 ] ) ;
253271 }
254272
255273 fn value ( self ) -> f64 {
256- self . sum + self . correction
274+ self . sums [ 0 ] + self . corrections [ 0 ]
257275 }
258276}
259277
260278/// Running means for several values over one or more independently sized windows.
261279/// All windows share the ring sized for the longest duration.
262280#[ derive( Debug ) ]
263- pub struct WindowedMeans < const VALUES : usize , const WINDOWS : usize > {
264- buffer : Box < [ [ f64 ; VALUES ] ] > ,
281+ pub struct WindowedMeans < const VALUES : usize , const WINDOWS : usize , T = f64 > {
282+ buffer : Box < [ [ T ; VALUES ] ] > ,
265283 capacities : [ usize ; WINDOWS ] ,
266- sums : [ [ CompensatedSum ; VALUES ] ; WINDOWS ] ,
267- // Periodic full-window sums bound compensation error without rescanning the ring.
268- refresh_sums : [ [ CompensatedSum ; VALUES ] ; WINDOWS ] ,
284+ sums : [ [ CompensatedPair ; VALUES ] ; WINDOWS ] ,
269285 refresh_counts : [ usize ; WINDOWS ] ,
270286 head : usize ,
271287 count : usize ,
272288}
273289
274- impl < const VALUES : usize , const WINDOWS : usize > WindowedMeans < VALUES , WINDOWS > {
290+ impl < const VALUES : usize , const WINDOWS : usize , T > WindowedMeans < VALUES , WINDOWS , T >
291+ where
292+ T : Copy + From < f32 > + Into < f64 > ,
293+ {
275294 pub fn new ( capacities : [ usize ; WINDOWS ] ) -> Self {
276295 let capacities = capacities. map ( |capacity| capacity. max ( 1 ) ) ;
277296 let len = capacities. iter ( ) . copied ( ) . max ( ) . unwrap_or ( 1 ) ;
278297 Self {
279- buffer : vec ! [ [ 0.0 ; VALUES ] ; len] . into_boxed_slice ( ) ,
298+ buffer : vec ! [ [ T :: from ( 0.0 ) ; VALUES ] ; len] . into_boxed_slice ( ) ,
280299 capacities,
281- sums : [ [ CompensatedSum :: ZERO ; VALUES ] ; WINDOWS ] ,
282- refresh_sums : [ [ CompensatedSum :: ZERO ; VALUES ] ; WINDOWS ] ,
300+ sums : [ [ CompensatedPair :: ZERO ; VALUES ] ; WINDOWS ] ,
283301 refresh_counts : [ 0 ; WINDOWS ] ,
284302 head : 0 ,
285303 count : 0 ,
286304 }
287305 }
288306
289- pub fn push < T : Copy + Into < f64 > > ( & mut self , values : [ T ; VALUES ] ) {
290- let values = values. map ( |value| {
291- let value = value. into ( ) ;
292- if value. is_finite ( ) { value } else { 0.0 }
307+ pub fn push ( & mut self , mut values : [ T ; VALUES ] ) {
308+ let mapped: [ f64 ; VALUES ] = std:: array:: from_fn ( |index| {
309+ let value = values[ index] . into ( ) ;
310+ if value. is_finite ( ) {
311+ value
312+ } else {
313+ values[ index] = T :: from ( 0.0 ) ;
314+ 0.0
315+ }
293316 } ) ;
294317 let len = self . buffer . len ( ) ;
295318 for window in 0 ..WINDOWS {
296319 let capacity = self . capacities [ window] ;
297320 let old =
298321 ( self . count >= capacity) . then ( || self . buffer [ ( self . head + len - capacity) % len] ) ;
299322 for value in 0 ..VALUES {
300- self . sums [ window] [ value] . add ( values [ value] ) ;
323+ self . sums [ window] [ value] . add_both ( mapped [ value] ) ;
301324 if let Some ( old) = old {
302- self . sums [ window] [ value] . add ( -old[ value] ) ;
325+ self . sums [ window] [ value] . add ( 0 , -old[ value] . into ( ) ) ;
303326 }
304- self . refresh_sums [ window] [ value] . add ( values[ value] ) ;
305327 }
306328 self . refresh_counts [ window] += 1 ;
307329 if self . refresh_counts [ window] == capacity {
308- self . sums [ window] = self . refresh_sums [ window] ;
309- self . refresh_sums [ window] = [ CompensatedSum :: ZERO ; VALUES ] ;
330+ self . sums [ window]
331+ . iter_mut ( )
332+ . for_each ( CompensatedPair :: refresh) ;
310333 self . refresh_counts [ window] = 0 ;
311334 }
312335 }
@@ -315,18 +338,18 @@ impl<const VALUES: usize, const WINDOWS: usize> WindowedMeans<VALUES, WINDOWS> {
315338 self . count = ( self . count + 1 ) . min ( len) ;
316339 }
317340
341+ pub fn with_leading_zeros ( capacities : [ usize ; WINDOWS ] , count : usize ) -> Self {
342+ let mut means = Self :: new ( capacities) ;
343+ means. head = count % means. buffer . len ( ) ;
344+ means. count = count. min ( means. buffer . len ( ) ) ;
345+ means. refresh_counts = means. capacities . map ( |capacity| count % capacity) ;
346+ means
347+ }
348+
318349 pub fn mean ( & self , window : usize ) -> [ f64 ; VALUES ] {
319350 let count = self . count . min ( self . capacities [ window] ) . max ( 1 ) ;
320351 std:: array:: from_fn ( |value| self . sums [ window] [ value] . value ( ) / count as f64 )
321352 }
322-
323- pub fn clear ( & mut self ) {
324- self . sums = [ [ CompensatedSum :: ZERO ; VALUES ] ; WINDOWS ] ;
325- self . refresh_sums = [ [ CompensatedSum :: ZERO ; VALUES ] ; WINDOWS ] ;
326- self . refresh_counts = [ 0 ; WINDOWS ] ;
327- self . head = 0 ;
328- self . count = 0 ;
329- }
330353}
331354
332355#[ derive( Debug , Clone , Copy ) ]
@@ -584,29 +607,11 @@ mod tests {
584607 let mut unsupported = [ Unknown ; MAX_AUDIO_CHANNELS ] ;
585608 unsupported[ ..2 ] . copy_from_slice ( & [ LowFrequency , Aux ( 0 ) ] ) ;
586609 assert_eq ! (
587- & AudioBlock :: with_positions( & [ ] , 2 , 48_000.0 , unsupported) . stereo_matrix( ) [ .. 2 ] ,
610+ AudioBlock :: with_positions( & [ ] , 8 , 48_000.0 , unsupported) . stereo_matrix( ) ,
588611 & [ [ 1.0 , 0.0 ] , [ 0.0 , 1.0 ] ]
589612 ) ;
590613 }
591614
592- #[ test]
593- fn running_means_clear_without_reallocating_or_replaying_old_values ( ) {
594- let mut means = WindowedMeans :: < 1 , 2 > :: new ( [ 2 , 4 ] ) ;
595- for value in [ 1.0 , 2.0 , 3.0 , 4.0 ] {
596- means. push ( [ value] ) ;
597- }
598- let storage = means. buffer . as_ptr ( ) ;
599- means. clear ( ) ;
600- assert_eq ! ( means. mean( 0 ) , [ 0.0 ] ) ;
601- assert_eq ! ( means. mean( 1 ) , [ 0.0 ] ) ;
602- assert_eq ! ( means. buffer. as_ptr( ) , storage) ;
603-
604- means. push ( [ 10.0 ] ) ;
605- means. push ( [ 20.0 ] ) ;
606- assert_eq ! ( means. mean( 0 ) , [ 15.0 ] ) ;
607- assert_eq ! ( means. mean( 1 ) , [ 15.0 ] ) ;
608- }
609-
610615 #[ test]
611616 fn running_means_sanitize_non_finite_values_without_poisoning_state ( ) {
612617 let mut means = WindowedMeans :: < 1 , 1 > :: new ( [ 1 ] ) ;
@@ -632,7 +637,7 @@ mod tests {
632637 }
633638 assert_eq ! ( means. mean( 0 ) , [ 1.0 ] ) ;
634639
635- means. clear ( ) ;
640+ let mut means = WindowedMeans :: < 1 , 1 > :: new ( [ 2 ] ) ;
636641 for value in [ 1.0e100 , 2.0 , 1.0e-100 , 1.0e-100 ] {
637642 means. push ( [ value] ) ;
638643 }
0 commit comments