mirror of
https://github.com/RustAudio/rodio
synced 2024-12-04 17:29:20 +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 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! {
|
||||
/// Check that resampling an empty input produces no output.
|
||||
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
|
||||
/// dropping a sample from each channel.
|
||||
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 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.
|
||||
let input = {
|
||||
|
@ -313,9 +319,9 @@ mod test {
|
|||
/// Check that, after multiplying the sample rate by k, every k-th
|
||||
/// sample in the output matches exactly with the input.
|
||||
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 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.
|
||||
let input = {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! Mixer that plays multiple sounds at the same time.
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
@ -27,6 +28,8 @@ where
|
|||
current_sources: Vec::with_capacity(16),
|
||||
input: input.clone(),
|
||||
sample_count: 0,
|
||||
still_pending: vec![],
|
||||
still_current: vec![],
|
||||
};
|
||||
|
||||
(input, output)
|
||||
|
@ -51,8 +54,10 @@ where
|
|||
T: Source<Item = S> + Send + 'static,
|
||||
{
|
||||
let uniform_source = UniformSourceIterator::new(source, self.channels, self.sample_rate);
|
||||
let mut pending = self.pending_sources.lock().unwrap();
|
||||
pending.push(Box::new(uniform_source) as Box<_>);
|
||||
self.pending_sources
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(Box::new(uniform_source) as Box<_>);
|
||||
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.
|
||||
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>
|
||||
|
@ -168,16 +179,18 @@ where
|
|||
// 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.
|
||||
fn start_pending_sources(&mut self) {
|
||||
let mut pending = self.input.pending_sources.lock().unwrap();
|
||||
let mut i = 0;
|
||||
while i < pending.len() {
|
||||
let in_step = self.sample_count % pending[i].channels() as usize == 0;
|
||||
let mut pending = self.input.pending_sources.lock().unwrap(); // TODO: relax ordering?
|
||||
|
||||
for source in pending.drain(..) {
|
||||
let in_step = self.sample_count % source.channels() as usize == 0;
|
||||
|
||||
if in_step {
|
||||
self.current_sources.push(pending.swap_remove(i));
|
||||
self.current_sources.push(source);
|
||||
} else {
|
||||
i += 1;
|
||||
self.still_pending.push(source);
|
||||
}
|
||||
}
|
||||
std::mem::swap(&mut self.still_pending, &mut pending);
|
||||
|
||||
let has_pending = !pending.is_empty();
|
||||
self.input.has_pending.store(has_pending, Ordering::SeqCst); // TODO: relax ordering?
|
||||
|
@ -185,15 +198,15 @@ where
|
|||
|
||||
fn sum_current_sources(&mut self) -> S {
|
||||
let mut sum = S::zero_value();
|
||||
let mut i = 0;
|
||||
while i < self.current_sources.len() {
|
||||
if let Some(value) = self.current_sources[i].next() {
|
||||
|
||||
for mut source in self.current_sources.drain(..) {
|
||||
if let Some(value) = source.next() {
|
||||
sum = sum.saturating_add(value);
|
||||
i += 1;
|
||||
} else {
|
||||
self.current_sources.swap_remove(i);
|
||||
self.still_current.push(source);
|
||||
}
|
||||
}
|
||||
std::mem::swap(&mut self.still_current, &mut self.current_sources);
|
||||
|
||||
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
|
||||
/// 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,
|
||||
|
|
|
@ -41,9 +41,9 @@ where
|
|||
target_sample_rate: u32,
|
||||
) -> UniformSourceIterator<I, D> {
|
||||
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),
|
||||
target_channels,
|
||||
target_sample_rate,
|
||||
|
@ -102,7 +102,8 @@ where
|
|||
.into_inner()
|
||||
.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();
|
||||
self.inner = Some(input);
|
||||
|
|
|
@ -96,10 +96,20 @@ impl SpatialSink {
|
|||
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
|
||||
/// change the play speed of the sound.
|
||||
/// # 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]
|
||||
pub fn speed(&self) -> f32 {
|
||||
self.sink.speed()
|
||||
|
@ -138,6 +148,14 @@ impl SpatialSink {
|
|||
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.
|
||||
#[inline]
|
||||
pub fn stop(&self) {
|
||||
|
@ -163,8 +181,43 @@ impl SpatialSink {
|
|||
}
|
||||
|
||||
/// Returns the number of sounds currently in the queue.
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
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.
|
||||
pub struct OutputStream {
|
||||
_stream: cpal::Stream,
|
||||
mixer: Arc<Mixer<f32>>,
|
||||
_stream: cpal::Stream,
|
||||
}
|
||||
|
||||
impl OutputStream {
|
||||
|
|
Loading…
Reference in a new issue