mirror of
https://github.com/RustAudio/rodio
synced 2024-12-12 13:12:30 +00:00
Add support for vorbis decoding
This commit is contained in:
parent
49b03e081a
commit
5a438bcdec
7 changed files with 93 additions and 13 deletions
|
@ -12,3 +12,4 @@ documentation = "http://tomaka.github.io/rodio/rodio/index.html"
|
|||
cpal = "0.1.1"
|
||||
hound = "1.0.0"
|
||||
lazy_static = "0.1.12"
|
||||
vorbis = "0.0.12"
|
||||
|
|
|
@ -9,8 +9,12 @@ fn main() {
|
|||
let file = std::fs::File::open("examples/beep2.wav").unwrap();
|
||||
rodio::play_once(file);
|
||||
|
||||
std::thread::sleep_ms(1000);
|
||||
let file = std::fs::File::open("examples/beep3.ogg").unwrap();
|
||||
rodio::play_once(file);
|
||||
|
||||
std::thread::sleep_ms(1000);
|
||||
beep1.stop();
|
||||
|
||||
std::thread::sleep_ms(8000);
|
||||
std::thread::sleep_ms(7000);
|
||||
}
|
||||
|
|
BIN
examples/beep3.ogg
Normal file
BIN
examples/beep3.ogg
Normal file
Binary file not shown.
|
@ -1,6 +1,7 @@
|
|||
use std::io::Read;
|
||||
use std::io::{Read, Seek};
|
||||
use cpal::Voice;
|
||||
|
||||
mod vorbis;
|
||||
mod wav;
|
||||
|
||||
/// Trait for objects that produce an audio stream.
|
||||
|
@ -10,8 +11,15 @@ pub trait Decoder {
|
|||
}
|
||||
|
||||
/// Builds a new `Decoder` from a data stream by determining the correct format.
|
||||
pub fn decode<R>(data: R) -> Box<Decoder + Send> where R: Read + Send + 'static {
|
||||
if let Ok(decoder) = wav::WavDecoder::new(data) {
|
||||
pub fn decode<R>(data: R) -> Box<Decoder + Send> where R: Read + Seek + Send + 'static {
|
||||
let data = match wav::WavDecoder::new(data) {
|
||||
Err(data) => data,
|
||||
Ok(decoder) => {
|
||||
return Box::new(decoder);
|
||||
}
|
||||
};
|
||||
|
||||
if let Ok(decoder) = vorbis::VorbisDecoder::new(data) {
|
||||
return Box::new(decoder);
|
||||
}
|
||||
|
||||
|
|
62
src/decoder/vorbis.rs
Normal file
62
src/decoder/vorbis.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use std::io::{Read, Seek};
|
||||
use std::mem;
|
||||
use super::Decoder;
|
||||
|
||||
use cpal::{self, Voice};
|
||||
use vorbis;
|
||||
|
||||
pub struct VorbisDecoder<R> where R: Read + Seek {
|
||||
decoder: vorbis::Decoder<R>,
|
||||
current_packet: Option<vorbis::Packet>,
|
||||
}
|
||||
|
||||
impl<R> VorbisDecoder<R> where R: Read + Seek {
|
||||
pub fn new(data: R) -> Result<VorbisDecoder<R>, ()> {
|
||||
let decoder = match vorbis::Decoder::new(data) {
|
||||
Err(_) => return Err(()),
|
||||
Ok(r) => r
|
||||
};
|
||||
|
||||
Ok(VorbisDecoder {
|
||||
decoder: decoder,
|
||||
current_packet: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Decoder for VorbisDecoder<R> where R: Read + Seek {
|
||||
fn write(&mut self, voice: &mut Voice) {
|
||||
// setting the current packet to `None` if there is no data left in it
|
||||
match &mut self.current_packet {
|
||||
packet @ &mut Some(_) => {
|
||||
if packet.as_ref().unwrap().data.len() == 0 {
|
||||
*packet = None;
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
};
|
||||
|
||||
// getting the next packet
|
||||
let packet = if let Some(ref mut packet) = self.current_packet {
|
||||
packet
|
||||
} else {
|
||||
let next = match self.decoder.packets().next().and_then(|r| r.ok()) {
|
||||
Some(p) => p,
|
||||
None => return, // TODO: handle
|
||||
};
|
||||
|
||||
self.current_packet = Some(next);
|
||||
self.current_packet.as_mut().unwrap()
|
||||
};
|
||||
|
||||
let mut buffer = voice.append_data(packet.channels, cpal::SamplesRate(packet.rate as u32),
|
||||
packet.data.len());
|
||||
|
||||
let src = mem::replace(&mut packet.data, Vec::new());
|
||||
let mut src = src.into_iter();
|
||||
for (dest, src) in buffer.iter_mut().zip(src.by_ref()) {
|
||||
*dest = src;
|
||||
}
|
||||
packet.data = src.collect();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::io::Read;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use super::Decoder;
|
||||
|
||||
use cpal::{self, Voice};
|
||||
|
@ -10,13 +10,17 @@ pub struct WavDecoder<R> where R: Read {
|
|||
spec: WavSpec,
|
||||
}
|
||||
|
||||
impl<R> WavDecoder<R> where R: Read {
|
||||
pub fn new(data: R) -> Result<WavDecoder<R>, ()> {
|
||||
let reader = match WavReader::new(data) {
|
||||
Err(_) => return Err(()),
|
||||
Ok(r) => r
|
||||
};
|
||||
impl<R> WavDecoder<R> where R: Read + Seek {
|
||||
pub fn new(mut data: R) -> Result<WavDecoder<R>, R> {
|
||||
let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
|
||||
|
||||
if WavReader::new(data.by_ref()).is_err() {
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
return Err(data);
|
||||
}
|
||||
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
let reader = WavReader::new(data).unwrap();
|
||||
let spec = reader.spec();
|
||||
|
||||
Ok(WavDecoder {
|
||||
|
|
|
@ -2,8 +2,9 @@ extern crate cpal;
|
|||
extern crate hound;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate vorbis;
|
||||
|
||||
use std::io::Read;
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
mod decoder;
|
||||
mod engine;
|
||||
|
@ -25,7 +26,7 @@ impl Handle {
|
|||
}
|
||||
|
||||
/// Plays a sound once. Returns a `Handle` that can be used to control the sound.
|
||||
pub fn play_once<R>(input: R) -> Handle where R: Read + Send + 'static {
|
||||
pub fn play_once<R>(input: R) -> Handle where R: Read + Seek + Send + 'static {
|
||||
let decoder = decoder::decode(input);
|
||||
Handle(ENGINE.play(decoder))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue