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"
|
cpal = "0.1.1"
|
||||||
hound = "1.0.0"
|
hound = "1.0.0"
|
||||||
lazy_static = "0.1.12"
|
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();
|
let file = std::fs::File::open("examples/beep2.wav").unwrap();
|
||||||
rodio::play_once(file);
|
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);
|
std::thread::sleep_ms(1000);
|
||||||
beep1.stop();
|
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;
|
use cpal::Voice;
|
||||||
|
|
||||||
|
mod vorbis;
|
||||||
mod wav;
|
mod wav;
|
||||||
|
|
||||||
/// Trait for objects that produce an audio stream.
|
/// 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.
|
/// 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 {
|
pub fn decode<R>(data: R) -> Box<Decoder + Send> where R: Read + Seek + Send + 'static {
|
||||||
if let Ok(decoder) = wav::WavDecoder::new(data) {
|
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);
|
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 super::Decoder;
|
||||||
|
|
||||||
use cpal::{self, Voice};
|
use cpal::{self, Voice};
|
||||||
|
@ -10,13 +10,17 @@ pub struct WavDecoder<R> where R: Read {
|
||||||
spec: WavSpec,
|
spec: WavSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> WavDecoder<R> where R: Read {
|
impl<R> WavDecoder<R> where R: Read + Seek {
|
||||||
pub fn new(data: R) -> Result<WavDecoder<R>, ()> {
|
pub fn new(mut data: R) -> Result<WavDecoder<R>, R> {
|
||||||
let reader = match WavReader::new(data) {
|
let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
|
||||||
Err(_) => return Err(()),
|
|
||||||
Ok(r) => r
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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();
|
let spec = reader.spec();
|
||||||
|
|
||||||
Ok(WavDecoder {
|
Ok(WavDecoder {
|
||||||
|
|
|
@ -2,8 +2,9 @@ extern crate cpal;
|
||||||
extern crate hound;
|
extern crate hound;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
extern crate vorbis;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
mod decoder;
|
mod decoder;
|
||||||
mod engine;
|
mod engine;
|
||||||
|
@ -25,7 +26,7 @@ impl Handle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Plays a sound once. Returns a `Handle` that can be used to control the sound.
|
/// 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);
|
let decoder = decoder::decode(input);
|
||||||
Handle(ENGINE.play(decoder))
|
Handle(ENGINE.play(decoder))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue