mirror of
https://github.com/RustAudio/rodio
synced 2024-12-13 13:42:34 +00:00
Start using one voice per endpoint and mixing samples manually
This commit is contained in:
parent
a6b5197a59
commit
92a4567f08
6 changed files with 174 additions and 162 deletions
|
@ -4,10 +4,8 @@ This module contains function that will convert from one PCM format to another.
|
|||
This includes conversion between samples formats, channels or sample rates.
|
||||
|
||||
*/
|
||||
use std::iter;
|
||||
use cpal::UnknownTypeBuffer;
|
||||
|
||||
pub use self::sample::Sample;
|
||||
pub use self::sample::DataConverter;
|
||||
pub use self::channels::ChannelsCountConverter;
|
||||
pub use self::samples_rate::SamplesRateConverter;
|
||||
pub use self::amplifier::AmplifierIterator;
|
||||
|
@ -16,34 +14,3 @@ mod amplifier;
|
|||
mod channels;
|
||||
mod sample;
|
||||
mod samples_rate;
|
||||
|
||||
///
|
||||
pub fn convert_and_write<I, S>(samples: I, output: &mut UnknownTypeBuffer)
|
||||
where I: Iterator<Item=S>, S: Sample
|
||||
{
|
||||
let samples = samples.chain(iter::repeat(Sample::zero_value()));
|
||||
|
||||
// note that it is important to do `buffer.zip(samples)` instead of `samples.zip(buffer)`
|
||||
// otherwise when the buffer's iterator is exhausted the value obtained from `samples` is
|
||||
// discarded
|
||||
|
||||
match output {
|
||||
&mut UnknownTypeBuffer::U16(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(samples) {
|
||||
*o = i.to_u16();
|
||||
}
|
||||
},
|
||||
|
||||
&mut UnknownTypeBuffer::I16(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(samples) {
|
||||
*o = i.to_i16();
|
||||
}
|
||||
},
|
||||
|
||||
&mut UnknownTypeBuffer::F32(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(samples) {
|
||||
*o = i.to_f32();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,41 @@
|
|||
use std::marker::PhantomData;
|
||||
use cpal;
|
||||
|
||||
/// Converts the samples data type to `O`.
|
||||
pub struct DataConverter<I, O> {
|
||||
input: I,
|
||||
marker: PhantomData<O>,
|
||||
}
|
||||
|
||||
impl<I, O> DataConverter<I, O> {
|
||||
/// Builds a new converter.
|
||||
#[inline]
|
||||
pub fn new(input: I) -> DataConverter<I, O> {
|
||||
DataConverter {
|
||||
input: input,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O> Iterator for DataConverter<I, O> where I: Iterator, I::Item: Sample, O: Sample {
|
||||
type Item = O;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<O> {
|
||||
self.input.next().map(|s| Sample::from(&s))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.input.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O> ExactSizeIterator for DataConverter<I, O>
|
||||
where I: ExactSizeIterator, I::Item: Sample, O: Sample {}
|
||||
|
||||
|
||||
/// Trait for containers that contain PCM data.
|
||||
pub trait Sample: cpal::Sample {
|
||||
fn lerp(first: Self, second: Self, numerator: u32, denominator: u32) -> Self;
|
||||
|
@ -10,6 +46,8 @@ pub trait Sample: cpal::Sample {
|
|||
fn to_i16(&self) -> i16;
|
||||
fn to_u16(&self) -> u16;
|
||||
fn to_f32(&self) -> f32;
|
||||
|
||||
fn from<S>(&S) -> Self where S: Sample;
|
||||
}
|
||||
|
||||
impl Sample for u16 {
|
||||
|
@ -46,6 +84,11 @@ impl Sample for u16 {
|
|||
fn to_f32(&self) -> f32 {
|
||||
self.to_i16().to_f32()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from<S>(sample: &S) -> Self where S: Sample {
|
||||
sample.to_u16()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample for i16 {
|
||||
|
@ -86,6 +129,11 @@ impl Sample for i16 {
|
|||
*self as f32 / ::std::i16::MAX as f32
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from<S>(sample: &S) -> Self where S: Sample {
|
||||
sample.to_i16()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample for f32 {
|
||||
|
@ -122,6 +170,11 @@ impl Sample for f32 {
|
|||
fn to_f32(&self) -> f32 {
|
||||
*self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from<S>(sample: &S) -> Self where S: Sample {
|
||||
sample.to_f32()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -8,34 +8,27 @@ mod vorbis;
|
|||
mod wav;
|
||||
|
||||
/// Trait for objects that produce an audio stream.
|
||||
pub trait Decoder {
|
||||
/// Appends 17ms of data to the voice.
|
||||
///
|
||||
/// Returns false if the sound is over.
|
||||
fn write(&mut self) -> bool;
|
||||
|
||||
pub trait Decoder: Iterator /*+ ExactSizeIterator*/ { // TODO: should be exact size, but not enforced yet
|
||||
/// Changes the volume of the sound.
|
||||
fn set_volume(&mut self, f32);
|
||||
|
||||
/// Returns the total duration of the second in milliseconds.
|
||||
fn get_total_duration_ms(&self) -> u32;
|
||||
|
||||
/// Returns the number of milliseconds before the end of the sound.
|
||||
fn get_remaining_duration_ms(&self) -> u32;
|
||||
}
|
||||
|
||||
/// Builds a new `Decoder` from a data stream by determining the correct format.
|
||||
pub fn decode<R>(endpoint: &Endpoint, data: R) -> Arc<Mutex<Decoder + Send>>
|
||||
pub fn decode<R>(data: R, output_channels: u16, output_samples_rate: u32)
|
||||
-> Arc<Mutex<Decoder<Item=f32> + Send>>
|
||||
where R: Read + Seek + Send + 'static
|
||||
{
|
||||
let data = match wav::WavDecoder::new(endpoint, data) {
|
||||
let data = match wav::WavDecoder::new(data, output_channels, output_samples_rate) {
|
||||
Err(data) => data,
|
||||
Ok(decoder) => {
|
||||
return Arc::new(Mutex::new(decoder));
|
||||
}
|
||||
};
|
||||
|
||||
if let Ok(decoder) = vorbis::VorbisDecoder::new(endpoint, data) {
|
||||
if let Ok(decoder) = vorbis::VorbisDecoder::new(data, output_channels, output_samples_rate) {
|
||||
return Arc::new(Mutex::new(decoder));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@ use cpal::{self, Endpoint, Voice};
|
|||
use vorbis;
|
||||
|
||||
pub struct VorbisDecoder {
|
||||
reader: conversions::AmplifierIterator<Box<Iterator<Item=i16> + Send>>,
|
||||
voice: Voice,
|
||||
reader: conversions::AmplifierIterator<Box<Iterator<Item=f32> + Send>>,
|
||||
}
|
||||
|
||||
impl VorbisDecoder {
|
||||
pub fn new<R>(endpoint: &Endpoint, data: R) -> Result<VorbisDecoder, ()>
|
||||
pub fn new<R>(data: R, output_channels: u16, output_samples_rate: u32)
|
||||
-> Result<VorbisDecoder, ()>
|
||||
where R: Read + Seek + Send + 'static
|
||||
{
|
||||
let decoder = match vorbis::Decoder::new(data) {
|
||||
|
@ -20,43 +20,23 @@ impl VorbisDecoder {
|
|||
Ok(r) => r
|
||||
};
|
||||
|
||||
// building the voice
|
||||
let voice_format = endpoint.get_supported_formats_list().unwrap().next().unwrap();
|
||||
let voice = Voice::new(endpoint, &voice_format).unwrap();
|
||||
|
||||
let to_channels = voice.get_channels();
|
||||
let to_samples_rate = voice.get_samples_rate();
|
||||
|
||||
let reader = decoder.into_packets().filter_map(|p| p.ok()).flat_map(move |packet| {
|
||||
let reader = packet.data.into_iter();
|
||||
let reader = conversions::ChannelsCountConverter::new(reader, packet.channels,
|
||||
to_channels);
|
||||
output_channels);
|
||||
let reader = conversions::SamplesRateConverter::new(reader, cpal::SamplesRate(packet.rate as u32),
|
||||
to_samples_rate, to_channels);
|
||||
cpal::SamplesRate(output_samples_rate), output_channels);
|
||||
let reader = conversions::DataConverter::new(reader);
|
||||
reader
|
||||
});
|
||||
|
||||
Ok(VorbisDecoder {
|
||||
reader: conversions::AmplifierIterator::new(Box::new(reader), 1.0),
|
||||
voice: voice,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for VorbisDecoder {
|
||||
fn write(&mut self) -> bool {
|
||||
// TODO: handle end
|
||||
|
||||
{
|
||||
let samples = self.voice.get_samples_rate().0 * self.voice.get_channels() as u32;
|
||||
let mut buffer = self.voice.append_data(samples as usize);
|
||||
conversions::convert_and_write(self.reader.by_ref(), &mut buffer);
|
||||
}
|
||||
|
||||
self.voice.play();
|
||||
true
|
||||
}
|
||||
|
||||
fn set_volume(&mut self, value: f32) {
|
||||
self.reader.set_amplification(value);
|
||||
}
|
||||
|
@ -64,8 +44,20 @@ impl Decoder for VorbisDecoder {
|
|||
fn get_total_duration_ms(&self) -> u32 {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_remaining_duration_ms(&self) -> u32 {
|
||||
unimplemented!()
|
||||
impl Iterator for VorbisDecoder {
|
||||
type Item = f32;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<f32> {
|
||||
self.reader.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.reader.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for VorbisDecoder {}
|
||||
|
|
|
@ -7,13 +7,13 @@ use cpal::{self, Endpoint, Voice};
|
|||
use hound::WavReader;
|
||||
|
||||
pub struct WavDecoder {
|
||||
reader: conversions::AmplifierIterator<Box<Iterator<Item=i16> + Send>>,
|
||||
voice: Voice,
|
||||
reader: conversions::AmplifierIterator<Box<Iterator<Item=f32> + Send>>,
|
||||
total_duration_ms: u32,
|
||||
}
|
||||
|
||||
impl WavDecoder {
|
||||
pub fn new<R>(endpoint: &Endpoint, mut data: R) -> Result<WavDecoder, R>
|
||||
pub fn new<R>(mut data: R, output_channels: u16, output_samples_rate: u32)
|
||||
-> Result<WavDecoder, R>
|
||||
where R: Read + Seek + Send + 'static
|
||||
{
|
||||
if !is_wave(data.by_ref()) {
|
||||
|
@ -24,52 +24,14 @@ impl WavDecoder {
|
|||
let spec = reader.spec();
|
||||
let total_duration_ms = reader.duration() * 1000 / spec.sample_rate;
|
||||
|
||||
// choosing a format amongst the ones available
|
||||
let voice_format = endpoint.get_supported_formats_list().unwrap().fold(None, |f1, f2| {
|
||||
if f1.is_none() {
|
||||
return Some(f2);
|
||||
}
|
||||
|
||||
let f1 = f1.unwrap();
|
||||
|
||||
if f1.samples_rate.0 % spec.sample_rate == 0 {
|
||||
return Some(f1);
|
||||
}
|
||||
|
||||
if f2.samples_rate.0 % spec.sample_rate == 0 {
|
||||
return Some(f2);
|
||||
}
|
||||
|
||||
if f1.channels.len() >= spec.channels as usize {
|
||||
return Some(f1);
|
||||
}
|
||||
|
||||
if f2.channels.len() >= spec.channels as usize {
|
||||
return Some(f2);
|
||||
}
|
||||
|
||||
if f1.data_type == cpal::SampleFormat::I16 {
|
||||
return Some(f1);
|
||||
}
|
||||
|
||||
if f2.data_type == cpal::SampleFormat::I16 {
|
||||
return Some(f2);
|
||||
}
|
||||
|
||||
Some(f1)
|
||||
}).unwrap();
|
||||
|
||||
let voice = Voice::new(endpoint, &voice_format).unwrap();
|
||||
|
||||
let reader = SamplesIterator { reader: reader, samples_read: 0 };
|
||||
let reader = conversions::ChannelsCountConverter::new(reader, spec.channels,
|
||||
voice.get_channels());
|
||||
let reader = conversions::ChannelsCountConverter::new(reader, spec.channels, 2);
|
||||
let reader = conversions::SamplesRateConverter::new(reader, cpal::SamplesRate(spec.sample_rate),
|
||||
voice.get_samples_rate(), voice.get_channels());
|
||||
cpal::SamplesRate(output_samples_rate), output_channels);
|
||||
let reader = conversions::DataConverter::new(reader);
|
||||
|
||||
Ok(WavDecoder {
|
||||
reader: conversions::AmplifierIterator::new(Box::new(reader), 1.0),
|
||||
voice: voice,
|
||||
total_duration_ms: total_duration_ms,
|
||||
})
|
||||
}
|
||||
|
@ -116,21 +78,6 @@ fn is_wave<R>(mut data: R) -> bool where R: Read + Seek {
|
|||
}
|
||||
|
||||
impl Decoder for WavDecoder {
|
||||
fn write(&mut self) -> bool {
|
||||
if let (0, _) = self.reader.size_hint() {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
let samples = self.voice.get_samples_rate().0 * self.voice.get_channels() as u32;
|
||||
let mut buffer = self.voice.append_data(samples as usize);
|
||||
conversions::convert_and_write(self.reader.by_ref(), &mut buffer);
|
||||
}
|
||||
|
||||
self.voice.play();
|
||||
true
|
||||
}
|
||||
|
||||
fn set_volume(&mut self, value: f32) {
|
||||
self.reader.set_amplification(value);
|
||||
}
|
||||
|
@ -138,12 +85,20 @@ impl Decoder for WavDecoder {
|
|||
fn get_total_duration_ms(&self) -> u32 {
|
||||
self.total_duration_ms
|
||||
}
|
||||
}
|
||||
|
||||
fn get_remaining_duration_ms(&self) -> u32 {
|
||||
let (num_samples, _) = self.reader.size_hint();
|
||||
let num_samples = num_samples + self.voice.get_pending_samples();
|
||||
impl Iterator for WavDecoder {
|
||||
type Item = f32;
|
||||
|
||||
(num_samples as u64 * 1000 /
|
||||
(self.voice.get_samples_rate().0 as u64 * self.voice.get_channels() as u64)) as u32
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<f32> {
|
||||
self.reader.next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.reader.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for WavDecoder {}
|
||||
|
|
100
src/engine.rs
100
src/engine.rs
|
@ -1,14 +1,18 @@
|
|||
use std::cmp;
|
||||
use std::mem;
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Seek};
|
||||
use std::thread::{self, Builder, Thread};
|
||||
use std::sync::mpsc::{self, Sender, Receiver};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use cpal::UnknownTypeBuffer;
|
||||
use cpal::Voice;
|
||||
use cpal::Endpoint;
|
||||
use decoder;
|
||||
use decoder::Decoder;
|
||||
use conversions::Sample;
|
||||
|
||||
use time;
|
||||
|
||||
|
@ -44,10 +48,10 @@ impl Engine {
|
|||
pub fn play<R>(&self, endpoint: &Endpoint, input: R) -> Handle
|
||||
where R: Read + Seek + Send + 'static
|
||||
{
|
||||
let decoder = decoder::decode(endpoint, input);
|
||||
let decoder = decoder::decode(input, 2, 44100);
|
||||
|
||||
let commands = self.commands.lock().unwrap();
|
||||
commands.send(Command::Play(decoder.clone())).unwrap();
|
||||
commands.send(Command::Play(endpoint.clone(), decoder.clone())).unwrap();
|
||||
|
||||
if let Some(ref thread) = self.thread {
|
||||
thread.unpark();
|
||||
|
@ -65,7 +69,7 @@ impl Engine {
|
|||
/// Note that dropping the handle doesn't stop the sound. You must call `stop` explicitely.
|
||||
pub struct Handle<'a> {
|
||||
engine: &'a Engine,
|
||||
decoder: Arc<Mutex<Decoder + Send>>,
|
||||
decoder: Arc<Mutex<Decoder<Item=f32> + Send>>,
|
||||
}
|
||||
|
||||
impl<'a> Handle<'a> {
|
||||
|
@ -101,41 +105,61 @@ impl<'a> Handle<'a> {
|
|||
#[inline]
|
||||
pub fn get_remaining_duration_ms(&self) -> u32 {
|
||||
let decoder = self.decoder.lock().unwrap();
|
||||
decoder.get_remaining_duration_ms()
|
||||
|
||||
let (num_samples, _) = decoder.size_hint();
|
||||
//let num_samples = num_samples + self.voice.get_pending_samples(); // TODO: !
|
||||
|
||||
(num_samples as u64 * 1000 / 44100 * 2) as u32 // FIXME: arbitrary values
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Command {
|
||||
Play(Arc<Mutex<Decoder + Send>>),
|
||||
Stop(Arc<Mutex<Decoder + Send>>),
|
||||
SetVolume(Arc<Mutex<Decoder + Send>>, f32),
|
||||
Play(Endpoint, Arc<Mutex<Decoder<Item=f32> + Send>>),
|
||||
Stop(Arc<Mutex<Decoder<Item=f32> + Send>>),
|
||||
SetVolume(Arc<Mutex<Decoder<Item=f32> + Send>>, f32),
|
||||
}
|
||||
|
||||
fn background(rx: Receiver<Command>) {
|
||||
let mut sounds: Vec<Arc<Mutex<Decoder + Send>>> = Vec::new();
|
||||
let mut sounds_to_remove: Vec<Arc<Mutex<Decoder + Send>>> = Vec::new();
|
||||
// for each endpoint name, stores the voice and the list of sounds
|
||||
let mut voices: HashMap<String, (Voice, Vec<Arc<Mutex<Decoder<Item=f32> + Send>>>)> = HashMap::new();
|
||||
|
||||
// list of sounds to stop playing
|
||||
let mut sounds_to_remove: Vec<Arc<Mutex<Decoder<Item=f32> + Send>>> = Vec::new();
|
||||
|
||||
loop {
|
||||
// polling for new commands
|
||||
if let Ok(command) = rx.try_recv() {
|
||||
match command {
|
||||
Command::Play(decoder) => {
|
||||
sounds.push(decoder);
|
||||
Command::Play(endpoint, decoder) => {
|
||||
let mut entry = voices.entry(endpoint.get_name()).or_insert_with(|| {
|
||||
// TODO: handle possible errors here
|
||||
// TODO: choose format better
|
||||
let format = endpoint.get_supported_formats_list().unwrap().next().unwrap();
|
||||
let voice = Voice::new(&endpoint, &format).unwrap();
|
||||
|
||||
(voice, Vec::new())
|
||||
});
|
||||
|
||||
entry.1.push(decoder);
|
||||
},
|
||||
|
||||
Command::Stop(decoder) => {
|
||||
let decoder = &*decoder as *const _;
|
||||
sounds.retain(|dec| {
|
||||
&**dec as *const _ != decoder
|
||||
})
|
||||
for (_, &mut (_, ref mut sounds)) in voices.iter_mut() {
|
||||
sounds.retain(|dec| {
|
||||
&**dec as *const _ != decoder
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
Command::SetVolume(decoder, volume) => {
|
||||
let decoder = &*decoder as *const _;
|
||||
if let Some(d) = sounds.iter_mut()
|
||||
.find(|dec| &***dec as *const _ != decoder)
|
||||
{
|
||||
d.lock().unwrap().set_volume(volume);
|
||||
for (_, &mut (_, ref mut sounds)) in voices.iter_mut() {
|
||||
if let Some(d) = sounds.iter_mut()
|
||||
.find(|dec| &***dec as *const _ != decoder)
|
||||
{
|
||||
d.lock().unwrap().set_volume(volume);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -144,16 +168,44 @@ fn background(rx: Receiver<Command>) {
|
|||
// removing sounds that have finished playing
|
||||
for decoder in mem::replace(&mut sounds_to_remove, Vec::new()) {
|
||||
let decoder = &*decoder as *const _;
|
||||
sounds.retain(|dec| &**dec as *const _ != decoder)
|
||||
for (_, &mut (_, ref mut sounds)) in voices.iter_mut() {
|
||||
sounds.retain(|dec| &**dec as *const _ != decoder);
|
||||
}
|
||||
}
|
||||
|
||||
let before_updates = time::precise_time_ns();
|
||||
|
||||
// updating the existing sounds
|
||||
for decoder in &sounds {
|
||||
if !decoder.lock().unwrap().write() {
|
||||
sounds_to_remove.push(decoder.clone());
|
||||
let before_updates = time::precise_time_ns();
|
||||
for (_, &mut (ref mut voice, ref mut sounds)) in voices.iter_mut() {
|
||||
// building an iterator that produces samples from `sounds`
|
||||
let num_sounds = sounds.len() as f32;
|
||||
let samples_iter = (0..).map(|_| {
|
||||
// FIXME: locking is slow
|
||||
sounds.iter().map(|s| s.lock().unwrap().next().unwrap_or(0.0) / num_sounds)
|
||||
.fold(0.0, |a, b| a + b)
|
||||
});
|
||||
|
||||
// starting the output
|
||||
{
|
||||
let mut buffer = {
|
||||
let samples_to_write = voice.get_samples_rate().0 * voice.get_channels() as u32;
|
||||
voice.append_data(samples_to_write as usize)
|
||||
};
|
||||
|
||||
match buffer {
|
||||
UnknownTypeBuffer::U16(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(samples_iter) { *o = i.to_u16(); }
|
||||
},
|
||||
UnknownTypeBuffer::I16(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(samples_iter) { *o = i.to_i16(); }
|
||||
},
|
||||
UnknownTypeBuffer::F32(ref mut buffer) => {
|
||||
for (o, i) in buffer.iter_mut().zip(samples_iter) { *o = i; }
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do better
|
||||
voice.play();
|
||||
}
|
||||
|
||||
// sleeping so that we get a loop every 17ms
|
||||
|
|
Loading…
Reference in a new issue