mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
commit
b1a560eb41
8 changed files with 154 additions and 4 deletions
|
@ -9,6 +9,7 @@ repository = "https://github.com/tomaka/rodio"
|
|||
documentation = "http://docs.rs/rodio"
|
||||
|
||||
[dependencies]
|
||||
claxon = "0.3.0"
|
||||
cpal = "0.4.0"
|
||||
futures = "0.1.1"
|
||||
hound = "1.0.0"
|
||||
|
|
|
@ -8,6 +8,7 @@ Rust playback library.
|
|||
- Playback is handled by [cpal](https://github.com/tomaka/cpal).
|
||||
- WAV decoding is handled by [hound](https://github.com/ruud-v-a/hound).
|
||||
- Vorbis decoding is handled by [lewton](https://github.com/est31/lewton).
|
||||
- Flac decoding is handled by [claxon](https://github.com/ruuda/claxon).
|
||||
|
||||
# [Documentation](http://docs.rs/rodio)
|
||||
|
||||
|
|
BIN
examples/music.flac
Normal file
BIN
examples/music.flac
Normal file
Binary file not shown.
13
examples/music_flac.rs
Normal file
13
examples/music_flac.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
extern crate rodio;
|
||||
|
||||
use std::io::BufReader;
|
||||
|
||||
fn main() {
|
||||
let endpoint = rodio::get_default_endpoint().unwrap();
|
||||
let sink = rodio::Sink::new(&endpoint);
|
||||
|
||||
let file = std::fs::File::open("examples/music.flac").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
||||
sink.sleep_until_end();
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
extern crate rodio;
|
||||
|
||||
use std::io::BufReader;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
let endpoint = rodio::get_default_endpoint().unwrap();
|
||||
|
@ -11,5 +9,5 @@ fn main() {
|
|||
let file = std::fs::File::open("examples/music.ogg").unwrap();
|
||||
sink.append(rodio::Decoder::new(BufReader::new(file)).unwrap());
|
||||
|
||||
thread::sleep(Duration::from_millis(60000));
|
||||
sink.sleep_until_end();
|
||||
}
|
||||
|
|
121
src/decoder/flac.rs
Normal file
121
src/decoder/flac.rs
Normal file
|
@ -0,0 +1,121 @@
|
|||
use std::mem;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::time::Duration;
|
||||
|
||||
use Source;
|
||||
|
||||
use claxon::FlacReader;
|
||||
|
||||
/// Decoder for the Flac format.
|
||||
pub struct FlacDecoder<R>
|
||||
where R: Read + Seek
|
||||
{
|
||||
reader: FlacReader<R>,
|
||||
current_block: Vec<i32>,
|
||||
current_block_channel_len: usize,
|
||||
current_block_off: usize,
|
||||
bits_per_sample: u32,
|
||||
samples_rate: u32,
|
||||
channels: u16,
|
||||
}
|
||||
|
||||
impl<R> FlacDecoder<R>
|
||||
where R: Read + Seek
|
||||
{
|
||||
/// Attempts to decode the data as Flac.
|
||||
pub fn new(mut data: R) -> Result<FlacDecoder<R>, R> {
|
||||
if !is_flac(data.by_ref()) {
|
||||
return Err(data);
|
||||
}
|
||||
|
||||
let reader = FlacReader::new(data).unwrap();
|
||||
let spec = reader.streaminfo();
|
||||
|
||||
Ok(FlacDecoder {
|
||||
reader: reader,
|
||||
current_block: Vec::with_capacity(spec.max_block_size as usize *
|
||||
spec.channels as usize),
|
||||
current_block_channel_len: 1,
|
||||
current_block_off: 0,
|
||||
bits_per_sample: spec.bits_per_sample,
|
||||
samples_rate: spec.sample_rate,
|
||||
channels: spec.channels as u16,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Source for FlacDecoder<R>
|
||||
where R: Read + Seek
|
||||
{
|
||||
#[inline]
|
||||
fn get_current_frame_len(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_channels(&self) -> u16 {
|
||||
self.channels
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_samples_rate(&self) -> u32 {
|
||||
self.samples_rate
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_total_duration(&self) -> Option<Duration> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Iterator for FlacDecoder<R>
|
||||
where R: Read + Seek
|
||||
{
|
||||
type Item = i16;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<i16> {
|
||||
loop {
|
||||
if self.current_block_off < self.current_block.len() {
|
||||
// Read from current block.
|
||||
let real_offset = (self.current_block_off % self.channels as usize) * self.current_block_channel_len + self.current_block_off / self.channels as usize;
|
||||
let raw_val = self.current_block[real_offset];
|
||||
self.current_block_off += 1;
|
||||
let real_val = if self.bits_per_sample == 16 {
|
||||
raw_val as i16
|
||||
} else if self.bits_per_sample < 16 {
|
||||
(raw_val << (16 - self.bits_per_sample)) as i16
|
||||
} else {
|
||||
(raw_val >> (self.bits_per_sample - 16)) as i16
|
||||
};
|
||||
return Some(real_val as i16);
|
||||
}
|
||||
|
||||
// Load the next block.
|
||||
self.current_block_off = 0;
|
||||
let buffer = mem::replace(&mut self.current_block, Vec::new());
|
||||
match self.reader.blocks().read_next_or_eof(buffer) {
|
||||
Ok(Some(block)) => {
|
||||
self.current_block_channel_len = (block.len() / block.channels()) as usize;
|
||||
self.current_block = block.into_buffer();
|
||||
},
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the stream contains Flac data, then resets it to where it was.
|
||||
fn is_flac<R>(mut data: R) -> bool
|
||||
where R: Read + Seek
|
||||
{
|
||||
let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
|
||||
|
||||
if FlacReader::new(data.by_ref()).is_err() {
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
return false;
|
||||
}
|
||||
|
||||
data.seek(SeekFrom::Start(stream_pos)).unwrap();
|
||||
true
|
||||
}
|
|
@ -8,12 +8,13 @@ use std::time::Duration;
|
|||
use Sample;
|
||||
use Source;
|
||||
|
||||
mod flac;
|
||||
mod vorbis;
|
||||
mod wav;
|
||||
|
||||
/// Source of audio samples from decoding a file.
|
||||
///
|
||||
/// Supports WAV and Vorbis.
|
||||
/// Supports WAV, Vorbis and Flac.
|
||||
pub struct Decoder<R>(DecoderImpl<R>) where R: Read + Seek;
|
||||
|
||||
enum DecoderImpl<R>
|
||||
|
@ -21,6 +22,7 @@ enum DecoderImpl<R>
|
|||
{
|
||||
Wav(wav::WavDecoder<R>),
|
||||
Vorbis(vorbis::VorbisDecoder<R>),
|
||||
Flac(flac::FlacDecoder<R>),
|
||||
}
|
||||
|
||||
impl<R> Decoder<R>
|
||||
|
@ -37,6 +39,13 @@ impl<R> Decoder<R>
|
|||
}
|
||||
};
|
||||
|
||||
let data = match flac::FlacDecoder::new(data) {
|
||||
Err(data) => data,
|
||||
Ok(decoder) => {
|
||||
return Ok(Decoder(DecoderImpl::Flac(decoder)));
|
||||
}
|
||||
};
|
||||
|
||||
if let Ok(decoder) = vorbis::VorbisDecoder::new(data) {
|
||||
return Ok(Decoder(DecoderImpl::Vorbis(decoder)));
|
||||
}
|
||||
|
@ -55,6 +64,7 @@ impl<R> Iterator for Decoder<R>
|
|||
match self.0 {
|
||||
DecoderImpl::Wav(ref mut source) => source.next().map(|s| s.to_f32()),
|
||||
DecoderImpl::Vorbis(ref mut source) => source.next().map(|s| s.to_f32()),
|
||||
DecoderImpl::Flac(ref mut source) => source.next().map(|s| s.to_f32()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +73,7 @@ impl<R> Iterator for Decoder<R>
|
|||
match self.0 {
|
||||
DecoderImpl::Wav(ref source) => source.size_hint(),
|
||||
DecoderImpl::Vorbis(ref source) => source.size_hint(),
|
||||
DecoderImpl::Flac(ref source) => source.size_hint(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +86,7 @@ impl<R> Source for Decoder<R>
|
|||
match self.0 {
|
||||
DecoderImpl::Wav(ref source) => source.get_current_frame_len(),
|
||||
DecoderImpl::Vorbis(ref source) => source.get_current_frame_len(),
|
||||
DecoderImpl::Flac(ref source) => source.get_current_frame_len(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,6 +95,7 @@ impl<R> Source for Decoder<R>
|
|||
match self.0 {
|
||||
DecoderImpl::Wav(ref source) => source.get_channels(),
|
||||
DecoderImpl::Vorbis(ref source) => source.get_channels(),
|
||||
DecoderImpl::Flac(ref source) => source.get_channels(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +104,7 @@ impl<R> Source for Decoder<R>
|
|||
match self.0 {
|
||||
DecoderImpl::Wav(ref source) => source.get_samples_rate(),
|
||||
DecoderImpl::Vorbis(ref source) => source.get_samples_rate(),
|
||||
DecoderImpl::Flac(ref source) => source.get_samples_rate(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +113,7 @@ impl<R> Source for Decoder<R>
|
|||
match self.0 {
|
||||
DecoderImpl::Wav(ref source) => source.get_total_duration(),
|
||||
DecoderImpl::Vorbis(ref source) => source.get_total_duration(),
|
||||
DecoderImpl::Flac(ref source) => source.get_total_duration(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
|
||||
#![cfg_attr(test, deny(missing_docs))]
|
||||
|
||||
extern crate claxon;
|
||||
extern crate cpal;
|
||||
extern crate futures;
|
||||
extern crate hound;
|
||||
|
|
Loading…
Reference in a new issue