mirror of
https://github.com/RustAudio/rodio
synced 2025-03-04 15:07:18 +00:00
Remove the Decoder trait and switch to the Source trait
This commit is contained in:
parent
102ec8fd2c
commit
2e09c3494d
5 changed files with 134 additions and 71 deletions
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue