Remove the Decoder trait and switch to the Source trait

This commit is contained in:
Pierre Krieger 2015-10-16 13:35:30 +02:00
parent 102ec8fd2c
commit 2e09c3494d
5 changed files with 134 additions and 71 deletions

View file

@ -1,29 +1,78 @@
use std::io::{Read, Seek};
mod vorbis;
mod wav;
use Sample;
use Source;
/// Trait for objects that produce an audio stream.
pub trait Decoder: Iterator /*+ ExactSizeIterator*/ { // TODO: should be exact size, but not enforced yet
/// Returns the total duration of the second in milliseconds.
fn get_total_duration_ms(&self) -> u32;
pub mod vorbis;
pub mod wav;
/// Source of audio samples from decoding a file.
pub enum Decoder<R> where R: Read + Seek {
Wav(wav::WavDecoder<R>),
Vorbis(vorbis::VorbisDecoder),
}
/// Builds a new `Decoder` from a data stream by determining the correct format.
pub fn decode<R>(data: R, output_channels: u16, output_samples_rate: u32)
-> Box<Decoder<Item=f32> + Send>
where R: Read + Seek + Send + 'static
{
let data = match wav::WavDecoder::new(data, output_channels, output_samples_rate) {
Err(data) => data,
Ok(decoder) => {
return Box::new(decoder);
}
};
impl<R> Decoder<R> where R: Read + Seek + Send + 'static {
pub fn new(data: R) -> Decoder<R> {
let data = match wav::WavDecoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Decoder::Wav(decoder);
}
};
if let Ok(decoder) = vorbis::VorbisDecoder::new(data, output_channels, output_samples_rate) {
return Box::new(decoder);
if let Ok(decoder) = vorbis::VorbisDecoder::new(data) {
return Decoder::Vorbis(decoder);
}
panic!("Invalid format");
}
}
impl<R> Iterator for Decoder<R> where R: Read + Seek {
type Item = f32;
#[inline]
fn next(&mut self) -> Option<f32> {
match self {
&mut Decoder::Wav(ref mut source) => source.next().map(|s| s.to_f32()),
&mut Decoder::Vorbis(ref mut source) => source.next(),
}
}
panic!("Invalid format");
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
&Decoder::Wav(ref source) => source.size_hint(),
&Decoder::Vorbis(ref source) => source.size_hint(),
}
}
}
// TODO: ExactSizeIterator
impl<R> Source for Decoder<R> where R: Read + Seek {
#[inline]
fn get_current_frame_len(&self) -> usize {
match self {
&Decoder::Wav(ref source) => source.get_current_frame_len(),
&Decoder::Vorbis(ref source) => source.get_current_frame_len(),
}
}
#[inline]
fn get_channels(&self) -> u16 {
match self {
&Decoder::Wav(ref source) => source.get_channels(),
&Decoder::Vorbis(ref source) => source.get_channels(),
}
}
#[inline]
fn get_samples_rate(&self) -> u32 {
match self {
&Decoder::Wav(ref source) => source.get_samples_rate(),
&Decoder::Vorbis(ref source) => source.get_samples_rate(),
}
}
}

View file

@ -1,20 +1,18 @@
use std::io::{Read, Seek};
use super::Decoder;
use conversions;
use cpal;
use vorbis;
use Source;
//use vorbis;
pub struct VorbisDecoder {
reader: Box<Iterator<Item=f32> + Send>,
}
impl VorbisDecoder {
pub fn new<R>(data: R, output_channels: u16, output_samples_rate: u32)
-> Result<VorbisDecoder, ()>
pub fn new<R>(_data: R) -> Result<VorbisDecoder, ()>
where R: Read + Seek + Send + 'static
{
let decoder = match vorbis::Decoder::new(data) {
/*let decoder = match vorbis::Decoder::new(data) {
Err(_) => return Err(()),
Ok(r) => r
};
@ -31,13 +29,26 @@ impl VorbisDecoder {
Ok(VorbisDecoder {
reader: Box::new(reader),
})
})*/
unimplemented!()
}
}
impl Decoder for VorbisDecoder {
fn get_total_duration_ms(&self) -> u32 {
10000 // FIXME: wrong
impl Source for VorbisDecoder {
#[inline]
fn get_current_frame_len(&self) -> usize {
self.len()
}
#[inline]
fn get_channels(&self) -> u16 {
unimplemented!()
}
#[inline]
fn get_samples_rate(&self) -> u32 {
unimplemented!()
}
}

View file

@ -1,39 +1,29 @@
use std::io::{Read, Seek, SeekFrom};
use super::Decoder;
use conversions::ChannelsCountConverter;
use conversions::SamplesRateConverter;
use conversions::DataConverter;
use Source;
use cpal;
use hound::WavReader;
pub struct WavDecoder<R> where R: Read + Seek {
reader: DataConverter<SamplesRateConverter<ChannelsCountConverter<SamplesIterator<R>>>, f32>,
total_duration_ms: u32,
reader: SamplesIterator<R>,
samples_rate: u32,
channels: u16,
}
impl<R> WavDecoder<R> where R: Read + Seek {
pub fn new(mut data: R, output_channels: u16, output_samples_rate: u32)
-> Result<WavDecoder<R>, R>
{
pub fn new(mut data: R) -> Result<WavDecoder<R>, R> {
if !is_wave(data.by_ref()) {
return Err(data);
}
let reader = WavReader::new(data).unwrap();
let spec = reader.spec();
let total_duration_ms = reader.duration() * 1000 / spec.sample_rate;
let reader = SamplesIterator { reader: reader, samples_read: 0 };
let reader = ChannelsCountConverter::new(reader, spec.channels, output_channels);
let reader = SamplesRateConverter::new(reader, cpal::SamplesRate(spec.sample_rate),
cpal::SamplesRate(output_samples_rate), output_channels);
let reader = DataConverter::new(reader);
Ok(WavDecoder {
reader: reader,
total_duration_ms: total_duration_ms,
samples_rate: spec.sample_rate,
channels: spec.channels,
})
}
}
@ -78,17 +68,28 @@ fn is_wave<R>(mut data: R) -> bool where R: Read + Seek {
true
}
impl<R> Decoder for WavDecoder<R> where R: Read + Seek {
fn get_total_duration_ms(&self) -> u32 {
self.total_duration_ms
impl<R> Source for WavDecoder<R> where R: Read + Seek {
#[inline]
fn get_current_frame_len(&self) -> usize {
self.len()
}
#[inline]
fn get_channels(&self) -> u16 {
self.channels
}
#[inline]
fn get_samples_rate(&self) -> u32 {
self.samples_rate
}
}
impl<R> Iterator for WavDecoder<R> where R: Read + Seek {
type Item = f32;
type Item = i16;
#[inline]
fn next(&mut self) -> Option<f32> {
fn next(&mut self) -> Option<i16> {
self.reader.next()
}

View file

@ -1,7 +1,6 @@
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::atomic::AtomicUsize;
@ -13,10 +12,11 @@ use cpal;
use cpal::UnknownTypeBuffer;
use cpal::Voice;
use cpal::Endpoint;
use decoder;
use decoder::Decoder;
use conversions::Sample;
use source::Source;
use source::UniformSourceIterator;
use time;
/// Duration of a loop of the engine in milliseconds.
@ -57,8 +57,8 @@ impl Engine {
}
/// Starts playing a sound and returns a `Handler` to control it.
pub fn play<R>(&self, endpoint: &Endpoint, input: R) -> Handle
where R: Read + Seek + Send + 'static
pub fn play<S>(&self, endpoint: &Endpoint, source: S) -> Handle
where S: Source + Send + 'static, S::Item: Sample, S::Item: Send
{
// try looking for an existing voice, or create one if there isn't one
let (new_voice, channels_count, samples_rate) = {
@ -99,13 +99,14 @@ impl Engine {
(new_voice, c, s)
};
// try build the decoder
let decoder = decoder::decode(input, channels_count, samples_rate);
let decoder_id = &*decoder as *const _ as *const u8 as usize;
// boxing the source and obtaining an ID for it
let source = UniformSourceIterator::new(source, channels_count, samples_rate);
let source = Box::new(source) as Box<Iterator<Item=f32> + Send + 'static>;
let source_id = &*source as *const _ as *const u8 as usize;
// getting some infos ; we are going to send the decoder to the background thread, so this
// is the last time we can get infos from it
let total_duration_ms = decoder.get_total_duration_ms();
let total_duration_ms = source.size_hint().0 * 1000 / (samples_rate as usize * channels_count as usize); // FIXME: use `len()` instead
// at each loop, the background thread will store the remaining time of the sound in this
// value
@ -113,7 +114,7 @@ impl Engine {
// send the play command
let commands = self.commands.lock().unwrap();
commands.send(Command::Play(endpoint.clone(), new_voice, decoder, remaining_duration_ms.clone())).unwrap();
commands.send(Command::Play(endpoint.clone(), new_voice, source, remaining_duration_ms.clone())).unwrap();
// unpark the background thread so that the sound starts playing immediately
if let Some(ref thread) = self.thread {
@ -122,8 +123,8 @@ impl Engine {
Handle {
engine: self,
decoder_id: decoder_id,
total_duration_ms: total_duration_ms,
source_id: source_id,
total_duration_ms: total_duration_ms as u32,
remaining_duration_ms: remaining_duration_ms,
}
}
@ -134,7 +135,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_id: usize,
source_id: usize,
total_duration_ms: u32,
remaining_duration_ms: Arc<AtomicUsize>,
}
@ -143,13 +144,13 @@ impl<'a> Handle<'a> {
#[inline]
pub fn set_volume(&self, value: f32) {
let commands = self.engine.commands.lock().unwrap();
commands.send(Command::SetVolume(self.decoder_id, value)).unwrap();
commands.send(Command::SetVolume(self.source_id, value)).unwrap();
}
#[inline]
pub fn stop(self) {
let commands = self.engine.commands.lock().unwrap();
commands.send(Command::Stop(self.decoder_id)).unwrap();
commands.send(Command::Stop(self.source_id)).unwrap();
if let Some(ref thread) = self.engine.thread {
thread.unpark();
@ -168,17 +169,17 @@ impl<'a> Handle<'a> {
}
pub enum Command {
Play(Endpoint, Option<Voice>, Box<Decoder<Item=f32> + Send>, Arc<AtomicUsize>),
Play(Endpoint, Option<Voice>, Box<Iterator<Item=f32> + Send>, Arc<AtomicUsize>),
Stop(usize),
SetVolume(usize, f32),
}
fn background(rx: Receiver<Command>) {
// for each endpoint name, stores the voice and the list of sounds with their volume
let mut voices: HashMap<String, (Voice, Vec<(Box<Decoder<Item=f32> + Send>, Arc<AtomicUsize>, f32)>)> = HashMap::new();
let mut voices: HashMap<String, (Voice, Vec<(Box<Iterator<Item=f32> + Send>, Arc<AtomicUsize>, f32)>)> = HashMap::new();
// list of sounds to stop playing
let mut sounds_to_remove: Vec<*const (Decoder<Item=f32> + Send)> = Vec::new();
let mut sounds_to_remove: Vec<*const (Iterator<Item=f32> + Send)> = Vec::new();
// stores the time when the next loop must start
let mut next_loop_timer = time::precise_time_ns();

View file

@ -71,6 +71,7 @@ impl Handle {
pub fn play_once<R>(endpoint: &Endpoint, input: R) -> Handle
where R: Read + Seek + Send + 'static
{
let input = decoder::Decoder::new(input);
Handle(ENGINE.play(&endpoint, input))
}