@@ -301,18 +301,21 @@ where
301301 FixedSync :: Input => {
302302 let min_chunk_in = sample_rate_input / gcd;
303303 let wanted_subsize = chunk_size / sub_chunks;
304- ( wanted_subsize as f32 / min_chunk_in as f32 ) . ceil ( ) as usize
304+ wanted_subsize. div_ceil ( min_chunk_in )
305305 }
306306 FixedSync :: Output => {
307307 let min_chunk_out = sample_rate_output / gcd;
308308 let wanted_subsize = chunk_size / sub_chunks;
309- ( wanted_subsize as f32 / min_chunk_out as f32 ) . ceil ( ) as usize
309+ wanted_subsize. div_ceil ( min_chunk_out )
310310 }
311311 FixedSync :: Both => {
312312 let min_chunk_in = sample_rate_input / gcd;
313- ( chunk_size as f32 / min_chunk_in as f32 ) . ceil ( ) as usize
313+ chunk_size. div_ceil ( min_chunk_in )
314314 }
315- } ;
315+ }
316+ // Asking for more sub chunks than there are frames rounds down to zero blocks,
317+ // which is not a usable resampler. Fall back to a single minimum sized block.
318+ . max ( 1 ) ;
316319 let fft_size_out = fft_chunks * sample_rate_output / gcd;
317320 let fft_size_in = fft_chunks * sample_rate_input / gcd;
318321
@@ -397,8 +400,6 @@ where
397400 /// A larger block moves it closer to Nyquist.
398401 /// When downsampling it is scaled down to keep it below the lower Nyquist
399402 /// frequency of the two sample rates.
400- ///
401- /// Multiply by `sample_rate_input / 2` to get the cutoff in Hz.
402403 pub fn cutoff ( & self ) -> f32 {
403404 self . resampler . cutoff
404405 }
@@ -412,21 +413,20 @@ where
412413 ) -> ( usize , usize ) {
413414 match fixed {
414415 FixedSync :: Input => {
415- let subchunks_available: f32 =
416- ( ( chunk_size + saved_frames) as f32 / fft_size_in as f32 ) . floor ( ) ;
417- let frames_available = ( subchunks_available as usize ) * fft_size_out;
416+ let subchunks_available = ( chunk_size + saved_frames) / fft_size_in;
417+ let frames_available = subchunks_available * fft_size_out;
418418 ( chunk_size, frames_available)
419419 }
420420 FixedSync :: Output => {
421- let subchunks_needed = ( ( chunk_size as f32 - saved_frames as f32 )
422- / fft_size_out as f32 )
423- . ceil ( )
424- . max ( 0.0 ) ;
425- let frames_needed = ( subchunks_needed as usize ) * fft_size_in;
421+ // Saturating, since more frames may be saved than the chunk needs.
422+ let subchunks_needed = chunk_size
423+ . saturating_sub ( saved_frames )
424+ . div_ceil ( fft_size_out ) ;
425+ let frames_needed = subchunks_needed * fft_size_in;
426426 ( frames_needed, chunk_size)
427427 }
428428 FixedSync :: Both => {
429- let subchunks_needed = ( chunk_size as f32 / fft_size_in as f32 ) . ceil ( ) as usize ;
429+ let subchunks_needed = chunk_size. div_ceil ( fft_size_in ) ;
430430 let frames_needed_in = subchunks_needed * fft_size_in;
431431 let frames_needed_out = subchunks_needed * fft_size_out;
432432 ( frames_needed_in, frames_needed_out)
@@ -467,9 +467,7 @@ where
467467 ) -> usize {
468468 match fixed {
469469 FixedSync :: Both | FixedSync :: Input => chunk_size_in,
470- FixedSync :: Output => {
471- ( chunk_size_out as f32 / fft_size_out as f32 ) . ceil ( ) as usize * fft_size_in
472- }
470+ FixedSync :: Output => chunk_size_out. div_ceil ( fft_size_out) * fft_size_in,
473471 }
474472 }
475473
@@ -759,6 +757,25 @@ mod tests {
759757 assert ! ( ( maxval - 1.0 ) . abs( ) < 0.1 ) ;
760758 }
761759
760+ #[ test_log:: test( test_matrix( [ FixedSync :: Input , FixedSync :: Output , FixedSync :: Both ] ) ) ]
761+ fn fft_more_sub_chunks_than_frames ( fixed : FixedSync ) {
762+ // Asking for more sub chunks than the chunk has frames rounds the sub chunk
763+ // size down to zero. That used to give zero FFT blocks, and a panic on the
764+ // first division by the block size.
765+ let resampler = Fft :: < f64 > :: new_custom (
766+ 44100 ,
767+ 48000 ,
768+ 100 ,
769+ 1000 ,
770+ 2 ,
771+ WindowFunction :: BlackmanHarris2 ,
772+ fixed,
773+ )
774+ . unwrap ( ) ;
775+ assert_eq ! ( resampler. fft_size_in( ) , 147 ) ;
776+ assert_eq ! ( resampler. fft_size_out( ) , 160 ) ;
777+ }
778+
762779 #[ test_log:: test( test_matrix(
763780 [ 512 , 1024 , 4096 ] ,
764781 [ ( 44100 , 48000 ) , ( 48000 , 44100 ) , ( 44100 , 88200 ) , ( 88200 , 44100 ) , ( 44100 , 192000 ) , ( 192000 , 44100 ) ] ,
0 commit comments