mirror of
https://github.com/RustAudio/rodio
synced 2024-12-05 01:39:15 +00:00
Revert extra changes for merge request
This commit is contained in:
parent
ebc673e315
commit
b720273847
6 changed files with 99 additions and 25 deletions
|
@ -259,6 +259,12 @@ mod test {
|
||||||
use cpal::SampleRate;
|
use cpal::SampleRate;
|
||||||
use quickcheck::quickcheck;
|
use quickcheck::quickcheck;
|
||||||
|
|
||||||
|
// TODO: Remove once cpal 0.12.2 is released and the dependency is updated
|
||||||
|
// (cpal#483 implemented ops::Mul on SampleRate)
|
||||||
|
const fn multiply_rate(r: SampleRate, k: u32) -> SampleRate {
|
||||||
|
SampleRate(k * r.0)
|
||||||
|
}
|
||||||
|
|
||||||
quickcheck! {
|
quickcheck! {
|
||||||
/// Check that resampling an empty input produces no output.
|
/// Check that resampling an empty input produces no output.
|
||||||
fn empty(from: u32, to: u32, n: u16) -> () {
|
fn empty(from: u32, to: u32, n: u16) -> () {
|
||||||
|
@ -289,9 +295,9 @@ mod test {
|
||||||
/// Check that dividing the sample rate by k (integer) is the same as
|
/// Check that dividing the sample rate by k (integer) is the same as
|
||||||
/// dropping a sample from each channel.
|
/// dropping a sample from each channel.
|
||||||
fn divide_sample_rate(to: u32, k: u32, input: Vec<u16>, n: u16) -> () {
|
fn divide_sample_rate(to: u32, k: u32, input: Vec<u16>, n: u16) -> () {
|
||||||
if k == 0 || n == 0 || to.checked_mul(k).is_none() { return; }
|
|
||||||
let to = if to == 0 { return; } else { SampleRate(to) };
|
let to = if to == 0 { return; } else { SampleRate(to) };
|
||||||
let from = to * k;
|
let from = multiply_rate(to, k);
|
||||||
|
if k == 0 || n == 0 { return; }
|
||||||
|
|
||||||
// Truncate the input, so it contains an integer number of frames.
|
// Truncate the input, so it contains an integer number of frames.
|
||||||
let input = {
|
let input = {
|
||||||
|
@ -313,9 +319,9 @@ mod test {
|
||||||
/// Check that, after multiplying the sample rate by k, every k-th
|
/// Check that, after multiplying the sample rate by k, every k-th
|
||||||
/// sample in the output matches exactly with the input.
|
/// sample in the output matches exactly with the input.
|
||||||
fn multiply_sample_rate(from: u32, k: u32, input: Vec<u16>, n: u16) -> () {
|
fn multiply_sample_rate(from: u32, k: u32, input: Vec<u16>, n: u16) -> () {
|
||||||
if k == 0 || n == 0 || from.checked_mul(k).is_none() { return; }
|
|
||||||
let from = if from == 0 { return; } else { SampleRate(from) };
|
let from = if from == 0 { return; } else { SampleRate(from) };
|
||||||
let to = from * k;
|
let to = multiply_rate(from, k);
|
||||||
|
if k == 0 || n == 0 { return; }
|
||||||
|
|
||||||
// Truncate the input, so it contains an integer number of frames.
|
// Truncate the input, so it contains an integer number of frames.
|
||||||
let input = {
|
let input = {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//! Mixer that plays multiple sounds at the same time.
|
//! Mixer that plays multiple sounds at the same time.
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -27,6 +28,8 @@ where
|
||||||
current_sources: Vec::with_capacity(16),
|
current_sources: Vec::with_capacity(16),
|
||||||
input: input.clone(),
|
input: input.clone(),
|
||||||
sample_count: 0,
|
sample_count: 0,
|
||||||
|
still_pending: vec![],
|
||||||
|
still_current: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
(input, output)
|
(input, output)
|
||||||
|
@ -51,8 +54,10 @@ where
|
||||||
T: Source<Item = S> + Send + 'static,
|
T: Source<Item = S> + Send + 'static,
|
||||||
{
|
{
|
||||||
let uniform_source = UniformSourceIterator::new(source, self.channels, self.sample_rate);
|
let uniform_source = UniformSourceIterator::new(source, self.channels, self.sample_rate);
|
||||||
let mut pending = self.pending_sources.lock().unwrap();
|
self.pending_sources
|
||||||
pending.push(Box::new(uniform_source) as Box<_>);
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.push(Box::new(uniform_source) as Box<_>);
|
||||||
self.has_pending.store(true, Ordering::SeqCst); // TODO: can we relax this ordering?
|
self.has_pending.store(true, Ordering::SeqCst); // TODO: can we relax this ordering?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +72,12 @@ pub struct MixerSource<S> {
|
||||||
|
|
||||||
// The number of samples produced so far.
|
// The number of samples produced so far.
|
||||||
sample_count: usize,
|
sample_count: usize,
|
||||||
|
|
||||||
|
// A temporary vec used in start_pending_sources.
|
||||||
|
still_pending: Vec<Box<dyn Source<Item = S> + Send>>,
|
||||||
|
|
||||||
|
// A temporary vec used in sum_current_sources.
|
||||||
|
still_current: Vec<Box<dyn Source<Item = S> + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Source for MixerSource<S>
|
impl<S> Source for MixerSource<S>
|
||||||
|
@ -168,16 +179,18 @@ where
|
||||||
// in-step with the modulo of the samples produced so far. Otherwise, the
|
// in-step with the modulo of the samples produced so far. Otherwise, the
|
||||||
// sound will play on the wrong channels, e.g. left / right will be reversed.
|
// sound will play on the wrong channels, e.g. left / right will be reversed.
|
||||||
fn start_pending_sources(&mut self) {
|
fn start_pending_sources(&mut self) {
|
||||||
let mut pending = self.input.pending_sources.lock().unwrap();
|
let mut pending = self.input.pending_sources.lock().unwrap(); // TODO: relax ordering?
|
||||||
let mut i = 0;
|
|
||||||
while i < pending.len() {
|
for source in pending.drain(..) {
|
||||||
let in_step = self.sample_count % pending[i].channels() as usize == 0;
|
let in_step = self.sample_count % source.channels() as usize == 0;
|
||||||
|
|
||||||
if in_step {
|
if in_step {
|
||||||
self.current_sources.push(pending.swap_remove(i));
|
self.current_sources.push(source);
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
self.still_pending.push(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::mem::swap(&mut self.still_pending, &mut pending);
|
||||||
|
|
||||||
let has_pending = !pending.is_empty();
|
let has_pending = !pending.is_empty();
|
||||||
self.input.has_pending.store(has_pending, Ordering::SeqCst); // TODO: relax ordering?
|
self.input.has_pending.store(has_pending, Ordering::SeqCst); // TODO: relax ordering?
|
||||||
|
@ -185,15 +198,15 @@ where
|
||||||
|
|
||||||
fn sum_current_sources(&mut self) -> S {
|
fn sum_current_sources(&mut self) -> S {
|
||||||
let mut sum = S::zero_value();
|
let mut sum = S::zero_value();
|
||||||
let mut i = 0;
|
|
||||||
while i < self.current_sources.len() {
|
for mut source in self.current_sources.drain(..) {
|
||||||
if let Some(value) = self.current_sources[i].next() {
|
if let Some(value) = source.next() {
|
||||||
sum = sum.saturating_add(value);
|
sum = sum.saturating_add(value);
|
||||||
i += 1;
|
self.still_current.push(source);
|
||||||
} else {
|
|
||||||
self.current_sources.swap_remove(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::mem::swap(&mut self.still_current, &mut self.current_sources);
|
||||||
|
|
||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,6 +145,7 @@ pub use self::noise::{pink, white, PinkNoise, WhiteNoise};
|
||||||
/// In order to properly handle this situation, the `current_frame_len()` method should return
|
/// 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
|
/// the number of samples that remain in the iterator before the samples rate and number of
|
||||||
/// channels can potentially change.
|
/// channels can potentially change.
|
||||||
|
///
|
||||||
pub trait Source: Iterator
|
pub trait Source: Iterator
|
||||||
where
|
where
|
||||||
Self::Item: Sample,
|
Self::Item: Sample,
|
||||||
|
|
|
@ -41,9 +41,9 @@ where
|
||||||
target_sample_rate: u32,
|
target_sample_rate: u32,
|
||||||
) -> UniformSourceIterator<I, D> {
|
) -> UniformSourceIterator<I, D> {
|
||||||
let total_duration = input.total_duration();
|
let total_duration = input.total_duration();
|
||||||
let input = Self::bootstrap(input, target_channels, target_sample_rate);
|
let input = UniformSourceIterator::bootstrap(input, target_channels, target_sample_rate);
|
||||||
|
|
||||||
Self {
|
UniformSourceIterator {
|
||||||
inner: Some(input),
|
inner: Some(input),
|
||||||
target_channels,
|
target_channels,
|
||||||
target_sample_rate,
|
target_sample_rate,
|
||||||
|
@ -102,7 +102,8 @@ where
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.iter;
|
.iter;
|
||||||
|
|
||||||
let mut input = Self::bootstrap(input, self.target_channels, self.target_sample_rate);
|
let mut input =
|
||||||
|
UniformSourceIterator::bootstrap(input, self.target_channels, self.target_sample_rate);
|
||||||
|
|
||||||
let value = input.next();
|
let value = input.next();
|
||||||
self.inner = Some(input);
|
self.inner = Some(input);
|
||||||
|
|
|
@ -96,10 +96,20 @@ impl SpatialSink {
|
||||||
self.sink.set_volume(value);
|
self.sink.set_volume(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the speed of the sound.
|
/// Changes the play speed of the sound. Does not adjust the samples, only the playback speed.
|
||||||
///
|
///
|
||||||
/// The value `1.0` is the "normal" speed (unfiltered input). Any value other than `1.0` will
|
/// # Note:
|
||||||
/// change the play speed of the sound.
|
/// 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]
|
#[inline]
|
||||||
pub fn speed(&self) -> f32 {
|
pub fn speed(&self) -> f32 {
|
||||||
self.sink.speed()
|
self.sink.speed()
|
||||||
|
@ -138,6 +148,14 @@ impl SpatialSink {
|
||||||
self.sink.is_paused()
|
self.sink.is_paused()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes all currently loaded `Source`s from the `SpatialSink` and pauses it.
|
||||||
|
///
|
||||||
|
/// See `pause()` for information about pausing a `Sink`.
|
||||||
|
#[inline]
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.sink.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// Stops the sink by emptying the queue.
|
/// Stops the sink by emptying the queue.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
|
@ -163,8 +181,43 @@ impl SpatialSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of sounds currently in the queue.
|
/// Returns the number of sounds currently in the queue.
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.sink.len()
|
self.sink.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to seek to a given position in the current source.
|
||||||
|
///
|
||||||
|
/// This blocks between 0 and ~5 milliseconds.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// When seeking beyond the end of a source this
|
||||||
|
/// function might return an error if the duration of the source is not known.
|
||||||
|
pub fn try_seek(&self, pos: Duration) -> Result<(), SeekError> {
|
||||||
|
self.sink.try_seek(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the position of the sound that's being played.
|
||||||
|
///
|
||||||
|
/// This takes into account any speedup or delay applied.
|
||||||
|
///
|
||||||
|
/// Example: if you apply a speedup of *2* to an mp3 decoder source and
|
||||||
|
/// [`get_pos()`](Sink::get_pos) returns *5s* then the position in the mp3
|
||||||
|
/// recording is *10s* from its start.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_pos(&self) -> Duration {
|
||||||
|
self.sink.get_pos()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100);
|
||||||
///
|
///
|
||||||
/// If this is dropped, playback will end, and the associated output stream will be disposed.
|
/// If this is dropped, playback will end, and the associated output stream will be disposed.
|
||||||
pub struct OutputStream {
|
pub struct OutputStream {
|
||||||
_stream: cpal::Stream,
|
|
||||||
mixer: Arc<Mixer<f32>>,
|
mixer: Arc<Mixer<f32>>,
|
||||||
|
_stream: cpal::Stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputStream {
|
impl OutputStream {
|
||||||
|
|
Loading…
Reference in a new issue