diff --git a/CHANGELOG.md b/CHANGELOG.md index a5f7bea09..b20065d43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Add `Display` and `FromStr` implementations for `HostId`. - Add support for custom `Host`s, `Device`s, and `Stream`s. - Add `Sample::bits_per_sample` method. +- Change `SampleRate` from struct to `u32` type alias. - Update `audio_thread_priority` to 0.34. - AAudio: Configure buffer to ensure consistent callback buffer sizes. - AAudio: Make `Stream` implement `Send` and `Sync`. @@ -17,7 +18,7 @@ - ALSA: Fix format selection to probe hardware endianness instead of assuming native byte order. - ALSA: Add support for 12, 24, 352.8, 384, 705.6, and 768 kHz sample rates. - ALSA: Update `alsa` to 0.10. -- ALSA(process_output): Pass `silent=true` to `PCM.try_recover`, so it doesn't write to stderr. +- ALSA: Pass `silent=true` to `PCM.try_recover`, so it doesn't write to stderr. - ASIO: Fix linker flags for MinGW cross-compilation. - ASIO: Add packed(4) to representation of ASIO time structs in bindings. - CI: Added native ARM64 Linux support in GitHub Actions. diff --git a/asio-sys/src/bindings/mod.rs b/asio-sys/src/bindings/mod.rs index d92884b43..8ecf63fb7 100644 --- a/asio-sys/src/bindings/mod.rs +++ b/asio-sys/src/bindings/mod.rs @@ -231,7 +231,7 @@ pub enum AsioMessageSelectors { kAsioSupportsTimeInfo, // if host returns true here, it will expect the // callback bufferSwitchTimeInfo to be called instead // of bufferSwitch - kAsioSupportsTimeCode, // + kAsioSupportsTimeCode, // kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this kAsioSupportsInputGain, // unused and undefined @@ -786,7 +786,7 @@ impl DriverState { } impl DriverInner { - fn lock_state(&self) -> MutexGuard { + fn lock_state(&self) -> MutexGuard<'_, DriverState> { self.state.lock().expect("failed to lock `DriverState`") } @@ -890,14 +890,14 @@ fn stream_data_type(is_input: bool) -> Result { /// ASIO uses null terminated c strings for driver names. /// /// This converts to utf8. -fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow { +fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<'_, str> { unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() } } /// ASIO uses null terminated c strings for channel names. /// /// This converts to utf8. -fn _channel_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow { +fn _channel_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<'_, str> { unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() } } diff --git a/asio-sys/src/lib.rs b/asio-sys/src/lib.rs index 204d92d3c..fee5d56bb 100644 --- a/asio-sys/src/lib.rs +++ b/asio-sys/src/lib.rs @@ -4,9 +4,6 @@ extern crate num_derive; extern crate num_traits; -#[cfg(asio)] pub mod bindings; -#[cfg(asio)] pub use bindings::errors::{AsioError, LoadDriverError}; -#[cfg(asio)] pub use bindings::*; diff --git a/examples/android/src/lib.rs b/examples/android/src/lib.rs index beb46acb1..fef071a43 100644 --- a/examples/android/src/lib.rs +++ b/examples/android/src/lib.rs @@ -42,7 +42,7 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh where T: SizedSample + FromSample, { - let sample_rate = config.sample_rate.0 as f32; + let sample_rate = config.sample_rate as f32; let channels = config.channels as usize; // Produce a sinusoid of maximum amplitude. diff --git a/examples/audioworklet-beep/src/lib.rs b/examples/audioworklet-beep/src/lib.rs index 88cf4dcd3..7fab78c37 100644 --- a/examples/audioworklet-beep/src/lib.rs +++ b/examples/audioworklet-beep/src/lib.rs @@ -68,7 +68,7 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Stream where T: cpal::Sample + cpal::SizedSample + cpal::FromSample, { - let sample_rate = config.sample_rate.0 as f32; + let sample_rate = config.sample_rate as f32; let channels = config.channels as usize; // Produce a sinusoid of maximum amplitude. diff --git a/examples/beep.rs b/examples/beep.rs index e9d74d0c5..50649d57c 100644 --- a/examples/beep.rs +++ b/examples/beep.rs @@ -98,7 +98,7 @@ pub fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), where T: SizedSample + FromSample, { - let sample_rate = config.sample_rate.0 as f32; + let sample_rate = config.sample_rate as f32; let channels = config.channels as usize; // Produce a sinusoid of maximum amplitude. diff --git a/examples/custom.rs b/examples/custom.rs index e0ef98747..639bc6943 100644 --- a/examples/custom.rs +++ b/examples/custom.rs @@ -78,8 +78,8 @@ impl DeviceTrait for MyDevice { ) -> Result { Ok(std::iter::once(cpal::SupportedStreamConfigRange::new( 2, - cpal::SampleRate(44100), - cpal::SampleRate(44100), + 44100, + 44100, cpal::SupportedBufferSize::Unknown, cpal::SampleFormat::F32, ))) @@ -96,7 +96,7 @@ impl DeviceTrait for MyDevice { ) -> Result { Ok(cpal::SupportedStreamConfig::new( 2, - cpal::SampleRate(44100), + 44100, cpal::SupportedBufferSize::Unknown, cpal::SampleFormat::I16, )) @@ -302,7 +302,7 @@ pub fn make_stream( let num_channels = config.channels as usize; let mut oscillator = Oscillator { waveform: Waveform::Sine, - sample_rate: config.sample_rate.0 as f32, + sample_rate: config.sample_rate as f32, current_sample_index: 0.0, frequency_hz: 440.0, }; diff --git a/examples/feedback.rs b/examples/feedback.rs index 76a0eaf14..8eff0413d 100644 --- a/examples/feedback.rs +++ b/examples/feedback.rs @@ -104,7 +104,7 @@ fn main() -> anyhow::Result<()> { let config: cpal::StreamConfig = input_device.default_input_config()?.into(); // Create a delay in case the input and output devices aren't synced. - let latency_frames = (opt.latency / 1_000.0) * config.sample_rate.0 as f32; + let latency_frames = (opt.latency / 1_000.0) * config.sample_rate as f32; let latency_samples = latency_frames as usize * config.channels as usize; // The buffer to share samples diff --git a/examples/ios-feedback/src/feedback.rs b/examples/ios-feedback/src/feedback.rs index 844ce7067..a2b8b5049 100644 --- a/examples/ios-feedback/src/feedback.rs +++ b/examples/ios-feedback/src/feedback.rs @@ -11,7 +11,10 @@ extern crate cpal; extern crate ringbuf; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -use ringbuf::{HeapRb, traits::{Split, Producer, Consumer}}; +use ringbuf::{ + traits::{Consumer, Producer, Split}, + HeapRb, +}; const LATENCY_MS: f32 = 1000.0; @@ -32,7 +35,7 @@ pub fn run_example() -> Result<(), anyhow::Error> { let config: cpal::StreamConfig = input_device.default_input_config()?.into(); // Create a delay in case the input and output devices aren't synced. - let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate.0 as f32; + let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate as f32; let latency_samples = latency_frames as usize * config.channels as usize; // The buffer to share samples diff --git a/examples/record_wav.rs b/examples/record_wav.rs index 6de0f33c4..1fea0ee89 100644 --- a/examples/record_wav.rs +++ b/examples/record_wav.rs @@ -160,7 +160,7 @@ fn sample_format(format: cpal::SampleFormat) -> hound::SampleFormat { fn wav_spec_from_config(config: &cpal::SupportedStreamConfig) -> hound::WavSpec { hound::WavSpec { channels: config.channels() as _, - sample_rate: config.sample_rate().0 as _, + sample_rate: config.sample_rate() as _, bits_per_sample: (config.sample_format().sample_size() * 8) as _, sample_format: sample_format(config.sample_format()), } diff --git a/examples/synth_tones.rs b/examples/synth_tones.rs index bc0adaf65..4b477002c 100644 --- a/examples/synth_tones.rs +++ b/examples/synth_tones.rs @@ -139,7 +139,7 @@ where let num_channels = config.channels as usize; let mut oscillator = Oscillator { waveform: Waveform::Sine, - sample_rate: config.sample_rate.0 as f32, + sample_rate: config.sample_rate as f32, current_sample_index: 0.0, frequency_hz: 440.0, }; diff --git a/examples/wasm-beep/src/lib.rs b/examples/wasm-beep/src/lib.rs index ffcaa1993..c1128f165 100644 --- a/examples/wasm-beep/src/lib.rs +++ b/examples/wasm-beep/src/lib.rs @@ -66,7 +66,7 @@ fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Stream where T: cpal::Sample + cpal::SizedSample + cpal::FromSample, { - let sample_rate = config.sample_rate.0 as f32; + let sample_rate = config.sample_rate as f32; let channels = config.channels as usize; // Produce a sinusoid of maximum amplitude. diff --git a/src/host/aaudio/mod.rs b/src/host/aaudio/mod.rs index f035bac85..e36a4d851 100644 --- a/src/host/aaudio/mod.rs +++ b/src/host/aaudio/mod.rs @@ -15,8 +15,8 @@ use crate::{ DeviceDescription, DeviceDescriptionBuilder, DeviceDirection, DeviceId, DeviceIdError, DeviceNameError, DeviceType, DevicesError, InputCallbackInfo, InputStreamTimestamp, InterfaceType, OutputCallbackInfo, OutputStreamTimestamp, PauseStreamError, PlayStreamError, - SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSize, - SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError, + SampleFormat, StreamConfig, StreamError, SupportedBufferSize, SupportedStreamConfig, + SupportedStreamConfigRange, SupportedStreamConfigsError, }; mod convert; @@ -203,8 +203,8 @@ fn default_supported_configs() -> VecIntoIter { for sample_rate in &SAMPLE_RATES { output.push(SupportedStreamConfigRange { channels: *channel_count, - min_sample_rate: SampleRate(*sample_rate as u32), - max_sample_rate: SampleRate(*sample_rate as u32), + min_sample_rate: *sample_rate as u32, + max_sample_rate: *sample_rate as u32, buffer_size, sample_format: *sample_format, }); @@ -249,8 +249,8 @@ fn device_supported_configs(device: &AudioDeviceInfo) -> VecIntoIter i64 { // Convert the given duration in frames at the given sample rate to a `std::time::Duration`. #[inline] fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration { - let secsf = frames as f64 / rate.0 as f64; + let secsf = frames as f64 / rate as f64; let secs = secsf as u64; let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32; std::time::Duration::new(secs, nanos) @@ -1273,7 +1273,7 @@ fn init_hw_params<'a>( let alsa_format = sample_format_to_alsa_format(&hw_params, sample_format)?; hw_params.set_format(alsa_format)?; - hw_params.set_rate(config.sample_rate.0, alsa::ValueOr::Nearest)?; + hw_params.set_rate(config.sample_rate, alsa::ValueOr::Nearest)?; hw_params.set_channels(config.channels as u32)?; Ok(hw_params) } diff --git a/src/host/asio/device.rs b/src/host/asio/device.rs index 13dde8b0c..1d4ceb442 100644 --- a/src/host/asio/device.rs +++ b/src/host/asio/device.rs @@ -11,7 +11,6 @@ use crate::DeviceIdError; use crate::DeviceNameError; use crate::DevicesError; use crate::SampleFormat; -use crate::SampleRate; use crate::SupportedBufferSize; use crate::SupportedStreamConfig; use crate::SupportedStreamConfigRange; @@ -94,7 +93,7 @@ impl Device { for &rate in crate::COMMON_SAMPLE_RATES { if !self .driver - .can_sample_rate(rate.0.into()) + .can_sample_rate(rate.into()) .ok() .unwrap_or(false) { @@ -131,7 +130,7 @@ impl Device { for &rate in crate::COMMON_SAMPLE_RATES { if !self .driver - .can_sample_rate(rate.0.into()) + .can_sample_rate(rate.into()) .ok() .unwrap_or(false) { @@ -153,7 +152,7 @@ impl Device { /// Returns the default input config pub fn default_input_config(&self) -> Result { let channels = self.driver.channels().map_err(default_config_err)?.ins as u16; - let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_config_err)? as _); + let sample_rate = self.driver.sample_rate().map_err(default_config_err)? as u32; let (min, max) = self.driver.buffersize_range().map_err(default_config_err)?; let buffer_size = SupportedBufferSize::Range { min: min as u32, @@ -174,7 +173,7 @@ impl Device { /// Returns the default output config pub fn default_output_config(&self) -> Result { let channels = self.driver.channels().map_err(default_config_err)?.outs as u16; - let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_config_err)? as _); + let sample_rate = self.driver.sample_rate().map_err(default_config_err)? as u32; let (min, max) = self.driver.buffersize_range().map_err(default_config_err)?; let buffer_size = SupportedBufferSize::Range { min: min as u32, diff --git a/src/host/asio/stream.rs b/src/host/asio/stream.rs index 548f665f7..f76bf94c3 100644 --- a/src/host/asio/stream.rs +++ b/src/host/asio/stream.rs @@ -656,9 +656,10 @@ fn system_time_to_stream_instant( crate::StreamInstant::new(secs, nanos) } -/// Convert the given duration in frames at the given sample rate to a `std::time::Duration`. +// Convert the given duration in frames at the given sample rate to a `std::time::Duration`. +#[inline] fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration { - let secsf = frames as f64 / rate.0 as f64; + let secsf = frames as f64 / rate as f64; let secs = secsf as u64; let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32; std::time::Duration::new(secs, nanos) @@ -692,7 +693,7 @@ fn check_config( } // Try and set the sample rate to what the user selected. - let sample_rate = sample_rate.0.into(); + let sample_rate = (*sample_rate).into(); if sample_rate != driver.sample_rate().map_err(build_stream_err)? { if driver .can_sample_rate(sample_rate) diff --git a/src/host/audioworklet/mod.rs b/src/host/audioworklet/mod.rs index faf5acec5..535cb07ec 100644 --- a/src/host/audioworklet/mod.rs +++ b/src/host/audioworklet/mod.rs @@ -31,9 +31,9 @@ pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs}; const MIN_CHANNELS: ChannelCount = 1; const MAX_CHANNELS: ChannelCount = 32; -const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000); -const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000); -const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100); +const MIN_SAMPLE_RATE: SampleRate = 8_000; +const MAX_SAMPLE_RATE: SampleRate = 96_000; +const DEFAULT_SAMPLE_RATE: SampleRate = 44_100; const SUPPORTED_SAMPLE_FORMAT: SampleFormat = SampleFormat::F32; impl Host { @@ -191,7 +191,7 @@ impl DeviceTrait for Device { let config = config.clone(); let stream_opts = web_sys::AudioContextOptions::new(); - stream_opts.set_sample_rate(config.sample_rate.0 as f32); + stream_opts.set_sample_rate(config.sample_rate as f32); let audio_context = web_sys::AudioContext::new_with_context_options(&stream_opts).map_err( |err| -> BuildStreamError { @@ -237,8 +237,7 @@ impl DeviceTrait for Device { let callback = crate::StreamInstant::from_secs_f64(now); - let buffer_duration = - frames_to_duration(frame_size as _, SampleRate(sample_rate)); + let buffer_duration = frames_to_duration(frame_size as _, sample_rate); let playback = callback.add(buffer_duration).expect( "`playback` occurs beyond representation supported by `StreamInstant`", ); @@ -336,7 +335,7 @@ fn valid_config(conf: &StreamConfig, sample_format: SampleFormat) -> bool { // Convert the given duration in frames at the given sample rate to a `std::time::Duration`. fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration { - let secsf = frames as f64 / rate.0 as f64; + let secsf = frames as f64 / rate as f64; let secs = secsf as u64; let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32; std::time::Duration::new(secs, nanos) diff --git a/src/host/coreaudio/ios/mod.rs b/src/host/coreaudio/ios/mod.rs index cf29a70a7..f80b6742d 100644 --- a/src/host/coreaudio/ios/mod.rs +++ b/src/host/coreaudio/ios/mod.rs @@ -323,7 +323,7 @@ fn set_audio_session_buffer_size( let audio_session = unsafe { AVAudioSession::sharedInstance() }; // Calculate preferred buffer duration in seconds - let buffer_duration = buffer_size as f64 / sample_rate.0 as f64; + let buffer_duration = buffer_size as f64 / sample_rate as f64; // Set the preferred IO buffer duration // SAFETY: setPreferredIOBufferDuration_error is safe to call with valid duration @@ -377,8 +377,8 @@ fn get_supported_stream_configs(is_input: bool) -> std::vec::IntoIter = (min_channels..=max_channels) .map(|channels| SupportedStreamConfigRange { channels, - min_sample_rate: SampleRate(sample_rate), - max_sample_rate: SampleRate(sample_rate), + min_sample_rate: sample_rate, + max_sample_rate: sample_rate, buffer_size, sample_format: SUPPORTED_SAMPLE_FORMAT, }) diff --git a/src/host/coreaudio/macos/device.rs b/src/host/coreaudio/macos/device.rs index aca999e48..444539e69 100644 --- a/src/host/coreaudio/macos/device.rs +++ b/src/host/coreaudio/macos/device.rs @@ -76,7 +76,7 @@ fn set_sample_rate( coreaudio::Error::from_os_status(status)?; // If the requested sample rate is different to the device sample rate, update the device. - if sample_rate as u32 != target_sample_rate.0 { + if sample_rate as u32 != target_sample_rate { // Get available sample rate ranges. property_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; let mut data_size = 0u32; @@ -108,7 +108,7 @@ fn set_sample_rate( let ranges: &[AudioValueRange] = unsafe { slice::from_raw_parts(ranges, n_ranges) }; // Now that we have the available ranges, pick the one matching the desired rate. - let sample_rate = target_sample_rate.0; + let sample_rate = target_sample_rate; let maybe_index = ranges .iter() .position(|r| r.mMinimum as u32 == sample_rate && r.mMaximum as u32 == sample_rate); @@ -185,7 +185,7 @@ fn set_sample_rate( return Err(BackendSpecificError { description }.into()); } Ok(Ok(reported_sample_rate)) => { - if reported_sample_rate == target_sample_rate.0 as f64 { + if reported_sample_rate == target_sample_rate as f64 { break; } } @@ -567,8 +567,8 @@ impl Device { } else if contains_different_sample_rates { let res = ranges.iter().map(|range| SupportedStreamConfigRange { channels: n_channels as ChannelCount, - min_sample_rate: SampleRate(range.mMinimum as u32), - max_sample_rate: SampleRate(range.mMaximum as u32), + min_sample_rate: range.mMinimum as u32, + max_sample_rate: range.mMaximum as u32, buffer_size, sample_format, }); @@ -576,20 +576,16 @@ impl Device { } else { let fmt = SupportedStreamConfigRange { channels: n_channels as ChannelCount, - min_sample_rate: SampleRate( - ranges - .iter() - .map(|v| v.mMinimum as u32) - .min() - .expect("the list must not be empty"), - ), - max_sample_rate: SampleRate( - ranges - .iter() - .map(|v| v.mMaximum as u32) - .max() - .expect("the list must not be empty"), - ), + min_sample_rate: ranges + .iter() + .map(|v| v.mMinimum as u32) + .min() + .expect("the list must not be empty"), + max_sample_rate: ranges + .iter() + .map(|v| v.mMaximum as u32) + .max() + .expect("the list must not be empty"), buffer_size, sample_format, }; @@ -693,7 +689,7 @@ impl Device { let buffer_size = get_io_buffer_frame_size_range(&audio_unit)?; let config = SupportedStreamConfig { - sample_rate: SampleRate(asbd.mSampleRate as _), + sample_rate: asbd.mSampleRate as _, channels: asbd.mChannelsPerFrame as _, buffer_size, sample_format, diff --git a/src/host/coreaudio/mod.rs b/src/host/coreaudio/mod.rs index 886e58a69..ebe08a210 100644 --- a/src/host/coreaudio/mod.rs +++ b/src/host/coreaudio/mod.rs @@ -41,7 +41,7 @@ fn asbd_from_config( sample_format: SampleFormat, ) -> AudioStreamBasicDescription { let n_channels = config.channels as usize; - let sample_rate = config.sample_rate.0; + let sample_rate = config.sample_rate; let bytes_per_channel = sample_format.sample_size(); let bits_per_channel = bytes_per_channel * 8; let bytes_per_frame = n_channels * bytes_per_channel; @@ -85,7 +85,7 @@ fn host_time_to_stream_instant( // Convert the given duration in frames at the given sample rate to a `std::time::Duration`. #[inline] fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration { - let secsf = frames as f64 / rate.0 as f64; + let secsf = frames as f64 / rate as f64; let secs = secsf as u64; let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32; std::time::Duration::new(secs, nanos) diff --git a/src/host/emscripten/mod.rs b/src/host/emscripten/mod.rs index 68a2a88fc..eff9ab44b 100644 --- a/src/host/emscripten/mod.rs +++ b/src/host/emscripten/mod.rs @@ -47,9 +47,9 @@ pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs}; const MIN_CHANNELS: u16 = 1; const MAX_CHANNELS: u16 = 32; -const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000); -const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000); -const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100); +const MIN_SAMPLE_RATE: SampleRate = 8_000; +const MAX_SAMPLE_RATE: SampleRate = 96_000; +const DEFAULT_SAMPLE_RATE: SampleRate = 44_100; const MIN_BUFFER_SIZE: u32 = 1; const MAX_BUFFER_SIZE: u32 = u32::MAX; const DEFAULT_BUFFER_SIZE: usize = 2048; @@ -281,7 +281,7 @@ where D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, { |stream, config, sample_format, buffer_size_frames| { - let sample_rate = config.sample_rate.0; + let sample_rate = config.sample_rate; let buffer_size_samples = buffer_size_frames * config.channels as u32; let audio_ctxt = &stream.audio_ctxt; diff --git a/src/host/jack/device.rs b/src/host/jack/device.rs index 99857e50b..433cfadc1 100644 --- a/src/host/jack/device.rs +++ b/src/host/jack/device.rs @@ -44,7 +44,7 @@ impl Device { Ok(client) => Ok(Device { // The name given to the client by JACK, could potentially be different from the name supplied e.g.if there is a name collision name: client.name().to_string(), - sample_rate: SampleRate(client.sample_rate() as u32), + sample_rate: client.sample_rate() as u32, buffer_size: SupportedBufferSize::Range { min: client.buffer_size(), max: client.buffer_size(), diff --git a/src/host/jack/stream.rs b/src/host/jack/stream.rs index c47232b7b..190a2258f 100644 --- a/src/host/jack/stream.rs +++ b/src/host/jack/stream.rs @@ -70,7 +70,7 @@ impl Stream { let input_process_handler = LocalProcessHandler::new( vec![], ports, - SampleRate(client.sample_rate() as u32), + client.sample_rate() as u32, client.buffer_size() as usize, Some(Box::new(data_callback)), None, @@ -135,7 +135,7 @@ impl Stream { let output_process_handler = LocalProcessHandler::new( ports, vec![], - SampleRate(client.sample_rate() as u32), + client.sample_rate() as u32, client.buffer_size() as usize, None, Some(Box::new(data_callback)), @@ -410,7 +410,7 @@ fn micros_to_stream_instant(micros: u64) -> crate::StreamInstant { // Convert the given duration in frames at the given sample rate to a `std::time::Duration`. fn frames_to_duration(frames: usize, rate: crate::SampleRate) -> std::time::Duration { - let secsf = frames as f64 / rate.0 as f64; + let secsf = frames as f64 / rate as f64; let secs = secsf as u64; let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32; std::time::Duration::new(secs, nanos) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index d8cdf0db7..c60eb7b96 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -251,7 +251,7 @@ unsafe fn format_from_waveformatex_ptr( _ => return None, }; - let sample_rate = SampleRate((*waveformatex_ptr).nSamplesPerSec); + let sample_rate = (*waveformatex_ptr).nSamplesPerSec; // GetBufferSizeLimits is only used for Hardware-Offloaded Audio // Processing, which was added in Windows 8, which places hardware @@ -278,8 +278,8 @@ unsafe fn format_from_waveformatex_ptr( .is_ok(); let buffer_size = if buffer_size_is_limited { SupportedBufferSize::Range { - min: buffer_duration_to_frames(min_buffer_duration, sample_rate.0), - max: buffer_duration_to_frames(max_buffer_duration, sample_rate.0), + min: buffer_duration_to_frames(min_buffer_duration, sample_rate), + max: buffer_duration_to_frames(max_buffer_duration, sample_rate), } } else { SupportedBufferSize::Range { @@ -694,8 +694,7 @@ impl Device { // Note: Buffer size validation is not needed here - `IAudioClient::Initialize` // will return `AUDCLNT_E_BUFFER_SIZE_ERROR` if the buffer size is not supported. - let buffer_duration = - buffer_size_to_duration(&config.buffer_size, config.sample_rate.0); + let buffer_duration = buffer_size_to_duration(&config.buffer_size, config.sample_rate); let mut stream_flags = Audio::AUDCLNT_STREAMFLAGS_EVENTCALLBACK; @@ -811,8 +810,7 @@ impl Device { // Note: Buffer size validation is not needed here - `IAudioClient::Initialize` // will return `AUDCLNT_E_BUFFER_SIZE_ERROR` if the buffer size is not supported. - let buffer_duration = - buffer_size_to_duration(&config.buffer_size, config.sample_rate.0); + let buffer_duration = buffer_size_to_duration(&config.buffer_size, config.sample_rate); // Computing the format and initializing the device. let waveformatex = { @@ -1156,7 +1154,7 @@ fn config_to_waveformatextensible( _ => return None, }; let channels = config.channels; - let sample_rate = config.sample_rate.0; + let sample_rate = config.sample_rate; let sample_bytes = sample_format.sample_size() as u16; let avg_bytes_per_sec = u32::from(channels) * sample_rate * u32::from(sample_bytes); let block_align = channels * sample_bytes; diff --git a/src/host/wasapi/stream.rs b/src/host/wasapi/stream.rs index 7aad1f4b1..6e681b9a7 100644 --- a/src/host/wasapi/stream.rs +++ b/src/host/wasapi/stream.rs @@ -357,7 +357,7 @@ fn boost_current_thread_priority(buffer_size: BufferSize, sample_rate: crate::Sa 0 }; - if let Err(err) = promote_current_thread_to_real_time(buffer_size, sample_rate.0) { + if let Err(err) = promote_current_thread_to_real_time(buffer_size, sample_rate) { eprintln!("Failed to promote audio thread to real-time priority: {err}"); } } @@ -532,7 +532,7 @@ fn process_output( /// Convert the given duration in frames at the given sample rate to a `std::time::Duration`. fn frames_to_duration(frames: u32, rate: crate::SampleRate) -> std::time::Duration { - let secsf = frames as f64 / rate.0 as f64; + let secsf = frames as f64 / rate as f64; let secs = secsf as u64; let nanos = ((secsf - secs as f64) * 1_000_000_000.0) as u32; std::time::Duration::new(secs, nanos) diff --git a/src/host/webaudio/mod.rs b/src/host/webaudio/mod.rs index d6a7f1eb3..eab19a7da 100644 --- a/src/host/webaudio/mod.rs +++ b/src/host/webaudio/mod.rs @@ -47,9 +47,9 @@ pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs}; const MIN_CHANNELS: u16 = 1; const MAX_CHANNELS: u16 = 32; -const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000); -const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000); -const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100); +const MIN_SAMPLE_RATE: SampleRate = 8_000; +const MAX_SAMPLE_RATE: SampleRate = 96_000; +const DEFAULT_SAMPLE_RATE: SampleRate = 44_100; const MIN_BUFFER_SIZE: u32 = 1; const MAX_BUFFER_SIZE: u32 = u32::MAX; const DEFAULT_BUFFER_SIZE: usize = 2048; @@ -231,7 +231,7 @@ impl DeviceTrait for Device { // Create the WebAudio stream. let stream_opts = AudioContextOptions::new(); - stream_opts.set_sample_rate(config.sample_rate.0 as f32); + stream_opts.set_sample_rate(config.sample_rate as f32); let ctx = AudioContext::new_with_context_options(&stream_opts).map_err( |err| -> BuildStreamError { let description = format!("{:?}", err); @@ -286,7 +286,7 @@ impl DeviceTrait for Device { .create_buffer( config.channels as u32, buffer_size_frames as u32, - config.sample_rate.0 as f32, + config.sample_rate as f32, ) .map_err(|err| -> BuildStreamError { let description = format!("{:?}", err); @@ -525,7 +525,7 @@ fn valid_config(conf: &StreamConfig, sample_format: SampleFormat) -> bool { } fn buffer_time_step_secs(buffer_size_frames: usize, sample_rate: SampleRate) -> f64 { - buffer_size_frames as f64 / sample_rate.0 as f64 + buffer_size_frames as f64 / sample_rate as f64 } #[cfg(target_feature = "atomics")] diff --git a/src/lib.rs b/src/lib.rs index 4c3339991..7ba2ab925 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,9 +171,8 @@ pub use platform::{ available_hosts, default_host, host_from_id, Device, Devices, Host, HostId, Stream, SupportedInputConfigs, SupportedOutputConfigs, ALL_HOSTS, }; -pub use samples_formats::{FromSample, Sample, SampleFormat, SizedSample, I24, I48, U24, U48}; +pub use samples_formats::{FromSample, Sample, SampleFormat, SizedSample, I24, U24}; use std::convert::TryInto; -use std::ops::{Div, Mul}; use std::time::Duration; #[cfg(target_os = "emscripten")] use wasm_bindgen::prelude::*; @@ -198,29 +197,7 @@ pub type OutputDevices = DevicesFiltered; pub type ChannelCount = u16; /// The number of samples processed per second for a single channel of audio. -#[cfg_attr(target_os = "emscripten", wasm_bindgen)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct SampleRate(pub u32); - -impl Mul for SampleRate -where - u32: Mul, -{ - type Output = Self; - fn mul(self, rhs: T) -> Self { - SampleRate(self.0 * rhs) - } -} - -impl Div for SampleRate -where - u32: Div, -{ - type Output = Self; - fn div(self, rhs: T) -> Self { - SampleRate(self.0 / rhs) - } -} +pub type SampleRate = u32; /// A frame represents one sample for each channel. For example, with stereo audio, /// one frame contains two samples (left and right channels). @@ -833,7 +810,7 @@ impl SupportedStreamConfigRange { return cmp_u16; } - const HZ_44100: SampleRate = SampleRate(44_100); + const HZ_44100: SampleRate = 44_100; let r44100_in_self = self.min_sample_rate <= HZ_44100 && HZ_44100 <= self.max_sample_rate; let r44100_in_other = other.min_sample_rate <= HZ_44100 && HZ_44100 <= other.max_sample_rate; @@ -852,36 +829,36 @@ fn test_cmp_default_heuristics() { SupportedStreamConfigRange { buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, channels: 2, - min_sample_rate: SampleRate(1), - max_sample_rate: SampleRate(96000), + min_sample_rate: 1, + max_sample_rate: 96000, sample_format: SampleFormat::F32, }, SupportedStreamConfigRange { buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, channels: 1, - min_sample_rate: SampleRate(1), - max_sample_rate: SampleRate(96000), + min_sample_rate: 1, + max_sample_rate: 96000, sample_format: SampleFormat::F32, }, SupportedStreamConfigRange { buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, channels: 2, - min_sample_rate: SampleRate(1), - max_sample_rate: SampleRate(96000), + min_sample_rate: 1, + max_sample_rate: 96000, sample_format: SampleFormat::I16, }, SupportedStreamConfigRange { buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, channels: 2, - min_sample_rate: SampleRate(1), - max_sample_rate: SampleRate(96000), + min_sample_rate: 1, + max_sample_rate: 96000, sample_format: SampleFormat::U16, }, SupportedStreamConfigRange { buffer_size: SupportedBufferSize::Range { min: 256, max: 512 }, channels: 2, - min_sample_rate: SampleRate(1), - max_sample_rate: SampleRate(22050), + min_sample_rate: 1, + max_sample_rate: 22050, sample_format: SampleFormat::F32, }, ]; @@ -890,28 +867,28 @@ fn test_cmp_default_heuristics() { // lowest-priority first: assert_eq!(formats[0].sample_format(), SampleFormat::F32); - assert_eq!(formats[0].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[0].max_sample_rate(), SampleRate(96000)); + assert_eq!(formats[0].min_sample_rate(), 1); + assert_eq!(formats[0].max_sample_rate(), 96000); assert_eq!(formats[0].channels(), 1); assert_eq!(formats[1].sample_format(), SampleFormat::U16); - assert_eq!(formats[1].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[1].max_sample_rate(), SampleRate(96000)); + assert_eq!(formats[1].min_sample_rate(), 1); + assert_eq!(formats[1].max_sample_rate(), 96000); assert_eq!(formats[1].channels(), 2); assert_eq!(formats[2].sample_format(), SampleFormat::I16); - assert_eq!(formats[2].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[2].max_sample_rate(), SampleRate(96000)); + assert_eq!(formats[2].min_sample_rate(), 1); + assert_eq!(formats[2].max_sample_rate(), 96000); assert_eq!(formats[2].channels(), 2); assert_eq!(formats[3].sample_format(), SampleFormat::F32); - assert_eq!(formats[3].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[3].max_sample_rate(), SampleRate(22050)); + assert_eq!(formats[3].min_sample_rate(), 1); + assert_eq!(formats[3].max_sample_rate(), 22050); assert_eq!(formats[3].channels(), 2); assert_eq!(formats[4].sample_format(), SampleFormat::F32); - assert_eq!(formats[4].min_sample_rate(), SampleRate(1)); - assert_eq!(formats[4].max_sample_rate(), SampleRate(96000)); + assert_eq!(formats[4].min_sample_rate(), 1); + assert_eq!(formats[4].max_sample_rate(), 96000); assert_eq!(formats[4].channels(), 2); } @@ -925,23 +902,8 @@ impl From for StreamConfig { // of commonly used rates. This is always the case for WASAPI and is sometimes the case for ALSA. #[allow(dead_code)] pub(crate) const COMMON_SAMPLE_RATES: &[SampleRate] = &[ - SampleRate(5512), - SampleRate(8000), - SampleRate(11025), - SampleRate(12000), - SampleRate(16000), - SampleRate(22050), - SampleRate(24000), - SampleRate(32000), - SampleRate(44100), - SampleRate(48000), - SampleRate(64000), - SampleRate(88200), - SampleRate(96000), - SampleRate(176400), - SampleRate(192000), - SampleRate(352800), - SampleRate(384000), + 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, + 176400, 192000, 352800, 384000, ]; #[test] diff --git a/src/samples_formats.rs b/src/samples_formats.rs index 355a48f9a..4b19120d5 100644 --- a/src/samples_formats.rs +++ b/src/samples_formats.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, mem}; #[cfg(target_os = "emscripten")] use wasm_bindgen::prelude::*; -pub use dasp_sample::{FromSample, Sample, I24, I48, U24, U48}; +pub use dasp_sample::{FromSample, Sample, I24, U24}; /// Format that each sample has. Usually, this corresponds to the sampling /// depth of the audio source. For example, 16 bit quantized samples can be