Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

490
vendor/rodio/src/source/agc.rs vendored Normal file
View File

@@ -0,0 +1,490 @@
//
// Automatic Gain Control (AGC) Algorithm
// Designed by @UnknownSuperficialNight
//
// Features:
// • Adaptive peak detection
// • RMS-based level estimation
// • Asymmetric attack/release
// • RMS-based general adjustments with peak limiting
//
// Optimized for smooth and responsive gain control
//
// Crafted with love. Enjoy! :)
//
use super::SeekError;
use crate::{Sample, Source};
#[cfg(feature = "experimental")]
use atomic_float::AtomicF32;
#[cfg(feature = "experimental")]
use std::sync::atomic::{AtomicBool, Ordering};
#[cfg(feature = "experimental")]
use std::sync::Arc;
use std::time::Duration;
#[cfg(feature = "tracing")]
use tracing;
/// Ensures `RMS_WINDOW_SIZE` is a power of two
const fn power_of_two(n: usize) -> usize {
assert!(
n.is_power_of_two(),
"RMS_WINDOW_SIZE must be a power of two"
);
n
}
/// Size of the circular buffer used for RMS calculation.
/// A larger size provides more stable RMS values but increases latency.
const RMS_WINDOW_SIZE: usize = power_of_two(8192);
#[cfg(feature = "experimental")]
/// Automatic Gain Control filter for maintaining consistent output levels.
///
/// This struct implements an AGC algorithm that dynamically adjusts audio levels
/// based on both **peak** and **RMS** (Root Mean Square) measurements.
#[derive(Clone, Debug)]
pub struct AutomaticGainControl<I> {
input: I,
target_level: Arc<AtomicF32>,
absolute_max_gain: Arc<AtomicF32>,
current_gain: f32,
attack_coeff: Arc<AtomicF32>,
release_coeff: Arc<AtomicF32>,
min_attack_coeff: f32,
peak_level: f32,
rms_window: CircularBuffer,
is_enabled: Arc<AtomicBool>,
}
#[cfg(not(feature = "experimental"))]
/// Automatic Gain Control filter for maintaining consistent output levels.
///
/// This struct implements an AGC algorithm that dynamically adjusts audio levels
/// based on both **peak** and **RMS** (Root Mean Square) measurements.
#[derive(Clone, Debug)]
pub struct AutomaticGainControl<I> {
input: I,
target_level: f32,
absolute_max_gain: f32,
current_gain: f32,
attack_coeff: f32,
release_coeff: f32,
min_attack_coeff: f32,
peak_level: f32,
rms_window: CircularBuffer,
is_enabled: bool,
}
/// A circular buffer for efficient RMS calculation over a sliding window.
///
/// This structure allows for constant-time updates and mean calculations,
/// which is crucial for real-time audio processing.
#[derive(Clone, Debug)]
struct CircularBuffer {
buffer: Box<[f32; RMS_WINDOW_SIZE]>,
sum: f32,
index: usize,
}
impl CircularBuffer {
/// Creates a new `CircularBuffer` with a fixed size determined at compile time.
#[inline]
fn new() -> Self {
CircularBuffer {
buffer: Box::new([0.0; RMS_WINDOW_SIZE]),
sum: 0.0,
index: 0,
}
}
/// Pushes a new value into the buffer and returns the old value.
///
/// This method maintains a running sum for efficient mean calculation.
#[inline]
fn push(&mut self, value: f32) -> f32 {
let old_value = self.buffer[self.index];
// Update the sum by first subtracting the old value and then adding the new value; this is more accurate.
self.sum = self.sum - old_value + value;
self.buffer[self.index] = value;
// Use bitwise AND for efficient index wrapping since RMS_WINDOW_SIZE is a power of two.
self.index = (self.index + 1) & (RMS_WINDOW_SIZE - 1);
old_value
}
/// Calculates the mean of all values in the buffer.
///
/// This operation is `O(1)` due to the maintained running sum.
#[inline]
fn mean(&self) -> f32 {
self.sum / RMS_WINDOW_SIZE as f32
}
}
/// Constructs an `AutomaticGainControl` object with specified parameters.
///
/// # Arguments
///
/// * `input` - The input audio source
/// * `target_level` - The desired output level
/// * `attack_time` - Time constant for gain increase
/// * `release_time` - Time constant for gain decrease
/// * `absolute_max_gain` - Maximum allowable gain
#[inline]
pub(crate) fn automatic_gain_control<I>(
input: I,
target_level: f32,
attack_time: f32,
release_time: f32,
absolute_max_gain: f32,
) -> AutomaticGainControl<I>
where
I: Source,
I::Item: Sample,
{
let sample_rate = input.sample_rate();
let attack_coeff = (-1.0 / (attack_time * sample_rate as f32)).exp();
let release_coeff = (-1.0 / (release_time * sample_rate as f32)).exp();
#[cfg(feature = "experimental")]
{
AutomaticGainControl {
input,
target_level: Arc::new(AtomicF32::new(target_level)),
absolute_max_gain: Arc::new(AtomicF32::new(absolute_max_gain)),
current_gain: 1.0,
attack_coeff: Arc::new(AtomicF32::new(attack_coeff)),
release_coeff: Arc::new(AtomicF32::new(release_coeff)),
min_attack_coeff: release_time,
peak_level: 0.0,
rms_window: CircularBuffer::new(),
is_enabled: Arc::new(AtomicBool::new(true)),
}
}
#[cfg(not(feature = "experimental"))]
{
AutomaticGainControl {
input,
target_level,
absolute_max_gain,
current_gain: 1.0,
attack_coeff,
release_coeff,
min_attack_coeff: release_time,
peak_level: 0.0,
rms_window: CircularBuffer::new(),
is_enabled: true,
}
}
}
impl<I> AutomaticGainControl<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn target_level(&self) -> f32 {
#[cfg(feature = "experimental")]
{
self.target_level.load(Ordering::Relaxed)
}
#[cfg(not(feature = "experimental"))]
{
self.target_level
}
}
#[inline]
fn absolute_max_gain(&self) -> f32 {
#[cfg(feature = "experimental")]
{
self.absolute_max_gain.load(Ordering::Relaxed)
}
#[cfg(not(feature = "experimental"))]
{
self.absolute_max_gain
}
}
#[inline]
fn attack_coeff(&self) -> f32 {
#[cfg(feature = "experimental")]
{
self.attack_coeff.load(Ordering::Relaxed)
}
#[cfg(not(feature = "experimental"))]
{
self.attack_coeff
}
}
#[inline]
fn release_coeff(&self) -> f32 {
#[cfg(feature = "experimental")]
{
self.release_coeff.load(Ordering::Relaxed)
}
#[cfg(not(feature = "experimental"))]
{
self.release_coeff
}
}
#[inline]
fn is_enabled(&self) -> bool {
#[cfg(feature = "experimental")]
{
self.is_enabled.load(Ordering::Relaxed)
}
#[cfg(not(feature = "experimental"))]
{
self.is_enabled
}
}
#[cfg(feature = "experimental")]
/// Access the target output level for real-time adjustment.
///
/// Use this to dynamically modify the AGC's target level while audio is processing.
/// Adjust this value to control the overall output amplitude of the processed signal.
#[inline]
pub fn get_target_level(&self) -> Arc<AtomicF32> {
Arc::clone(&self.target_level)
}
#[cfg(feature = "experimental")]
/// Access the maximum gain limit for real-time adjustment.
///
/// Use this to dynamically modify the AGC's maximum allowable gain during runtime.
/// Adjusting this value helps prevent excessive amplification in low-level signals.
#[inline]
pub fn get_absolute_max_gain(&self) -> Arc<AtomicF32> {
Arc::clone(&self.absolute_max_gain)
}
#[cfg(feature = "experimental")]
/// Access the attack coefficient for real-time adjustment.
///
/// Use this to dynamically modify how quickly the AGC responds to level increases.
/// Smaller values result in faster response, larger values in slower response.
/// Adjust during runtime to fine-tune AGC behavior for different audio content.
#[inline]
pub fn get_attack_coeff(&self) -> Arc<AtomicF32> {
Arc::clone(&self.attack_coeff)
}
#[cfg(feature = "experimental")]
/// Access the release coefficient for real-time adjustment.
///
/// Use this to dynamically modify how quickly the AGC responds to level decreases.
/// Smaller values result in faster response, larger values in slower response.
/// Adjust during runtime to optimize AGC behavior for varying audio dynamics.
#[inline]
pub fn get_release_coeff(&self) -> Arc<AtomicF32> {
Arc::clone(&self.release_coeff)
}
#[cfg(feature = "experimental")]
/// Access the AGC on/off control for real-time adjustment.
///
/// Use this to dynamically enable or disable AGC processing during runtime.
/// Useful for comparing processed and unprocessed audio or for disabling/enabling AGC at runtime.
#[inline]
pub fn get_agc_control(&self) -> Arc<AtomicBool> {
Arc::clone(&self.is_enabled)
}
#[cfg(not(feature = "experimental"))]
/// Enable or disable AGC processing.
///
/// Use this to enable or disable AGC processing.
/// Useful for comparing processed and unprocessed audio or for disabling/enabling AGC.
#[inline]
pub fn set_enabled(&mut self, enabled: bool) {
self.is_enabled = enabled;
}
/// Updates the peak level with an adaptive attack coefficient
///
/// This method adjusts the peak level using a variable attack coefficient.
/// It responds faster to sudden increases in signal level by using a
/// minimum attack coefficient of `min_attack_coeff` when the sample value exceeds the
/// current peak level. This adaptive behavior helps capture transients
/// more accurately while maintaining smoother behavior for gradual changes.
#[inline]
fn update_peak_level(&mut self, sample_value: f32) {
let attack_coeff = if sample_value > self.peak_level {
self.attack_coeff().min(self.min_attack_coeff) // User-defined attack time limited via release_time
} else {
self.release_coeff()
};
self.peak_level = attack_coeff * self.peak_level + (1.0 - attack_coeff) * sample_value;
}
/// Updates the RMS (Root Mean Square) level using a circular buffer approach.
/// This method calculates a moving average of the squared input samples,
/// providing a measure of the signal's average power over time.
#[inline]
fn update_rms(&mut self, sample_value: f32) -> f32 {
let squared_sample = sample_value * sample_value;
self.rms_window.push(squared_sample);
self.rms_window.mean().sqrt()
}
/// Calculate gain adjustments based on peak levels
/// This method determines the appropriate gain level to apply to the audio
/// signal, considering the peak level.
/// The peak level helps prevent sudden spikes in the output signal.
#[inline]
fn calculate_peak_gain(&self) -> f32 {
if self.peak_level > 0.0 {
(self.target_level() / self.peak_level).min(self.absolute_max_gain())
} else {
self.absolute_max_gain()
}
}
#[inline]
fn process_sample(&mut self, sample: I::Item) -> I::Item {
// Convert the sample to its absolute float value for level calculations
let sample_value = sample.to_f32().abs();
// Dynamically adjust peak level using an adaptive attack coefficient
self.update_peak_level(sample_value);
// Calculate the current RMS (Root Mean Square) level using a sliding window approach
let rms = self.update_rms(sample_value);
// Compute the gain adjustment required to reach the target level based on RMS
let rms_gain = if rms > 0.0 {
self.target_level() / rms
} else {
self.absolute_max_gain() // Default to max gain if RMS is zero
};
// Calculate the peak limiting gain
let peak_gain = self.calculate_peak_gain();
// Use RMS for general adjustments, but limit by peak gain to prevent clipping
let desired_gain = rms_gain.min(peak_gain);
// Adaptive attack/release speed for AGC (Automatic Gain Control)
//
// This mechanism implements an asymmetric approach to gain adjustment:
// 1. **Slow increase**: Prevents abrupt amplification of noise during quiet periods.
// 2. **Fast decrease**: Rapidly attenuates sudden loud signals to avoid distortion.
//
// The asymmetry is crucial because:
// - Gradual gain increases sound more natural and less noticeable to listeners.
// - Quick gain reductions are necessary to prevent clipping and maintain audio quality.
//
// This approach addresses several challenges associated with high attack times:
// 1. **Slow response**: With a high attack time, the AGC responds very slowly to changes in input level.
// This means it takes longer for the gain to adjust to new signal levels.
// 2. **Initial gain calculation**: When the audio starts or after a period of silence, the initial gain
// calculation might result in a very high gain value, especially if the input signal starts quietly.
// 3. **Overshooting**: As the gain slowly increases (due to the high attack time), it might overshoot
// the desired level, causing the signal to become too loud.
// 4. **Overcorrection**: The AGC then tries to correct this by reducing the gain, but due to the slow response,
// it might reduce the gain too much, causing the sound to drop to near-zero levels.
// 5. **Slow recovery**: Again, due to the high attack time, it takes a while for the gain to increase
// back to the appropriate level.
//
// By using a faster release time for decreasing gain, we can mitigate these issues and provide
// more responsive control over sudden level increases while maintaining smooth gain increases.
let attack_speed = if desired_gain > self.current_gain {
self.attack_coeff()
} else {
self.release_coeff()
};
// Gradually adjust the current gain towards the desired gain for smooth transitions
self.current_gain = self.current_gain * attack_speed + desired_gain * (1.0 - attack_speed);
// Ensure the calculated gain stays within the defined operational range
self.current_gain = self.current_gain.clamp(0.1, self.absolute_max_gain());
// Output current gain value for developers to fine tune their inputs to automatic_gain_control
#[cfg(feature = "tracing")]
tracing::debug!("AGC gain: {}", self.current_gain,);
// Apply the computed gain to the input sample and return the result
sample.amplify(self.current_gain)
}
/// Returns a mutable reference to the inner source.
pub fn inner(&self) -> &I {
&self.input
}
/// Returns the inner source.
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
}
impl<I> Iterator for AutomaticGainControl<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next().map(|sample| {
if self.is_enabled() {
self.process_sample(sample)
} else {
sample
}
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for AutomaticGainControl<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for AutomaticGainControl<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

103
vendor/rodio/src/source/amplify.rs vendored Normal file
View File

@@ -0,0 +1,103 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `Amplify` object.
pub fn amplify<I>(input: I, factor: f32) -> Amplify<I>
where
I: Source,
I::Item: Sample,
{
Amplify { input, factor }
}
/// Filter that modifies each sample by a given value.
#[derive(Clone, Debug)]
pub struct Amplify<I> {
input: I,
factor: f32,
}
impl<I> Amplify<I> {
/// Modifies the amplification factor.
#[inline]
pub fn set_factor(&mut self, factor: f32) {
self.factor = factor;
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for Amplify<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next().map(|value| value.amplify(self.factor))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for Amplify<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for Amplify<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

252
vendor/rodio/src/source/blt.rs vendored Normal file
View File

@@ -0,0 +1,252 @@
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
/// Internal function that builds a `BltFilter` object.
pub fn low_pass<I>(input: I, freq: u32) -> BltFilter<I>
where
I: Source<Item = f32>,
{
low_pass_with_q(input, freq, 0.5)
}
pub fn high_pass<I>(input: I, freq: u32) -> BltFilter<I>
where
I: Source<Item = f32>,
{
high_pass_with_q(input, freq, 0.5)
}
/// Same as low_pass but allows the q value (bandwidth) to be changed
pub fn low_pass_with_q<I>(input: I, freq: u32, q: f32) -> BltFilter<I>
where
I: Source<Item = f32>,
{
BltFilter {
input,
formula: BltFormula::LowPass { freq, q },
applier: None,
x_n1: 0.0,
x_n2: 0.0,
y_n1: 0.0,
y_n2: 0.0,
}
}
/// Same as high_pass but allows the q value (bandwidth) to be changed
pub fn high_pass_with_q<I>(input: I, freq: u32, q: f32) -> BltFilter<I>
where
I: Source<Item = f32>,
{
BltFilter {
input,
formula: BltFormula::HighPass { freq, q },
applier: None,
x_n1: 0.0,
x_n2: 0.0,
y_n1: 0.0,
y_n2: 0.0,
}
}
/// This applies an audio filter, it can be a high or low pass filter.
#[derive(Clone, Debug)]
pub struct BltFilter<I> {
input: I,
formula: BltFormula,
applier: Option<BltApplier>,
x_n1: f32,
x_n2: f32,
y_n1: f32,
y_n2: f32,
}
impl<I> BltFilter<I> {
/// Modifies this filter so that it becomes a low-pass filter.
pub fn to_low_pass(&mut self, freq: u32) {
self.to_low_pass_with_q(freq, 0.5);
}
/// Modifies this filter so that it becomes a high-pass filter
pub fn to_high_pass(&mut self, freq: u32) {
self.to_high_pass_with_q(freq, 0.5);
}
/// Same as to_low_pass but allows the q value (bandwidth) to be changed
pub fn to_low_pass_with_q(&mut self, freq: u32, q: f32) {
self.formula = BltFormula::LowPass { freq, q };
self.applier = None;
}
/// Same as to_high_pass but allows the q value (bandwidth) to be changed
pub fn to_high_pass_with_q(&mut self, freq: u32, q: f32) {
self.formula = BltFormula::HighPass { freq, q };
self.applier = None;
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for BltFilter<I>
where
I: Source<Item = f32>,
{
type Item = f32;
#[inline]
fn next(&mut self) -> Option<f32> {
let last_in_frame = self.input.current_frame_len() == Some(1);
if self.applier.is_none() {
self.applier = Some(self.formula.to_applier(self.input.sample_rate()));
}
let sample = match self.input.next() {
None => return None,
Some(s) => s,
};
let result = self
.applier
.as_ref()
.unwrap()
.apply(sample, self.x_n1, self.x_n2, self.y_n1, self.y_n2);
self.y_n2 = self.y_n1;
self.x_n2 = self.x_n1;
self.y_n1 = result;
self.x_n1 = sample;
if last_in_frame {
self.applier = None;
}
Some(result)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for BltFilter<I> where I: Source<Item = f32> + ExactSizeIterator {}
impl<I> Source for BltFilter<I>
where
I: Source<Item = f32>,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}
#[derive(Clone, Debug)]
enum BltFormula {
LowPass { freq: u32, q: f32 },
HighPass { freq: u32, q: f32 },
}
impl BltFormula {
fn to_applier(&self, sampling_frequency: u32) -> BltApplier {
match *self {
BltFormula::LowPass { freq, q } => {
let w0 = 2.0 * PI * freq as f32 / sampling_frequency as f32;
let alpha = w0.sin() / (2.0 * q);
let b1 = 1.0 - w0.cos();
let b0 = b1 / 2.0;
let b2 = b0;
let a0 = 1.0 + alpha;
let a1 = -2.0 * w0.cos();
let a2 = 1.0 - alpha;
BltApplier {
b0: b0 / a0,
b1: b1 / a0,
b2: b2 / a0,
a1: a1 / a0,
a2: a2 / a0,
}
}
BltFormula::HighPass { freq, q } => {
let w0 = 2.0 * PI * freq as f32 / sampling_frequency as f32;
let cos_w0 = w0.cos();
let alpha = w0.sin() / (2.0 * q);
let b0 = (1.0 + cos_w0) / 2.0;
let b1 = -1.0 - cos_w0;
let b2 = b0;
let a0 = 1.0 + alpha;
let a1 = -2.0 * cos_w0;
let a2 = 1.0 - alpha;
BltApplier {
b0: b0 / a0,
b1: b1 / a0,
b2: b2 / a0,
a1: a1 / a0,
a2: a2 / a0,
}
}
}
}
}
#[derive(Clone, Debug)]
struct BltApplier {
b0: f32,
b1: f32,
b2: f32,
a1: f32,
a2: f32,
}
impl BltApplier {
#[inline]
fn apply(&self, x_n: f32, x_n1: f32, x_n2: f32, y_n1: f32, y_n2: f32) -> f32 {
self.b0 * x_n + self.b1 * x_n1 + self.b2 * x_n2 - self.a1 * y_n1 - self.a2 * y_n2
}
}

268
vendor/rodio/src/source/buffered.rs vendored Normal file
View File

@@ -0,0 +1,268 @@
use std::cmp;
use std::mem;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `Buffered` object.
#[inline]
pub fn buffered<I>(input: I) -> Buffered<I>
where
I: Source,
I::Item: Sample,
{
let total_duration = input.total_duration();
let first_frame = extract(input);
Buffered {
current_frame: first_frame,
position_in_frame: 0,
total_duration,
}
}
/// Iterator that at the same time extracts data from the iterator and stores it in a buffer.
pub struct Buffered<I>
where
I: Source,
I::Item: Sample,
{
/// Immutable reference to the next frame of data. Cannot be `Frame::Input`.
current_frame: Arc<Frame<I>>,
/// The position in number of samples of this iterator inside `current_frame`.
position_in_frame: usize,
/// Obtained once at creation and never modified again.
total_duration: Option<Duration>,
}
enum Frame<I>
where
I: Source,
I::Item: Sample,
{
/// Data that has already been extracted from the iterator. Also contains a pointer to the
/// next frame.
Data(FrameData<I>),
/// No more data.
End,
/// Unextracted data. The `Option` should never be `None` and is only here for easier data
/// processing.
Input(Mutex<Option<I>>),
}
struct FrameData<I>
where
I: Source,
I::Item: Sample,
{
data: Vec<I::Item>,
channels: u16,
rate: u32,
next: Mutex<Arc<Frame<I>>>,
}
impl<I> Drop for FrameData<I>
where
I: Source,
I::Item: Sample,
{
fn drop(&mut self) {
// This is necessary to prevent stack overflows deallocating long chains of the mutually
// recursive `Frame` and `FrameData` types. This iteratively traverses as much of the
// chain as needs to be deallocated, and repeatedly "pops" the head off the list. This
// solves the problem, as when the time comes to actually deallocate the `FrameData`,
// the `next` field will contain a `Frame::End`, or an `Arc` with additional references,
// so the depth of recursive drops will be bounded.
while let Ok(arc_next) = self.next.get_mut() {
if let Some(next_ref) = Arc::get_mut(arc_next) {
// This allows us to own the next Frame.
let next = mem::replace(next_ref, Frame::End);
if let Frame::Data(next_data) = next {
// Swap the current FrameData with the next one, allowing the current one
// to go out of scope.
*self = next_data;
} else {
break;
}
} else {
break;
}
}
}
}
/// Builds a frame from the input iterator.
fn extract<I>(mut input: I) -> Arc<Frame<I>>
where
I: Source,
I::Item: Sample,
{
let frame_len = input.current_frame_len();
if frame_len == Some(0) {
return Arc::new(Frame::End);
}
let channels = input.channels();
let rate = input.sample_rate();
let data: Vec<I::Item> = input
.by_ref()
.take(cmp::min(frame_len.unwrap_or(32768), 32768))
.collect();
if data.is_empty() {
return Arc::new(Frame::End);
}
Arc::new(Frame::Data(FrameData {
data,
channels,
rate,
next: Mutex::new(Arc::new(Frame::Input(Mutex::new(Some(input))))),
}))
}
impl<I> Buffered<I>
where
I: Source,
I::Item: Sample,
{
/// Advances to the next frame.
fn next_frame(&mut self) {
let next_frame = {
let mut next_frame_ptr = match &*self.current_frame {
Frame::Data(FrameData { next, .. }) => next.lock().unwrap(),
_ => unreachable!(),
};
let next_frame = match &**next_frame_ptr {
Frame::Data(_) => next_frame_ptr.clone(),
Frame::End => next_frame_ptr.clone(),
Frame::Input(input) => {
let input = input.lock().unwrap().take().unwrap();
extract(input)
}
};
*next_frame_ptr = next_frame.clone();
next_frame
};
self.current_frame = next_frame;
self.position_in_frame = 0;
}
}
impl<I> Iterator for Buffered<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
let current_sample;
let advance_frame;
match &*self.current_frame {
Frame::Data(FrameData { data, .. }) => {
current_sample = Some(data[self.position_in_frame]);
self.position_in_frame += 1;
advance_frame = self.position_in_frame >= data.len();
}
Frame::End => {
current_sample = None;
advance_frame = false;
}
Frame::Input(_) => unreachable!(),
};
if advance_frame {
self.next_frame();
}
current_sample
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
// TODO:
(0, None)
}
}
// TODO: uncomment when `size_hint` is fixed
/*impl<I> ExactSizeIterator for Amplify<I> where I: Source + ExactSizeIterator, I::Item: Sample {
}*/
impl<I> Source for Buffered<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
match &*self.current_frame {
Frame::Data(FrameData { data, .. }) => Some(data.len() - self.position_in_frame),
Frame::End => Some(0),
Frame::Input(_) => unreachable!(),
}
}
#[inline]
fn channels(&self) -> u16 {
match *self.current_frame {
Frame::Data(FrameData { channels, .. }) => channels,
Frame::End => 1,
Frame::Input(_) => unreachable!(),
}
}
#[inline]
fn sample_rate(&self) -> u32 {
match *self.current_frame {
Frame::Data(FrameData { rate, .. }) => rate,
Frame::End => 44100,
Frame::Input(_) => unreachable!(),
}
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.total_duration
}
/// Can not support seek, in the end state we lose the underlying source
/// which makes seeking back impossible.
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Err(SeekError::NotSupported {
underlying_source: std::any::type_name::<Self>(),
})
}
}
impl<I> Clone for Buffered<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn clone(&self) -> Buffered<I> {
Buffered {
current_frame: self.current_frame.clone(),
position_in_frame: self.position_in_frame,
total_duration: self.total_duration,
}
}
}

View File

@@ -0,0 +1,150 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Combines channels in input into a single mono source, then plays that mono sound
/// to each channel at the volume given for that channel.
#[derive(Clone, Debug)]
pub struct ChannelVolume<I>
where
I: Source,
I::Item: Sample,
{
input: I,
// Channel number is used as index for amplification value.
channel_volumes: Vec<f32>,
// Current listener being processed.
current_channel: usize,
current_sample: Option<I::Item>,
}
impl<I> ChannelVolume<I>
where
I: Source,
I::Item: Sample,
{
/// Wrap the input source and make it mono. Play that mono sound to each
/// channel at the volume set by the user. The volume can be changed using
/// [`ChannelVolume::set_volume`].
pub fn new(mut input: I, channel_volumes: Vec<f32>) -> ChannelVolume<I>
where
I: Source,
I::Item: Sample,
{
let mut sample = None;
for _ in 0..input.channels() {
if let Some(s) = input.next() {
sample = Some(
sample
.get_or_insert_with(I::Item::zero_value)
.saturating_add(s),
);
}
}
ChannelVolume {
input,
channel_volumes,
current_channel: 0,
current_sample: sample,
}
}
/// Sets the volume for a given channel number. Will panic if channel number
/// is invalid.
pub fn set_volume(&mut self, channel: usize, volume: f32) {
self.channel_volumes[channel] = volume;
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for ChannelVolume<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
let ret = self
.current_sample
.map(|sample| sample.amplify(self.channel_volumes[self.current_channel]));
self.current_channel += 1;
if self.current_channel >= self.channel_volumes.len() {
self.current_channel = 0;
self.current_sample = None;
for _ in 0..self.input.channels() {
if let Some(s) = self.input.next() {
self.current_sample = Some(
self.current_sample
.get_or_insert_with(I::Item::zero_value)
.saturating_add(s),
);
}
}
}
ret
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for ChannelVolume<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for ChannelVolume<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.channel_volumes.len() as u16
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

76
vendor/rodio/src/source/chirp.rs vendored Normal file
View File

@@ -0,0 +1,76 @@
//! Chirp/sweep source.
use std::{f32::consts::TAU, time::Duration};
use crate::Source;
/// Convenience function to create a new `Chirp` source.
#[inline]
pub fn chirp(
sample_rate: cpal::SampleRate,
start_frequency: f32,
end_frequency: f32,
duration: Duration,
) -> Chirp {
Chirp::new(sample_rate, start_frequency, end_frequency, duration)
}
/// Generate a sine wave with an instantaneous frequency that changes/sweeps linearly over time.
/// At the end of the chirp, once the `end_frequency` is reached, the source is exhausted.
#[derive(Clone, Debug)]
pub struct Chirp {
start_frequency: f32,
end_frequency: f32,
sample_rate: cpal::SampleRate,
total_samples: u64,
elapsed_samples: u64,
}
impl Chirp {
fn new(
sample_rate: cpal::SampleRate,
start_frequency: f32,
end_frequency: f32,
duration: Duration,
) -> Self {
Self {
sample_rate,
start_frequency,
end_frequency,
total_samples: (duration.as_secs_f64() * (sample_rate.0 as f64)) as u64,
elapsed_samples: 0,
}
}
}
impl Iterator for Chirp {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
let i = self.elapsed_samples;
let ratio = self.elapsed_samples as f32 / self.total_samples as f32;
self.elapsed_samples += 1;
let freq = self.start_frequency * (1.0 - ratio) + self.end_frequency * ratio;
let t = (i as f32 / self.sample_rate() as f32) * TAU * freq;
Some(t.sin())
}
}
impl Source for Chirp {
fn current_frame_len(&self) -> Option<usize> {
None
}
fn channels(&self) -> u16 {
1
}
fn sample_rate(&self) -> u32 {
self.sample_rate.0
}
fn total_duration(&self) -> Option<Duration> {
let secs: f64 = self.total_samples as f64 / self.sample_rate.0 as f64;
Some(Duration::new(1, 0).mul_f64(secs))
}
}

79
vendor/rodio/src/source/crossfade.rs vendored Normal file
View File

@@ -0,0 +1,79 @@
use std::time::Duration;
use cpal::FromSample;
use crate::source::{FadeIn, Mix, TakeDuration};
use crate::{Sample, Source};
/// Mixes one sound fading out with another sound fading in for the given
/// duration.
///
/// Only the crossfaded portion (beginning of fadeout, beginning of fadein) is
/// returned.
pub fn crossfade<I1, I2>(
input_fadeout: I1,
input_fadein: I2,
duration: Duration,
) -> Crossfade<I1, I2>
where
I1: Source,
I2: Source,
I1::Item: FromSample<I2::Item> + Sample,
I2::Item: Sample,
{
let mut input_fadeout = input_fadeout.take_duration(duration);
input_fadeout.set_filter_fadeout();
let input_fadein = input_fadein.take_duration(duration).fade_in(duration);
input_fadeout.mix(input_fadein)
}
/// Mixes one sound fading out with another sound fading in for the given
/// duration.
///
/// Only the crossfaded portion (beginning of fadeout, beginning of fadein) is
/// covered.
pub type Crossfade<I1, I2> = Mix<TakeDuration<I1>, FadeIn<TakeDuration<I2>>>;
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::SamplesBuffer;
fn dummysource(length: u8) -> SamplesBuffer<f32> {
let data: Vec<f32> = (1..=length).map(f32::from).collect();
SamplesBuffer::new(1, 1, data)
}
#[test]
fn test_crossfade_with_self() {
let source1 = dummysource(10);
let source2 = dummysource(10);
let mut mixed = crossfade(
source1,
source2,
Duration::from_secs(5) + Duration::from_nanos(1),
);
assert_eq!(mixed.next(), Some(1.0));
assert_eq!(mixed.next(), Some(2.0));
assert_eq!(mixed.next(), Some(3.0));
assert_eq!(mixed.next(), Some(4.0));
assert_eq!(mixed.next(), Some(5.0));
assert_eq!(mixed.next(), None);
}
#[test]
fn test_crossfade() {
let source1 = dummysource(10);
let source2 = dummysource(10).amplify(0.0);
let mut mixed = crossfade(
source1,
source2,
Duration::from_secs(5) + Duration::from_nanos(1),
);
assert_eq!(mixed.next(), Some(1.0 * 1.0));
assert_eq!(mixed.next(), Some(2.0 * 0.8));
assert_eq!(mixed.next(), Some(3.0 * 0.6));
assert_eq!(mixed.next(), Some(4.0 * 0.4));
assert_eq!(mixed.next(), Some(5.0 * 0.2));
assert_eq!(mixed.next(), None);
}
}

138
vendor/rodio/src/source/delay.rs vendored Normal file
View File

@@ -0,0 +1,138 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
fn remaining_samples(until_playback: Duration, sample_rate: u32, channels: u16) -> 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
}
/// Internal function that builds a `Delay` object.
pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
where
I: Source,
I::Item: Sample,
{
Delay {
remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()),
requested_duration: duration,
input,
}
}
/// A source that delays the given source by a certain amount.
#[derive(Clone, Debug)]
pub struct Delay<I> {
input: I,
remaining_samples: usize,
requested_duration: Duration,
}
impl<I> Delay<I>
where
I: Source,
I::Item: Sample,
{
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for Delay<I>
where
I: Source,
I::Item: Sample,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
if self.remaining_samples >= 1 {
self.remaining_samples -= 1;
Some(Sample::zero_value())
} else {
self.input.next()
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.input.size_hint();
(
min + self.remaining_samples,
max.map(|v| v + self.remaining_samples),
)
}
}
impl<I> Source for Delay<I>
where
I: Iterator + Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input
.current_frame_len()
.map(|val| val + self.remaining_samples)
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input
.total_duration()
.map(|val| val + self.requested_duration)
}
/// Pos is seen from the perspective of the api user.
///
/// # Example
///
/// ```ignore
/// use std::time::Duration;
///
/// let mut source = inner_source.delay(Duration::from_secs(10));
/// source.try_seek(Duration::from_secs(15));
///
/// // inner_source is now at pos: Duration::from_secs(5);
/// ```
///
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
if pos < self.requested_duration {
self.input.try_seek(Duration::ZERO)?;
let until_playback = self.requested_duration - pos;
self.remaining_samples =
remaining_samples(until_playback, self.sample_rate(), self.channels());
}
let compensated_for_delay = pos.saturating_sub(self.requested_duration);
self.input.try_seek(compensated_for_delay)
}
}

99
vendor/rodio/src/source/done.rs vendored Normal file
View File

@@ -0,0 +1,99 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// When the inner source is empty this decrements a `AtomicUsize`.
#[derive(Debug, Clone)]
pub struct Done<I> {
input: I,
signal: Arc<AtomicUsize>,
signal_sent: bool,
}
impl<I> Done<I> {
/// When the inner source is empty the AtomicUsize passed in is decremented.
/// If it was zero it will overflow negatively.
#[inline]
pub fn new(input: I, signal: Arc<AtomicUsize>) -> Done<I> {
Done {
input,
signal,
signal_sent: false,
}
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I: Source> Iterator for Done<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
let next = self.input.next();
if !self.signal_sent && next.is_none() {
self.signal.fetch_sub(1, Ordering::Relaxed);
self.signal_sent = true;
}
next
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for Done<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

67
vendor/rodio/src/source/empty.rs vendored Normal file
View File

@@ -0,0 +1,67 @@
use std::marker::PhantomData;
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// An empty source.
#[derive(Debug, Copy, Clone)]
pub struct Empty<S>(PhantomData<S>);
impl<S> Default for Empty<S> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<S> Empty<S> {
/// An empty source that immediately ends without ever returning a sample to
/// play
#[inline]
pub fn new() -> Empty<S> {
Empty(PhantomData)
}
}
impl<S> Iterator for Empty<S> {
type Item = S;
#[inline]
fn next(&mut self) -> Option<S> {
None
}
}
impl<S> Source for Empty<S>
where
S: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
1
}
#[inline]
fn sample_rate(&self) -> u32 {
48000
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
Some(Duration::new(0, 0))
}
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Err(SeekError::NotSupported {
underlying_source: std::any::type_name::<Self>(),
})
}
}

View File

@@ -0,0 +1,70 @@
use std::marker::PhantomData;
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// An empty source which executes a callback function
pub struct EmptyCallback<S> {
#[allow(missing_docs)] // See: https://github.com/RustAudio/rodio/issues/615
pub phantom_data: PhantomData<S>,
#[allow(missing_docs)] // See: https://github.com/RustAudio/rodio/issues/615
pub callback: Box<dyn Send + Fn()>,
}
impl<S> EmptyCallback<S> {
#[inline]
/// Create an empty source which executes a callback function.
/// Example use-case:
///
/// Detect and do something when the source before this one has ended.
pub fn new(callback: Box<dyn Send + Fn()>) -> EmptyCallback<S> {
EmptyCallback {
phantom_data: PhantomData,
callback,
}
}
}
impl<S> Iterator for EmptyCallback<S> {
type Item = S;
#[inline]
fn next(&mut self) -> Option<S> {
(self.callback)();
None
}
}
impl<S> Source for EmptyCallback<S>
where
S: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
1
}
#[inline]
fn sample_rate(&self) -> u32 {
48000
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
Some(Duration::new(0, 0))
}
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Err(SeekError::NotSupported {
underlying_source: std::any::type_name::<Self>(),
})
}
}

102
vendor/rodio/src/source/fadein.rs vendored Normal file
View File

@@ -0,0 +1,102 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::{linear_ramp::linear_gain_ramp, LinearGainRamp, SeekError};
/// Internal function that builds a `FadeIn` object.
pub fn fadein<I>(input: I, duration: Duration) -> FadeIn<I>
where
I: Source,
I::Item: Sample,
{
FadeIn {
input: linear_gain_ramp(input, duration, 0.0f32, 1.0f32, false),
}
}
/// Filter that modifies raises the volume from silence over a time period.
#[derive(Clone, Debug)]
pub struct FadeIn<I> {
input: LinearGainRamp<I>,
}
impl<I> FadeIn<I>
where
I: Source,
I::Item: Sample,
{
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
self.input.inner()
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
self.input.inner_mut()
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input.into_inner()
}
}
impl<I> Iterator for FadeIn<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for FadeIn<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for FadeIn<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.inner().current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.inner().channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.inner().sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.inner().total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.inner_mut().try_seek(pos)
}
}

102
vendor/rodio/src/source/fadeout.rs vendored Normal file
View File

@@ -0,0 +1,102 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::{linear_ramp::linear_gain_ramp, LinearGainRamp, SeekError};
/// Internal function that builds a `FadeOut` object.
pub fn fadeout<I>(input: I, duration: Duration) -> FadeOut<I>
where
I: Source,
I::Item: Sample,
{
FadeOut {
input: linear_gain_ramp(input, duration, 1.0f32, 0.0f32, true),
}
}
/// Filter that modifies lowers the volume to silence over a time period.
#[derive(Clone, Debug)]
pub struct FadeOut<I> {
input: LinearGainRamp<I>,
}
impl<I> FadeOut<I>
where
I: Source,
I::Item: Sample,
{
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
self.input.inner()
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
self.input.inner_mut()
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input.into_inner()
}
}
impl<I> Iterator for FadeOut<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for FadeOut<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for FadeOut<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.inner().current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.inner().channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.inner().sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.inner().total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.inner_mut().try_seek(pos)
}
}

37
vendor/rodio/src/source/from_factory.rs vendored Normal file
View File

@@ -0,0 +1,37 @@
use crate::source::{from_iter, FromIter};
/// Builds a source that chains sources built from a factory.
///
/// The `factory` parameter is a function that produces a source. The source is then played.
/// Whenever the source ends, `factory` is called again in order to produce the source that is
/// played next.
///
/// If the `factory` closure returns `None`, then the sound ends.
pub fn from_factory<F, S>(factory: F) -> FromIter<FromFactoryIter<F>>
where
F: FnMut() -> Option<S>,
{
from_iter(FromFactoryIter { factory })
}
/// Internal type used by `from_factory`.
pub struct FromFactoryIter<F> {
factory: F,
}
impl<F, S> Iterator for FromFactoryIter<F>
where
F: FnMut() -> Option<S>,
{
type Item = S;
#[inline]
fn next(&mut self) -> Option<S> {
(self.factory)()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}
}

183
vendor/rodio/src/source/from_iter.rs vendored Normal file
View File

@@ -0,0 +1,183 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Builds a source that chains sources provided by an iterator.
///
/// The `iterator` parameter is an iterator that produces a source. The source is then played.
/// Whenever the source ends, the `iterator` is used again in order to produce the source that is
/// played next.
///
/// If the `iterator` produces `None`, then the sound ends.
pub fn from_iter<I>(iterator: I) -> FromIter<I::IntoIter>
where
I: IntoIterator,
{
let mut iterator = iterator.into_iter();
let first_source = iterator.next();
FromIter {
iterator,
current_source: first_source,
}
}
/// A source that chains sources provided by an iterator.
#[derive(Clone)]
pub struct FromIter<I>
where
I: Iterator,
{
// The iterator that provides sources.
iterator: I,
// Is only ever `None` if the first element of the iterator is `None`.
current_source: Option<I::Item>,
}
impl<I> Iterator for FromIter<I>
where
I: Iterator,
I::Item: Iterator + Source,
<I::Item as Iterator>::Item: Sample,
{
type Item = <I::Item as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I::Item as Iterator>::Item> {
loop {
if let Some(src) = &mut self.current_source {
if let Some(value) = src.next() {
return Some(value);
}
}
if let Some(src) = self.iterator.next() {
self.current_source = Some(src);
} else {
return None;
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if let Some(cur) = &self.current_source {
(cur.size_hint().0, None)
} else {
(0, None)
}
}
}
impl<I> Source for FromIter<I>
where
I: Iterator,
I::Item: Iterator + Source,
<I::Item as Iterator>::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
// This function is non-trivial because the boundary between the current source and the
// next must be a frame boundary as well.
//
// The current sound is free to return `None` for `current_frame_len()`, in which case
// we *should* return the number of samples remaining the current sound.
// This can be estimated with `size_hint()`.
//
// If the `size_hint` is `None` as well, we are in the worst case scenario. To handle this
// situation we force a frame to have a maximum number of samples indicate by this
// constant.
const THRESHOLD: usize = 10240;
// Try the current `current_frame_len`.
if let Some(src) = &self.current_source {
if let Some(val) = src.current_frame_len() {
if val != 0 {
return Some(val);
}
}
}
// Try the size hint.
if let Some(src) = &self.current_source {
if let Some(val) = src.size_hint().1 {
if val < THRESHOLD && val != 0 {
return Some(val);
}
}
}
// Otherwise we use the constant value.
Some(THRESHOLD)
}
#[inline]
fn channels(&self) -> u16 {
if let Some(src) = &self.current_source {
src.channels()
} else {
// Dummy value that only happens if the iterator was empty.
2
}
}
#[inline]
fn sample_rate(&self) -> u32 {
if let Some(src) = &self.current_source {
src.sample_rate()
} else {
// Dummy value that only happens if the iterator was empty.
44100
}
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
if let Some(source) = self.current_source.as_mut() {
source.try_seek(pos)
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use crate::buffer::SamplesBuffer;
use crate::source::{from_iter, Source};
#[test]
fn basic() {
let mut rx = from_iter((0..2).map(|n| {
if n == 0 {
SamplesBuffer::new(1, 48000, vec![10i16, -10, 10, -10])
} else if n == 1 {
SamplesBuffer::new(2, 96000, vec![5i16, 5, 5, 5])
} else {
unreachable!()
}
}));
assert_eq!(rx.channels(), 1);
assert_eq!(rx.sample_rate(), 48000);
assert_eq!(rx.next(), Some(10));
assert_eq!(rx.next(), Some(-10));
assert_eq!(rx.next(), Some(10));
assert_eq!(rx.next(), Some(-10));
/*assert_eq!(rx.channels(), 2);
assert_eq!(rx.sample_rate(), 96000);*/
// FIXME: not working
assert_eq!(rx.next(), Some(5));
assert_eq!(rx.next(), Some(5));
assert_eq!(rx.next(), Some(5));
assert_eq!(rx.next(), Some(5));
assert_eq!(rx.next(), None);
}
}

238
vendor/rodio/src/source/linear_ramp.rs vendored Normal file
View File

@@ -0,0 +1,238 @@
use std::time::Duration;
use super::SeekError;
use crate::{Sample, Source};
/// Internal function that builds a `LinearRamp` object.
pub fn linear_gain_ramp<I>(
input: I,
duration: Duration,
start_gain: f32,
end_gain: f32,
clamp_end: bool,
) -> LinearGainRamp<I>
where
I: Source,
I::Item: Sample,
{
let duration_nanos = duration.as_nanos() as f32;
assert!(duration_nanos > 0.0f32);
LinearGainRamp {
input,
elapsed_ns: 0.0f32,
total_ns: duration_nanos,
start_gain,
end_gain,
clamp_end,
sample_idx: 0u64,
}
}
/// Filter that adds a linear gain ramp to the source over a given time range.
#[derive(Clone, Debug)]
pub struct LinearGainRamp<I> {
input: I,
elapsed_ns: f32,
total_ns: f32,
start_gain: f32,
end_gain: f32,
clamp_end: bool,
sample_idx: u64,
}
impl<I> LinearGainRamp<I>
where
I: Source,
I::Item: Sample,
{
/// Returns a reference to the innner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for LinearGainRamp<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
let factor: f32;
let remaining_ns = self.total_ns - self.elapsed_ns;
if remaining_ns < 0.0 {
if self.clamp_end {
factor = self.end_gain;
} else {
factor = 1.0f32;
}
} else {
self.sample_idx += 1;
let p = self.elapsed_ns / self.total_ns;
factor = self.start_gain * (1.0f32 - p) + self.end_gain * p;
}
if self.sample_idx % (self.channels() as u64) == 0 {
self.elapsed_ns += 1000000000.0 / (self.input.sample_rate() as f32);
}
self.input.next().map(|value| value.amplify(factor))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for LinearGainRamp<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for LinearGainRamp<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.elapsed_ns = pos.as_nanos() as f32;
self.input.try_seek(pos)
}
}
#[cfg(test)]
mod tests {
use approx::assert_abs_diff_eq;
use super::*;
use crate::buffer::SamplesBuffer;
/// Create a SamplesBuffer of identical samples with value `value`.
/// Returned buffer is one channel and has a sample rate of 1 hz.
fn const_source(length: u8, value: f32) -> SamplesBuffer<f32> {
let data: Vec<f32> = (1..=length).map(|_| value).collect();
SamplesBuffer::new(1, 1, data)
}
/// Create a SamplesBuffer of repeating sample values from `values`.
fn cycle_source(length: u8, values: Vec<f32>) -> SamplesBuffer<f32> {
let data: Vec<f32> = (1..=length)
.enumerate()
.map(|(i, _)| values[i % values.len()])
.collect();
SamplesBuffer::new(1, 1, data)
}
#[test]
fn test_linear_ramp() {
let source1 = const_source(10, 1.0f32);
let mut faded = linear_gain_ramp(source1, Duration::from_secs(4), 0.0, 1.0, true);
assert_eq!(faded.next(), Some(0.0));
assert_eq!(faded.next(), Some(0.25));
assert_eq!(faded.next(), Some(0.5));
assert_eq!(faded.next(), Some(0.75));
assert_eq!(faded.next(), Some(1.0));
assert_eq!(faded.next(), Some(1.0));
assert_eq!(faded.next(), Some(1.0));
assert_eq!(faded.next(), Some(1.0));
assert_eq!(faded.next(), Some(1.0));
assert_eq!(faded.next(), Some(1.0));
assert_eq!(faded.next(), None);
}
#[test]
fn test_linear_ramp_clamped() {
let source1 = const_source(10, 1.0f32);
let mut faded = linear_gain_ramp(source1, Duration::from_secs(4), 0.0, 0.5, true);
assert_eq!(faded.next(), Some(0.0)); // fading in...
assert_eq!(faded.next(), Some(0.125));
assert_eq!(faded.next(), Some(0.25));
assert_eq!(faded.next(), Some(0.375));
assert_eq!(faded.next(), Some(0.5)); // fade is done
assert_eq!(faded.next(), Some(0.5));
assert_eq!(faded.next(), Some(0.5));
assert_eq!(faded.next(), Some(0.5));
assert_eq!(faded.next(), Some(0.5));
assert_eq!(faded.next(), Some(0.5));
assert_eq!(faded.next(), None);
}
#[test]
fn test_linear_ramp_seek() {
let source1 = cycle_source(20, vec![0.0f32, 0.4f32, 0.8f32]);
let mut faded = linear_gain_ramp(source1, Duration::from_secs(10), 0.0, 1.0, true);
assert_abs_diff_eq!(faded.next().unwrap(), 0.0); // source value 0
assert_abs_diff_eq!(faded.next().unwrap(), 0.04); // source value 0.4, ramp gain 0.1
assert_abs_diff_eq!(faded.next().unwrap(), 0.16); // source value 0.8, ramp gain 0.2
if let Ok(_result) = faded.try_seek(Duration::from_secs(5)) {
assert_abs_diff_eq!(faded.next().unwrap(), 0.40); // source value 0.8, ramp gain 0.5
assert_abs_diff_eq!(faded.next().unwrap(), 0.0); // source value 0, ramp gain 0.6
assert_abs_diff_eq!(faded.next().unwrap(), 0.28); // source value 0.4. ramp gain 0.7
} else {
panic!("try_seek() failed!");
}
if let Ok(_result) = faded.try_seek(Duration::from_secs(0)) {
assert_abs_diff_eq!(faded.next().unwrap(), 0.0); // source value 0, ramp gain 0.0
assert_abs_diff_eq!(faded.next().unwrap(), 0.04); // source value 0.4, ramp gain 0.1
assert_abs_diff_eq!(faded.next().unwrap(), 0.16); // source value 0.8. ramp gain 0.2
} else {
panic!("try_seek() failed!");
}
if let Ok(_result) = faded.try_seek(Duration::from_secs(10)) {
assert_abs_diff_eq!(faded.next().unwrap(), 0.4); // source value 0.4, ramp gain 1.0
assert_abs_diff_eq!(faded.next().unwrap(), 0.8); // source value 0.8, ramp gain 1.0
assert_abs_diff_eq!(faded.next().unwrap(), 0.0); // source value 0. ramp gain 1.0
} else {
panic!("try_seek() failed!");
}
}
}

144
vendor/rodio/src/source/mix.rs vendored Normal file
View File

@@ -0,0 +1,144 @@
use std::cmp;
use std::time::Duration;
use crate::source::uniform::UniformSourceIterator;
use crate::source::SeekError;
use crate::{Sample, Source};
use cpal::{FromSample, Sample as CpalSample};
/// Internal function that builds a `Mix` object.
pub fn mix<I1, I2>(input1: I1, input2: I2) -> Mix<I1, I2>
where
I1: Source,
I1::Item: FromSample<I2::Item> + Sample,
I2: Source,
I2::Item: Sample,
{
let channels = input1.channels();
let rate = input1.sample_rate();
Mix {
input1: UniformSourceIterator::new(input1, channels, rate),
input2: UniformSourceIterator::new(input2, channels, rate),
}
}
/// Filter that modifies each sample by a given value.
#[derive(Clone)]
pub struct Mix<I1, I2>
where
I1: Source,
I1::Item: FromSample<I2::Item> + Sample,
I2: Source,
I2::Item: Sample,
{
input1: UniformSourceIterator<I1, I1::Item>,
input2: UniformSourceIterator<I2, I2::Item>,
}
impl<I1, I2> Iterator for Mix<I1, I2>
where
I1: Source,
I1::Item: FromSample<I2::Item> + Sample,
I2: Source,
I2::Item: Sample,
{
type Item = I1::Item;
#[inline]
fn next(&mut self) -> Option<I1::Item> {
let s1 = self.input1.next();
let s2 = self.input2.next();
match (s1, s2) {
(Some(s1), Some(s2)) => Some(s1.saturating_add(CpalSample::from_sample(s2))),
(Some(s1), None) => Some(s1),
(None, Some(s2)) => Some(CpalSample::from_sample(s2)),
(None, None) => None,
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let s1 = self.input1.size_hint();
let s2 = self.input2.size_hint();
let min = cmp::max(s1.0, s2.0);
let max = match (s1.1, s2.1) {
(Some(s1), Some(s2)) => Some(cmp::max(s1, s2)),
_ => None,
};
(min, max)
}
}
impl<I1, I2> ExactSizeIterator for Mix<I1, I2>
where
I1: Source + ExactSizeIterator,
I1::Item: FromSample<I2::Item> + Sample,
I2: Source + ExactSizeIterator,
I2::Item: Sample,
{
}
impl<I1, I2> Source for Mix<I1, I2>
where
I1: Source,
I1::Item: FromSample<I2::Item> + Sample,
I2: Source,
I2::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
let f1 = self.input1.current_frame_len();
let f2 = self.input2.current_frame_len();
match (f1, f2) {
(Some(f1), Some(f2)) => Some(cmp::min(f1, f2)),
_ => None,
}
}
#[inline]
fn channels(&self) -> u16 {
self.input1.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input1.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
let f1 = self.input1.total_duration();
let f2 = self.input2.total_duration();
match (f1, f2) {
(Some(f1), Some(f2)) => Some(cmp::max(f1, f2)),
_ => None,
}
}
/// Will only attempt a seek if both underlying sources support seek.
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Err(SeekError::NotSupported {
underlying_source: std::any::type_name::<Self>(),
})
// uncomment when #510 is implemented (query position of playback)
// TODO use source_intact to check if rollback makes sense
// let org_pos = self.input1.playback_pos();
// self.input1.try_seek(pos)?;
//
// let res = self.input2.try_seek(pos);
// if res.is_err() { // rollback seek in input1
// self.input1.try_seek(org_pos)?;
// }
//
// res
}
}

697
vendor/rodio/src/source/mod.rs vendored Normal file
View File

@@ -0,0 +1,697 @@
//! Sources of sound and various filters.
use core::fmt;
use core::time::Duration;
use cpal::FromSample;
use crate::Sample;
pub use self::agc::AutomaticGainControl;
pub use self::amplify::Amplify;
pub use self::blt::BltFilter;
pub use self::buffered::Buffered;
pub use self::channel_volume::ChannelVolume;
pub use self::chirp::{chirp, Chirp};
pub use self::crossfade::Crossfade;
pub use self::delay::Delay;
pub use self::done::Done;
pub use self::empty::Empty;
pub use self::empty_callback::EmptyCallback;
pub use self::fadein::FadeIn;
pub use self::fadeout::FadeOut;
pub use self::from_factory::{from_factory, FromFactoryIter};
pub use self::from_iter::{from_iter, FromIter};
pub use self::linear_ramp::LinearGainRamp;
pub use self::mix::Mix;
pub use self::pausable::Pausable;
pub use self::periodic::PeriodicAccess;
pub use self::position::TrackPosition;
pub use self::repeat::Repeat;
pub use self::samples_converter::SamplesConverter;
pub use self::signal_generator::{Function, SignalGenerator};
pub use self::sine::SineWave;
pub use self::skip::SkipDuration;
pub use self::skippable::Skippable;
pub use self::spatial::Spatial;
pub use self::speed::Speed;
pub use self::stoppable::Stoppable;
pub use self::take::TakeDuration;
pub use self::uniform::UniformSourceIterator;
pub use self::zero::Zero;
mod agc;
mod amplify;
mod blt;
mod buffered;
mod channel_volume;
mod chirp;
mod crossfade;
mod delay;
mod done;
mod empty;
mod empty_callback;
mod fadein;
mod fadeout;
mod from_factory;
mod from_iter;
mod linear_ramp;
mod mix;
mod pausable;
mod periodic;
mod position;
mod repeat;
mod samples_converter;
mod signal_generator;
mod sine;
mod skip;
mod skippable;
mod spatial;
mod speed;
mod stoppable;
mod take;
mod uniform;
mod zero;
#[cfg(feature = "noise")]
mod noise;
#[cfg(feature = "noise")]
pub use self::noise::{pink, white, PinkNoise, WhiteNoise};
/// A source of samples.
///
/// # A quick lesson about sounds
///
/// ## Sampling
///
/// A sound is a vibration that propagates through air and reaches your ears. This vibration can
/// be represented as an analog signal.
///
/// In order to store this signal in the computer's memory or on the disk, we perform what is
/// called *sampling*. The consists in choosing an interval of time (for example 20µs) and reading
/// the amplitude of the signal at each interval (for example, if the interval is 20µs we read the
/// amplitude every 20µs). By doing so we obtain a list of numerical values, each value being
/// called a *sample*.
///
/// Therefore a sound can be represented in memory by a frequency and a list of samples. The
/// frequency is expressed in hertz and corresponds to the number of samples that have been
/// read per second. For example if we read one sample every 20µs, the frequency would be
/// 50000 Hz. In reality, common values for the frequency are 44100, 48000 and 96000.
///
/// ## Channels
///
/// But a frequency and a list of values only represent one signal. When you listen to a sound,
/// your left and right ears don't receive exactly the same signal. In order to handle this,
/// we usually record not one but two different signals: one for the left ear and one for the right
/// ear. We say that such a sound has two *channels*.
///
/// Sometimes sounds even have five or six channels, each corresponding to a location around the
/// head of the listener.
///
/// The standard in audio manipulation is to *interleave* the multiple channels. In other words,
/// in a sound with two channels the list of samples contains the first sample of the first
/// channel, then the first sample of the second channel, then the second sample of the first
/// channel, then the second sample of the second channel, and so on. The same applies if you have
/// more than two channels. The rodio library only supports this schema.
///
/// Therefore in order to represent a sound in memory in fact we need three characteristics: the
/// frequency, the number of channels, and the list of samples.
///
/// ## The `Source` trait
///
/// A Rust object that represents a sound should implement the `Source` trait.
///
/// The three characteristics that describe a sound are provided through this trait:
///
/// - The number of channels can be retrieved with `channels`.
/// - The frequency can be retrieved with `sample_rate`.
/// - The list of values can be retrieved by iterating on the source. The `Source` trait requires
/// that the `Iterator` trait be implemented as well. When a `Source` returns None the
/// sound has ended.
///
/// # Frames
///
/// The samples rate and number of channels of some sound sources can change by itself from time
/// to time.
///
/// > **Note**: As a basic example, if you play two audio files one after the other and treat the
/// > whole as a single source, then the channels and samples rate of that source may change at the
/// > transition between the two files.
///
/// However, for optimization purposes rodio supposes that the number of channels and the frequency
/// stay the same for long periods of time and avoids calling `channels()` and
/// `sample_rate` too frequently.
///
/// In order to properly handle this situation, the `current_frame_len()` method should return
/// the number of samples that remain in the iterator before the samples rate and number of
/// channels can potentially change.
///
pub trait Source: Iterator
where
Self::Item: Sample,
{
/// Returns the number of samples before the current frame ends. `None` means "infinite" or
/// "until the sound ends".
/// Should never return 0 unless there's no more data.
///
/// After the engine has finished reading the specified number of samples, it will check
/// whether the value of `channels()` and/or `sample_rate()` have changed.
fn current_frame_len(&self) -> Option<usize>;
/// Returns the number of channels. Channels are always interleaved.
fn channels(&self) -> u16;
/// Returns the rate at which the source should be played. In number of samples per second.
fn sample_rate(&self) -> u32;
/// Returns the total duration of this source, if known.
///
/// `None` indicates at the same time "infinite" or "unknown".
fn total_duration(&self) -> Option<Duration>;
/// Stores the source in a buffer in addition to returning it. This iterator can be cloned.
#[inline]
fn buffered(self) -> Buffered<Self>
where
Self: Sized,
{
buffered::buffered(self)
}
/// Mixes this source with another one.
#[inline]
fn mix<S>(self, other: S) -> Mix<Self, S>
where
Self: Sized,
Self::Item: FromSample<S::Item>,
S: Source,
S::Item: Sample,
{
mix::mix(self, other)
}
/// Repeats this source forever.
///
/// Note that this works by storing the data in a buffer, so the amount of memory used is
/// proportional to the size of the sound.
#[inline]
fn repeat_infinite(self) -> Repeat<Self>
where
Self: Sized,
{
repeat::repeat(self)
}
/// Takes a certain duration of this source and then stops.
#[inline]
fn take_duration(self, duration: Duration) -> TakeDuration<Self>
where
Self: Sized,
{
take::take_duration(self, duration)
}
/// Delays the sound by a certain duration.
///
/// The rate and channels of the silence will use the same format as the first frame of the
/// source.
#[inline]
fn delay(self, duration: Duration) -> Delay<Self>
where
Self: Sized,
{
delay::delay(self, duration)
}
/// Immediately skips a certain duration of this source.
///
/// If the specified duration is longer than the source itself, `skip_duration` will skip to the end of the source.
#[inline]
fn skip_duration(self, duration: Duration) -> SkipDuration<Self>
where
Self: Sized,
{
skip::skip_duration(self, duration)
}
/// Amplifies the sound by the given value.
#[inline]
fn amplify(self, value: f32) -> Amplify<Self>
where
Self: Sized,
{
amplify::amplify(self, value)
}
/// Applies automatic gain control to the sound.
///
/// Automatic Gain Control (AGC) adjusts the amplitude of the audio signal
/// to maintain a consistent output level.
///
/// # Parameters
///
/// `target_level`:
/// **TL;DR**: Desired output level. 1.0 = original level, > 1.0 amplifies, < 1.0 reduces.
///
/// The desired output level, where 1.0 represents the original sound level.
/// Values above 1.0 will amplify the sound, while values below 1.0 will lower it.
/// For example, a target_level of 1.4 means that at normal sound levels, the AGC
/// will aim to increase the gain by a factor of 1.4, resulting in a minimum 40% amplification.
/// A recommended level is `1.0`, which maintains the original sound level.
///
/// `attack_time`:
/// **TL;DR**: Response time for volume increases. Shorter = faster but may cause abrupt changes. **Recommended: `4.0` seconds**.
///
/// The time (in seconds) for the AGC to respond to input level increases.
/// Shorter times mean faster response but may cause abrupt changes. Longer times result
/// in smoother transitions but slower reactions to sudden volume changes. Too short can
/// lead to overreaction to peaks, causing unnecessary adjustments. Too long can make the
/// AGC miss important volume changes or react too slowly to sudden loud passages. Very
/// high values might result in excessively loud output or sluggish response, as the AGC's
/// adjustment speed is limited by the attack time. Balance is key for optimal performance.
/// A recommended attack_time of `4.0` seconds provides a sweet spot for most applications.
///
/// `release_time`:
/// **TL;DR**: Response time for volume decreases. Shorter = faster gain reduction. **Recommended: `0.005` seconds**.
///
/// The time (in seconds) for the AGC to respond to input level decreases.
/// This parameter controls how quickly the gain is reduced when the signal level drops.
/// Shorter release times result in faster gain reduction, which can be useful for quick
/// adaptation to quieter passages but may lead to pumping effects. Longer release times
/// provide smoother transitions but may be slower to respond to sudden decreases in volume.
/// However, if the release_time is too high, the AGC may not be able to lower the gain
/// quickly enough, potentially leading to clipping and distorted sound before it can adjust.
/// Finding the right balance is crucial for maintaining natural-sounding dynamics and
/// preventing distortion. A recommended release_time of `0.005` seconds often works well for
/// general use, providing a good balance between responsiveness and smooth transitions.
///
/// `absolute_max_gain`:
/// **TL;DR**: Maximum allowed gain. Prevents over-amplification. **Recommended: `5.0`**.
///
/// The maximum gain that can be applied to the signal.
/// This parameter acts as a safeguard against excessive amplification of quiet signals
/// or background noise. It establishes an upper boundary for the AGC's signal boost,
/// effectively preventing distortion or overamplification of low-level sounds.
/// This is crucial for maintaining audio quality and preventing unexpected volume spikes.
/// A recommended value for `absolute_max_gain` is `5`, which provides a good balance between
/// amplification capability and protection against distortion in most scenarios.
///
/// Use `get_agc_control` to obtain a handle for real-time enabling/disabling of the AGC.
///
/// # Example (Quick start)
///
/// ```rust
/// // Apply Automatic Gain Control to the source (AGC is on by default)
/// let agc_source = source.automatic_gain_control(1.0, 4.0, 0.005, 5.0);
///
/// // Get a handle to control the AGC's enabled state (optional)
/// let agc_control = agc_source.get_agc_control();
///
/// // You can toggle AGC on/off at any time (optional)
/// agc_control.store(false, std::sync::atomic::Ordering::Relaxed);
///
/// // Add the AGC-controlled source to the sink
/// sink.append(agc_source);
///
/// // Note: Using agc_control is optional. If you don't need to toggle AGC,
/// // you can simply use the agc_source directly without getting agc_control.
/// ```
#[inline]
fn automatic_gain_control(
self,
target_level: f32,
attack_time: f32,
release_time: f32,
absolute_max_gain: f32,
) -> AutomaticGainControl<Self>
where
Self: Sized,
{
// Added Limits to prevent the AGC from blowing up. ;)
const MIN_ATTACK_TIME: f32 = 10.0;
const MIN_RELEASE_TIME: f32 = 10.0;
let attack_time = attack_time.min(MIN_ATTACK_TIME);
let release_time = release_time.min(MIN_RELEASE_TIME);
agc::automatic_gain_control(
self,
target_level,
attack_time,
release_time,
absolute_max_gain,
)
}
/// Mixes this sound fading out with another sound fading in for the given duration.
///
/// Only the crossfaded portion (beginning of self, beginning of other) is returned.
#[inline]
fn take_crossfade_with<S: Source>(self, other: S, duration: Duration) -> Crossfade<Self, S>
where
Self: Sized,
Self::Item: FromSample<S::Item>,
<S as Iterator>::Item: Sample,
{
crossfade::crossfade(self, other, duration)
}
/// Fades in the sound.
#[inline]
fn fade_in(self, duration: Duration) -> FadeIn<Self>
where
Self: Sized,
{
fadein::fadein(self, duration)
}
/// Fades out the sound.
#[inline]
fn fade_out(self, duration: Duration) -> FadeOut<Self>
where
Self: Sized,
{
fadeout::fadeout(self, duration)
}
/// Applies a linear gain ramp to the sound.
///
/// If `clamp_end` is `true`, all samples subsequent to the end of the ramp
/// will be scaled by the `end_value`. If `clamp_end` is `false`, all
/// subsequent samples will not have any scaling applied.
#[inline]
fn linear_gain_ramp(
self,
duration: Duration,
start_value: f32,
end_value: f32,
clamp_end: bool,
) -> LinearGainRamp<Self>
where
Self: Sized,
{
linear_ramp::linear_gain_ramp(self, duration, start_value, end_value, clamp_end)
}
/// Calls the `access` closure on `Self` the first time the source is iterated and every
/// time `period` elapses.
///
/// Later changes in either `sample_rate()` or `channels_count()` won't be reflected in
/// the rate of access.
///
/// The rate is based on playback speed, so both the following will call `access` when the
/// same samples are reached:
/// `periodic_access(Duration::from_secs(1), ...).speed(2.0)`
/// `speed(2.0).periodic_access(Duration::from_secs(2), ...)`
#[inline]
fn periodic_access<F>(self, period: Duration, access: F) -> PeriodicAccess<Self, F>
where
Self: Sized,
F: FnMut(&mut Self),
{
periodic::periodic(self, period, access)
}
/// Changes the play speed of the sound. Does not adjust the samples, only the playback speed.
///
/// # Note:
/// 1. **Increasing the speed will increase the pitch by the same factor**
/// - If you set the speed to 0.5 this will halve the frequency of the sound
/// lowering its pitch.
/// - If you set the speed to 2 the frequency will double raising the
/// pitch of the sound.
/// 2. **Change in the speed affect the total duration inversely**
/// - If you set the speed to 0.5, the total duration will be twice as long.
/// - If you set the speed to 2 the total duration will be halve of what it
/// was.
///
/// See [`Speed`] for details
#[inline]
fn speed(self, ratio: f32) -> Speed<Self>
where
Self: Sized,
{
speed::speed(self, ratio)
}
/// Adds a basic reverb effect.
///
/// This function requires the source to implement `Clone`. This can be done by using
/// `buffered()`.
///
/// # Example
///
/// ```ignore
/// use std::time::Duration;
///
/// let source = source.buffered().reverb(Duration::from_millis(100), 0.7);
/// ```
#[inline]
fn reverb(self, duration: Duration, amplitude: f32) -> Mix<Self, Delay<Amplify<Self>>>
where
Self: Sized + Clone,
{
let echo = self.clone().amplify(amplitude).delay(duration);
self.mix(echo)
}
/// Converts the samples of this source to another type.
#[inline]
fn convert_samples<D>(self) -> SamplesConverter<Self, D>
where
Self: Sized,
D: Sample,
{
SamplesConverter::new(self)
}
/// Makes the sound pausable.
// TODO: add example
#[inline]
fn pausable(self, initially_paused: bool) -> Pausable<Self>
where
Self: Sized,
{
pausable::pausable(self, initially_paused)
}
/// Makes the sound stoppable.
// TODO: add example
#[inline]
fn stoppable(self) -> Stoppable<Self>
where
Self: Sized,
{
stoppable::stoppable(self)
}
/// Adds a method [`Skippable::skip`] for skipping this source. Skipping
/// makes Source::next() return None. Which in turn makes the Sink skip to
/// the next source.
fn skippable(self) -> Skippable<Self>
where
Self: Sized,
{
skippable::skippable(self)
}
/// Start tracking the elapsed duration since the start of the underlying
/// source.
///
/// If a speedup and or delay is applied after this that will not be reflected
/// in the position returned by [`get_pos`](TrackPosition::get_pos).
///
/// This can get confusing when using [`get_pos()`](TrackPosition::get_pos)
/// together with [`Source::try_seek()`] as the latter does take all
/// speedup's and delay's into account. Its recommended therefore to apply
/// track_position after speedup's and delay's.
fn track_position(self) -> TrackPosition<Self>
where
Self: Sized,
{
position::track_position(self)
}
/// Applies a low-pass filter to the source.
/// **Warning**: Probably buggy.
#[inline]
fn low_pass(self, freq: u32) -> BltFilter<Self>
where
Self: Sized,
Self: Source<Item = f32>,
{
blt::low_pass(self, freq)
}
/// Applies a high-pass filter to the source.
#[inline]
fn high_pass(self, freq: u32) -> BltFilter<Self>
where
Self: Sized,
Self: Source<Item = f32>,
{
blt::high_pass(self, freq)
}
/// Applies a low-pass filter to the source while allowing the q (bandwidth) to be changed.
#[inline]
fn low_pass_with_q(self, freq: u32, q: f32) -> BltFilter<Self>
where
Self: Sized,
Self: Source<Item = f32>,
{
blt::low_pass_with_q(self, freq, q)
}
/// Applies a high-pass filter to the source while allowing the q (bandwidth) to be changed.
#[inline]
fn high_pass_with_q(self, freq: u32, q: f32) -> BltFilter<Self>
where
Self: Sized,
Self: Source<Item = f32>,
{
blt::high_pass_with_q(self, freq, q)
}
// There is no `can_seek()` method as it is impossible to use correctly. Between
// checking if a source supports seeking and actually seeking the sink can
// switch to a new source.
/// Attempts to seek to a given position in the current source.
///
/// As long as the duration of the source is known seek is guaranteed to saturate
/// at the end of the source. For example given a source that reports a total duration
/// of 42 seconds calling `try_seek()` with 60 seconds as argument will seek to
/// 42 seconds.
///
/// # Errors
/// This function will return [`SeekError::NotSupported`] if one of the underlying
/// sources does not support seeking.
///
/// It will return an error if an implementation ran
/// into one during the seek.
///
/// Seeking beyond the end of a source might return an error if the total duration of
/// the source is not known.
#[allow(unused_variables)]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
Err(SeekError::NotSupported {
underlying_source: std::any::type_name::<Self>(),
})
}
}
// We might add decoders requiring new error types, without non_exhaustive
// this would break users builds
/// Occurs when try_seek fails because the underlying decoder has an error or
/// does not support seeking.
#[non_exhaustive]
#[derive(Debug)]
pub enum SeekError {
/// One of the underlying sources does not support seeking
NotSupported {
/// The source that did not support seek
underlying_source: &'static str,
},
#[cfg(feature = "symphonia")]
/// The symphonia decoder ran into an issue
SymphoniaDecoder(crate::decoder::symphonia::SeekError),
#[cfg(feature = "wav")]
/// The hound (wav) decoder ran into an issue
HoundDecoder(std::io::Error),
// Prefer adding an enum variant to using this. Its meant for end users their
// own try_seek implementations
/// Any other error probably in a custom Source
Other(Box<dyn std::error::Error + Send>),
}
impl fmt::Display for SeekError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SeekError::NotSupported { underlying_source } => {
write!(
f,
"Seeking is not supported by source: {}",
underlying_source
)
}
#[cfg(feature = "symphonia")]
SeekError::SymphoniaDecoder(err) => write!(f, "Error seeking: {}", err),
#[cfg(feature = "wav")]
SeekError::HoundDecoder(err) => write!(f, "Error seeking in wav source: {}", err),
SeekError::Other(_) => write!(f, "An error occurred"),
}
}
}
impl std::error::Error for SeekError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
SeekError::NotSupported { .. } => None,
#[cfg(feature = "symphonia")]
SeekError::SymphoniaDecoder(err) => Some(err),
#[cfg(feature = "wav")]
SeekError::HoundDecoder(err) => Some(err),
SeekError::Other(err) => Some(err.as_ref()),
}
}
}
#[cfg(feature = "symphonia")]
impl From<crate::decoder::symphonia::SeekError> for SeekError {
fn from(source: crate::decoder::symphonia::SeekError) -> Self {
SeekError::SymphoniaDecoder(source)
}
}
impl SeekError {
/// Will the source remain playing at its position before the seek or is it
/// broken?
pub fn source_intact(&self) -> bool {
match self {
SeekError::NotSupported { .. } => true,
#[cfg(feature = "symphonia")]
SeekError::SymphoniaDecoder(_) => false,
#[cfg(feature = "wav")]
SeekError::HoundDecoder(_) => false,
SeekError::Other(_) => false,
}
}
}
macro_rules! source_pointer_impl {
($($sig:tt)+) => {
impl $($sig)+ {
#[inline]
fn current_frame_len(&self) -> Option<usize> {
(**self).current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
(**self).channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
(**self).sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
(**self).total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
(**self).try_seek(pos)
}
}
};
}
source_pointer_impl!(<S> Source for Box<dyn Source<Item = S>> where S: Sample,);
source_pointer_impl!(<S> Source for Box<dyn Source<Item = S> + Send> where S: Sample,);
source_pointer_impl!(<S> Source for Box<dyn Source<Item = S> + Send + Sync> where S: Sample,);
source_pointer_impl!(<'a, S, C> Source for &'a mut C where S: Sample, C: Source<Item = S>,);

158
vendor/rodio/src/source/noise.rs vendored Normal file
View File

@@ -0,0 +1,158 @@
//! Noise sources.
//!
//!
use crate::Source;
use super::SeekError;
use rand::{rngs::SmallRng, RngCore, SeedableRng};
/// Convenience function to create a new `WhiteNoise` noise source.
#[inline]
pub fn white(sample_rate: cpal::SampleRate) -> WhiteNoise {
WhiteNoise::new(sample_rate)
}
/// Convenience function to create a new `PinkNoise` noise source.
#[inline]
pub fn pink(sample_rate: cpal::SampleRate) -> PinkNoise {
PinkNoise::new(sample_rate)
}
/// Generates an infinite stream of random samples in [-1.0, 1.0]. This source generates random
/// samples as provided by the `rand::rngs::SmallRng` randomness source.
#[derive(Clone, Debug)]
pub struct WhiteNoise {
sample_rate: cpal::SampleRate,
rng: SmallRng,
}
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 {
Self {
sample_rate,
rng: SmallRng::seed_from_u64(seed),
}
}
/// Create a new white noise generator, seeding the RNG with system entropy.
pub fn new(sample_rate: cpal::SampleRate) -> Self {
Self {
sample_rate,
rng: SmallRng::from_entropy(),
}
}
}
impl Iterator for WhiteNoise {
type Item = f32;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let rand = self.rng.next_u32() as f32 / u32::MAX as f32;
let scaled = rand * 2.0 - 1.0;
Some(scaled)
}
}
impl Source for WhiteNoise {
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
1
}
#[inline]
fn sample_rate(&self) -> u32 {
self.sample_rate.0
}
#[inline]
fn total_duration(&self) -> Option<std::time::Duration> {
None
}
#[inline]
fn try_seek(&mut self, _: std::time::Duration) -> Result<(), SeekError> {
// Does nothing, should do nothing
Ok(())
}
}
/// Generates an infinite stream of pink noise samples in [-1.0, 1.0].
///
/// The output of the source is the result of taking the output of the `WhiteNoise` source and
/// filtering it according to a weighted-sum of seven FIR filters after [Paul Kellett's
/// method][pk_method] from *musicdsp.org*.
///
/// [pk_method]: https://www.musicdsp.org/en/latest/Filters/76-pink-noise-filter.html
pub struct PinkNoise {
white_noise: WhiteNoise,
b: [f32; 7],
}
impl PinkNoise {
pub fn new(sample_rate: cpal::SampleRate) -> Self {
Self {
white_noise: WhiteNoise::new(sample_rate),
b: [0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32],
}
}
}
impl Iterator for PinkNoise {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
let white = self.white_noise.next().unwrap();
self.b[0] = 0.99886 * self.b[0] + white * 0.0555179;
self.b[1] = 0.99332 * self.b[1] + white * 0.0750759;
self.b[2] = 0.969 * self.b[2] + white * 0.153852;
self.b[3] = 0.8665 * self.b[3] + white * 0.3104856;
self.b[4] = 0.550 * self.b[4] + white * 0.5329522;
self.b[5] = -0.7616 * self.b[5] - white * 0.016898;
let pink = self.b[0]
+ self.b[1]
+ self.b[2]
+ self.b[3]
+ self.b[4]
+ self.b[5]
+ self.b[6]
+ white * 0.5362;
self.b[6] = white * 0.115926;
Some(pink)
}
}
impl Source for PinkNoise {
fn current_frame_len(&self) -> Option<usize> {
None
}
fn channels(&self) -> u16 {
1
}
fn sample_rate(&self) -> u32 {
self.white_noise.sample_rate()
}
fn total_duration(&self) -> Option<std::time::Duration> {
None
}
#[inline]
fn try_seek(&mut self, _: std::time::Duration) -> Result<(), SeekError> {
// Does nothing, should do nothing
Ok(())
}
}

131
vendor/rodio/src/source/pausable.rs vendored Normal file
View File

@@ -0,0 +1,131 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Builds a `Pausable` object.
pub fn pausable<I>(source: I, paused: bool) -> Pausable<I>
where
I: Source,
I::Item: Sample,
{
let paused_channels = if paused {
Some(source.channels())
} else {
None
};
Pausable {
input: source,
paused_channels,
remaining_paused_samples: 0,
}
}
/// Wraps a source and makes it pausable by calling [`Pausable::set_paused`] on
/// this object. When the source is paused it returns zero value samples.
///
/// You can usually still use this from another source wrapping this one by
/// calling `inner_mut` on it. Similarly this provides [`Pausable::inner`] and
/// mutable/destructing variants for accessing the underlying source.
#[derive(Clone, Debug)]
pub struct Pausable<I> {
input: I,
paused_channels: Option<u16>,
remaining_paused_samples: u16,
}
impl<I> Pausable<I>
where
I: Source,
I::Item: Sample,
{
/// Sets whether the filter applies.
///
/// If set to true, the inner sound stops playing and no samples are processed from it.
#[inline]
pub fn set_paused(&mut self, paused: bool) {
match (self.paused_channels, paused) {
(None, true) => self.paused_channels = Some(self.input.channels()),
(Some(_), false) => self.paused_channels = None,
_ => (),
}
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for Pausable<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.remaining_paused_samples > 0 {
self.remaining_paused_samples -= 1;
return Some(I::Item::zero_value());
}
if let Some(paused_channels) = self.paused_channels {
self.remaining_paused_samples = paused_channels - 1;
return Some(I::Item::zero_value());
}
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for Pausable<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

174
vendor/rodio/src/source/periodic.rs vendored Normal file
View File

@@ -0,0 +1,174 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `PeriodicAccess` object.
pub fn periodic<I, F>(source: I, period: Duration, modifier: F) -> PeriodicAccess<I, F>
where
I: Source,
I::Item: Sample,
{
// TODO: handle the fact that the samples rate can change
// TODO: generally, just wrong
let update_ms = period.as_secs() as u32 * 1_000 + period.subsec_millis();
let update_frequency = (update_ms * source.sample_rate()) / 1000 * source.channels() as u32;
PeriodicAccess {
input: source,
modifier,
// Can overflow when subtracting if this is 0
update_frequency: if update_frequency == 0 {
1
} else {
update_frequency
},
samples_until_update: 1,
}
}
/// Calls a function on a source every time a period elapsed.
#[derive(Clone, Debug)]
pub struct PeriodicAccess<I, F> {
// The inner source.
input: I,
// Closure that gets access to `inner`.
modifier: F,
// The frequency with which local_volume should be updated by remote_volume
update_frequency: u32,
// How many samples remain until it is time to update local_volume with remote_volume.
samples_until_update: u32,
}
impl<I, F> PeriodicAccess<I, F>
where
I: Source,
I::Item: Sample,
F: FnMut(&mut I),
{
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I, F> Iterator for PeriodicAccess<I, F>
where
I: Source,
I::Item: Sample,
F: FnMut(&mut I),
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.samples_until_update -= 1;
if self.samples_until_update == 0 {
(self.modifier)(&mut self.input);
self.samples_until_update = self.update_frequency;
}
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I, F> Source for PeriodicAccess<I, F>
where
I: Source,
I::Item: Sample,
F: FnMut(&mut I),
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}
#[cfg(test)]
mod tests {
use std::cell::RefCell;
use std::time::Duration;
use crate::buffer::SamplesBuffer;
use crate::source::Source;
#[test]
fn stereo_access() {
// Stereo, 1Hz audio buffer
let inner = SamplesBuffer::new(2, 1, vec![10i16, -10, 10, -10, 20, -20]);
let cnt = RefCell::new(0);
let mut source = inner.periodic_access(Duration::from_millis(1000), |_src| {
*cnt.borrow_mut() += 1;
});
assert_eq!(*cnt.borrow(), 0);
// Always called on first access!
assert_eq!(source.next(), Some(10));
assert_eq!(*cnt.borrow(), 1);
// Called every 1 second afterwards
assert_eq!(source.next(), Some(-10));
assert_eq!(*cnt.borrow(), 1);
assert_eq!(source.next(), Some(10));
assert_eq!(*cnt.borrow(), 2);
assert_eq!(source.next(), Some(-10));
assert_eq!(*cnt.borrow(), 2);
assert_eq!(source.next(), Some(20));
assert_eq!(*cnt.borrow(), 3);
assert_eq!(source.next(), Some(-20));
assert_eq!(*cnt.borrow(), 3);
}
#[test]
fn fast_access_overflow() {
// 1hz is lower than 0.5 samples per 5ms
let inner = SamplesBuffer::new(1, 1, vec![10i16, -10, 10, -10, 20, -20]);
let mut source = inner.periodic_access(Duration::from_millis(5), |_src| {});
source.next();
source.next(); // Would overflow here.
}
}

199
vendor/rodio/src/source/position.rs vendored Normal file
View File

@@ -0,0 +1,199 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `TrackPosition` object. See trait docs for
/// details
pub fn track_position<I>(source: I) -> TrackPosition<I> {
TrackPosition {
input: source,
samples_counted: 0,
offset_duration: 0.0,
current_frame_sample_rate: 0,
current_frame_channels: 0,
current_frame_len: None,
}
}
/// Tracks the elapsed duration since the start of the underlying source.
#[derive(Debug)]
pub struct TrackPosition<I> {
input: I,
samples_counted: usize,
offset_duration: f64,
current_frame_sample_rate: u32,
current_frame_channels: u16,
current_frame_len: Option<usize>,
}
impl<I> TrackPosition<I> {
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> TrackPosition<I>
where
I: Source,
I::Item: Sample,
{
/// Returns the position of the underlying source relative to its start.
///
/// If a speedup and or delay is applied after applying a
/// [`Source::track_position`] it will not be reflected in the position
/// returned by [`get_pos`](TrackPosition::get_pos).
///
/// This can get confusing when using [`get_pos()`](TrackPosition::get_pos)
/// together with [`Source::try_seek()`] as the the latter does take all
/// speedup's and delay's into account. Its recommended therefore to apply
/// track_position after speedup's and delay's.
#[inline]
pub fn get_pos(&self) -> Duration {
let seconds = self.samples_counted as f64
/ self.input.sample_rate() as f64
/ self.input.channels() as f64
+ self.offset_duration;
Duration::from_secs_f64(seconds)
}
#[inline]
fn set_current_frame(&mut self) {
self.current_frame_len = self.current_frame_len();
self.current_frame_sample_rate = self.sample_rate();
self.current_frame_channels = self.channels();
}
}
impl<I> Iterator for TrackPosition<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
// This should only be executed once at the first call to next.
if self.current_frame_len.is_none() {
self.set_current_frame();
}
let item = self.input.next();
if item.is_some() {
self.samples_counted += 1;
// At the end of a frame add the duration of this frame to
// offset_duration and start collecting samples again.
if Some(self.samples_counted) == self.current_frame_len() {
self.offset_duration += self.samples_counted as f64
/ self.current_frame_sample_rate as f64
/ self.current_frame_channels as f64;
// Reset.
self.samples_counted = 0;
self.set_current_frame();
};
};
item
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for TrackPosition<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
let result = self.input.try_seek(pos);
if result.is_ok() {
self.offset_duration = pos.as_secs_f64();
// This assumes that the seek implementation of the codec always
// starts again at the beginning of a frame. Which is the case with
// symphonia.
self.samples_counted = 0;
}
result
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use crate::buffer::SamplesBuffer;
use crate::source::Source;
#[test]
fn test_position() {
let inner = SamplesBuffer::new(1, 1, vec![10i16, -10, 10, -10, 20, -20]);
let mut source = inner.track_position();
assert_eq!(source.get_pos().as_secs_f32(), 0.0);
source.next();
assert_eq!(source.get_pos().as_secs_f32(), 1.0);
source.next();
assert_eq!(source.get_pos().as_secs_f32(), 2.0);
assert_eq!(source.try_seek(Duration::new(1, 0)).is_ok(), true);
assert_eq!(source.get_pos().as_secs_f32(), 1.0);
}
#[test]
fn test_position_in_presence_of_speedup() {
let inner = SamplesBuffer::new(1, 1, vec![10i16, -10, 10, -10, 20, -20]);
let mut source = inner.speed(2.0).track_position();
assert_eq!(source.get_pos().as_secs_f32(), 0.0);
source.next();
assert_eq!(source.get_pos().as_secs_f32(), 0.5);
source.next();
assert_eq!(source.get_pos().as_secs_f32(), 1.0);
assert_eq!(source.try_seek(Duration::new(1, 0)).is_ok(), true);
assert_eq!(source.get_pos().as_secs_f32(), 1.0);
}
}

108
vendor/rodio/src/source/repeat.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
use std::time::Duration;
use crate::source::buffered::Buffered;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `Repeat` object.
pub fn repeat<I>(input: I) -> Repeat<I>
where
I: Source,
I::Item: Sample,
{
let input = input.buffered();
Repeat {
inner: input.clone(),
next: input,
}
}
/// A source that repeats the given source.
pub struct Repeat<I>
where
I: Source,
I::Item: Sample,
{
inner: Buffered<I>,
next: Buffered<I>,
}
impl<I> Iterator for Repeat<I>
where
I: Source,
I::Item: Sample,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
if let Some(value) = self.inner.next() {
return Some(value);
}
self.inner = self.next.clone();
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
// infinite
(0, None)
}
}
impl<I> Source for Repeat<I>
where
I: Iterator + Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
match self.inner.current_frame_len() {
Some(0) => self.next.current_frame_len(),
a => a,
}
}
#[inline]
fn channels(&self) -> u16 {
match self.inner.current_frame_len() {
Some(0) => self.next.channels(),
_ => self.inner.channels(),
}
}
#[inline]
fn sample_rate(&self) -> u32 {
match self.inner.current_frame_len() {
Some(0) => self.next.sample_rate(),
_ => self.inner.sample_rate(),
}
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.inner.try_seek(pos)
}
}
impl<I> Clone for Repeat<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn clone(&self) -> Repeat<I> {
Repeat {
inner: self.inner.clone(),
next: self.next.clone(),
}
}
}

View File

@@ -0,0 +1,104 @@
use std::marker::PhantomData;
use std::time::Duration;
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)]
pub struct SamplesConverter<I, D> {
inner: I,
dest: PhantomData<D>,
}
impl<I, D> SamplesConverter<I, D> {
/// Wrap the input and lazily converts the samples it provides to the type
/// specified by the generic parameter D
#[inline]
pub fn new(input: I) -> SamplesConverter<I, D> {
SamplesConverter {
inner: input,
dest: PhantomData,
}
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.inner
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.inner
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.inner
}
}
impl<I, D> Iterator for SamplesConverter<I, D>
where
I: Source,
I::Item: Sample,
D: FromSample<I::Item> + Sample,
{
type Item = D;
#[inline]
fn next(&mut self) -> Option<D> {
self.inner.next().map(|s| CpalSample::from_sample(s))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<I, D> ExactSizeIterator for SamplesConverter<I, D>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
D: FromSample<I::Item> + Sample,
{
}
impl<I, D> Source for SamplesConverter<I, D>
where
I: Source,
I::Item: Sample,
D: FromSample<I::Item> + Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.inner.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.inner.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.inner.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.inner.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.inner.try_seek(pos)
}
}

View File

@@ -0,0 +1,185 @@
//! Generator sources for various periodic test waveforms.
//!
//! This module provides several periodic, deterministic waveforms for testing other sources and
//! for simple additive sound synthesis. Every source is monoaural and in the codomain [-1.0f32,
//! 1.0f32].
//!
//! # Example
//!
//! ```
//! use rodio::source::{SignalGenerator,Function};
//!
//! let tone = SignalGenerator::new(cpal::SampleRate(48000), 440.0, Function::Sine);
//! ```
use std::f32::consts::TAU;
use std::time::Duration;
use super::SeekError;
use crate::Source;
/// Waveform functions.
#[derive(Clone, Debug)]
pub enum Function {
/// A sinusoidal waveform.
Sine,
/// A triangle waveform.
Triangle,
/// A square wave, rising edge at t=0.
Square,
/// A rising sawtooth wave.
Sawtooth,
}
impl Function {
/// Create a single sample for the given waveform
#[inline]
fn render(&self, i: u64, period: f32) -> f32 {
let cycle_pos: f32 = i as f32 / period;
match self {
Self::Sine => (TAU * cycle_pos).sin(),
Self::Triangle => 4.0f32 * (cycle_pos - (cycle_pos + 0.5f32).floor()).abs() - 1f32,
Self::Square => {
if cycle_pos % 1.0f32 < 0.5f32 {
1.0f32
} else {
-1.0f32
}
}
Self::Sawtooth => 2.0f32 * (cycle_pos - (cycle_pos + 0.5f32).floor()),
}
}
}
/// An infinite source that produces one of a selection of test waveforms.
#[derive(Clone, Debug)]
pub struct SignalGenerator {
sample_rate: cpal::SampleRate,
period: f32,
function: Function,
i: u64,
}
impl SignalGenerator {
/// Create a new `TestWaveform` object that generates an endless waveform
/// `f`.
///
/// # Panics
///
/// Will panic if `frequency` is equal to zero.
#[inline]
pub fn new(sample_rate: cpal::SampleRate, frequency: f32, f: Function) -> SignalGenerator {
assert!(frequency != 0.0, "frequency must be greater than zero");
let period = sample_rate.0 as f32 / frequency;
SignalGenerator {
sample_rate,
period,
function: f,
i: 0,
}
}
}
impl Iterator for SignalGenerator {
type Item = f32;
#[inline]
fn next(&mut self) -> Option<f32> {
let val = Some(self.function.render(self.i, self.period));
self.i += 1;
val
}
}
impl Source for SignalGenerator {
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
1
}
#[inline]
fn sample_rate(&self) -> u32 {
self.sample_rate.0
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
#[inline]
fn try_seek(&mut self, duration: Duration) -> Result<(), SeekError> {
self.i = (self.sample_rate.0 as f32 * duration.as_secs_f32()) as u64;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::source::{Function, SignalGenerator};
use approx::assert_abs_diff_eq;
#[test]
fn square() {
let mut wf = SignalGenerator::new(cpal::SampleRate(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));
assert_eq!(wf.next(), Some(-1.0f32));
assert_eq!(wf.next(), Some(1.0f32));
assert_eq!(wf.next(), Some(1.0f32));
assert_eq!(wf.next(), Some(-1.0f32));
assert_eq!(wf.next(), Some(-1.0f32));
}
#[test]
fn triangle() {
let mut wf = SignalGenerator::new(cpal::SampleRate(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));
assert_eq!(wf.next(), Some(0.5f32));
assert_eq!(wf.next(), Some(1.0f32));
assert_eq!(wf.next(), Some(0.5f32));
assert_eq!(wf.next(), Some(0.0f32));
assert_eq!(wf.next(), Some(-0.5f32));
assert_eq!(wf.next(), Some(-1.0f32));
assert_eq!(wf.next(), Some(-0.5f32));
assert_eq!(wf.next(), Some(0.0f32));
assert_eq!(wf.next(), Some(0.5f32));
assert_eq!(wf.next(), Some(1.0f32));
assert_eq!(wf.next(), Some(0.5f32));
assert_eq!(wf.next(), Some(0.0f32));
assert_eq!(wf.next(), Some(-0.5f32));
}
#[test]
fn saw() {
let mut wf = SignalGenerator::new(cpal::SampleRate(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));
assert_eq!(wf.next(), Some(-0.5f32));
assert_eq!(wf.next(), Some(0.0f32));
assert_eq!(wf.next(), Some(0.5f32));
assert_eq!(wf.next(), Some(-1.0f32));
}
#[test]
fn sine() {
let mut wf = SignalGenerator::new(cpal::SampleRate(1000), 100f32, Function::Sine);
assert_abs_diff_eq!(wf.next().unwrap(), 0.0f32);
assert_abs_diff_eq!(wf.next().unwrap(), 0.58778525f32);
assert_abs_diff_eq!(wf.next().unwrap(), 0.95105652f32);
assert_abs_diff_eq!(wf.next().unwrap(), 0.95105652f32);
assert_abs_diff_eq!(wf.next().unwrap(), 0.58778525f32);
assert_abs_diff_eq!(wf.next().unwrap(), 0.0f32);
assert_abs_diff_eq!(wf.next().unwrap(), -0.58778554f32);
}
}

66
vendor/rodio/src/source/sine.rs vendored Normal file
View File

@@ -0,0 +1,66 @@
use std::time::Duration;
use crate::source::{Function, SignalGenerator};
use crate::Source;
use super::SeekError;
/// An infinite source that produces a sine.
///
/// Always has a rate of 48kHz and one channel.
#[derive(Clone, Debug)]
pub struct SineWave {
test_sine: SignalGenerator,
}
impl SineWave {
const SAMPLE_RATE: u32 = 48000;
/// 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),
}
}
}
impl Iterator for SineWave {
type Item = f32;
#[inline]
fn next(&mut self) -> Option<f32> {
self.test_sine.next()
}
}
impl Source for SineWave {
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
1
}
#[inline]
fn sample_rate(&self) -> u32 {
Self::SAMPLE_RATE
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
/// `try_seek()` does nothing on the sine generator. If you need to
/// generate a sine tone with a precise phase or sample offset, consider
/// using `skip::skip_samples()`.
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Ok(())
}
}

259
vendor/rodio/src/source/skip.rs vendored Normal file
View File

@@ -0,0 +1,259 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
const NS_PER_SECOND: u128 = 1_000_000_000;
/// Internal function that builds a `SkipDuration` object.
pub fn skip_duration<I>(mut input: I, duration: Duration) -> SkipDuration<I>
where
I: Source,
I::Item: Sample,
{
do_skip_duration(&mut input, duration);
SkipDuration {
input,
skipped_duration: duration,
}
}
/// Skips specified `duration` of the given `input` source from it's current position.
fn do_skip_duration<I>(input: &mut I, mut duration: Duration)
where
I: Source,
I::Item: Sample,
{
while duration > Duration::new(0, 0) {
if input.current_frame_len().is_none() {
// Sample rate and the amount of channels will be the same till the end.
do_skip_duration_unchecked(input, duration);
return;
}
// .unwrap() safety: if `current_frame_len()` is None, the body of the `if` statement
// above returns before we get here.
let frame_len: usize = input.current_frame_len().unwrap();
// If frame_len is zero, then there is no more data to skip. Instead
// just bail out.
if frame_len == 0 {
return;
}
let ns_per_sample: u128 =
NS_PER_SECOND / input.sample_rate() as u128 / input.channels() as u128;
// Check if we need to skip only part of the current frame.
if frame_len as u128 * ns_per_sample > duration.as_nanos() {
skip_samples(input, (duration.as_nanos() / ns_per_sample) as usize);
return;
}
skip_samples(input, frame_len);
duration -= Duration::from_nanos((frame_len * ns_per_sample as usize) as u64);
}
}
/// Skips specified `duration` from the `input` source assuming that sample rate
/// and amount of channels are not changing.
fn do_skip_duration_unchecked<I>(input: &mut I, duration: Duration)
where
I: Source,
I::Item: Sample,
{
let samples_per_channel: u128 =
duration.as_nanos() * input.sample_rate() as u128 / NS_PER_SECOND;
let samples_to_skip: u128 = samples_per_channel * input.channels() as u128;
skip_samples(input, samples_to_skip as usize);
}
/// Skips `n` samples from the given `input` source.
fn skip_samples<I>(input: &mut I, n: usize)
where
I: Source,
I::Item: Sample,
{
for _ in 0..n {
if input.next().is_none() {
break;
}
}
}
/// A source that skips specified duration of the given source from it's current position.
#[derive(Clone, Debug)]
pub struct SkipDuration<I> {
input: I,
skipped_duration: Duration,
}
impl<I> SkipDuration<I>
where
I: Source,
I::Item: Sample,
{
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for SkipDuration<I>
where
I: Source,
I::Item: Sample,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for SkipDuration<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration().map(|val| {
val.checked_sub(self.skipped_duration)
.unwrap_or_else(|| Duration::from_secs(0))
})
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use crate::buffer::SamplesBuffer;
use crate::source::Source;
fn test_skip_duration_samples_left(
channels: u16,
sample_rate: u32,
seconds: u32,
seconds_to_skip: u32,
) {
let data: Vec<f32> = (1..=(sample_rate * channels as u32 * seconds))
.map(|_| 0f32)
.collect();
let test_buffer = SamplesBuffer::new(channels, sample_rate, data);
let seconds_left = seconds.saturating_sub(seconds_to_skip);
let samples_left_expected = (sample_rate * channels as u32 * seconds_left) as usize;
let samples_left = test_buffer
.skip_duration(Duration::from_secs(seconds_to_skip as u64))
.count();
assert_eq!(samples_left, samples_left_expected);
}
macro_rules! skip_duration_test_block {
($(channels: $ch:expr, sample rate: $sr:expr, seconds: $sec:expr, seconds to skip: $sec_to_skip:expr;)+) => {
$(
test_skip_duration_samples_left($ch, $sr, $sec, $sec_to_skip);
)+
}
}
#[test]
fn skip_duration_shorter_than_source() {
skip_duration_test_block! {
channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 3;
channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 3;
channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 3;
channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 3;
channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 3;
channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 3;
}
}
#[test]
fn skip_duration_zero_duration() {
skip_duration_test_block! {
channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 0;
channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 0;
channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 0;
channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 0;
channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 0;
channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 0;
}
}
#[test]
fn skip_duration_longer_than_source() {
skip_duration_test_block! {
channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 5;
channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 11;
channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 5;
channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 11;
channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 5;
channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 11;
}
}
#[test]
fn skip_duration_equal_to_source_length() {
skip_duration_test_block! {
channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 1;
channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 10;
channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 1;
channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 10;
channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 1;
channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 10;
}
}
}

104
vendor/rodio/src/source/skippable.rs vendored Normal file
View File

@@ -0,0 +1,104 @@
use std::time::Duration;
use crate::Sample;
use crate::Source;
use super::SeekError;
/// Wrap the source in a skippable. It allows ending the current source early by
/// calling [`Skippable::skip`]. If this source is in a queue such as the Sink
/// ending the source early is equal to skipping the source.
pub fn skippable<I>(source: I) -> Skippable<I> {
Skippable {
input: source,
do_skip: false,
}
}
/// Wrap the source in a skippable. It allows ending the current source early by
/// calling [`Skippable::skip`]. If this source is in a queue such as the Sink
/// ending the source early is equal to skipping the source.
#[derive(Clone, Debug)]
pub struct Skippable<I> {
input: I,
do_skip: bool,
}
impl<I> Skippable<I> {
/// Skips the current source
#[inline]
pub fn skip(&mut self) {
self.do_skip = true;
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for Skippable<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.do_skip {
None
} else {
self.input.next()
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for Skippable<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

129
vendor/rodio/src/source/spatial.rs vendored Normal file
View File

@@ -0,0 +1,129 @@
use std::time::Duration;
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.
#[derive(Clone)]
pub struct Spatial<I>
where
I: Source,
I::Item: Sample,
{
input: ChannelVolume<I>,
}
fn dist_sq(a: [f32; 3], b: [f32; 3]) -> f32 {
a.iter()
.zip(b.iter())
.map(|(a, b)| (a - b) * (a - b))
.sum::<f32>()
}
impl<I> Spatial<I>
where
I: Source,
I::Item: Sample,
{
/// Builds a new `SpatialSink`, beginning playback on a stream.
pub fn new(
input: I,
emitter_position: [f32; 3],
left_ear: [f32; 3],
right_ear: [f32; 3],
) -> Spatial<I>
where
I: Source,
I::Item: Sample,
{
let mut ret = Spatial {
input: ChannelVolume::new(input, vec![0.0, 0.0]),
};
ret.set_positions(emitter_position, left_ear, right_ear);
ret
}
/// Sets the position of the emitter and ears in the 3D world.
pub fn set_positions(
&mut self,
emitter_pos: [f32; 3],
left_ear: [f32; 3],
right_ear: [f32; 3],
) {
debug_assert!(left_ear != right_ear);
let left_dist_sq = dist_sq(left_ear, emitter_pos);
let right_dist_sq = dist_sq(right_ear, emitter_pos);
let max_diff = dist_sq(left_ear, right_ear).sqrt();
let left_dist = left_dist_sq.sqrt();
let right_dist = right_dist_sq.sqrt();
let left_diff_modifier = (((left_dist - right_dist) / max_diff + 1.0) / 4.0 + 0.5).min(1.0);
let right_diff_modifier =
(((right_dist - left_dist) / max_diff + 1.0) / 4.0 + 0.5).min(1.0);
let left_dist_modifier = (1.0 / left_dist_sq).min(1.0);
let right_dist_modifier = (1.0 / right_dist_sq).min(1.0);
self.input
.set_volume(0, left_diff_modifier * left_dist_modifier);
self.input
.set_volume(1, right_diff_modifier * right_dist_modifier);
}
}
impl<I> Iterator for Spatial<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for Spatial<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for Spatial<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

149
vendor/rodio/src/source/speed.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
//! Playback Speed control Module.
//!
//! The main concept of this module is the [`Speed`] struct, which
//! encapsulates playback speed controls of the current sink.
//!
//! In order to speed up a sink, the speed struct:
//! - Increases the current sample rate by the given factor
//! - Updates the total duration function to cover for the new factor by dividing by the factor
//! - Updates the try_seek function by multiplying the audio position by the factor
//!
//! To speed up a source from sink all you need to do is call the `set_speed(factor: f32)` function
//! For example, here is how you speed up your sound by using sink or playing raw
//!
//! ```no_run
//!# use std::fs::File;
//!# use std::io::BufReader;
//!# use rodio::{Decoder, Sink, OutputStream, source::{Source, SineWave}};
//!
//! // Get an output stream handle to the default physical sound device.
//! // Note that no sound will be played if _stream is dropped
//! let (_stream, stream_handle) = OutputStream::try_default().unwrap();
//! // Load a sound from a file, using a path relative to Cargo.toml
//! let file = BufReader::new(File::open("examples/music.ogg").unwrap());
//! // Decode that sound file into a source
//! let source = Decoder::new(file).unwrap();
//! // Play the sound directly on the device 2x faster
//! stream_handle.play_raw(source.convert_samples().speed(2.0));
//! std::thread::sleep(std::time::Duration::from_secs(5));
//! ```
//! here is how you would do it using the sink
//! ```
//! let source = SineWave::new(440.0)
//! .take_duration(Duration::from_secs_f32(20.25))
//! .amplify(0.20);
//!
//! let sink = Sink::try_new(&stream_handle)?;
//! sink.set_speed(2.0);
//! sink.append(source);
//! std::thread::sleep(std::time::Duration::from_secs(5));
//! ```
//! Notice the increase in pitch as the factor increases
//!
//! Since the samples are played faster the audio wave get shorter increasing their frequencies
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `Speed` object.
pub fn speed<I>(input: I, factor: f32) -> Speed<I> {
Speed { input, factor }
}
/// Filter that modifies each sample by a given value.
#[derive(Clone, Debug)]
pub struct Speed<I> {
input: I,
factor: f32,
}
impl<I> Speed<I>
where
I: Source,
I::Item: Sample,
{
/// Modifies the speed factor.
#[inline]
pub fn set_factor(&mut self, factor: f32) {
self.factor = factor;
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for Speed<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
self.input.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> ExactSizeIterator for Speed<I>
where
I: Source + ExactSizeIterator,
I::Item: Sample,
{
}
impl<I> Source for Speed<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
(self.input.sample_rate() as f32 * self.factor) as u32
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration().map(|d| d.div_f32(self.factor))
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
let pos_accounting_for_speedup = pos.mul_f32(self.factor);
self.input.try_seek(pos_accounting_for_speedup)
}
}

99
vendor/rodio/src/source/stoppable.rs vendored Normal file
View File

@@ -0,0 +1,99 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// This is the same as [`skippable`](crate::source::skippable) see its docs
pub fn stoppable<I>(source: I) -> Stoppable<I> {
Stoppable {
input: source,
stopped: false,
}
}
/// This is the same as [`Skippable`](crate::source::Skippable) see its docs
#[derive(Clone, Debug)]
pub struct Stoppable<I> {
input: I,
stopped: bool,
}
impl<I> Stoppable<I> {
/// Stops the sound.
#[inline]
pub fn stop(&mut self) {
self.stopped = true;
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
}
impl<I> Iterator for Stoppable<I>
where
I: Source,
I::Item: Sample,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.stopped {
None
} else {
self.input.next()
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.input.size_hint()
}
}
impl<I> Source for Stoppable<I>
where
I: Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.input.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.input.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

189
vendor/rodio/src/source/take.rs vendored Normal file
View File

@@ -0,0 +1,189 @@
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// Internal function that builds a `TakeDuration` object.
pub fn take_duration<I>(input: I, duration: Duration) -> TakeDuration<I>
where
I: Source,
I::Item: Sample,
{
TakeDuration {
current_frame_len: input.current_frame_len(),
duration_per_sample: TakeDuration::get_duration_per_sample(&input),
input,
remaining_duration: duration,
requested_duration: duration,
filter: None,
}
}
/// A filter that can be applied to a `TakeDuration`.
#[derive(Clone, Debug)]
enum DurationFilter {
FadeOut,
}
impl DurationFilter {
fn apply<I: Iterator>(
&self,
sample: <I as Iterator>::Item,
parent: &TakeDuration<I>,
) -> <I as Iterator>::Item
where
I::Item: Sample,
{
use self::DurationFilter::*;
match self {
FadeOut => {
let remaining = parent.remaining_duration.as_millis() as f32;
let total = parent.requested_duration.as_millis() as f32;
sample.amplify(remaining / total)
}
}
}
}
const NANOS_PER_SEC: u64 = 1_000_000_000;
/// A source that truncates the given source to a certain duration.
#[derive(Clone, Debug)]
pub struct TakeDuration<I> {
input: I,
remaining_duration: Duration,
requested_duration: Duration,
filter: Option<DurationFilter>,
// Remaining samples in current frame.
current_frame_len: Option<usize>,
// Only updated when the current frame len is exhausted.
duration_per_sample: Duration,
}
impl<I> TakeDuration<I>
where
I: Source,
I::Item: Sample,
{
/// Returns the duration elapsed for each sample extracted.
#[inline]
fn get_duration_per_sample(input: &I) -> Duration {
let ns = NANOS_PER_SEC / (input.sample_rate() as u64 * input.channels() as u64);
// \|/ the maximum value of `ns` is one billion, so this can't fail
Duration::new(0, ns as u32)
}
/// Returns a reference to the inner source.
#[inline]
pub fn inner(&self) -> &I {
&self.input
}
/// Returns a mutable reference to the inner source.
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.input
}
/// Returns the inner source.
#[inline]
pub fn into_inner(self) -> I {
self.input
}
/// Make the truncated source end with a FadeOut. The fadeout covers the
/// entire length of the take source.
pub fn set_filter_fadeout(&mut self) {
self.filter = Some(DurationFilter::FadeOut);
}
/// Remove any filter set.
pub fn clear_filter(&mut self) {
self.filter = None;
}
}
impl<I> Iterator for TakeDuration<I>
where
I: Source,
I::Item: Sample,
{
type Item = <I as Iterator>::Item;
fn next(&mut self) -> Option<<I as Iterator>::Item> {
if let Some(frame_len) = self.current_frame_len.take() {
if frame_len > 0 {
self.current_frame_len = Some(frame_len - 1);
} else {
self.current_frame_len = self.input.current_frame_len();
// Sample rate might have changed
self.duration_per_sample = Self::get_duration_per_sample(&self.input);
}
}
if self.remaining_duration <= self.duration_per_sample {
None
} else if let Some(sample) = self.input.next() {
let sample = match &self.filter {
Some(filter) => filter.apply(sample, self),
None => sample,
};
self.remaining_duration -= self.duration_per_sample;
Some(sample)
} else {
None
}
}
// TODO: size_hint
}
impl<I> Source for TakeDuration<I>
where
I: Iterator + Source,
I::Item: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
let remaining_nanos = self.remaining_duration.as_secs() * NANOS_PER_SEC
+ self.remaining_duration.subsec_nanos() as u64;
let nanos_per_sample = self.duration_per_sample.as_secs() * NANOS_PER_SEC
+ self.duration_per_sample.subsec_nanos() as u64;
let remaining_samples = (remaining_nanos / nanos_per_sample) as usize;
self.input
.current_frame_len()
.filter(|value| *value < remaining_samples)
.or(Some(remaining_samples))
}
#[inline]
fn channels(&self) -> u16 {
self.input.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.input.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
if let Some(duration) = self.input.total_duration() {
if duration < self.requested_duration {
Some(duration)
} else {
Some(self.requested_duration)
}
} else {
None
}
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.input.try_seek(pos)
}
}

212
vendor/rodio/src/source/uniform.rs vendored Normal file
View File

@@ -0,0 +1,212 @@
use std::cmp;
use std::time::Duration;
use cpal::FromSample;
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.
///
/// It implements `Source` as well, but all the data is guaranteed to be in a
/// single frame whose channels and samples rate have been passed to `new`.
#[derive(Clone)]
pub struct UniformSourceIterator<I, D>
where
I: Source,
I::Item: Sample,
D: Sample,
{
inner: Option<DataConverter<ChannelCountConverter<SampleRateConverter<Take<I>>>, D>>,
target_channels: u16,
target_sample_rate: u32,
total_duration: Option<Duration>,
}
impl<I, D> UniformSourceIterator<I, D>
where
I: Source,
I::Item: Sample,
D: Sample,
{
/// Wrap a `Source` and lazily convert its samples to a specific type,
/// sample-rate and channels count.
#[inline]
pub fn new(
input: I,
target_channels: u16,
target_sample_rate: u32,
) -> UniformSourceIterator<I, D> {
let total_duration = input.total_duration();
let input = UniformSourceIterator::bootstrap(input, target_channels, target_sample_rate);
UniformSourceIterator {
inner: Some(input),
target_channels,
target_sample_rate,
total_duration,
}
}
#[inline]
fn bootstrap(
input: I,
target_channels: u16,
target_sample_rate: u32,
) -> DataConverter<ChannelCountConverter<SampleRateConverter<Take<I>>>, D> {
// Limit the frame length to something reasonable
let frame_len = input.current_frame_len().map(|x| x.min(32768));
let from_channels = input.channels();
let from_sample_rate = input.sample_rate();
let input = Take {
iter: input,
n: frame_len,
};
let input = SampleRateConverter::new(
input,
cpal::SampleRate(from_sample_rate),
cpal::SampleRate(target_sample_rate),
from_channels,
);
let input = ChannelCountConverter::new(input, from_channels, target_channels);
DataConverter::new(input)
}
}
impl<I, D> Iterator for UniformSourceIterator<I, D>
where
I: Source,
I::Item: Sample,
D: FromSample<I::Item> + Sample,
{
type Item = D;
#[inline]
fn next(&mut self) -> Option<D> {
if let Some(value) = self.inner.as_mut().unwrap().next() {
return Some(value);
}
let input = self
.inner
.take()
.unwrap()
.into_inner()
.into_inner()
.into_inner()
.iter;
let mut input =
UniformSourceIterator::bootstrap(input, self.target_channels, self.target_sample_rate);
let value = input.next();
self.inner = Some(input);
value
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.inner.as_ref().unwrap().size_hint().0, None)
}
}
impl<I, D> Source for UniformSourceIterator<I, D>
where
I: Iterator + Source,
I::Item: Sample,
D: FromSample<I::Item> + Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
self.target_channels
}
#[inline]
fn sample_rate(&self) -> u32 {
self.target_sample_rate
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.total_duration
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
if let Some(input) = self.inner.as_mut() {
input
.inner_mut()
.inner_mut()
.inner_mut()
.inner_mut()
.try_seek(pos)
} else {
Ok(())
}
}
}
#[derive(Clone, Debug)]
struct Take<I> {
iter: I,
n: Option<usize>,
}
impl<I> Take<I> {
#[inline]
pub fn inner_mut(&mut self) -> &mut I {
&mut self.iter
}
}
impl<I> Iterator for Take<I>
where
I: Iterator,
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
if let Some(n) = &mut self.n {
if *n != 0 {
*n -= 1;
self.iter.next()
} else {
None
}
} else {
self.iter.next()
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if let Some(n) = self.n {
let (lower, upper) = self.iter.size_hint();
let lower = cmp::min(lower, n);
let upper = match upper {
Some(x) if x < n => Some(x),
_ => Some(n),
};
(lower, upper)
} else {
self.iter.size_hint()
}
}
}
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}

91
vendor/rodio/src/source/zero.rs vendored Normal file
View File

@@ -0,0 +1,91 @@
use std::marker::PhantomData;
use std::time::Duration;
use crate::{Sample, Source};
use super::SeekError;
/// 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<S> {
channels: u16,
sample_rate: u32,
num_samples: Option<usize>,
marker: PhantomData<S>,
}
impl<S> Zero<S> {
/// Create a new source that never ends and produces total silence.
#[inline]
pub fn new(channels: u16, sample_rate: u32) -> Zero<S> {
Zero {
channels,
sample_rate,
num_samples: None,
marker: PhantomData,
}
}
/// 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<S> {
Zero {
channels,
sample_rate,
num_samples: Some(num_samples),
marker: PhantomData,
}
}
}
impl<S> Iterator for Zero<S>
where
S: Sample,
{
type Item = S;
#[inline]
fn next(&mut self) -> Option<S> {
if let Some(num_samples) = self.num_samples {
if num_samples > 0 {
self.num_samples = Some(num_samples - 1);
Some(S::zero_value())
} else {
None
}
} else {
Some(S::zero_value())
}
}
}
impl<S> Source for Zero<S>
where
S: Sample,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.num_samples
}
#[inline]
fn channels(&self) -> u16 {
self.channels
}
#[inline]
fn sample_rate(&self) -> u32 {
self.sample_rate
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Ok(())
}
}