use std::fmt;
use std::io;
use std::io::Read;
use std::path;
use std::sync::Arc;
use rodio;
use context::Context;
use GameError;
use GameResult;
pub struct AudioContext {
endpoint: rodio::Endpoint,
}
impl AudioContext {
pub fn new() -> GameResult<AudioContext> {
let error = GameError::AudioError(String::from("Could not initialize sound system (for \
some reason)"));
let e = rodio::get_default_endpoint().ok_or(error)?;
Ok(AudioContext { endpoint: e })
}
}
impl fmt::Debug for AudioContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<AudioContext: {:p}>", self)
}
}
#[derive(Clone, Debug)]
pub struct SoundData(Arc<Vec<u8>>);
impl SoundData {
pub fn from_bytes(data: &[u8]) -> Self {
let mut buffer = Vec::with_capacity(data.len());
buffer.extend(data);
SoundData::from(buffer)
}
pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
where R: Read
{
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer)?;
Ok(SoundData::from(buffer))
}
}
impl From<Vec<u8>> for SoundData {
fn from(v: Vec<u8>) -> Self {
SoundData(Arc::new(v))
}
}
impl AsRef<[u8]> for SoundData {
fn as_ref(&self) -> &[u8] {
self.0.as_ref().as_ref()
}
}
pub struct Source {
data: io::Cursor<SoundData>,
sink: rodio::Sink,
}
impl Source {
pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
let path = path.as_ref();
let data = {
let file = &mut context.filesystem.open(path)?;
SoundData::from_read(file)?
};
Source::from_data(context, data)
}
pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
let sink = rodio::Sink::new(&context.audio_context.endpoint);
let cursor = io::Cursor::new(data);
Ok(Source {
data: cursor,
sink: sink,
})
}
pub fn play(&self) -> GameResult<()> {
let cursor = self.data.clone();
let decoder = rodio::Decoder::new(cursor)?;
self.sink.append(decoder);
Ok(())
}
pub fn pause(&self) {
self.sink.pause()
}
pub fn resume(&self) {
self.sink.play()
}
pub fn stop(&self) {
self.sink.stop()
}
pub fn volume(&self) -> f32 {
self.sink.volume()
}
pub fn set_volume(&mut self, value: f32) {
self.sink.set_volume(value)
}
pub fn paused(&self) -> bool {
self.sink.is_paused()
}
pub fn playing(&self) -> bool {
!self.paused() }
}
impl fmt::Debug for Source {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Audio source: {:p}>", self)
}
}