Implement decoding Flac

This commit is contained in:
Pierre Krieger 2017-02-09 11:49:44 +01:00
parent 953681a14d
commit 99419b64ec
8 changed files with 148 additions and 4 deletions

View file

@ -9,6 +9,7 @@ repository = "https://github.com/tomaka/rodio"
documentation = "http://tomaka.github.io/rodio/rodio/index.html"
[dependencies]
claxon = "0.3.0"
cpal = "0.4.0"
futures = "0.1.1"
hound = "1.0.0"

View file

@ -9,6 +9,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://tomaka.github.io/rodio/rodio/index.html)

BIN
examples/music.flac Normal file

Binary file not shown.

13
examples/music_flac.rs Normal file
View 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();
}

View file

@ -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();
}

115
src/decoder/flac.rs Normal file
View file

@ -0,0 +1,115 @@
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_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_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 raw_val = self.current_block[self.current_block_off];
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 = 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
}

View file

@ -6,12 +6,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>
@ -19,6 +20,7 @@ enum DecoderImpl<R>
{
Wav(wav::WavDecoder<R>),
Vorbis(vorbis::VorbisDecoder<R>),
Flac(flac::FlacDecoder<R>),
}
impl<R> Decoder<R>
@ -35,6 +37,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)));
}
@ -53,6 +62,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()),
}
}
@ -61,6 +71,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(),
}
}
}
@ -73,6 +84,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(),
}
}
@ -81,6 +93,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(),
}
}
@ -89,6 +102,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(),
}
}
@ -97,6 +111,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(),
}
}
}

View file

@ -53,6 +53,7 @@
#![cfg_attr(test, deny(missing_docs))]
extern crate claxon;
extern crate cpal;
extern crate futures;
extern crate hound;