From 8993f67e3a1e9d7e349a0b0ba4861cb8cda63a3e Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Wed, 25 Dec 2024 21:14:24 +0400 Subject: [PATCH 01/11] Declare SampleRate and ChannelCount types inside rodio --- Cargo.toml | 6 ++--- benches/shared.rs | 4 ++-- examples/custom_config.rs | 4 ++-- examples/noise_generator.rs | 8 +++---- examples/signal_generator.rs | 2 +- src/buffer.rs | 19 ++++++++------- src/conversions/channels.rs | 16 ++++++------- src/conversions/sample_rate.rs | 42 ++++++++++++++++----------------- src/decoder/flac.rs | 11 +++++---- src/decoder/mod.rs | 13 +++++----- src/decoder/mp3.rs | 4 ++-- src/decoder/symphonia.rs | 10 ++++---- src/decoder/vorbis.rs | 7 +++--- src/decoder/wav.rs | 13 +++++----- src/file_output.rs | 5 ++-- src/lib.rs | 7 +++++- src/mixer.rs | 16 ++++++------- src/queue.rs | 5 ++-- src/source/agc.rs | 5 ++-- src/source/amplify.rs | 8 +++---- src/source/blt.rs | 8 +++---- src/source/buffered.rs | 12 +++++----- src/source/channel_volume.rs | 10 ++++---- src/source/chirp.rs | 20 ++++++++-------- src/source/delay.rs | 14 +++++++---- src/source/done.rs | 8 +++---- src/source/empty.rs | 8 +++---- src/source/empty_callback.rs | 8 +++---- src/source/fadein.rs | 8 +++---- src/source/fadeout.rs | 8 +++---- src/source/from_iter.rs | 8 +++---- src/source/linear_ramp.rs | 5 ++-- src/source/mix.rs | 5 ++-- src/source/mod.rs | 12 +++++----- src/source/noise.rs | 19 ++++++++------- src/source/pausable.rs | 12 +++++----- src/source/periodic.rs | 8 +++---- src/source/position.rs | 12 +++++----- src/source/repeat.rs | 8 +++---- src/source/samples_converter.rs | 8 +++---- src/source/sawtooth.rs | 13 +++++----- src/source/signal_generator.rs | 32 ++++++++++++------------- src/source/sine.rs | 11 ++++----- src/source/skip.rs | 13 +++++----- src/source/skippable.rs | 8 +++---- src/source/spatial.rs | 8 +++---- src/source/speed.rs | 8 +++---- src/source/square.rs | 11 ++++----- src/source/stoppable.rs | 8 +++---- src/source/take.rs | 8 +++---- src/source/triangle.rs | 13 +++++----- src/source/uniform.rs | 28 ++++++++++------------ src/source/zero.rs | 20 +++++++++------- src/static_buffer.rs | 15 ++++++++---- src/stream.rs | 31 ++++++++++++------------ tests/seek.rs | 22 ++++++++++------- 56 files changed, 337 insertions(+), 318 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 599cb059..81b39df8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,11 @@ exclude = ["assets/**", "tests/**"] edition = "2021" [dependencies] -cpal = "0.15.3" +cpal = { version = "0.15.3", optional = true } claxon = { version = "0.4.2", optional = true } hound = { version = "3.3.1", optional = true } lewton = { version = "0.10", optional = true } -minimp3_fixed = { version = "0.5.4", optional = true} +minimp3_fixed = { version = "0.5.4", optional = true } symphonia = { version = "0.5.4", optional = true, default-features = false } crossbeam-channel = { version = "0.5.8", optional = true } @@ -25,7 +25,7 @@ atomic_float = { version = "1.1.0", optional = true } num-rational = "0.4.2" [features] -default = ["flac", "vorbis", "wav", "mp3"] +default = ["flac", "vorbis", "wav", "mp3", "cpal"] tracing = ["dep:tracing"] experimental = ["dep:atomic_float"] diff --git a/benches/shared.rs b/benches/shared.rs index 77e426d7..6122f64f 100644 --- a/benches/shared.rs +++ b/benches/shared.rs @@ -30,11 +30,11 @@ impl Source for TestSource { None // forever } - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.channels } - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate } diff --git a/examples/custom_config.rs b/examples/custom_config.rs index 40b6ca47..4e1ff76a 100644 --- a/examples/custom_config.rs +++ b/examples/custom_config.rs @@ -1,5 +1,5 @@ use cpal::traits::HostTrait; -use cpal::{BufferSize, SampleFormat, SampleRate}; +use cpal::{BufferSize, SampleFormat}; use rodio::source::SineWave; use rodio::Source; use std::error::Error; @@ -15,7 +15,7 @@ fn main() -> Result<(), Box> { // No need to set all parameters explicitly here, // the defaults were set from the device's description. .with_buffer_size(BufferSize::Fixed(256)) - .with_sample_rate(SampleRate(48_000)) + .with_sample_rate(48_000) .with_sample_format(SampleFormat::F32) // Note that the function below still tries alternative configs if the specified one fails. // If you need to only use the exact specified configuration, diff --git a/examples/noise_generator.rs b/examples/noise_generator.rs index 577f9d01..23a86b90 100644 --- a/examples/noise_generator.rs +++ b/examples/noise_generator.rs @@ -22,11 +22,9 @@ fn main() -> Result<(), Box> { thread::sleep(interval_duration); - stream_handle.mixer().add( - pink(cpal::SampleRate(48000)) - .amplify(0.1) - .take_duration(noise_duration), - ); + stream_handle + .mixer() + .add(pink(48000).amplify(0.1).take_duration(noise_duration)); println!("Playing pink noise"); thread::sleep(interval_duration); diff --git a/examples/signal_generator.rs b/examples/signal_generator.rs index e746692d..1ae4048e 100644 --- a/examples/signal_generator.rs +++ b/examples/signal_generator.rs @@ -11,7 +11,7 @@ fn main() -> Result<(), Box> { let test_signal_duration = Duration::from_millis(1000); let interval_duration = Duration::from_millis(1500); - let sample_rate = cpal::SampleRate(48000); + let sample_rate = 48000; println!("Playing 1000 Hz tone"); stream_handle.mixer().add( diff --git a/src/buffer.rs b/src/buffer.rs index 1522faf9..ebaf114b 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -10,18 +10,18 @@ //! ``` //! -use std::time::Duration; - +use crate::common::{ChannelCount, SampleRate}; use crate::source::SeekError; use crate::{Sample, Source}; +use std::time::Duration; /// A buffer of samples treated as a source. #[derive(Debug, Clone)] pub struct SamplesBuffer { data: Vec, pos: usize, - channels: u16, - sample_rate: u32, + channels: ChannelCount, + sample_rate: SampleRate, duration: Duration, } @@ -38,7 +38,7 @@ where /// - Panics if the length of the buffer is larger than approximately 16 billion elements. /// This is because the calculation of the duration would overflow. /// - pub fn new(channels: u16, sample_rate: u32, data: D) -> SamplesBuffer + pub fn new(channels: ChannelCount, sample_rate: SampleRate, data: D) -> SamplesBuffer where D: Into>, { @@ -74,12 +74,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate } @@ -174,12 +174,13 @@ mod tests { #[cfg(test)] mod try_seek { use super::*; + use crate::common::{ChannelCount, SampleRate}; use std::time::Duration; #[test] fn channel_order_stays_correct() { - const SAMPLE_RATE: u32 = 100; - const CHANNELS: u16 = 2; + const SAMPLE_RATE: SampleRate = 100; + const CHANNELS: ChannelCount = 2; let mut buf = SamplesBuffer::new( CHANNELS, SAMPLE_RATE, diff --git a/src/conversions/channels.rs b/src/conversions/channels.rs index 45bf767f..ac8980b9 100644 --- a/src/conversions/channels.rs +++ b/src/conversions/channels.rs @@ -1,3 +1,4 @@ +use crate::common::ChannelCount; use cpal::Sample; /// Iterator that converts from a certain channel count to another. @@ -7,10 +8,10 @@ where I: Iterator, { input: I, - from: cpal::ChannelCount, - to: cpal::ChannelCount, + from: ChannelCount, + to: ChannelCount, sample_repeat: Option, - next_output_sample_pos: cpal::ChannelCount, + next_output_sample_pos: ChannelCount, } impl ChannelCountConverter @@ -24,11 +25,7 @@ where /// Panics if `from` or `to` are equal to 0. /// #[inline] - pub fn new( - input: I, - from: cpal::ChannelCount, - to: cpal::ChannelCount, - ) -> ChannelCountConverter { + pub fn new(input: I, from: ChannelCount, to: ChannelCount) -> ChannelCountConverter { assert!(from >= 1); assert!(to >= 1); @@ -118,6 +115,7 @@ where #[cfg(test)] mod test { use super::ChannelCountConverter; + use crate::common::ChannelCount; #[test] fn remove_channels() { @@ -147,7 +145,7 @@ mod test { #[test] fn size_hint() { - fn test(input: &[i16], from: cpal::ChannelCount, to: cpal::ChannelCount) { + fn test(input: &[i16], from: ChannelCount, to: ChannelCount) { let mut converter = ChannelCountConverter::new(input.iter().copied(), from, to); let count = converter.clone().count(); for left_in_iter in (0..=count).rev() { diff --git a/src/conversions/sample_rate.rs b/src/conversions/sample_rate.rs index 05f8a2e9..3d882d9f 100644 --- a/src/conversions/sample_rate.rs +++ b/src/conversions/sample_rate.rs @@ -1,5 +1,6 @@ use crate::conversions::Sample; +use crate::common::{ChannelCount, SampleRate}; use num_rational::Ratio; use std::mem; @@ -16,7 +17,7 @@ where /// We convert chunks of `from` samples into chunks of `to` samples. to: u32, /// Number of channels in the stream - channels: cpal::ChannelCount, + channels: ChannelCount, /// One sample per channel, extracted from `input`. current_span: Vec, /// Position of `current_sample` modulo `from`. @@ -51,12 +52,12 @@ where #[inline] pub fn new( mut input: I, - from: cpal::SampleRate, - to: cpal::SampleRate, - num_channels: cpal::ChannelCount, + from: SampleRate, + to: SampleRate, + num_channels: ChannelCount, ) -> SampleRateConverter { - let from = from.0; - let to = to.0; + let from = from; + let to = to; assert!(num_channels >= 1); assert!(from >= 1); @@ -251,8 +252,8 @@ where #[cfg(test)] mod test { use super::SampleRateConverter; + use crate::common::{ChannelCount, SampleRate}; use core::time::Duration; - use cpal::{ChannelCount, SampleRate}; use quickcheck::{quickcheck, TestResult}; quickcheck! { @@ -264,8 +265,8 @@ mod test { { return TestResult::discard(); } - let from = SampleRate(from as u32); - let to = SampleRate(to as u32); + let from = from as SampleRate; + let to = to as SampleRate; let input: Vec = Vec::new(); let output = @@ -279,7 +280,7 @@ mod test { /// Check that resampling to the same rate does not change the signal. fn identity(from: u16, channels: u8, input: Vec) -> TestResult { if channels == 0 || channels > 128 || from == 0 { return TestResult::discard(); } - let from = SampleRate(from as u32); + let from = from as SampleRate; let output = SampleRateConverter::new(input.clone().into_iter(), from, from, channels as ChannelCount) @@ -295,7 +296,7 @@ mod test { return TestResult::discard(); } - let to = SampleRate(to as u32); + let to = to as SampleRate; let from = to * k as u32; // Truncate the input, so it contains an integer number of spans. @@ -321,7 +322,7 @@ mod test { return TestResult::discard(); } - let from = SampleRate(from as u32); + let from = from as SampleRate; let to = from * k as u32; // Truncate the input, so it contains an integer number of spans. @@ -345,19 +346,19 @@ mod test { /// Check that resampling does not change the audio duration, /// except by a negligible amount (± 1ms). Reproduces #316. /// Ignored, pending a bug fix. - fn preserve_durations(d: Duration, freq: f32, to: u32) -> TestResult { + fn preserve_durations(d: Duration, freq: f32, to: SampleRate) -> TestResult { if to == 0 { return TestResult::discard(); } use crate::source::{SineWave, Source}; - let to = SampleRate(to); + let to = to; let source = SineWave::new(freq).take_duration(d); - let from = SampleRate(source.sample_rate()); + let from = source.sample_rate(); let resampled = SampleRateConverter::new(source, from, to, 1); let duration = - Duration::from_secs_f32(resampled.count() as f32 / to.0 as f32); + Duration::from_secs_f32(resampled.count() as f32 / to as f32); let delta = if d < duration { duration - d } else { d - duration }; TestResult::from_bool(delta < Duration::from_millis(1)) @@ -367,8 +368,7 @@ mod test { #[test] fn upsample() { let input = vec![2u16, 16, 4, 18, 6, 20, 8, 22]; - let output = - SampleRateConverter::new(input.into_iter(), SampleRate(2000), SampleRate(3000), 2); + let output = SampleRateConverter::new(input.into_iter(), 2000, 3000, 2); assert_eq!(output.len(), 12); // Test the source's Iterator::size_hint() let output = output.collect::>(); @@ -378,8 +378,7 @@ mod test { #[test] fn upsample2() { let input = vec![1u16, 14]; - let output = - SampleRateConverter::new(input.into_iter(), SampleRate(1000), SampleRate(7000), 1); + let output = SampleRateConverter::new(input.into_iter(), 1000, 7000, 1); let size_estimation = output.len(); let output = output.collect::>(); assert_eq!(output, [1, 2, 4, 6, 8, 10, 12, 14]); @@ -389,8 +388,7 @@ mod test { #[test] fn downsample() { let input = Vec::from_iter(0u16..17); - let output = - SampleRateConverter::new(input.into_iter(), SampleRate(12000), SampleRate(2400), 1); + let output = SampleRateConverter::new(input.into_iter(), 12000, 2400, 1); let size_estimation = output.len(); let output = output.collect::>(); assert_eq!(output, [0, 5, 10, 15]); diff --git a/src/decoder/flac.rs b/src/decoder/flac.rs index a3ab8532..9773f9d8 100644 --- a/src/decoder/flac.rs +++ b/src/decoder/flac.rs @@ -6,6 +6,7 @@ use std::time::Duration; use crate::source::SeekError; use crate::Source; +use crate::common::{ChannelCount, SampleRate}; use claxon::FlacReader; /// Decoder for the Flac format. @@ -18,8 +19,8 @@ where current_block_channel_len: usize, current_block_off: usize, bits_per_sample: u32, - sample_rate: u32, - channels: u16, + sample_rate: SampleRate, + channels: ChannelCount, samples: Option, } @@ -45,7 +46,7 @@ where current_block_off: 0, bits_per_sample: spec.bits_per_sample, sample_rate: spec.sample_rate, - channels: spec.channels as u16, + channels: spec.channels as ChannelCount, samples: spec.samples, }) } @@ -64,12 +65,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 29ba027a..ad1e61d7 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -13,6 +13,7 @@ use crate::Source; #[cfg(feature = "symphonia")] use self::read_seek_source::ReadSeekSource; +use crate::common::{ChannelCount, SampleRate}; #[cfg(feature = "symphonia")] use ::symphonia::core::io::{MediaSource, MediaSourceStream}; @@ -118,7 +119,7 @@ impl DecoderImpl { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { match self { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.channels(), @@ -135,7 +136,7 @@ impl DecoderImpl { } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { match self { #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))] DecoderImpl::Wav(source) => source.sample_rate(), @@ -418,11 +419,11 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.0.channels() } - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.0.sample_rate() } @@ -516,12 +517,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.0.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.0.sample_rate() } diff --git a/src/decoder/mp3.rs b/src/decoder/mp3.rs index ebc9a759..f85605c7 100644 --- a/src/decoder/mp3.rs +++ b/src/decoder/mp3.rs @@ -59,12 +59,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.current_span.channels as _ } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.current_span.sample_rate as _ } diff --git a/src/decoder/symphonia.rs b/src/decoder/symphonia.rs index 77da85ac..c466e6ee 100644 --- a/src/decoder/symphonia.rs +++ b/src/decoder/symphonia.rs @@ -14,9 +14,9 @@ use symphonia::{ default::get_probe, }; -use crate::{source, Source}; - use super::DecoderError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{source, Source}; // Decoder errors are not considered fatal. // The correct action is to just get a new packet and try again. @@ -159,12 +159,12 @@ impl Source for SymphoniaDecoder { } #[inline] - fn channels(&self) -> u16 { - self.spec.channels.count() as u16 + fn channels(&self) -> ChannelCount { + self.spec.channels.count() as ChannelCount } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.spec.rate } diff --git a/src/decoder/vorbis.rs b/src/decoder/vorbis.rs index dcf6a441..2e936171 100644 --- a/src/decoder/vorbis.rs +++ b/src/decoder/vorbis.rs @@ -4,6 +4,7 @@ use std::time::Duration; use crate::source::SeekError; use crate::Source; +use crate::common::{ChannelCount, SampleRate}; use lewton::inside_ogg::OggStreamReader; /// Decoder for an OGG file that contains Vorbis sound format. @@ -62,12 +63,12 @@ where } #[inline] - fn channels(&self) -> u16 { - self.stream_reader.ident_hdr.audio_channels as u16 + fn channels(&self) -> ChannelCount { + self.stream_reader.ident_hdr.audio_channels as ChannelCount } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.stream_reader.ident_hdr.audio_sample_rate } diff --git a/src/decoder/wav.rs b/src/decoder/wav.rs index b4a3eaa2..76c27150 100644 --- a/src/decoder/wav.rs +++ b/src/decoder/wav.rs @@ -4,6 +4,7 @@ use std::time::Duration; use crate::source::SeekError; use crate::Source; +use crate::common::{ChannelCount, SampleRate}; use hound::{SampleFormat, WavReader}; /// Decoder for the WAV format. @@ -13,8 +14,8 @@ where { reader: SamplesIterator, total_duration: Duration, - sample_rate: u32, - channels: u16, + sample_rate: SampleRate, + channels: ChannelCount, } impl WavDecoder @@ -43,8 +44,8 @@ where Ok(WavDecoder { reader, total_duration, - sample_rate, - channels, + sample_rate: sample_rate as SampleRate, + channels: channels as ChannelCount, }) } pub fn into_inner(self) -> R { @@ -115,12 +116,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate } diff --git a/src/file_output.rs b/src/file_output.rs index 322c94a2..21f2c41a 100644 --- a/src/file_output.rs +++ b/src/file_output.rs @@ -10,7 +10,7 @@ pub fn output_to_wav( wav_file: impl AsRef, ) -> Result<(), Box> { let format = WavSpec { - channels: source.channels(), + channels: source.channels() as u16, sample_rate: source.sample_rate(), bits_per_sample: 32, sample_format: SampleFormat::Float, @@ -26,6 +26,7 @@ pub fn output_to_wav( #[cfg(test)] mod test { use super::output_to_wav; + use crate::common::ChannelCount; use crate::Source; use std::io::BufReader; use std::time::Duration; @@ -46,7 +47,7 @@ mod test { hound::WavReader::new(BufReader::new(file)).expect("wav file can be read back"); let reference = make_source(); assert_eq!(reference.sample_rate(), reader.spec().sample_rate); - assert_eq!(reference.channels(), reader.spec().channels); + assert_eq!(reference.channels(), reader.spec().channels as ChannelCount); let actual_samples: Vec = reader.samples::().map(|x| x.unwrap()).collect(); let expected_samples: Vec = reference.convert_samples().collect(); diff --git a/src/lib.rs b/src/lib.rs index 339f319f..0450eb95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ //! use rodio::{Decoder, OutputStream, source::Source}; //! //! // Get an output stream handle to the default physical sound device. -//! // Note that the playback stops when the stream_handle is dropped. +//! // Note that the playback stops when the stream_handle is dropped.//! //! let stream_handle = rodio::OutputStreamBuilder::open_default_stream() //! .expect("open default audio stream"); //! let sink = rodio::Sink::connect_new(&stream_handle.mixer()); @@ -150,14 +150,17 @@ //! down your program). #![cfg_attr(test, deny(missing_docs))] +#[cfg(feature = "cpal")] pub use cpal::{ self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices, SupportedStreamConfig, }; +mod common; mod conversions; mod sink; mod spatial_sink; +#[cfg(feature = "cpal")] mod stream; pub mod buffer; @@ -168,10 +171,12 @@ pub mod queue; pub mod source; pub mod static_buffer; +pub use crate::common::{ChannelCount, SampleRate}; pub use crate::conversions::Sample; pub use crate::decoder::Decoder; pub use crate::file_output::output_to_wav; pub use crate::sink::Sink; pub use crate::source::Source; pub use crate::spatial_sink::SpatialSink; +#[cfg(feature = "cpal")] pub use crate::stream::{play, OutputStream, OutputStreamBuilder, PlayError, StreamError}; diff --git a/src/mixer.rs b/src/mixer.rs index 313e4654..f2719c83 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -1,19 +1,19 @@ //! Mixer that plays multiple sounds at the same time. +use crate::common::{ChannelCount, SampleRate}; +use crate::source::{SeekError, Source, UniformSourceIterator}; +use crate::Sample; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; -use crate::source::{SeekError, Source, UniformSourceIterator}; -use crate::Sample; - /// Builds a new mixer. /// /// You can choose the characteristics of the output thanks to this constructor. All the sounds /// added to the mixer will be converted to these values. /// /// After creating a mixer, you can add new sounds with the controller. -pub fn mixer(channels: u16, sample_rate: u32) -> (Arc>, MixerSource) +pub fn mixer(channels: ChannelCount, sample_rate: SampleRate) -> (Arc>, MixerSource) where S: Sample + Send + 'static, { @@ -39,8 +39,8 @@ where pub struct Mixer { has_pending: AtomicBool, pending_sources: Mutex + Send>>>, - channels: u16, - sample_rate: u32, + channels: ChannelCount, + sample_rate: SampleRate, } impl Mixer @@ -90,12 +90,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate } diff --git a/src/queue.rs b/src/queue.rs index cb17973b..2a2f434f 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -7,6 +7,7 @@ use std::time::Duration; use crate::source::{Empty, SeekError, Source, Zero}; use crate::Sample; +use crate::common::{ChannelCount, SampleRate}; #[cfg(feature = "crossbeam-channel")] use crossbeam_channel::{unbounded as channel, Receiver, Sender}; #[cfg(not(feature = "crossbeam-channel"))] @@ -159,12 +160,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.current.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.current.sample_rate() } diff --git a/src/source/agc.rs b/src/source/agc.rs index 88958558..1268e9fb 100644 --- a/src/source/agc.rs +++ b/src/source/agc.rs @@ -23,6 +23,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Duration; +use crate::common::{ChannelCount, SampleRate}; #[cfg(feature = "tracing")] use tracing; @@ -472,12 +473,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/amplify.rs b/src/source/amplify.rs index 14382ceb..11225e1b 100644 --- a/src/source/amplify.rs +++ b/src/source/amplify.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `Amplify` object. pub fn amplify(input: I, factor: f32) -> Amplify @@ -82,12 +82,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/blt.rs b/src/source/blt.rs index 1ba26198..6a973d7b 100644 --- a/src/source/blt.rs +++ b/src/source/blt.rs @@ -1,8 +1,8 @@ +use crate::common::{ChannelCount, SampleRate}; +use crate::Source; use std::f32::consts::PI; use std::time::Duration; -use crate::Source; - use super::SeekError; // Implemented following http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt @@ -163,12 +163,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/buffered.rs b/src/source/buffered.rs index 52b5ff7a..dc85db73 100644 --- a/src/source/buffered.rs +++ b/src/source/buffered.rs @@ -3,9 +3,9 @@ use std::mem; use std::sync::{Arc, Mutex}; use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `Buffered` object. #[inline] @@ -63,8 +63,8 @@ where I::Item: Sample, { data: Vec, - channels: u16, - rate: u32, + channels: ChannelCount, + rate: SampleRate, next: Mutex>>, } @@ -220,7 +220,7 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { match *self.current_span { Span::Data(SpanData { channels, .. }) => channels, Span::End => 1, @@ -229,7 +229,7 @@ where } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { match *self.current_span { Span::Data(SpanData { rate, .. }) => rate, Span::End => 44100, diff --git a/src/source/channel_volume.rs b/src/source/channel_volume.rs index 7dce1a6f..84862875 100644 --- a/src/source/channel_volume.rs +++ b/src/source/channel_volume.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Combines channels in input into a single mono source, then plays that mono sound /// to each channel at the volume given for that channel. @@ -129,12 +129,12 @@ where } #[inline] - fn channels(&self) -> u16 { - self.channel_volumes.len() as u16 + fn channels(&self) -> ChannelCount { + self.channel_volumes.len() as ChannelCount } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/chirp.rs b/src/source/chirp.rs index 11d97d31..4b99eb85 100644 --- a/src/source/chirp.rs +++ b/src/source/chirp.rs @@ -1,13 +1,13 @@ //! Chirp/sweep source. -use std::{f32::consts::TAU, time::Duration}; - +use crate::common::{ChannelCount, SampleRate}; use crate::Source; +use std::{f32::consts::TAU, time::Duration}; /// Convenience function to create a new `Chirp` source. #[inline] pub fn chirp( - sample_rate: cpal::SampleRate, + sample_rate: SampleRate, start_frequency: f32, end_frequency: f32, duration: Duration, @@ -21,14 +21,14 @@ pub fn chirp( pub struct Chirp { start_frequency: f32, end_frequency: f32, - sample_rate: cpal::SampleRate, + sample_rate: SampleRate, total_samples: u64, elapsed_samples: u64, } impl Chirp { fn new( - sample_rate: cpal::SampleRate, + sample_rate: SampleRate, start_frequency: f32, end_frequency: f32, duration: Duration, @@ -37,7 +37,7 @@ impl Chirp { sample_rate, start_frequency, end_frequency, - total_samples: (duration.as_secs_f64() * (sample_rate.0 as f64)) as u64, + total_samples: (duration.as_secs_f64() * (sample_rate as f64)) as u64, elapsed_samples: 0, } } @@ -61,16 +61,16 @@ impl Source for Chirp { None } - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } - fn sample_rate(&self) -> u32 { - self.sample_rate.0 + fn sample_rate(&self) -> SampleRate { + self.sample_rate } fn total_duration(&self) -> Option { - let secs: f64 = self.total_samples as f64 / self.sample_rate.0 as f64; + let secs: f64 = self.total_samples as f64 / self.sample_rate as f64; Some(Duration::new(1, 0).mul_f64(secs)) } } diff --git a/src/source/delay.rs b/src/source/delay.rs index 80384981..a10e5311 100644 --- a/src/source/delay.rs +++ b/src/source/delay.rs @@ -1,10 +1,14 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; -fn remaining_samples(until_playback: Duration, sample_rate: u32, channels: u16) -> usize { +fn remaining_samples( + until_playback: Duration, + sample_rate: SampleRate, + channels: ChannelCount, +) -> usize { let ns = until_playback.as_secs() * 1_000_000_000 + until_playback.subsec_nanos() as u64; let samples = ns * channels as u64 * sample_rate as u64 / 1_000_000_000; samples as usize @@ -95,12 +99,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/done.rs b/src/source/done.rs index c3087434..3ce8a5a3 100644 --- a/src/source/done.rs +++ b/src/source/done.rs @@ -2,9 +2,9 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// When the inner source is empty this decrements a `AtomicUsize`. #[derive(Debug, Clone)] @@ -78,12 +78,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/empty.rs b/src/source/empty.rs index db61defe..c546e5be 100644 --- a/src/source/empty.rs +++ b/src/source/empty.rs @@ -1,9 +1,9 @@ use std::marker::PhantomData; use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// An empty source. #[derive(Debug, Copy, Clone)] @@ -44,12 +44,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { 48000 } diff --git a/src/source/empty_callback.rs b/src/source/empty_callback.rs index 0f7864eb..df7e2a20 100644 --- a/src/source/empty_callback.rs +++ b/src/source/empty_callback.rs @@ -1,9 +1,9 @@ use std::marker::PhantomData; use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// An empty source which executes a callback function pub struct EmptyCallback { @@ -47,12 +47,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { 48000 } diff --git a/src/source/fadein.rs b/src/source/fadein.rs index af884fb7..3eb202c9 100644 --- a/src/source/fadein.rs +++ b/src/source/fadein.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::{linear_ramp::linear_gain_ramp, LinearGainRamp, SeekError}; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `FadeIn` object. pub fn fadein(input: I, duration: Duration) -> FadeIn @@ -81,12 +81,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.inner().channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.inner().sample_rate() } diff --git a/src/source/fadeout.rs b/src/source/fadeout.rs index e3a07fe6..24cac2b3 100644 --- a/src/source/fadeout.rs +++ b/src/source/fadeout.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::{linear_ramp::linear_gain_ramp, LinearGainRamp, SeekError}; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `FadeOut` object. pub fn fadeout(input: I, duration: Duration) -> FadeOut @@ -81,12 +81,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.inner().channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.inner().sample_rate() } diff --git a/src/source/from_iter.rs b/src/source/from_iter.rs index fe8d9fe6..f1709301 100644 --- a/src/source/from_iter.rs +++ b/src/source/from_iter.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Builds a source that chains sources provided by an iterator. /// @@ -114,7 +114,7 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { if let Some(src) = &self.current_source { src.channels() } else { @@ -124,7 +124,7 @@ where } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { if let Some(src) = &self.current_source { src.sample_rate() } else { diff --git a/src/source/linear_ramp.rs b/src/source/linear_ramp.rs index c1ddebfa..bf03855c 100644 --- a/src/source/linear_ramp.rs +++ b/src/source/linear_ramp.rs @@ -1,6 +1,7 @@ use std::time::Duration; use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; use crate::{Sample, Source}; /// Internal function that builds a `LinearRamp` object. @@ -121,12 +122,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/mix.rs b/src/source/mix.rs index d32e55b1..9c573811 100644 --- a/src/source/mix.rs +++ b/src/source/mix.rs @@ -1,6 +1,7 @@ use std::cmp; use std::time::Duration; +use crate::common::{ChannelCount, SampleRate}; use crate::source::uniform::UniformSourceIterator; use crate::source::SeekError; use crate::{Sample, Source}; @@ -101,12 +102,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input1.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input1.sample_rate() } diff --git a/src/source/mod.rs b/src/source/mod.rs index a5f6a3e9..3211301e 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -3,9 +3,9 @@ use core::fmt; use core::time::Duration; -use cpal::FromSample; - +use crate::common::{ChannelCount, SampleRate}; use crate::Sample; +use cpal::FromSample; pub use self::agc::AutomaticGainControl; pub use self::amplify::Amplify; @@ -165,10 +165,10 @@ where fn current_span_len(&self) -> Option; /// Returns the number of channels. Channels are always interleaved. - fn channels(&self) -> u16; + fn channels(&self) -> ChannelCount; /// 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) -> SampleRate; /// Returns the total duration of this source, if known. /// @@ -669,12 +669,12 @@ macro_rules! source_pointer_impl { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { (**self).channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { (**self).sample_rate() } diff --git a/src/source/noise.rs b/src/source/noise.rs index 350050a9..60937446 100644 --- a/src/source/noise.rs +++ b/src/source/noise.rs @@ -6,17 +6,18 @@ use crate::Source; use super::SeekError; +use crate::common::SampleRate; use rand::{rngs::SmallRng, RngCore, SeedableRng}; /// Convenience function to create a new `WhiteNoise` noise source. #[inline] -pub fn white(sample_rate: cpal::SampleRate) -> WhiteNoise { +pub fn white(sample_rate: SampleRate) -> WhiteNoise { WhiteNoise::new(sample_rate) } /// Convenience function to create a new `PinkNoise` noise source. #[inline] -pub fn pink(sample_rate: cpal::SampleRate) -> PinkNoise { +pub fn pink(sample_rate: SampleRate) -> PinkNoise { PinkNoise::new(sample_rate) } @@ -24,7 +25,7 @@ pub fn pink(sample_rate: cpal::SampleRate) -> PinkNoise { /// samples as provided by the `rand::rngs::SmallRng` randomness source. #[derive(Clone, Debug)] pub struct WhiteNoise { - sample_rate: cpal::SampleRate, + sample_rate: SampleRate, rng: SmallRng, } @@ -38,7 +39,7 @@ impl WhiteNoise { } /// Create a new white noise generator, seeding the RNG with system entropy. - pub fn new(sample_rate: cpal::SampleRate) -> Self { + pub fn new(sample_rate: SampleRate) -> Self { Self { sample_rate, rng: SmallRng::from_entropy(), @@ -64,12 +65,12 @@ impl Source for WhiteNoise { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate.0 } @@ -99,7 +100,7 @@ pub struct PinkNoise { impl PinkNoise { /// Create new pink noise source with given sample rate. - pub fn new(sample_rate: cpal::SampleRate) -> Self { + pub fn new(sample_rate: SampleRate) -> Self { Self { white_noise: WhiteNoise::new(sample_rate), b: [0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32], @@ -139,11 +140,11 @@ impl Source for PinkNoise { None } - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.white_noise.sample_rate() } diff --git a/src/source/pausable.rs b/src/source/pausable.rs index fa3a5266..220ed69b 100644 --- a/src/source/pausable.rs +++ b/src/source/pausable.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Builds a `Pausable` object. pub fn pausable(source: I, paused: bool) -> Pausable @@ -31,8 +31,8 @@ where #[derive(Clone, Debug)] pub struct Pausable { input: I, - paused_channels: Option, - remaining_paused_samples: u16, + paused_channels: Option, + remaining_paused_samples: ChannelCount, } impl Pausable @@ -110,12 +110,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/periodic.rs b/src/source/periodic.rs index 08e4f25c..5ce4f74b 100644 --- a/src/source/periodic.rs +++ b/src/source/periodic.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `PeriodicAccess` object. pub fn periodic(source: I, period: Duration, modifier: F) -> PeriodicAccess @@ -106,12 +106,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/position.rs b/src/source/position.rs index 92758568..b06cc021 100644 --- a/src/source/position.rs +++ b/src/source/position.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `TrackPosition` object. See trait docs for /// details @@ -23,8 +23,8 @@ pub struct TrackPosition { input: I, samples_counted: usize, offset_duration: f64, - current_span_sample_rate: u32, - current_span_channels: u16, + current_span_sample_rate: SampleRate, + current_span_channels: ChannelCount, current_span_len: Option, } @@ -130,12 +130,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/repeat.rs b/src/source/repeat.rs index 122f24c8..5ccb879e 100644 --- a/src/source/repeat.rs +++ b/src/source/repeat.rs @@ -2,9 +2,9 @@ use std::time::Duration; use crate::source::buffered::Buffered; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `Repeat` object. pub fn repeat(input: I) -> Repeat @@ -67,7 +67,7 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { match self.inner.current_span_len() { Some(0) => self.next.channels(), _ => self.inner.channels(), @@ -75,7 +75,7 @@ where } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { match self.inner.current_span_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 2dbd42bc..173d262b 100644 --- a/src/source/samples_converter.rs +++ b/src/source/samples_converter.rs @@ -1,11 +1,11 @@ use std::marker::PhantomData; use std::time::Duration; +use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; use crate::{Sample, Source}; use cpal::{FromSample, Sample as CpalSample}; -use super::SeekError; - /// Wrap the input and lazily converts the samples it provides to the type /// specified by the generic parameter D #[derive(Clone)] @@ -83,12 +83,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.inner.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.inner.sample_rate() } diff --git a/src/source/sawtooth.rs b/src/source/sawtooth.rs index 58e56d03..c6ae01f3 100644 --- a/src/source/sawtooth.rs +++ b/src/source/sawtooth.rs @@ -1,7 +1,7 @@ -use std::time::Duration; - +use crate::common::{ChannelCount, SampleRate}; use crate::source::{Function, SignalGenerator}; use crate::Source; +use std::time::Duration; use super::SeekError; @@ -17,14 +17,13 @@ pub struct SawtoothWave { } impl SawtoothWave { - const SAMPLE_RATE: u32 = 48000; + const SAMPLE_RATE: SampleRate = 48000; /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> SawtoothWave { - let sr = cpal::SampleRate(Self::SAMPLE_RATE); SawtoothWave { - test_saw: SignalGenerator::new(sr, freq, Function::Sawtooth), + test_saw: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Sawtooth), } } } @@ -45,12 +44,12 @@ impl Source for SawtoothWave { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { Self::SAMPLE_RATE } diff --git a/src/source/signal_generator.rs b/src/source/signal_generator.rs index e724297b..e0c33bb8 100644 --- a/src/source/signal_generator.rs +++ b/src/source/signal_generator.rs @@ -9,13 +9,13 @@ //! ``` //! use rodio::source::{SignalGenerator,Function}; //! -//! let tone = SignalGenerator::new(cpal::SampleRate(48000), 440.0, Function::Sine); +//! let tone = SignalGenerator::new(48000, 440.0, Function::Sine); //! ``` -use std::f32::consts::TAU; -use std::time::Duration; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; use crate::Source; +use std::f32::consts::TAU; +use std::time::Duration; /// Generator function. /// @@ -71,7 +71,7 @@ fn sawtooth_signal(phase: f32) -> f32 { /// An infinite source that produces one of a selection of test waveforms. #[derive(Clone, Debug)] pub struct SignalGenerator { - sample_rate: cpal::SampleRate, + sample_rate: SampleRate, function: GeneratorFunction, phase_step: f32, phase: f32, @@ -86,7 +86,7 @@ impl SignalGenerator { /// /// Will panic if `frequency` is equal to zero. #[inline] - pub fn new(sample_rate: cpal::SampleRate, frequency: f32, f: Function) -> Self { + pub fn new(sample_rate: SampleRate, frequency: f32, f: Function) -> Self { let function: GeneratorFunction = match f { Function::Sine => sine_signal, Function::Triangle => triangle_signal, @@ -105,12 +105,12 @@ impl SignalGenerator { /// Will panic if `frequency` is equal to zero. #[inline] pub fn with_function( - sample_rate: cpal::SampleRate, + sample_rate: SampleRate, frequency: f32, generator_function: GeneratorFunction, ) -> Self { assert!(frequency != 0.0, "frequency must be greater than zero"); - let period = sample_rate.0 as f32 / frequency; + let period = sample_rate as f32 / frequency; let phase_step = 1.0f32 / period; SignalGenerator { @@ -142,13 +142,13 @@ impl Source for SignalGenerator { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { - self.sample_rate.0 + fn sample_rate(&self) -> SampleRate { + self.sample_rate } #[inline] @@ -158,7 +158,7 @@ impl Source for SignalGenerator { #[inline] fn try_seek(&mut self, duration: Duration) -> Result<(), SeekError> { - let seek = duration.as_secs_f32() * (self.sample_rate.0 as f32) / self.period; + let seek = duration.as_secs_f32() * (self.sample_rate as f32) / self.period; self.phase = seek.rem_euclid(1.0f32); Ok(()) } @@ -171,7 +171,7 @@ mod tests { #[test] fn square() { - let mut wf = SignalGenerator::new(cpal::SampleRate(2000), 500.0f32, Function::Square); + let mut wf = SignalGenerator::new(2000, 500.0f32, Function::Square); assert_eq!(wf.next(), Some(1.0f32)); assert_eq!(wf.next(), Some(1.0f32)); assert_eq!(wf.next(), Some(-1.0f32)); @@ -184,7 +184,7 @@ mod tests { #[test] fn triangle() { - let mut wf = SignalGenerator::new(cpal::SampleRate(8000), 1000.0f32, Function::Triangle); + let mut wf = SignalGenerator::new(8000, 1000.0f32, Function::Triangle); assert_eq!(wf.next(), Some(-1.0f32)); assert_eq!(wf.next(), Some(-0.5f32)); assert_eq!(wf.next(), Some(0.0f32)); @@ -205,7 +205,7 @@ mod tests { #[test] fn saw() { - let mut wf = SignalGenerator::new(cpal::SampleRate(200), 50.0f32, Function::Sawtooth); + let mut wf = SignalGenerator::new(200, 50.0f32, Function::Sawtooth); assert_eq!(wf.next(), Some(0.0f32)); assert_eq!(wf.next(), Some(0.5f32)); assert_eq!(wf.next(), Some(-1.0f32)); @@ -217,7 +217,7 @@ mod tests { #[test] fn sine() { - let mut wf = SignalGenerator::new(cpal::SampleRate(1000), 100f32, Function::Sine); + let mut wf = SignalGenerator::new(1000, 100f32, Function::Sine); assert_abs_diff_eq!(wf.next().unwrap(), 0.0f32); assert_abs_diff_eq!(wf.next().unwrap(), 0.58778525f32); diff --git a/src/source/sine.rs b/src/source/sine.rs index c10c536c..e3814435 100644 --- a/src/source/sine.rs +++ b/src/source/sine.rs @@ -1,7 +1,7 @@ -use std::time::Duration; - +use crate::common::{ChannelCount, SampleRate}; use crate::source::{Function, SignalGenerator}; use crate::Source; +use std::time::Duration; use super::SeekError; @@ -22,9 +22,8 @@ impl SineWave { /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> SineWave { - let sr = cpal::SampleRate(Self::SAMPLE_RATE); SineWave { - test_sine: SignalGenerator::new(sr, freq, Function::Sine), + test_sine: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Sine), } } } @@ -45,12 +44,12 @@ impl Source for SineWave { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { Self::SAMPLE_RATE } diff --git a/src/source/skip.rs b/src/source/skip.rs index 96ebd3c9..ef80227e 100644 --- a/src/source/skip.rs +++ b/src/source/skip.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; const NS_PER_SECOND: u128 = 1_000_000_000; @@ -143,12 +143,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } @@ -171,11 +171,12 @@ mod tests { use std::time::Duration; use crate::buffer::SamplesBuffer; + use crate::common::{ChannelCount, SampleRate}; use crate::source::Source; fn test_skip_duration_samples_left( - channels: u16, - sample_rate: u32, + channels: ChannelCount, + sample_rate: SampleRate, seconds: u32, seconds_to_skip: u32, ) { diff --git a/src/source/skippable.rs b/src/source/skippable.rs index 9bcd559a..d77447cf 100644 --- a/src/source/skippable.rs +++ b/src/source/skippable.rs @@ -1,7 +1,7 @@ -use std::time::Duration; - +use crate::common::{ChannelCount, SampleRate}; use crate::Sample; use crate::Source; +use std::time::Duration; use super::SeekError; @@ -83,12 +83,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/spatial.rs b/src/source/spatial.rs index 3c0f4b70..f8a2b5ca 100644 --- a/src/source/spatial.rs +++ b/src/source/spatial.rs @@ -1,10 +1,10 @@ use std::time::Duration; +use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; use crate::source::ChannelVolume; use crate::{Sample, Source}; -use super::SeekError; - /// A simple spatial audio source. The underlying source is transformed to Mono /// and then played in stereo. The left and right channel's volume are amplified /// differently depending on the distance of the left and right ear to the source. @@ -108,12 +108,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/speed.rs b/src/source/speed.rs index 76f00e4f..6409dff2 100644 --- a/src/source/speed.rs +++ b/src/source/speed.rs @@ -47,9 +47,9 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `Speed` object. pub fn speed(input: I, factor: f32) -> Speed { @@ -129,12 +129,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { (self.input.sample_rate() as f32 * self.factor) as u32 } diff --git a/src/source/square.rs b/src/source/square.rs index 40c10511..ac6bd678 100644 --- a/src/source/square.rs +++ b/src/source/square.rs @@ -1,7 +1,7 @@ -use std::time::Duration; - +use crate::common::{ChannelCount, SampleRate}; use crate::source::{Function, SignalGenerator}; use crate::Source; +use std::time::Duration; use super::SeekError; @@ -22,9 +22,8 @@ impl SquareWave { /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> SquareWave { - let sr = cpal::SampleRate(Self::SAMPLE_RATE); SquareWave { - test_square: SignalGenerator::new(sr, freq, Function::Square), + test_square: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Square), } } } @@ -45,12 +44,12 @@ impl Source for SquareWave { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { Self::SAMPLE_RATE } diff --git a/src/source/stoppable.rs b/src/source/stoppable.rs index cde1b1d2..116efe39 100644 --- a/src/source/stoppable.rs +++ b/src/source/stoppable.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// This is the same as [`skippable`](crate::source::skippable) see its docs pub fn stoppable(source: I) -> Stoppable { @@ -78,12 +78,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/take.rs b/src/source/take.rs index 6b8f4bbf..9e036f6e 100644 --- a/src/source/take.rs +++ b/src/source/take.rs @@ -1,8 +1,8 @@ use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// Internal function that builds a `TakeDuration` object. pub fn take_duration(input: I, duration: Duration) -> TakeDuration @@ -160,12 +160,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.input.channels() } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.input.sample_rate() } diff --git a/src/source/triangle.rs b/src/source/triangle.rs index 89889a98..eb73801d 100644 --- a/src/source/triangle.rs +++ b/src/source/triangle.rs @@ -1,7 +1,7 @@ -use std::time::Duration; - +use crate::common::{ChannelCount, SampleRate}; use crate::source::{Function, SignalGenerator}; use crate::Source; +use std::time::Duration; use super::SeekError; @@ -17,14 +17,13 @@ pub struct TriangleWave { } impl TriangleWave { - const SAMPLE_RATE: u32 = 48000; + const SAMPLE_RATE: SampleRate = 48000; /// The frequency of the sine. #[inline] pub fn new(freq: f32) -> TriangleWave { - let sr = cpal::SampleRate(Self::SAMPLE_RATE); TriangleWave { - test_tri: SignalGenerator::new(sr, freq, Function::Triangle), + test_tri: SignalGenerator::new(Self::SAMPLE_RATE, freq, Function::Triangle), } } } @@ -45,12 +44,12 @@ impl Source for TriangleWave { } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { 1 } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { Self::SAMPLE_RATE } diff --git a/src/source/uniform.rs b/src/source/uniform.rs index 8454927d..30472ed9 100644 --- a/src/source/uniform.rs +++ b/src/source/uniform.rs @@ -3,11 +3,11 @@ use std::time::Duration; use cpal::FromSample; +use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; use crate::conversions::{ChannelCountConverter, DataConverter, SampleRateConverter}; use crate::{Sample, Source}; -use super::SeekError; - /// An iterator that reads from a `Source` and converts the samples to a /// specific type, sample-rate and channels count. /// @@ -21,8 +21,8 @@ where D: Sample, { inner: Option>>, D>>, - target_channels: u16, - target_sample_rate: u32, + target_channels: ChannelCount, + target_sample_rate: SampleRate, total_duration: Option, } @@ -37,8 +37,8 @@ where #[inline] pub fn new( input: I, - target_channels: u16, - target_sample_rate: u32, + target_channels: ChannelCount, + target_sample_rate: SampleRate, ) -> UniformSourceIterator { let total_duration = input.total_duration(); let input = UniformSourceIterator::bootstrap(input, target_channels, target_sample_rate); @@ -54,8 +54,8 @@ where #[inline] fn bootstrap( input: I, - target_channels: u16, - target_sample_rate: u32, + target_channels: ChannelCount, + target_sample_rate: SampleRate, ) -> DataConverter>>, D> { // Limit the span length to something reasonable let span_len = input.current_span_len().map(|x| x.min(32768)); @@ -67,12 +67,8 @@ where iter: input, n: span_len, }; - let input = SampleRateConverter::new( - input, - cpal::SampleRate(from_sample_rate), - cpal::SampleRate(target_sample_rate), - from_channels, - ); + let input = + SampleRateConverter::new(input, from_sample_rate, target_sample_rate, from_channels); let input = ChannelCountConverter::new(input, from_channels, target_channels); DataConverter::new(input) @@ -128,12 +124,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.target_channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.target_sample_rate } diff --git a/src/source/zero.rs b/src/source/zero.rs index 8fe2dda7..69e3a295 100644 --- a/src/source/zero.rs +++ b/src/source/zero.rs @@ -1,17 +1,17 @@ use std::marker::PhantomData; use std::time::Duration; -use crate::{Sample, Source}; - use super::SeekError; +use crate::common::{ChannelCount, SampleRate}; +use crate::{Sample, Source}; /// An source that produces samples with value zero (silence). Depending on if /// it where created with [`Zero::new`] or [`Zero::new_samples`] it can be never /// ending or finite. #[derive(Clone, Debug)] pub struct Zero { - channels: u16, - sample_rate: u32, + channels: ChannelCount, + sample_rate: SampleRate, num_samples: Option, marker: PhantomData, } @@ -19,7 +19,7 @@ pub struct Zero { impl Zero { /// Create a new source that never ends and produces total silence. #[inline] - pub fn new(channels: u16, sample_rate: u32) -> Zero { + pub fn new(channels: ChannelCount, sample_rate: SampleRate) -> Zero { Zero { channels, sample_rate, @@ -29,7 +29,11 @@ impl Zero { } /// Create a new source that never ends and produces total silence. #[inline] - pub fn new_samples(channels: u16, sample_rate: u32, num_samples: usize) -> Zero { + pub fn new_samples( + channels: ChannelCount, + sample_rate: SampleRate, + num_samples: usize, + ) -> Zero { Zero { channels, sample_rate, @@ -70,12 +74,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate } diff --git a/src/static_buffer.rs b/src/static_buffer.rs index b43c1917..4b2c650e 100644 --- a/src/static_buffer.rs +++ b/src/static_buffer.rs @@ -13,6 +13,7 @@ use std::slice::Iter as SliceIter; use std::time::Duration; +use crate::common::{ChannelCount, SampleRate}; use crate::source::SeekError; use crate::{Sample, Source}; @@ -23,8 +24,8 @@ where S: 'static, { data: SliceIter<'static, S>, - channels: u16, - sample_rate: u32, + channels: ChannelCount, + sample_rate: SampleRate, duration: Duration, } @@ -41,7 +42,11 @@ where /// - Panics if the length of the buffer is larger than approximately 16 billion elements. /// This is because the calculation of the duration would overflow. /// - pub fn new(channels: u16, sample_rate: u32, data: &'static [S]) -> StaticSamplesBuffer { + pub fn new( + channels: ChannelCount, + sample_rate: SampleRate, + data: &'static [S], + ) -> StaticSamplesBuffer { assert!(channels != 0); assert!(sample_rate != 0); @@ -72,12 +77,12 @@ where } #[inline] - fn channels(&self) -> u16 { + fn channels(&self) -> ChannelCount { self.channels } #[inline] - fn sample_rate(&self) -> u32 { + fn sample_rate(&self) -> SampleRate { self.sample_rate } diff --git a/src/stream.rs b/src/stream.rs index 246f0c98..48616eea 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -3,16 +3,14 @@ use std::marker::Sync; use std::sync::Arc; use std::{error, fmt}; +use crate::common::{ChannelCount, SampleRate}; use crate::decoder; use crate::mixer::{mixer, Mixer, MixerSource}; use crate::sink::Sink; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -use cpal::{ - BufferSize, ChannelCount, FrameCount, Sample, SampleFormat, SampleRate, StreamConfig, - SupportedBufferSize, -}; +use cpal::{BufferSize, FrameCount, Sample, SampleFormat, StreamConfig, SupportedBufferSize}; -const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100); +const HZ_44100: SampleRate = 44_100; /// `cpal::Stream` container. /// Use `mixer()` method to control output. @@ -85,14 +83,14 @@ impl OutputStreamBuilder { } /// Sets number of output stream's channels. - pub fn with_channels(mut self, channel_count: cpal::ChannelCount) -> OutputStreamBuilder { + pub fn with_channels(mut self, channel_count: ChannelCount) -> OutputStreamBuilder { assert!(channel_count > 0); self.config.channel_count = channel_count; self } /// Sets output stream's sample rate. - pub fn with_sample_rate(mut self, sample_rate: cpal::SampleRate) -> OutputStreamBuilder { + pub fn with_sample_rate(mut self, sample_rate: SampleRate) -> OutputStreamBuilder { self.config.sample_rate = sample_rate; self } @@ -118,8 +116,8 @@ impl OutputStreamBuilder { config: &cpal::SupportedStreamConfig, ) -> OutputStreamBuilder { self.config = OutputStreamConfig { - channel_count: config.channels(), - sample_rate: config.sample_rate(), + channel_count: config.channels() as ChannelCount, + sample_rate: config.sample_rate().0 as SampleRate, // In case of supported range limit buffer size to avoid unexpectedly long playback delays. buffer_size: clamp_supported_buffer_size(config.buffer_size(), 1024), sample_format: config.sample_format(), @@ -130,8 +128,8 @@ impl OutputStreamBuilder { /// Set all output stream parameters at once from CPAL stream config. pub fn with_config(mut self, config: &cpal::StreamConfig) -> OutputStreamBuilder { self.config = OutputStreamConfig { - channel_count: config.channels, - sample_rate: config.sample_rate, + channel_count: config.channels as ChannelCount, + sample_rate: config.sample_rate.0 as SampleRate, buffer_size: config.buffer_size, ..self.config }; @@ -220,8 +218,8 @@ where impl From<&OutputStreamConfig> for StreamConfig { fn from(config: &OutputStreamConfig) -> Self { cpal::StreamConfig { - channels: config.channel_count, - sample_rate: config.sample_rate, + channels: config.channel_count as cpal::ChannelCount, + sample_rate: cpal::SampleRate(config.sample_rate), buffer_size: config.buffer_size, } } @@ -307,7 +305,7 @@ impl OutputStream { device: &cpal::Device, config: &OutputStreamConfig, ) -> Result { - let (controller, source) = mixer(config.channel_count, config.sample_rate.0); + let (controller, source) = mixer(config.channel_count, config.sample_rate); Self::init_stream(device, config, source) .map_err(StreamError::BuildStreamError) .and_then(|stream| { @@ -458,8 +456,9 @@ fn supported_output_configs( let max_rate = sf.max_sample_rate(); let min_rate = sf.min_sample_rate(); let mut formats = vec![sf.with_max_sample_rate()]; - if HZ_44100 < max_rate && HZ_44100 > min_rate { - formats.push(sf.with_sample_rate(HZ_44100)) + let preferred_rate = cpal::SampleRate(HZ_44100); + if preferred_rate < max_rate && preferred_rate > min_rate { + formats.push(sf.with_sample_rate(preferred_rate)) } formats.push(sf.with_sample_rate(min_rate)); formats diff --git a/tests/seek.rs b/tests/seek.rs index 4c49ad80..0cc47c97 100644 --- a/tests/seek.rs +++ b/tests/seek.rs @@ -1,11 +1,10 @@ +use rodio::{ChannelCount, Decoder, Source}; +use rstest::rstest; +use rstest_reuse::{self, *}; use std::io::{BufReader, Read, Seek}; use std::path::Path; use std::time::Duration; -use rodio::{Decoder, Source}; -use rstest::rstest; -use rstest_reuse::{self, *}; - #[template] #[rstest] // note: disabled, broken decoder see issue: #516 and #539 @@ -203,17 +202,22 @@ where .next_multiple_of(channels); let samples = &samples[beep_starts..beep_starts + 100]; - assert!(is_silent(samples, channels as u16, 0), "{samples:?}"); - assert!(!is_silent(samples, channels as u16, 1), "{samples:?}"); + assert!( + is_silent(samples, channels as ChannelCount, 0), + "{samples:?}" + ); + assert!( + !is_silent(samples, channels as ChannelCount, 1), + "{samples:?}" + ); beep_starts..beep_ends } -fn is_silent(samples: &[f32], channels: u16, channel: usize) -> bool { +fn is_silent(samples: &[f32], channels: ChannelCount, channel: usize) -> bool { assert_eq!(samples.len(), 100); let channel = samples.iter().skip(channel).step_by(channels as usize); - let volume = - channel.map(|s| s.abs()).sum::() as f32 / samples.len() as f32 * channels as f32; + let volume = channel.map(|s| s.abs()).sum::() / samples.len() as f32 * channels as f32; const BASICALLY_ZERO: f32 = 0.0001; volume < BASICALLY_ZERO From 9799c72372d1ab14ad3c6ef5a6469cf5df97e526 Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Wed, 25 Dec 2024 21:30:57 +0400 Subject: [PATCH 02/11] Add missing file --- src/common.rs | 5 +++++ src/source/noise.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/common.rs diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 00000000..95b60c27 --- /dev/null +++ b/src/common.rs @@ -0,0 +1,5 @@ +/// Stream sample rate (samples per second per channel). +pub type SampleRate = u32; + +/// Number of channels in a stream. +pub type ChannelCount = u16; diff --git a/src/source/noise.rs b/src/source/noise.rs index 60937446..16db4ff2 100644 --- a/src/source/noise.rs +++ b/src/source/noise.rs @@ -31,7 +31,7 @@ pub struct WhiteNoise { impl WhiteNoise { /// Create a new white noise generator, seeding the RNG with `seed`. - pub fn new_with_seed(sample_rate: cpal::SampleRate, seed: u64) -> Self { + pub fn new_with_seed(sample_rate: SampleRate, seed: u64) -> Self { Self { sample_rate, rng: SmallRng::seed_from_u64(seed), From 0b7b9415e10da1747e5d51e51e12ac88c691a118 Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 26 Dec 2024 00:42:23 +0400 Subject: [PATCH 03/11] Benches build fix, clippy cleanup --- benches/shared.rs | 2 +- src/conversions/sample_rate.rs | 3 --- src/file_output.rs | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/benches/shared.rs b/benches/shared.rs index 6122f64f..d800dc4d 100644 --- a/benches/shared.rs +++ b/benches/shared.rs @@ -2,7 +2,7 @@ use std::io::Cursor; use std::time::Duration; use std::vec; -use rodio::Source; +use rodio::{ChannelCount, SampleRate, Source}; pub struct TestSource { samples: vec::IntoIter, diff --git a/src/conversions/sample_rate.rs b/src/conversions/sample_rate.rs index 3d882d9f..3f95dff0 100644 --- a/src/conversions/sample_rate.rs +++ b/src/conversions/sample_rate.rs @@ -56,9 +56,6 @@ where to: SampleRate, num_channels: ChannelCount, ) -> SampleRateConverter { - let from = from; - let to = to; - assert!(num_channels >= 1); assert!(from >= 1); assert!(to >= 1); diff --git a/src/file_output.rs b/src/file_output.rs index 21f2c41a..ce088908 100644 --- a/src/file_output.rs +++ b/src/file_output.rs @@ -1,4 +1,4 @@ -use crate::{Sample, Source}; +use crate::{ChannelCount, Sample, Source}; use hound::{SampleFormat, WavSpec}; use std::path; @@ -10,7 +10,7 @@ pub fn output_to_wav( wav_file: impl AsRef, ) -> Result<(), Box> { let format = WavSpec { - channels: source.channels() as u16, + channels: source.channels() as ChannelCount, sample_rate: source.sample_rate(), bits_per_sample: 32, sample_format: SampleFormat::Float, From 9af97ba4b4b0b892d29abb1a425ecc846d91501e Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 26 Dec 2024 00:53:58 +0400 Subject: [PATCH 04/11] BUild fix, make clippy happy --- examples/basic.rs | 2 -- examples/noise_generator.rs | 2 +- src/source/noise.rs | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/basic.rs b/examples/basic.rs index fa3ef3ea..ce8b298b 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -4,8 +4,6 @@ use std::error::Error; use std::io::BufReader; use std::thread; use std::time::Duration; -#[cfg(feature = "tracing")] -use tracing; fn main() -> Result<(), Box> { let stream_handle = rodio::OutputStreamBuilder::open_default_stream()?; diff --git a/examples/noise_generator.rs b/examples/noise_generator.rs index 23a86b90..5abb5eb4 100644 --- a/examples/noise_generator.rs +++ b/examples/noise_generator.rs @@ -14,7 +14,7 @@ fn main() -> Result<(), Box> { let interval_duration = Duration::from_millis(1500); stream_handle.mixer().add( - white(cpal::SampleRate(48000)) + white(48000) .amplify(0.1) .take_duration(noise_duration), ); diff --git a/src/source/noise.rs b/src/source/noise.rs index 16db4ff2..dc517385 100644 --- a/src/source/noise.rs +++ b/src/source/noise.rs @@ -2,7 +2,7 @@ //! //! -use crate::Source; +use crate::{ChannelCount, Source}; use super::SeekError; @@ -71,7 +71,7 @@ impl Source for WhiteNoise { #[inline] fn sample_rate(&self) -> SampleRate { - self.sample_rate.0 + self.sample_rate } #[inline] From 5bf9dc39fca9f56fec141177a34f74787d4ace19 Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 26 Dec 2024 15:33:53 +0400 Subject: [PATCH 05/11] cargo fmt --- examples/noise_generator.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/noise_generator.rs b/examples/noise_generator.rs index 5abb5eb4..f22d3712 100644 --- a/examples/noise_generator.rs +++ b/examples/noise_generator.rs @@ -13,11 +13,9 @@ fn main() -> Result<(), Box> { let noise_duration = Duration::from_millis(1000); let interval_duration = Duration::from_millis(1500); - stream_handle.mixer().add( - white(48000) - .amplify(0.1) - .take_duration(noise_duration), - ); + stream_handle + .mixer() + .add(white(48000).amplify(0.1).take_duration(noise_duration)); println!("Playing white noise"); thread::sleep(interval_duration); From a9e4122552b595cf6ff5ec1c9ed04424587cd73d Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 26 Dec 2024 16:42:48 +0400 Subject: [PATCH 06/11] Use sample conversions from dasp_sample Previously used the same types re-exported by cpal. --- Cargo.toml | 1 + benches/conversions.rs | 2 +- src/conversions/sample.rs | 6 +++--- src/sink.rs | 2 +- src/source/crossfade.rs | 2 +- src/source/mod.rs | 2 +- src/source/uniform.rs | 2 +- src/spatial_sink.rs | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 81b39df8..54e9b100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" [dependencies] cpal = { version = "0.15.3", optional = true } +dasp_sample = "0.11.0" claxon = { version = "0.4.2", optional = true } hound = { version = "3.3.1", optional = true } lewton = { version = "0.10", optional = true } diff --git a/benches/conversions.rs b/benches/conversions.rs index b5c89d19..9bebb974 100644 --- a/benches/conversions.rs +++ b/benches/conversions.rs @@ -1,4 +1,4 @@ -use cpal::FromSample; +use dasp_sample::FromSample; use divan::Bencher; use rodio::Source; diff --git a/src/conversions/sample.rs b/src/conversions/sample.rs index 5ab68005..f1534285 100644 --- a/src/conversions/sample.rs +++ b/src/conversions/sample.rs @@ -1,4 +1,4 @@ -use cpal::{FromSample, Sample as CpalSample}; +use dasp_sample::{FromSample, Sample as DaspSample}; use std::marker::PhantomData; /// Converts the samples data type to `O`. @@ -41,7 +41,7 @@ where #[inline] fn next(&mut self) -> Option { - self.input.next().map(|s| CpalSample::from_sample(s)) + self.input.next().map(|s| DaspSample::from_sample(s)) } #[inline] @@ -71,7 +71,7 @@ where /// /// You can implement this trait on your own type as well if you wish so. /// -pub trait Sample: CpalSample { +pub trait Sample: DaspSample { /// Linear interpolation between two samples. /// /// The result should be equivalent to diff --git a/src/sink.rs b/src/sink.rs index 8dd5175c..bd190d88 100644 --- a/src/sink.rs +++ b/src/sink.rs @@ -2,9 +2,9 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; -use cpal::FromSample; #[cfg(feature = "crossbeam-channel")] use crossbeam_channel::{Receiver, Sender}; +use dasp_sample::FromSample; #[cfg(not(feature = "crossbeam-channel"))] use std::sync::mpsc::{Receiver, Sender}; diff --git a/src/source/crossfade.rs b/src/source/crossfade.rs index 03c21178..c7a82343 100644 --- a/src/source/crossfade.rs +++ b/src/source/crossfade.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use cpal::FromSample; +use dasp_sample::FromSample; use crate::source::{FadeIn, Mix, TakeDuration}; use crate::{Sample, Source}; diff --git a/src/source/mod.rs b/src/source/mod.rs index 3211301e..605057e8 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -5,7 +5,7 @@ use core::time::Duration; use crate::common::{ChannelCount, SampleRate}; use crate::Sample; -use cpal::FromSample; +use dasp_sample::FromSample; pub use self::agc::AutomaticGainControl; pub use self::amplify::Amplify; diff --git a/src/source/uniform.rs b/src/source/uniform.rs index 30472ed9..793dfae4 100644 --- a/src/source/uniform.rs +++ b/src/source/uniform.rs @@ -1,7 +1,7 @@ use std::cmp; use std::time::Duration; -use cpal::FromSample; +use dasp_sample::FromSample; use super::SeekError; use crate::common::{ChannelCount, SampleRate}; diff --git a/src/spatial_sink.rs b/src/spatial_sink.rs index 6a4a0c95..d85b3a94 100644 --- a/src/spatial_sink.rs +++ b/src/spatial_sink.rs @@ -2,7 +2,7 @@ use std::f32; use std::sync::{Arc, Mutex}; use std::time::Duration; -use cpal::FromSample; +use dasp_sample::FromSample; use crate::mixer::Mixer; use crate::source::{SeekError, Spatial}; From 3eece54f6e30ae34707e606ec96b57d4c7f23a9a Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 26 Dec 2024 20:59:16 +0400 Subject: [PATCH 07/11] Use dasp_sample, minimal build example, fix conditional compilation --- .github/workflows/ci.yml | 3 +++ Cargo.toml | 5 +++++ README.md | 13 ++++++++++++- benches/shared.rs | 2 +- examples/into_file.rs | 17 +++++++++++++++++ src/conversions/channels.rs | 2 +- src/conversions/sample_rate.rs | 1 - src/lib.rs | 6 ++++-- src/source/mix.rs | 6 +++--- src/source/samples_converter.rs | 4 ++-- src/{file_output.rs => wav_output.rs} | 0 tests/flac_test.rs | 4 +++- tests/seek.rs | 6 ++---- tests/wav_test.rs | 5 +++-- 14 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 examples/into_file.rs rename src/{file_output.rs => wav_output.rs} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4fed37b7..aed0fc7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,9 @@ jobs: # `cargo test` does not check benchmarks and `cargo test --all-targets` excludes # documentation tests. Therefore, we need an additional docs test command here. - run: cargo test --doc + # Check minimal build. `tests/seek.rs` fails if there are no decoders at all, + # adding one to make the tests check pass. + - run: cargo check --tests --lib --no-default-features --features mp3 cargo-publish: if: github.event_name == 'push' && github.ref == 'refs/heads/master' env: diff --git a/Cargo.toml b/Cargo.toml index 54e9b100..3c4906fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ num-rational = "0.4.2" default = ["flac", "vorbis", "wav", "mp3", "cpal"] tracing = ["dep:tracing"] experimental = ["dep:atomic_float"] +cpal = ["dep:cpal"] flac = ["claxon"] vorbis = ["lewton"] @@ -75,3 +76,7 @@ required-features = ["symphonia-isomp4", "symphonia-aac"] [[example]] name = "noise_generator" required-features = ["noise"] + +[[example]] +name = "into_file" +required-features = ["wav", "mp3"] diff --git a/README.md b/README.md index 81c17a56..6f670b14 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,18 @@ See [the docs](https://docs.rs/rodio/latest/rodio/#alternative-decoder-backends) ## Dependencies(Linux only) -Rodio uses `cpal` to send audio to the OS for playback. On Linux `cpal` needs the ALSA development files. These are provided as part of the libasound2-dev package on Debian and Ubuntu distributions and alsa-lib-devel on Fedora. +Rodio uses `cpal` to send audio to the OS for playback. On Linux `cpal` needs the ALSA development files. These are provided as part of the `libasound2-dev` package on Debian and Ubuntu distributions and `alsa-lib-devel` on Fedora. + +### Minimal build + +It is possible to build `rodio` without support for audio output. In this mode `cpal` dependency and its requirements are excluded. This configuration may be useful, for example, only for decoding and processing audio, or in situations when the audio output is not available (e.g. in case of Linux, when ALSA is not installed). See `into_file` example that works with this build. + +To use `rodio` in this configuration disable default features and add the necessary ones. In this case the `Cargo.toml` dependency would look like: +```toml +[dependencies] +rodio = { version = "0.20.1", default-features = false, features = ["symphonia-all"] } +``` + # Contributing diff --git a/benches/shared.rs b/benches/shared.rs index d800dc4d..8cab969d 100644 --- a/benches/shared.rs +++ b/benches/shared.rs @@ -70,7 +70,7 @@ impl TestSource { total_duration, } = self; let samples = samples - .map(|s| cpal::Sample::from_sample(s)) + .map(|s| dasp_sample::Sample::from_sample(s)) .collect::>() .into_iter(); TestSource { diff --git a/examples/into_file.rs b/examples/into_file.rs new file mode 100644 index 00000000..5dbba4df --- /dev/null +++ b/examples/into_file.rs @@ -0,0 +1,17 @@ +use rodio::output_to_wav; +use std::error::Error; +use std::io::BufReader; + +/// Converts mp3 file to a wav file. +/// This example does not use any audio devices +/// and can be used in build configurations without `cpal` feature enabled. +fn main() -> Result<(), Box> { + let file = std::fs::File::open("assets/music.mp3")?; + let mut audio = rodio::Decoder::new(BufReader::new(file))?; + + let wav_path = "music_mp3_converted.wav"; + println!("Storing converted audio into {}", wav_path); + output_to_wav(&mut audio, wav_path)?; + + Ok(()) +} diff --git a/src/conversions/channels.rs b/src/conversions/channels.rs index ac8980b9..8bdd85cb 100644 --- a/src/conversions/channels.rs +++ b/src/conversions/channels.rs @@ -1,5 +1,5 @@ use crate::common::ChannelCount; -use cpal::Sample; +use dasp_sample::Sample; /// Iterator that converts from a certain channel count to another. #[derive(Clone, Debug)] diff --git a/src/conversions/sample_rate.rs b/src/conversions/sample_rate.rs index 3f95dff0..ab85d407 100644 --- a/src/conversions/sample_rate.rs +++ b/src/conversions/sample_rate.rs @@ -348,7 +348,6 @@ mod test { use crate::source::{SineWave, Source}; - let to = to; let source = SineWave::new(freq).take_duration(d); let from = source.sample_rate(); diff --git a/src/lib.rs b/src/lib.rs index 0450eb95..199361d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,10 +162,11 @@ mod sink; mod spatial_sink; #[cfg(feature = "cpal")] mod stream; +#[cfg(feature = "wav")] +mod wav_output; pub mod buffer; pub mod decoder; -mod file_output; pub mod mixer; pub mod queue; pub mod source; @@ -174,9 +175,10 @@ pub mod static_buffer; pub use crate::common::{ChannelCount, SampleRate}; pub use crate::conversions::Sample; pub use crate::decoder::Decoder; -pub use crate::file_output::output_to_wav; pub use crate::sink::Sink; pub use crate::source::Source; pub use crate::spatial_sink::SpatialSink; #[cfg(feature = "cpal")] pub use crate::stream::{play, OutputStream, OutputStreamBuilder, PlayError, StreamError}; +#[cfg(feature = "wav")] +pub use crate::wav_output::output_to_wav; diff --git a/src/source/mix.rs b/src/source/mix.rs index 9c573811..5ae4b2ae 100644 --- a/src/source/mix.rs +++ b/src/source/mix.rs @@ -5,7 +5,7 @@ use crate::common::{ChannelCount, SampleRate}; use crate::source::uniform::UniformSourceIterator; use crate::source::SeekError; use crate::{Sample, Source}; -use cpal::{FromSample, Sample as CpalSample}; +use dasp_sample::{FromSample, Sample as DaspSample}; /// Internal function that builds a `Mix` object. pub fn mix(input1: I1, input2: I2) -> Mix @@ -52,9 +52,9 @@ where let s2 = self.input2.next(); match (s1, s2) { - (Some(s1), Some(s2)) => Some(s1.saturating_add(CpalSample::from_sample(s2))), + (Some(s1), Some(s2)) => Some(s1.saturating_add(DaspSample::from_sample(s2))), (Some(s1), None) => Some(s1), - (None, Some(s2)) => Some(CpalSample::from_sample(s2)), + (None, Some(s2)) => Some(DaspSample::from_sample(s2)), (None, None) => None, } } diff --git a/src/source/samples_converter.rs b/src/source/samples_converter.rs index 173d262b..67452fd2 100644 --- a/src/source/samples_converter.rs +++ b/src/source/samples_converter.rs @@ -4,7 +4,7 @@ use std::time::Duration; use super::SeekError; use crate::common::{ChannelCount, SampleRate}; use crate::{Sample, Source}; -use cpal::{FromSample, Sample as CpalSample}; +use dasp_sample::{FromSample, Sample as DaspSample}; /// Wrap the input and lazily converts the samples it provides to the type /// specified by the generic parameter D @@ -54,7 +54,7 @@ where #[inline] fn next(&mut self) -> Option { - self.inner.next().map(|s| CpalSample::from_sample(s)) + self.inner.next().map(|s| DaspSample::from_sample(s)) } #[inline] diff --git a/src/file_output.rs b/src/wav_output.rs similarity index 100% rename from src/file_output.rs rename to src/wav_output.rs diff --git a/tests/flac_test.rs b/tests/flac_test.rs index db920ba7..3f0e7169 100644 --- a/tests/flac_test.rs +++ b/tests/flac_test.rs @@ -1,11 +1,13 @@ #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))] use rodio::Source; -use std::io::BufReader; #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))] use std::time::Duration; +#[cfg(any(feature = "flac", feature = "symphonia-flac"))] #[test] fn test_flac_encodings() { + use std::io::BufReader; + // 16 bit FLAC file exported from Audacity (2 channels, compression level 5) let file = std::fs::File::open("assets/audacity16bit_level5.flac").unwrap(); let mut decoder = rodio::Decoder::new(BufReader::new(file)).unwrap(); diff --git a/tests/seek.rs b/tests/seek.rs index 0cc47c97..ff401219 100644 --- a/tests/seek.rs +++ b/tests/seek.rs @@ -233,14 +233,12 @@ fn time_remaining(decoder: Decoder) -> Duration { fn get_music(format: &str) -> Decoder { let asset = Path::new("assets/music").with_extension(format); let file = std::fs::File::open(asset).unwrap(); - let decoder = rodio::Decoder::new(BufReader::new(file)).unwrap(); - decoder + rodio::Decoder::new(BufReader::new(file)).unwrap() } fn get_rl(format: &str) -> Decoder { let asset = Path::new("assets/RL").with_extension(format); println!("opening: {}", asset.display()); let file = std::fs::File::open(asset).unwrap(); - let decoder = rodio::Decoder::new(BufReader::new(file)).unwrap(); - decoder + rodio::Decoder::new(BufReader::new(file)).unwrap() } diff --git a/tests/wav_test.rs b/tests/wav_test.rs index 76dc1d41..bcb34804 100644 --- a/tests/wav_test.rs +++ b/tests/wav_test.rs @@ -1,7 +1,8 @@ -use std::io::BufReader; - +#[cfg(feature = "wav")] #[test] fn test_wav_encodings() { + use std::io::BufReader; + // 16 bit wav file exported from Audacity (1 channel) let file = std::fs::File::open("assets/audacity16bit.wav").unwrap(); let mut decoder = rodio::Decoder::new(BufReader::new(file)).unwrap(); From 1cbfce2578158580cbb78f04a365403affaf587a Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Thu, 26 Dec 2024 21:04:33 +0400 Subject: [PATCH 08/11] Clarify minimal build in readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f670b14..cf32e74a 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ Rodio uses `cpal` to send audio to the OS for playback. On Linux `cpal` needs th ### Minimal build -It is possible to build `rodio` without support for audio output. In this mode `cpal` dependency and its requirements are excluded. This configuration may be useful, for example, only for decoding and processing audio, or in situations when the audio output is not available (e.g. in case of Linux, when ALSA is not installed). See `into_file` example that works with this build. +It is possible to build `rodio` without support for audio output. In this configuration `cpal` dependency and its requirements are excluded. This configuration may be useful, for example, for decoding and processing audio in environments when the audio output is not available (e.g. in case of Linux, when ALSA is not available). See `into_file` example that works with this build. -To use `rodio` in this configuration disable default features and add the necessary ones. In this case the `Cargo.toml` dependency would look like: +In order to use `rodio` in this configuration disable default features and add the necessary ones. In this case the `Cargo.toml` dependency would look like: ```toml [dependencies] rodio = { version = "0.20.1", default-features = false, features = ["symphonia-all"] } From 5fbb12c212e705ed84422f7bde21673ad5c97499 Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Fri, 27 Dec 2024 17:04:47 +0400 Subject: [PATCH 09/11] Update changelog --- CHANGELOG.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f73fcde9..7a23a6f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,21 +2,25 @@ All notable changes to this project will be documented in this file. +Migration guides for incompatible versions can be found in `UPGRADE.md` file. + The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added -- Adds a function to write a `Source` to a `wav` file, see `output_to_wav` +- Adds a function to write a `Source` to a `wav` file, see `output_to_wav`. - Output audio stream buffer size can now be adjusted. -- Sources for directly generating square waves, triangle waves, square waves and +- Sources for directly generating square waves, triangle waves, square waves, and sawtooths have been added. - An interface for defining `SignalGenerator` patterns with an `fn`, see `GeneratorFunction`. +- Minimal builds without `cpal` audio output are now supported. + See `README.md` for instructions. (#349) ### Changed -- Breaking: `OutputStreamBuilder` should now be used to initialize audio output stream. +- Breaking: `OutputStreamBuilder` should now be used to initialize an audio output stream. - Breaking: `OutputStreamHandle` removed, use `OutputStream` and `OutputStream::mixer()` instead. - Breaking: `DynamicMixerController` renamed to `Mixer`, `DynamicMixer` renamed to `MixerSource`. - Breaking: `Sink::try_new` renamed to `connect_new` and does not return error anymore. @@ -25,10 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The term 'frame' was renamed to 'span' in the crate and documentation. ### Fixed - - Symphonia decoder `total_duration` incorrect value caused by conversion from `Time` to `Duration`. - An issue with `SignalGenerator` that caused it to create increasingly distorted waveforms - over long run times has been corrected. + over long run times has been corrected. (#201) # Version 0.20.1 (2024-11-08) From 40fa1a680a76e8d6290839876afbf280b8b187a1 Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Sun, 29 Dec 2024 22:23:04 +0400 Subject: [PATCH 10/11] Show more features in into_file example --- examples/into_file.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/into_file.rs b/examples/into_file.rs index 5dbba4df..193932b2 100644 --- a/examples/into_file.rs +++ b/examples/into_file.rs @@ -1,4 +1,4 @@ -use rodio::output_to_wav; +use rodio::{output_to_wav, Source}; use std::error::Error; use std::io::BufReader; @@ -7,7 +7,9 @@ use std::io::BufReader; /// and can be used in build configurations without `cpal` feature enabled. fn main() -> Result<(), Box> { let file = std::fs::File::open("assets/music.mp3")?; - let mut audio = rodio::Decoder::new(BufReader::new(file))?; + let mut audio = rodio::Decoder::new(BufReader::new(file))? + .automatic_gain_control(1.0, 4.0, 0.005, 3.0) + .speed(0.8); let wav_path = "music_mp3_converted.wav"; println!("Storing converted audio into {}", wav_path); From c30421e456fd221fcfbddf78d79b3deea1e995fc Mon Sep 17 00:00:00 2001 From: Petr Gladkikh Date: Sun, 29 Dec 2024 22:51:00 +0400 Subject: [PATCH 11/11] Rename `cpal` feature to `playback` --- Cargo.toml | 4 ++-- README.md | 6 +++--- src/lib.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3c4906fb..296ea901 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,10 +26,10 @@ atomic_float = { version = "1.1.0", optional = true } num-rational = "0.4.2" [features] -default = ["flac", "vorbis", "wav", "mp3", "cpal"] +default = ["playback", "flac", "vorbis", "wav", "mp3"] tracing = ["dep:tracing"] experimental = ["dep:atomic_float"] -cpal = ["dep:cpal"] +playback = ["dep:cpal"] flac = ["claxon"] vorbis = ["lewton"] diff --git a/README.md b/README.md index cf32e74a..c2e5c914 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ See [the docs](https://docs.rs/rodio/latest/rodio/#alternative-decoder-backends) [The documentation](http://docs.rs/rodio) contains an introduction to the library. -## Dependencies(Linux only) +## Dependencies (Linux only) -Rodio uses `cpal` to send audio to the OS for playback. On Linux `cpal` needs the ALSA development files. These are provided as part of the `libasound2-dev` package on Debian and Ubuntu distributions and `alsa-lib-devel` on Fedora. +Rodio uses `cpal` library to send audio to the OS for playback. ALSA development files are needed to build `cpal` on Linux. These are provided as part of the `libasound2-dev` package on Debian and Ubuntu distributions and `alsa-lib-devel` on Fedora. ### Minimal build -It is possible to build `rodio` without support for audio output. In this configuration `cpal` dependency and its requirements are excluded. This configuration may be useful, for example, for decoding and processing audio in environments when the audio output is not available (e.g. in case of Linux, when ALSA is not available). See `into_file` example that works with this build. +It is possible to build `rodio` without support for audio playback. In this configuration `cpal` dependency and its requirements are excluded. This configuration may be useful, for example, for decoding and processing audio in environments when the audio output is not available (e.g. in case of Linux, when ALSA is not available). See `into_file` example that works with this build. In order to use `rodio` in this configuration disable default features and add the necessary ones. In this case the `Cargo.toml` dependency would look like: ```toml diff --git a/src/lib.rs b/src/lib.rs index 199361d1..4d17d3b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,7 +150,7 @@ //! down your program). #![cfg_attr(test, deny(missing_docs))] -#[cfg(feature = "cpal")] +#[cfg(feature = "playback")] pub use cpal::{ self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices, SupportedStreamConfig, @@ -160,7 +160,7 @@ mod common; mod conversions; mod sink; mod spatial_sink; -#[cfg(feature = "cpal")] +#[cfg(feature = "playback")] mod stream; #[cfg(feature = "wav")] mod wav_output; @@ -178,7 +178,7 @@ pub use crate::decoder::Decoder; pub use crate::sink::Sink; pub use crate::source::Source; pub use crate::spatial_sink::SpatialSink; -#[cfg(feature = "cpal")] +#[cfg(feature = "playback")] pub use crate::stream::{play, OutputStream, OutputStreamBuilder, PlayError, StreamError}; #[cfg(feature = "wav")] pub use crate::wav_output::output_to_wav;