diff --git a/src/source/agc.rs b/src/source/agc.rs index 06642ffe..0d10a517 100644 --- a/src/source/agc.rs +++ b/src/source/agc.rs @@ -522,15 +522,10 @@ where #[inline] fn next(&mut self) -> Option { - let current_sample_rate = self.input.sample_rate(); - let current_channels = self.input.channels(); - let input_span_len = self.input.current_span_len(); - - let detection = self - .span - .advance(input_span_len, current_sample_rate, current_channels); + let detection = self.span.advance(&self.input); if detection.at_span_boundary && detection.parameters_changed { + let current_sample_rate = self.input.sample_rate(); // Recalculate coefficients for new sample rate #[cfg(feature = "experimental")] { diff --git a/src/source/blt.rs b/src/source/blt.rs index 3b7eb904..ae88cb72 100644 --- a/src/source/blt.rs +++ b/src/source/blt.rs @@ -119,15 +119,12 @@ where fn next(&mut self) -> Option { let sample = self.inner.as_mut().unwrap().next()?; - let input_span_len = self.inner.as_ref().unwrap().current_span_len(); - let current_sample_rate = self.inner.as_ref().unwrap().sample_rate(); - let current_channels = self.inner.as_ref().unwrap().channels(); - - let detection = self - .span - .advance(input_span_len, current_sample_rate, current_channels); + let detection = self.span.advance(self.inner.as_ref().unwrap()); if detection.at_span_boundary && detection.parameters_changed { + let current_sample_rate = self.inner.as_ref().unwrap().sample_rate(); + let current_channels = self.inner.as_ref().unwrap().channels(); + if current_channels != self.inner.as_ref().unwrap().channels() { let old_inner = self.inner.take().unwrap(); let (input, formula) = old_inner.into_parts(); diff --git a/src/source/dither.rs b/src/source/dither.rs index 8370a449..3db8371d 100644 --- a/src/source/dither.rs +++ b/src/source/dither.rs @@ -217,15 +217,11 @@ where fn next(&mut self) -> Option { let input_sample = self.input.next()?; - let input_span_len = self.input.current_span_len(); - let current_sample_rate = self.input.sample_rate(); - let current_channels = self.input.channels(); - - let detection = self - .span - .advance(input_span_len, current_sample_rate, current_channels); + let detection = self.span.advance(&self.input); if detection.at_span_boundary { + let current_sample_rate = self.input.sample_rate(); + let current_channels = self.input.channels(); if detection.parameters_changed { self.noise .update_parameters(current_sample_rate, current_channels); diff --git a/src/source/limit.rs b/src/source/limit.rs index 495e7e94..1d466e5a 100644 --- a/src/source/limit.rs +++ b/src/source/limit.rs @@ -649,15 +649,10 @@ where fn next(&mut self) -> Option { let sample = self.inner.as_mut().unwrap().next()?; - let input_span_len = self.inner.as_ref().unwrap().current_span_len(); - let current_channels = self.inner.as_ref().unwrap().channels(); - let current_sample_rate = self.inner.as_ref().unwrap().sample_rate(); - - let detection = self - .span - .advance(input_span_len, current_sample_rate, current_channels); + let detection = self.span.advance(self.inner.as_ref().unwrap()); if detection.at_span_boundary && detection.parameters_changed { + let current_channels = self.inner.as_ref().unwrap().channels(); let new_channels_count = current_channels.get() as usize; let needs_reconstruction = match self.inner.as_ref().unwrap() { diff --git a/src/source/linear_ramp.rs b/src/source/linear_ramp.rs index f5f00400..4467e730 100644 --- a/src/source/linear_ramp.rs +++ b/src/source/linear_ramp.rs @@ -77,14 +77,8 @@ where #[inline] fn next(&mut self) -> Option { - let current_sample_rate = self.input.sample_rate(); - let current_channels = self.input.channels(); - let input_span_len = self.input.current_span_len(); - // Elapsed time was accumulated in real time and remains valid across parameter changes. - let _ = self - .span - .advance(input_span_len, current_sample_rate, current_channels); + let _ = self.span.advance(&self.input); let factor = if self.elapsed >= self.total { if self.clamp_end { @@ -100,10 +94,10 @@ where if self .sample_idx - .is_multiple_of(current_channels.get() as u64) + .is_multiple_of(self.input.channels().get() as u64) { let sample_duration = - Duration::from_nanos(NANOS_PER_SEC / current_sample_rate.get() as u64); + Duration::from_nanos(NANOS_PER_SEC / self.input.sample_rate().get() as u64); self.elapsed += sample_duration; } diff --git a/src/source/position.rs b/src/source/position.rs index 7443c0a7..f41848eb 100644 --- a/src/source/position.rs +++ b/src/source/position.rs @@ -82,18 +82,12 @@ where fn next(&mut self) -> Option { let item = self.input.next()?; - let input_span_len = self.input.current_span_len(); - let current_sample_rate = self.input.sample_rate(); - let current_channels = self.input.channels(); - // Capture state before advance() resets samples_counted at a boundary. let samples_before_boundary = self.span.samples_counted; let old_rate = self.span.last_sample_rate; let old_channels = self.span.last_channels; - let detection = self - .span - .advance(input_span_len, current_sample_rate, current_channels); + let detection = self.span.advance(&self.input); if detection.at_span_boundary { // Accumulate duration using the OLD parameters. advance() increments diff --git a/src/source/span.rs b/src/source/span.rs index 33663028..aef4d027 100644 --- a/src/source/span.rs +++ b/src/source/span.rs @@ -63,14 +63,11 @@ impl SpanTracker { /// Advances the tracker by one sample and reports whether a span boundary was crossed. #[inline] - pub fn advance( - &mut self, - input_span_len: Option, - current_sample_rate: SampleRate, - current_channels: ChannelCount, - ) -> SpanDetection { + pub fn advance(&mut self, source: &I) -> SpanDetection { self.samples_counted = self.samples_counted.saturating_add(1); + let input_span_len = source.current_span_len(); + // If input reports no span length, parameters are stable by contract. let mut parameters_changed = false; let at_span_boundary = input_span_len.is_some_and(|_| { @@ -81,8 +78,12 @@ impl SpanTracker { // In span-counting mode, parameters can only change at a boundary. // In seek mode, we check every sample for a parameter change. if known_boundary.is_none_or(|at_boundary| at_boundary) { + let current_channels = source.channels(); + let current_sample_rate = source.sample_rate(); parameters_changed = current_channels != self.last_channels || current_sample_rate != self.last_sample_rate; + self.last_channels = current_channels; + self.last_sample_rate = current_sample_rate; } known_boundary.unwrap_or(parameters_changed) @@ -91,10 +92,6 @@ impl SpanTracker { if at_span_boundary { self.samples_counted = 0; self.cached_span_len = input_span_len; - if parameters_changed { - self.last_sample_rate = current_sample_rate; - self.last_channels = current_channels; - } } SpanDetection { diff --git a/src/source/take.rs b/src/source/take.rs index 17b5f157..fb6ef286 100644 --- a/src/source/take.rs +++ b/src/source/take.rs @@ -126,13 +126,7 @@ where // Try to get the next sample from the input. let sample = self.input.next()?; - let input_span_len = self.input.current_span_len(); - let current_sample_rate = self.input.sample_rate(); - let current_channels = self.input.channels(); - - let detection = - self.span - .advance(input_span_len, current_sample_rate, current_channels); + let detection = self.span.advance(&self.input); if detection.at_span_boundary && detection.parameters_changed { self.duration_per_sample = Self::get_duration_per_sample(&self.input); @@ -140,7 +134,7 @@ where } self.samples_in_current_frame = - (self.samples_in_current_frame + 1) % current_channels.get() as usize; + (self.samples_in_current_frame + 1) % self.input.channels().get() as usize; let sample = match &self.filter { Some(filter) => filter.apply(sample, self),