mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
Merge branch 'master' into seek_runtime_err
This commit is contained in:
commit
6f1f44f04a
15 changed files with 99 additions and 61 deletions
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -43,12 +43,8 @@ jobs:
|
|||
# Don't use a 'components:' entry--we don't need them with beta/nightly, plus nightly often doesn't have them
|
||||
override: true
|
||||
|
||||
# This block can be uncommented to add clippy to CI, but first the existing clippy warnings need to be fixed!
|
||||
# - name: clippy
|
||||
# run: |
|
||||
# rustup component add clippy
|
||||
# cargo clippy -- -D warnings
|
||||
# if: matrix.toolchain == 'stable' && matrix.os == 'ubuntu-latest'
|
||||
- run: cargo clippy -- -D warnings
|
||||
if: matrix.toolchain == 'stable' && matrix.os == 'ubuntu-latest'
|
||||
|
||||
- run: |
|
||||
rustup component add rustfmt
|
||||
|
|
|
@ -28,6 +28,7 @@ wav = ["hound"]
|
|||
mp3 = ["symphonia-mp3"]
|
||||
minimp3 = ["dep:minimp3_fixed"]
|
||||
wasm-bindgen = ["cpal/wasm-bindgen"]
|
||||
cpal-shared-stdcxx = ["cpal/oboe-shared-stdcxx"]
|
||||
symphonia-aac = ["symphonia/aac"]
|
||||
symphonia-all = ["symphonia-aac", "symphonia-flac", "symphonia-isomp4", "symphonia-mp3", "symphonia-vorbis", "symphonia-wav"]
|
||||
symphonia-flac = ["symphonia/flac"]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use cpal::Sample;
|
||||
|
||||
/// Iterator that converts from a certain channel count to another.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ChannelCountConverter<I>
|
||||
|
@ -19,7 +21,7 @@ where
|
|||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panicks if `from` or `to` are equal to 0.
|
||||
/// Panics if `from` or `to` are equal to 0.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(
|
||||
|
@ -55,25 +57,29 @@ where
|
|||
impl<I> Iterator for ChannelCountConverter<I>
|
||||
where
|
||||
I: Iterator,
|
||||
I::Item: Clone,
|
||||
I::Item: Sample,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
let result = if self.next_output_sample_pos == self.from - 1 {
|
||||
let value = self.input.next();
|
||||
self.sample_repeat = value.clone();
|
||||
value
|
||||
} else if self.next_output_sample_pos < self.from {
|
||||
self.input.next()
|
||||
} else {
|
||||
self.sample_repeat.clone()
|
||||
let result = match self.next_output_sample_pos {
|
||||
0 => {
|
||||
// save first sample for mono -> stereo conversion
|
||||
let value = self.input.next();
|
||||
self.sample_repeat = value;
|
||||
value
|
||||
}
|
||||
x if x < self.from => self.input.next(),
|
||||
1 => self.sample_repeat,
|
||||
_ => Some(I::Item::EQUILIBRIUM),
|
||||
};
|
||||
|
||||
self.next_output_sample_pos += 1;
|
||||
if result.is_some() {
|
||||
self.next_output_sample_pos += 1;
|
||||
}
|
||||
|
||||
if self.next_output_sample_pos == self.to {
|
||||
self.next_output_sample_pos -= self.to;
|
||||
self.next_output_sample_pos = 0;
|
||||
|
||||
if self.from > self.to {
|
||||
for _ in self.to..self.from {
|
||||
|
@ -89,11 +95,14 @@ where
|
|||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (min, max) = self.input.size_hint();
|
||||
|
||||
let min =
|
||||
(min / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize;
|
||||
let max = max.map(|max| {
|
||||
(max / self.from as usize) * self.to as usize + self.next_output_sample_pos as usize
|
||||
});
|
||||
let consumed = std::cmp::min(self.from, self.next_output_sample_pos) as usize;
|
||||
let calculate = |size| {
|
||||
(size + consumed) / self.from as usize * self.to as usize
|
||||
- self.next_output_sample_pos as usize
|
||||
};
|
||||
|
||||
let min = calculate(min);
|
||||
let max = max.map(calculate);
|
||||
|
||||
(min, max)
|
||||
}
|
||||
|
@ -102,7 +111,7 @@ where
|
|||
impl<I> ExactSizeIterator for ChannelCountConverter<I>
|
||||
where
|
||||
I: ExactSizeIterator,
|
||||
I::Item: Clone,
|
||||
I::Item: Sample,
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -112,36 +121,60 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn remove_channels() {
|
||||
let input = vec![1u16, 2, 3, 1, 2, 3];
|
||||
let input = vec![1u16, 2, 3, 4, 5, 6];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 3, 2).collect::<Vec<_>>();
|
||||
assert_eq!(output, [1, 2, 1, 2]);
|
||||
assert_eq!(output, [1, 2, 4, 5]);
|
||||
|
||||
let input = vec![1u16, 2, 3, 4, 1, 2, 3, 4];
|
||||
let input = vec![1u16, 2, 3, 4, 5, 6, 7, 8];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 4, 1).collect::<Vec<_>>();
|
||||
assert_eq!(output, [1, 1]);
|
||||
assert_eq!(output, [1, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_channels() {
|
||||
let input = vec![1u16, 2, 1, 2];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 2, 3).collect::<Vec<_>>();
|
||||
assert_eq!(output, [1, 2, 2, 1, 2, 2]);
|
||||
let input = vec![1i16, 2, 3, 4];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 1, 2).collect::<Vec<_>>();
|
||||
assert_eq!(output, [1, 1, 2, 2, 3, 3, 4, 4]);
|
||||
|
||||
let input = vec![1u16, 2, 1, 2];
|
||||
let input = vec![1i16, 2];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 1, 4).collect::<Vec<_>>();
|
||||
assert_eq!(output, [1, 1, 0, 0, 2, 2, 0, 0]);
|
||||
|
||||
let input = vec![1i16, 2, 3, 4];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 2, 4).collect::<Vec<_>>();
|
||||
assert_eq!(output, [1, 2, 2, 2, 1, 2, 2, 2]);
|
||||
assert_eq!(output, [1, 2, 0, 0, 3, 4, 0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn size_hint() {
|
||||
fn test(input: &[i16], from: cpal::ChannelCount, to: cpal::ChannelCount) {
|
||||
let mut converter = ChannelCountConverter::new(input.iter().copied(), from, to);
|
||||
let count = converter.clone().count();
|
||||
for left_in_iter in (0..=count).rev() {
|
||||
println!("left_in_iter = {}", left_in_iter);
|
||||
assert_eq!(converter.size_hint(), (left_in_iter, Some(left_in_iter)));
|
||||
converter.next();
|
||||
}
|
||||
assert_eq!(converter.size_hint(), (0, Some(0)));
|
||||
}
|
||||
|
||||
test(&[1i16, 2, 3], 1, 2);
|
||||
test(&[1i16, 2, 3, 4], 2, 4);
|
||||
test(&[1i16, 2, 3, 4], 4, 2);
|
||||
test(&[1i16, 2, 3, 4, 5, 6], 3, 8);
|
||||
test(&[1i16, 2, 3, 4, 5, 6, 7, 8], 4, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len_more() {
|
||||
let input = vec![1u16, 2, 1, 2];
|
||||
let input = vec![1i16, 2, 3, 4];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 2, 3);
|
||||
assert_eq!(output.len(), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len_less() {
|
||||
let input = vec![1u16, 2, 1, 2];
|
||||
let input = vec![1i16, 2, 3, 4];
|
||||
let output = ChannelCountConverter::new(input.into_iter(), 2, 1);
|
||||
assert_eq!(output.len(), 2);
|
||||
}
|
||||
|
|
|
@ -110,12 +110,12 @@ where
|
|||
Ordering::Equal => raw_val as i16,
|
||||
Ordering::Greater => (raw_val >> (self.bits_per_sample - 16)) as i16,
|
||||
};
|
||||
return Some(real_val as i16);
|
||||
return Some(real_val);
|
||||
}
|
||||
|
||||
// Load the next block.
|
||||
self.current_block_off = 0;
|
||||
let buffer = mem::replace(&mut self.current_block, Vec::new());
|
||||
let buffer = mem::take(&mut self.current_block);
|
||||
match self.reader.blocks().read_next_or_eof(buffer) {
|
||||
Ok(Some(block)) => {
|
||||
self.current_block_channel_len = (block.len() / block.channels()) as usize;
|
||||
|
@ -132,7 +132,7 @@ fn is_flac<R>(mut data: R) -> bool
|
|||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
|
||||
let stream_pos = data.stream_position().unwrap();
|
||||
|
||||
if FlacReader::new(data.by_ref()).is_err() {
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::error::Error;
|
|||
use std::fmt;
|
||||
#[allow(unused_imports)]
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::marker::Sync;
|
||||
use std::mem;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
@ -41,6 +40,9 @@ pub struct LoopedDecoder<R>(DecoderImpl<R>)
|
|||
where
|
||||
R: Read + Seek;
|
||||
|
||||
// can not really reduce the size of the VorbisDecoder. There are not any
|
||||
// arrays just a lot of struct fields.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum DecoderImpl<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
|
@ -231,9 +233,7 @@ where
|
|||
|
||||
match symphonia::SymphoniaDecoder::new(mss, None) {
|
||||
Err(e) => Err(e),
|
||||
Ok(decoder) => {
|
||||
return Ok(Decoder(DecoderImpl::Symphonia(decoder)));
|
||||
}
|
||||
Ok(decoder) => Ok(Decoder(DecoderImpl::Symphonia(decoder))),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "symphonia"))]
|
||||
|
@ -324,9 +324,7 @@ where
|
|||
|
||||
match symphonia::SymphoniaDecoder::new(mss, Some(hint)) {
|
||||
Err(e) => Err(e),
|
||||
Ok(decoder) => {
|
||||
return Ok(Decoder(DecoderImpl::Symphonia(decoder)));
|
||||
}
|
||||
Ok(decoder) => Ok(Decoder(DecoderImpl::Symphonia(decoder))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -479,7 +477,7 @@ where
|
|||
}
|
||||
#[cfg(feature = "symphonia")]
|
||||
DecoderImpl::Symphonia(source) => {
|
||||
let mut reader = Box::new(source).into_inner();
|
||||
let mut reader = source.into_inner();
|
||||
reader.seek(SeekFrom::Start(0)).ok()?;
|
||||
let mut source = symphonia::SymphoniaDecoder::new(reader, None).ok()?;
|
||||
let sample = source.next();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::io::{Read, Result, Seek, SeekFrom};
|
||||
use std::marker::Sync;
|
||||
|
||||
use symphonia::core::io::MediaSource;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ impl SymphoniaDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self: Box<Self>) -> MediaSourceStream {
|
||||
pub(crate) fn into_inner(self) -> MediaSourceStream {
|
||||
self.format.into_inner()
|
||||
}
|
||||
|
||||
|
@ -106,23 +106,22 @@ impl SymphoniaDecoder {
|
|||
};
|
||||
let spec = decoded.spec().to_owned();
|
||||
let buffer = SymphoniaDecoder::get_buffer(decoded, &spec);
|
||||
|
||||
return Ok(Some(SymphoniaDecoder {
|
||||
Ok(Some(SymphoniaDecoder {
|
||||
decoder,
|
||||
current_frame_offset: 0,
|
||||
format: probed.format,
|
||||
total_duration,
|
||||
buffer,
|
||||
spec,
|
||||
}));
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_buffer(decoded: AudioBufferRef, spec: &SignalSpec) -> SampleBuffer<i16> {
|
||||
let duration = units::Duration::from(decoded.capacity() as u64);
|
||||
let mut buffer = SampleBuffer::<i16>::new(duration, spec.clone());
|
||||
let mut buffer = SampleBuffer::<i16>::new(duration, *spec);
|
||||
buffer.copy_interleaved_ref(decoded);
|
||||
return buffer;
|
||||
buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ fn is_vorbis<R>(mut data: R) -> bool
|
|||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
|
||||
let stream_pos = data.stream_position().unwrap();
|
||||
|
||||
if OggStreamReader::new(data.by_ref()).is_err() {
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
|
|
|
@ -179,7 +179,7 @@ fn is_wave<R>(mut data: R) -> bool
|
|||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
|
||||
let stream_pos = data.stream_position().unwrap();
|
||||
|
||||
if WavReader::new(data.by_ref()).is_err() {
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
|
|
|
@ -43,9 +43,12 @@ where
|
|||
|
||||
// TODO: consider reimplementing this with `from_factory`
|
||||
|
||||
type Sound<S> = Box<dyn Source<Item = S> + Send>;
|
||||
type SignalDone = Option<Sender<()>>;
|
||||
|
||||
/// The input of the queue.
|
||||
pub struct SourcesQueueInput<S> {
|
||||
next_sounds: Mutex<Vec<(Box<dyn Source<Item = S> + Send>, Option<Sender<()>>)>>,
|
||||
next_sounds: Mutex<Vec<(Sound<S>, SignalDone)>>,
|
||||
|
||||
// See constructor.
|
||||
keep_alive_if_empty: AtomicBool,
|
||||
|
|
|
@ -131,7 +131,7 @@ impl Sink {
|
|||
{
|
||||
let mut to_clear = controls.to_clear.lock().unwrap();
|
||||
if *to_clear > 0 {
|
||||
let _ = src.inner_mut().skip();
|
||||
src.inner_mut().skip();
|
||||
*to_clear -= 1;
|
||||
}
|
||||
}
|
||||
|
@ -298,6 +298,7 @@ impl Sink {
|
|||
}
|
||||
|
||||
/// Returns the number of sounds currently in the queue.
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.sound_count.load(Ordering::Relaxed)
|
||||
|
|
|
@ -50,7 +50,7 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
skip_samples(input, frame_len as usize);
|
||||
skip_samples(input, frame_len);
|
||||
|
||||
duration -= Duration::from_nanos((frame_len * ns_per_sample as usize) as u64);
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ where
|
|||
None
|
||||
} else if let Some(sample) = self.input.next() {
|
||||
let sample = match &self.filter {
|
||||
Some(filter) => filter.apply(sample, &self),
|
||||
Some(filter) => filter.apply(sample, self),
|
||||
None => sample,
|
||||
};
|
||||
|
||||
|
|
|
@ -135,6 +135,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) {
|
||||
|
@ -160,6 +168,7 @@ 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()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use std::io::{Read, Seek};
|
||||
use std::marker::Sync;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::{error, fmt};
|
||||
|
||||
|
@ -353,7 +352,7 @@ fn supported_output_formats(
|
|||
if HZ_44100 < max_rate && HZ_44100 > min_rate {
|
||||
formats.push(sf.clone().with_sample_rate(HZ_44100))
|
||||
}
|
||||
formats.push(sf.with_sample_rate(min_rate));
|
||||
formats.push(sf.clone().with_sample_rate(min_rate));
|
||||
formats
|
||||
}))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue