diff --git a/CHANGELOG.md b/CHANGELOG.md index ee9544e1..d3b9cf8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Sink.try_seek` now updates `controls.position` before returning. Calls to `Sink.get_pos` done immediately after a seek will now return the correct value. +- `ChannelVolume` fixed to support numbers of channels apart from powers of two. + ### Changed - `SamplesBuffer` is now `Clone` diff --git a/Cargo.lock b/Cargo.lock index 636ea8cc..b83e68ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,18 +165,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstyle", "clap_lex", @@ -479,9 +479,9 @@ checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -529,10 +529,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb15147158e79fd8b8afd0252522769c4f48725460b37338544d8379d94fc8f9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1197,9 +1198,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.89" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1208,9 +1209,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -1323,9 +1324,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.96" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21d3b25c3ea1126a2ad5f4f9068483c2af1e64168f847abe863a526b8dbfe00b" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -1334,9 +1335,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.96" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52857d4c32e496dc6537646b5b117081e71fd2ff06de792e3577a150627db283" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -1349,9 +1350,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.46" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951fe82312ed48443ac78b66fa43eded9999f738f6022e67aead7b708659e49a" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", @@ -1362,9 +1363,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.96" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920b0ffe069571ebbfc9ddc0b36ba305ef65577c94b06262ed793716a1afd981" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1372,9 +1373,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.96" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf59002391099644be3524e23b781fa43d2be0c5aa0719a18c0731b9d195cab6" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -1385,15 +1386,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.96" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5047c5392700766601942795a436d7d2599af60dcc3cc1248c9120bfb0827b0" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "web-sys" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "476364ff87d0ae6bfb661053a9104ab312542658c3d8f963b7ace80b6f9b26b9" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/benches/resampler.rs b/benches/resampler.rs index 22ddbf15..c7be6608 100644 --- a/benches/resampler.rs +++ b/benches/resampler.rs @@ -17,7 +17,7 @@ fn no_resampling(bencher: Bencher) { (source.channels(), source.sample_rate(), source) }) .bench_values(|(channels, sample_rate, source)| { - UniformSourceIterator::<_, i16>::new(source, channels, sample_rate) + UniformSourceIterator::<_, i16>::new(source, channels.unwrap(), sample_rate.unwrap()) .for_each(divan::black_box_drop) }) } @@ -36,7 +36,7 @@ fn resample_to(bencher: Bencher, target_sample_rate: u32) { (source.channels(), source) }) .bench_values(|(channels, source)| { - UniformSourceIterator::<_, i16>::new(source, channels, target_sample_rate) + UniformSourceIterator::<_, i16>::new(source, channels.unwrap(), target_sample_rate) .for_each(divan::black_box_drop) }) } diff --git a/benches/shared.rs b/benches/shared.rs index 0feff6a4..13b89e63 100644 --- a/benches/shared.rs +++ b/benches/shared.rs @@ -30,12 +30,12 @@ impl Source for TestSource { None // forever } - fn channels(&self) -> u16 { - self.channels + fn channels(&self) -> Option { + Some(self.channels) } - fn sample_rate(&self) -> u32 { - self.sample_rate + fn sample_rate(&self) -> Option { + Some(self.sample_rate) } fn total_duration(&self) -> Option { @@ -54,8 +54,8 @@ impl TestSource { .take_duration(duration); TestSource { - channels: sound.channels(), - sample_rate: sound.sample_rate(), + channels: sound.channels().unwrap(), + sample_rate: sound.sample_rate().unwrap(), total_duration: duration, samples: sound.into_iter().collect::>().into_iter(), } diff --git a/examples/channel_volume.rs b/examples/channel_volume.rs new file mode 100644 index 00000000..e03ef080 --- /dev/null +++ b/examples/channel_volume.rs @@ -0,0 +1,12 @@ +use rodio::source::ChannelVolume; + +fn main() { + let stream_handle = rodio::OutputStreamBuilder::open_default_stream().unwrap(); + let sink = rodio::Sink::connect_new(&stream_handle.mixer()); + + let input = rodio::source::SineWave::new(440.0); + let chan_vol = ChannelVolume::new(input, vec![0.01, 0.0, 0.1, 0.1, 0.1, 0.5]); + sink.append(chan_vol); + + sink.sleep_until_end(); +} diff --git a/src/buffer.rs b/src/buffer.rs index de21fdcb..689441bf 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -74,13 +74,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channels + fn channels(&self) -> Option { + Some(self.channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate + fn sample_rate(&self) -> Option { + Some(self.sample_rate) } #[inline] @@ -95,14 +95,16 @@ where /// This jumps in memory till the sample for `pos`. #[inline] fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> { - let curr_channel = self.pos % self.channels() as usize; - let new_pos = pos.as_secs_f32() * self.sample_rate() as f32 * self.channels() as f32; + let curr_channel = self.pos % self.channels().unwrap() as usize; + let new_pos = pos.as_secs_f32() + * self.sample_rate().unwrap() as f32 + * self.channels().unwrap() as f32; // saturate pos at the end of the source let new_pos = new_pos as usize; let new_pos = new_pos.min(self.data.len()); // make sure the next sample is for the right channel - let new_pos = new_pos.next_multiple_of(self.channels() as usize); + let new_pos = new_pos.next_multiple_of(self.channels().unwrap() as usize); let new_pos = new_pos - curr_channel; self.pos = new_pos; diff --git a/src/conversions/channels.rs b/src/conversions/channels.rs index 45bf767f..6c20fedb 100644 --- a/src/conversions/channels.rs +++ b/src/conversions/channels.rs @@ -29,8 +29,8 @@ where from: cpal::ChannelCount, to: cpal::ChannelCount, ) -> ChannelCountConverter { - assert!(from >= 1); assert!(to >= 1); + assert!(from >= 1); ChannelCountConverter { input, @@ -178,4 +178,20 @@ mod test { let output = ChannelCountConverter::new(input.into_iter(), 2, 1); assert_eq!(output.len(), 2); } + + #[test] + #[should_panic] + fn zero_input() { + let input = vec![1u16, 2, 3, 4, 5, 6]; + // Panics because from is 0 + let _output = ChannelCountConverter::new(input.into_iter(), 0, 3); + } + + #[test] + #[should_panic] + fn zero_output() { + let input = vec![1u16, 2, 3, 4, 5, 6]; + // Panics because to is 0 + let _output = ChannelCountConverter::new(input.into_iter(), 3, 0); + } } diff --git a/src/conversions/sample_rate.rs b/src/conversions/sample_rate.rs index b76c23d0..ddf038b1 100644 --- a/src/conversions/sample_rate.rs +++ b/src/conversions/sample_rate.rs @@ -55,7 +55,10 @@ where to: cpal::SampleRate, num_channels: cpal::ChannelCount, ) -> SampleRateConverter { - let from = from.0; + let from = match from.0 { + 0 => to.0, + n => n, + }; let to = to.0; assert!(num_channels >= 1); @@ -353,7 +356,7 @@ mod test { let to = SampleRate(to); let source = SineWave::new(freq).take_duration(d); - let from = SampleRate(source.sample_rate()); + let from = SampleRate(source.sample_rate().unwrap()); let resampled = SampleRateConverter::new(source, from, to, 1); diff --git a/src/decoder/flac.rs b/src/decoder/flac.rs index 9dbc0c43..35992a2a 100644 --- a/src/decoder/flac.rs +++ b/src/decoder/flac.rs @@ -64,13 +64,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channels + fn channels(&self) -> Option { + Some(self.channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate + fn sample_rate(&self) -> Option { + Some(self.sample_rate) } #[inline] diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 8a3883ee..8272863e 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -118,7 +118,7 @@ impl DecoderImpl { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { match self { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.channels(), @@ -130,12 +130,12 @@ impl DecoderImpl { DecoderImpl::Mp3(source) => source.channels(), #[cfg(feature = "symphonia")] DecoderImpl::Symphonia(source) => source.channels(), - DecoderImpl::None(_) => 0, + DecoderImpl::None(_) => None, // FIX-ME? I changed this from `0` to `None` instead of `Some(0)` } } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { match self { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.sample_rate(), @@ -147,7 +147,7 @@ impl DecoderImpl { DecoderImpl::Mp3(source) => source.sample_rate(), #[cfg(feature = "symphonia")] DecoderImpl::Symphonia(source) => source.sample_rate(), - DecoderImpl::None(_) => 1, + DecoderImpl::None(_) => Some(1), } } @@ -418,11 +418,11 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.0.channels() } - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.0.sample_rate() } @@ -516,12 +516,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.0.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.0.sample_rate() } diff --git a/src/decoder/symphonia.rs b/src/decoder/symphonia.rs index 57054455..b16cd5d4 100644 --- a/src/decoder/symphonia.rs +++ b/src/decoder/symphonia.rs @@ -159,13 +159,13 @@ impl Source for SymphoniaDecoder { } #[inline] - fn channels(&self) -> u16 { - self.spec.channels.count() as u16 + fn channels(&self) -> Option { + Some(self.spec.channels.count() as u16) } #[inline] - fn sample_rate(&self) -> u32 { - self.spec.rate + fn sample_rate(&self) -> Option { + Some(self.spec.rate) } #[inline] @@ -188,7 +188,7 @@ impl Source for SymphoniaDecoder { }; // make sure the next sample is for the right channel - let to_skip = self.current_frame_offset % self.channels() as usize; + let to_skip = self.current_frame_offset % self.channels().unwrap() as usize; let seek_res = self .format @@ -285,7 +285,7 @@ impl SymphoniaDecoder { let decoded = decoded.map_err(SeekError::Decoding)?; decoded.spec().clone_into(&mut self.spec); self.buffer = SymphoniaDecoder::get_buffer(decoded, &self.spec); - self.current_frame_offset = samples_to_pass as usize * self.channels() as usize; + self.current_frame_offset = samples_to_pass as usize * self.channels().unwrap() as usize; Ok(()) } } diff --git a/src/decoder/vorbis.rs b/src/decoder/vorbis.rs index a620c221..24e09a34 100644 --- a/src/decoder/vorbis.rs +++ b/src/decoder/vorbis.rs @@ -62,13 +62,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.stream_reader.ident_hdr.audio_channels as u16 + fn channels(&self) -> Option { + Some(self.stream_reader.ident_hdr.audio_channels as u16) } #[inline] - fn sample_rate(&self) -> u32 { - self.stream_reader.ident_hdr.audio_sample_rate + fn sample_rate(&self) -> Option { + Some(self.stream_reader.ident_hdr.audio_sample_rate) } #[inline] diff --git a/src/decoder/wav.rs b/src/decoder/wav.rs index d87ceb95..ab839d44 100644 --- a/src/decoder/wav.rs +++ b/src/decoder/wav.rs @@ -115,13 +115,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channels + fn channels(&self) -> Option { + Some(self.channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate + fn sample_rate(&self) -> Option { + Some(self.sample_rate) } #[inline] @@ -133,18 +133,18 @@ where fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> { let file_len = self.reader.reader.duration(); - let new_pos = pos.as_secs_f32() * self.sample_rate() as f32; + let new_pos = pos.as_secs_f32() * self.sample_rate as f32; let new_pos = new_pos as u32; let new_pos = new_pos.min(file_len); // saturate pos at the end of the source // make sure the next sample is for the right channel - let to_skip = self.reader.samples_read % self.channels() as u32; + let to_skip = self.reader.samples_read % self.channels as u32; self.reader .reader .seek(new_pos) .map_err(SeekError::HoundDecoder)?; - self.reader.samples_read = new_pos * self.channels() as u32; + self.reader.samples_read = new_pos * self.channels as u32; for _ in 0..to_skip { self.next(); diff --git a/src/mixer.rs b/src/mixer.rs index 92b3e4eb..20fdd797 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -90,13 +90,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.input.channels + fn channels(&self) -> Option { + Some(self.input.channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.input.sample_rate + fn sample_rate(&self) -> Option { + Some(self.input.sample_rate) } #[inline] @@ -113,12 +113,12 @@ where // uncomment when #510 is implemented (query position of playback) // let mut org_positions = Vec::with_capacity(self.current_sources.len()); - // let mut encounterd_err = None; + // let mut encountered_err = None; // // for source in &mut self.current_sources { // let pos = /* source.playback_pos() */ todo!(); // if let Err(e) = source.try_seek(pos) { - // encounterd_err = Some(e); + // encountered_err = Some(e); // break; // } else { // // store pos in case we need to roll back @@ -126,8 +126,8 @@ where // } // } // - // if let Some(e) = encounterd_err { - // // rollback seeks that happend before err + // if let Some(e) = encountered_err { + // // rollback seeks that happened before err // for (pos, source) in org_positions // .into_iter() // .zip(self.current_sources.iter_mut()) @@ -182,7 +182,7 @@ where let mut pending = self.input.pending_sources.lock().unwrap(); // TODO: relax ordering? for source in pending.drain(..) { - let in_step = self.sample_count % source.channels() as usize == 0; + let in_step = self.sample_count % source.channels().unwrap() as usize == 0; if in_step { self.current_sources.push(source); @@ -224,8 +224,8 @@ mod tests { tx.add(SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])); tx.add(SamplesBuffer::new(1, 48000, vec![5i16, 5, 5, 5])); - assert_eq!(rx.channels(), 1); - assert_eq!(rx.sample_rate(), 48000); + assert_eq!(rx.channels(), Some(1)); + assert_eq!(rx.sample_rate(), Some(48000)); assert_eq!(rx.next(), Some(15)); assert_eq!(rx.next(), Some(-5)); assert_eq!(rx.next(), Some(15)); @@ -240,8 +240,8 @@ mod tests { tx.add(SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])); tx.add(SamplesBuffer::new(1, 48000, vec![5i16, 5, 5, 5])); - assert_eq!(rx.channels(), 2); - assert_eq!(rx.sample_rate(), 48000); + assert_eq!(rx.channels(), Some(2)); + assert_eq!(rx.sample_rate(), Some(48000)); assert_eq!(rx.next(), Some(15)); assert_eq!(rx.next(), Some(15)); assert_eq!(rx.next(), Some(-5)); @@ -260,8 +260,8 @@ mod tests { tx.add(SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])); tx.add(SamplesBuffer::new(1, 48000, vec![5i16, 5, 5, 5])); - assert_eq!(rx.channels(), 1); - assert_eq!(rx.sample_rate(), 96000); + assert_eq!(rx.channels(), Some(1)); + assert_eq!(rx.sample_rate(), Some(96000)); assert_eq!(rx.next(), Some(15)); assert_eq!(rx.next(), Some(5)); assert_eq!(rx.next(), Some(-5)); diff --git a/src/queue.rs b/src/queue.rs index c06b3672..34fee896 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -159,12 +159,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.current.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.current.sample_rate() } @@ -265,14 +265,14 @@ mod tests { tx.append(SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])); tx.append(SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])); - assert_eq!(rx.channels(), 1); - assert_eq!(rx.sample_rate(), 48000); + assert_eq!(rx.channels(), Some(1)); + assert_eq!(rx.sample_rate(), Some(48000)); assert_eq!(rx.next(), Some(10)); assert_eq!(rx.next(), Some(-10)); assert_eq!(rx.next(), Some(10)); assert_eq!(rx.next(), Some(-10)); - assert_eq!(rx.channels(), 2); - assert_eq!(rx.sample_rate(), 96000); + assert_eq!(rx.channels(), Some(2)); + assert_eq!(rx.sample_rate(), Some(96000)); assert_eq!(rx.next(), Some(5)); assert_eq!(rx.next(), Some(5)); assert_eq!(rx.next(), Some(5)); diff --git a/src/source/agc.rs b/src/source/agc.rs index 1685b22f..ca046808 100644 --- a/src/source/agc.rs +++ b/src/source/agc.rs @@ -143,7 +143,7 @@ where I: Source, I::Item: Sample, { - let sample_rate = input.sample_rate(); + let sample_rate = input.sample_rate().unwrap(); let attack_coeff = (-1.0 / (attack_time * sample_rate as f32)).exp(); let release_coeff = (-1.0 / (release_time * sample_rate as f32)).exp(); @@ -472,12 +472,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/amplify.rs b/src/source/amplify.rs index 42e6955c..e2139097 100644 --- a/src/source/amplify.rs +++ b/src/source/amplify.rs @@ -82,12 +82,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/blt.rs b/src/source/blt.rs index c7be7310..95ed058c 100644 --- a/src/source/blt.rs +++ b/src/source/blt.rs @@ -119,7 +119,7 @@ where let last_in_frame = self.input.current_frame_len() == Some(1); if self.applier.is_none() { - self.applier = Some(self.formula.to_applier(self.input.sample_rate())); + self.applier = Some(self.formula.to_applier(self.input.sample_rate().unwrap())); } let sample = match self.input.next() { @@ -163,12 +163,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/buffered.rs b/src/source/buffered.rs index 16c03128..133a8ca6 100644 --- a/src/source/buffered.rs +++ b/src/source/buffered.rs @@ -123,8 +123,8 @@ where Arc::new(Frame::Data(FrameData { data, - channels, - rate, + channels: channels.unwrap(), + rate: rate.unwrap(), next: Mutex::new(Arc::new(Frame::Input(Mutex::new(Some(input))))), })) } @@ -220,19 +220,19 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { match *self.current_frame { - Frame::Data(FrameData { channels, .. }) => channels, - Frame::End => 1, + Frame::Data(FrameData { channels, .. }) => Some(channels), + Frame::End => Some(1), // FIX-ME? Why is it 1? Frame::Input(_) => unreachable!(), } } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { match *self.current_frame { - Frame::Data(FrameData { rate, .. }) => rate, - Frame::End => 44100, + Frame::Data(FrameData { rate, .. }) => Some(rate), + Frame::End => Some(44100), // FIX-ME? Why is it 44100? Frame::Input(_) => unreachable!(), } } diff --git a/src/source/channel_volume.rs b/src/source/channel_volume.rs index 89412372..81148b26 100644 --- a/src/source/channel_volume.rs +++ b/src/source/channel_volume.rs @@ -34,7 +34,7 @@ where I::Item: Sample, { let mut sample = None; - for _ in 0..input.channels() { + for _ in 0..input.channels().unwrap() { if let Some(s) = input.next() { sample = Some( sample @@ -92,7 +92,7 @@ where if self.current_channel >= self.channel_volumes.len() { self.current_channel = 0; self.current_sample = None; - for _ in 0..self.input.channels() { + for _ in 0..self.input.channels().unwrap() { if let Some(s) = self.input.next() { self.current_sample = Some( self.current_sample @@ -129,12 +129,12 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channel_volumes.len() as u16 + fn channels(&self) -> Option { + Some(self.channel_volumes.len() as u16) } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } @@ -148,3 +148,29 @@ where self.input.try_seek(pos) } } + +#[cfg(test)] +mod test { + use super::*; + + use crate::buffer::SamplesBuffer; + use crate::source::Source; + + #[test] + fn test_channel_volume_iterator() { + let input_source = SamplesBuffer::new(1, 48000, vec![100i16]); + + let mut channel_volume = + ChannelVolume::new(input_source, vec![0.01, 0.01, 0.0, 0.0, 0.0, 0.0]); + + assert_eq!(channel_volume.channels(), Some(6)); + assert_eq!(channel_volume.sample_rate(), Some(48000)); + assert_eq!(channel_volume.next(), Some(1)); + assert_eq!(channel_volume.next(), Some(1)); + assert_eq!(channel_volume.next(), Some(0)); + assert_eq!(channel_volume.next(), Some(0)); + assert_eq!(channel_volume.next(), Some(0)); + assert_eq!(channel_volume.next(), Some(0)); + assert_eq!(channel_volume.next(), None); + } +} diff --git a/src/source/chirp.rs b/src/source/chirp.rs index 9942cab4..bffa2284 100644 --- a/src/source/chirp.rs +++ b/src/source/chirp.rs @@ -51,7 +51,7 @@ impl Iterator for Chirp { let ratio = self.elapsed_samples as f32 / self.total_samples as f32; self.elapsed_samples += 1; let freq = self.start_frequency * (1.0 - ratio) + self.end_frequency * ratio; - let t = (i as f32 / self.sample_rate() as f32) * TAU * freq; + let t = (i as f32 / self.sample_rate().unwrap() as f32) * TAU * freq; Some(t.sin()) } } @@ -61,12 +61,12 @@ impl Source for Chirp { None } - fn channels(&self) -> u16 { - 1 + fn channels(&self) -> Option { + Some(1) } - fn sample_rate(&self) -> u32 { - self.sample_rate.0 + fn sample_rate(&self) -> Option { + Some(self.sample_rate.0) } fn total_duration(&self) -> Option { diff --git a/src/source/delay.rs b/src/source/delay.rs index c79c7e70..fe5ede4c 100644 --- a/src/source/delay.rs +++ b/src/source/delay.rs @@ -17,7 +17,11 @@ where I::Item: Sample, { Delay { - remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()), + remaining_samples: remaining_samples( + duration, + input.sample_rate().unwrap(), + input.channels().unwrap(), + ), requested_duration: duration, input, } @@ -95,12 +99,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } @@ -129,8 +133,11 @@ where if pos < self.requested_duration { self.input.try_seek(Duration::ZERO)?; let until_playback = self.requested_duration - pos; - self.remaining_samples = - remaining_samples(until_playback, self.sample_rate(), self.channels()); + self.remaining_samples = remaining_samples( + until_playback, + self.sample_rate().unwrap(), + self.channels().unwrap(), + ); } let compensated_for_delay = pos.saturating_sub(self.requested_duration); self.input.try_seek(compensated_for_delay) diff --git a/src/source/done.rs b/src/source/done.rs index 152233c1..c806e32c 100644 --- a/src/source/done.rs +++ b/src/source/done.rs @@ -78,12 +78,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/empty.rs b/src/source/empty.rs index d7b12980..5da40056 100644 --- a/src/source/empty.rs +++ b/src/source/empty.rs @@ -6,6 +6,9 @@ use crate::{Sample, Source}; use super::SeekError; /// An empty source. +/// +/// The empty source is special in that it will never return any data. +/// It also reports 0 channels, a sample rate of 0, and a Duration of 0. #[derive(Debug, Copy, Clone)] pub struct Empty(PhantomData); @@ -44,13 +47,13 @@ where } #[inline] - fn channels(&self) -> u16 { - 1 + fn channels(&self) -> Option { + None } #[inline] - fn sample_rate(&self) -> u32 { - 48000 + fn sample_rate(&self) -> Option { + None } #[inline] diff --git a/src/source/empty_callback.rs b/src/source/empty_callback.rs index ad1c66b8..8c963f6a 100644 --- a/src/source/empty_callback.rs +++ b/src/source/empty_callback.rs @@ -47,13 +47,13 @@ where } #[inline] - fn channels(&self) -> u16 { - 1 + fn channels(&self) -> Option { + Some(1) } #[inline] - fn sample_rate(&self) -> u32 { - 48000 + fn sample_rate(&self) -> Option { + Some(48000) } #[inline] diff --git a/src/source/fadein.rs b/src/source/fadein.rs index eac958f4..bee2bed0 100644 --- a/src/source/fadein.rs +++ b/src/source/fadein.rs @@ -81,12 +81,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.inner().channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.inner().sample_rate() } diff --git a/src/source/fadeout.rs b/src/source/fadeout.rs index b71de926..3a1b9047 100644 --- a/src/source/fadeout.rs +++ b/src/source/fadeout.rs @@ -81,12 +81,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.inner().channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.inner().sample_rate() } diff --git a/src/source/from_iter.rs b/src/source/from_iter.rs index 45e4b23a..74b5ea53 100644 --- a/src/source/from_iter.rs +++ b/src/source/from_iter.rs @@ -114,22 +114,22 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { if let Some(src) = &self.current_source { src.channels() } else { // Dummy value that only happens if the iterator was empty. - 2 + Some(2) // FIX-ME? Should we use None in this case, like we do with `Empty`? } } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { if let Some(src) = &self.current_source { src.sample_rate() } else { // Dummy value that only happens if the iterator was empty. - 44100 + Some(44100) // FIX-ME? Should we use None in this case, like we do with `Empty`? } } @@ -165,8 +165,8 @@ mod tests { } })); - assert_eq!(rx.channels(), 1); - assert_eq!(rx.sample_rate(), 48000); + assert_eq!(rx.channels(), Some(1)); + assert_eq!(rx.sample_rate(), Some(48000)); assert_eq!(rx.next(), Some(10)); assert_eq!(rx.next(), Some(-10)); assert_eq!(rx.next(), Some(10)); diff --git a/src/source/linear_ramp.rs b/src/source/linear_ramp.rs index 0e46a681..2a531d9b 100644 --- a/src/source/linear_ramp.rs +++ b/src/source/linear_ramp.rs @@ -46,7 +46,7 @@ where I: Source, I::Item: Sample, { - /// Returns a reference to the innner source. + /// Returns a reference to the inner source. #[inline] pub fn inner(&self) -> &I { &self.input @@ -90,8 +90,8 @@ where factor = self.start_gain * (1.0f32 - p) + self.end_gain * p; } - if self.sample_idx % (self.channels() as u64) == 0 { - self.elapsed_ns += 1000000000.0 / (self.input.sample_rate() as f32); + if self.sample_idx % (self.channels().unwrap() as u64) == 0 { + self.elapsed_ns += 1000000000.0 / (self.input.sample_rate().unwrap() as f32); } self.input.next().map(|value| value.amplify(factor)) @@ -121,12 +121,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/mix.rs b/src/source/mix.rs index f2396546..9ed04a86 100644 --- a/src/source/mix.rs +++ b/src/source/mix.rs @@ -14,8 +14,8 @@ where I2: Source, I2::Item: Sample, { - let channels = input1.channels(); - let rate = input1.sample_rate(); + let channels = input1.channels().unwrap(); + let rate = input1.sample_rate().unwrap(); Mix { input1: UniformSourceIterator::new(input1, channels, rate), @@ -101,12 +101,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input1.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input1.sample_rate() } diff --git a/src/source/mod.rs b/src/source/mod.rs index e730e802..ad62541b 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -159,10 +159,10 @@ where fn current_frame_len(&self) -> Option; /// Returns the number of channels. Channels are always interleaved. - fn channels(&self) -> u16; + fn channels(&self) -> Option; // FIX-ME? Should we consider using an `Option` here? /// Returns the rate at which the source should be played. In number of samples per second. - fn sample_rate(&self) -> u32; + fn sample_rate(&self) -> Option; /// Returns the total duration of this source, if known. /// @@ -663,12 +663,12 @@ macro_rules! source_pointer_impl { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { (**self).channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { (**self).sample_rate() } diff --git a/src/source/pausable.rs b/src/source/pausable.rs index 74b20601..b2925157 100644 --- a/src/source/pausable.rs +++ b/src/source/pausable.rs @@ -10,11 +10,7 @@ where I: Source, I::Item: Sample, { - let paused_channels = if paused { - Some(source.channels()) - } else { - None - }; + let paused_channels = if paused { source.channels() } else { None }; Pausable { input: source, paused_channels, @@ -45,8 +41,9 @@ where /// If set to true, the inner sound stops playing and no samples are processed from it. #[inline] pub fn set_paused(&mut self, paused: bool) { + // FIX-ME? What happens if `self.input.channels()` is `None`? match (self.paused_channels, paused) { - (None, true) => self.paused_channels = Some(self.input.channels()), + (None, true) => self.paused_channels = self.input.channels(), (Some(_), false) => self.paused_channels = None, _ => (), } @@ -110,12 +107,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/periodic.rs b/src/source/periodic.rs index 58ed89a1..13b50473 100644 --- a/src/source/periodic.rs +++ b/src/source/periodic.rs @@ -13,7 +13,8 @@ where // TODO: handle the fact that the samples rate can change // TODO: generally, just wrong let update_ms = period.as_secs() as u32 * 1_000 + period.subsec_millis(); - let update_frequency = (update_ms * source.sample_rate()) / 1000 * source.channels() as u32; + let update_frequency = + (update_ms * source.sample_rate().unwrap()) / 1000 * source.channels().unwrap() as u32; PeriodicAccess { input: source, @@ -106,12 +107,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/position.rs b/src/source/position.rs index 2ab92aac..83156a9d 100644 --- a/src/source/position.rs +++ b/src/source/position.rs @@ -66,8 +66,8 @@ where #[inline] pub fn get_pos(&self) -> Duration { let seconds = self.samples_counted as f64 - / self.input.sample_rate() as f64 - / self.input.channels() as f64 + / self.input.sample_rate().unwrap() as f64 + / self.input.channels().unwrap() as f64 + self.offset_duration; Duration::from_secs_f64(seconds) } @@ -75,8 +75,8 @@ where #[inline] fn set_current_frame(&mut self) { self.current_frame_len = self.current_frame_len(); - self.current_frame_sample_rate = self.sample_rate(); - self.current_frame_channels = self.channels(); + self.current_frame_sample_rate = self.sample_rate().unwrap(); + self.current_frame_channels = self.channels().unwrap(); } } @@ -130,12 +130,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/repeat.rs b/src/source/repeat.rs index 90b652f2..ea7979cd 100644 --- a/src/source/repeat.rs +++ b/src/source/repeat.rs @@ -67,7 +67,7 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { match self.inner.current_frame_len() { Some(0) => self.next.channels(), _ => self.inner.channels(), @@ -75,7 +75,7 @@ where } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { match self.inner.current_frame_len() { Some(0) => self.next.sample_rate(), _ => self.inner.sample_rate(), diff --git a/src/source/samples_converter.rs b/src/source/samples_converter.rs index 568e01b7..23417982 100644 --- a/src/source/samples_converter.rs +++ b/src/source/samples_converter.rs @@ -83,12 +83,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.inner.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.inner.sample_rate() } diff --git a/src/source/signal_generator.rs b/src/source/signal_generator.rs index 54969ed5..a87e4556 100644 --- a/src/source/signal_generator.rs +++ b/src/source/signal_generator.rs @@ -98,13 +98,13 @@ impl Source for SignalGenerator { } #[inline] - fn channels(&self) -> u16 { - 1 + fn channels(&self) -> Option { + Some(1) } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate.0 + fn sample_rate(&self) -> Option { + Some(self.sample_rate.0) } #[inline] diff --git a/src/source/sine.rs b/src/source/sine.rs index da4f8b2c..f89917ec 100644 --- a/src/source/sine.rs +++ b/src/source/sine.rs @@ -42,13 +42,13 @@ impl Source for SineWave { } #[inline] - fn channels(&self) -> u16 { - 1 + fn channels(&self) -> Option { + Some(1) } #[inline] - fn sample_rate(&self) -> u32 { - Self::SAMPLE_RATE + fn sample_rate(&self) -> Option { + Some(Self::SAMPLE_RATE) } #[inline] diff --git a/src/source/skip.rs b/src/source/skip.rs index a836ae87..be7858af 100644 --- a/src/source/skip.rs +++ b/src/source/skip.rs @@ -41,8 +41,9 @@ where return; } - let ns_per_sample: u128 = - NS_PER_SECOND / input.sample_rate() as u128 / input.channels() as u128; + let ns_per_sample: u128 = NS_PER_SECOND + / input.sample_rate().unwrap() as u128 + / input.channels().unwrap() as u128; // Check if we need to skip only part of the current frame. if frame_len as u128 * ns_per_sample > duration.as_nanos() { @@ -64,8 +65,8 @@ where I::Item: Sample, { let samples_per_channel: u128 = - duration.as_nanos() * input.sample_rate() as u128 / NS_PER_SECOND; - let samples_to_skip: u128 = samples_per_channel * input.channels() as u128; + duration.as_nanos() * input.sample_rate().unwrap() as u128 / NS_PER_SECOND; + let samples_to_skip: u128 = samples_per_channel * input.channels().unwrap() as u128; skip_samples(input, samples_to_skip as usize); } @@ -143,12 +144,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/skippable.rs b/src/source/skippable.rs index 082bc016..27d50621 100644 --- a/src/source/skippable.rs +++ b/src/source/skippable.rs @@ -83,12 +83,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/spatial.rs b/src/source/spatial.rs index 954e65f4..21dd26b0 100644 --- a/src/source/spatial.rs +++ b/src/source/spatial.rs @@ -108,12 +108,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/speed.rs b/src/source/speed.rs index 6fb09a3c..bde7ae4e 100644 --- a/src/source/speed.rs +++ b/src/source/speed.rs @@ -129,13 +129,13 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { - (self.input.sample_rate() as f32 * self.factor) as u32 + fn sample_rate(&self) -> Option { + Some((self.input.sample_rate().unwrap() as f32 * self.factor) as u32) } #[inline] diff --git a/src/source/stoppable.rs b/src/source/stoppable.rs index 88078706..89753c91 100644 --- a/src/source/stoppable.rs +++ b/src/source/stoppable.rs @@ -78,12 +78,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/take.rs b/src/source/take.rs index c6196994..fdc35a4e 100644 --- a/src/source/take.rs +++ b/src/source/take.rs @@ -68,7 +68,8 @@ where /// Returns the duration elapsed for each sample extracted. #[inline] fn get_duration_per_sample(input: &I) -> Duration { - let ns = NANOS_PER_SEC / (input.sample_rate() as u64 * input.channels() as u64); + let ns = NANOS_PER_SEC + / (input.sample_rate().unwrap() as u64 * input.channels().unwrap() as u64); // \|/ the maximum value of `ns` is one billion, so this can't fail Duration::new(0, ns as u32) } @@ -160,12 +161,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> Option { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> Option { self.input.sample_rate() } diff --git a/src/source/uniform.rs b/src/source/uniform.rs index b9d146d1..de0ddc7c 100644 --- a/src/source/uniform.rs +++ b/src/source/uniform.rs @@ -60,8 +60,11 @@ where // Limit the frame length to something reasonable let frame_len = input.current_frame_len().map(|x| x.min(32768)); - let from_channels = input.channels(); - let from_sample_rate = input.sample_rate(); + let from_channels = match input.channels() { + None | Some(0) => target_channels, // Ideally we wouldn't have to have `Some(0)` to pattern match against + Some(n) => n, + }; + let from_sample_rate = input.sample_rate().unwrap_or(48000); let input = Take { iter: input, @@ -128,13 +131,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.target_channels + fn channels(&self) -> Option { + Some(self.target_channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.target_sample_rate + fn sample_rate(&self) -> Option { + Some(self.target_sample_rate) } #[inline] diff --git a/src/source/zero.rs b/src/source/zero.rs index 82c38d66..9b536405 100644 --- a/src/source/zero.rs +++ b/src/source/zero.rs @@ -70,13 +70,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channels + fn channels(&self) -> Option { + Some(self.channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate + fn sample_rate(&self) -> Option { + Some(self.sample_rate) } #[inline] diff --git a/src/static_buffer.rs b/src/static_buffer.rs index 95184423..1ef38c53 100644 --- a/src/static_buffer.rs +++ b/src/static_buffer.rs @@ -72,13 +72,13 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channels + fn channels(&self) -> Option { + Some(self.channels) } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate + fn sample_rate(&self) -> Option { + Some(self.sample_rate) } #[inline] diff --git a/tests/seek.rs b/tests/seek.rs index 4c49ad80..64567164 100644 --- a/tests/seek.rs +++ b/tests/seek.rs @@ -121,19 +121,21 @@ fn seek_does_not_break_channel_order( #[case] _decoder_name: &'static str, ) { let mut source = get_rl(format).convert_samples(); - let channels = source.channels(); + let channels = source.channels().unwrap(); assert_eq!(channels, 2, "test needs a stereo beep file"); let beep_range = second_channel_beep_range(&mut source); let beep_start = Duration::from_secs_f32( - beep_range.start as f32 / source.channels() as f32 / source.sample_rate() as f32, + beep_range.start as f32 + / source.channels().unwrap() as f32 + / source.sample_rate().unwrap() as f32, ); let mut source = get_rl(format).convert_samples(); let mut channel_offset = 0; for offset in [1, 4, 7, 40, 41, 120, 179] - .map(|offset| offset as f32 / (source.sample_rate() as f32)) + .map(|offset| offset as f32 / (source.sample_rate().unwrap() as f32)) .map(Duration::from_secs_f32) { source.next(); // WINDOW is even, make the amount of calls to next @@ -145,16 +147,16 @@ fn seek_does_not_break_channel_order( let samples: Vec<_> = source.by_ref().take(100).collect(); let channel0 = 0 + channel_offset; assert!( - is_silent(&samples, source.channels(), channel0), - "channel0 should be silent, + is_silent(&samples, source.channels().unwrap(), channel0), + "channel0 should be silent, channel0 starts at idx: {channel0} seek: {beep_start:?} + {offset:?} samples: {samples:?}" ); let channel1 = (1 + channel_offset) % 2; assert!( - !is_silent(&samples, source.channels(), channel1), - "channel1 should not be silent, + !is_silent(&samples, source.channels().unwrap(), channel1), + "channel1 should not be silent, channel1; starts at idx: {channel1} seek: {beep_start:?} + {offset:?} samples: {samples:?}" @@ -166,7 +168,7 @@ fn second_channel_beep_range(source: &mut R) -> std::ops::Rang where R: Iterator, { - let channels = source.channels() as usize; + let channels = source.channels().unwrap() as usize; let samples: Vec = source.by_ref().collect(); const WINDOW: usize = 50; @@ -220,8 +222,8 @@ fn is_silent(samples: &[f32], channels: u16, channel: usize) -> bool { } fn time_remaining(decoder: Decoder) -> Duration { - let rate = decoder.sample_rate() as f64; - let n_channels = decoder.channels() as f64; + let rate = decoder.sample_rate().unwrap() as f64; + let n_channels = decoder.channels().unwrap() as f64; let n_samples = decoder.into_iter().count() as f64; Duration::from_secs_f64(n_samples / rate / n_channels) }