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 {
device: rodio::Device,
}
impl AudioContext {
pub fn new() -> GameResult<AudioContext> {
let device = rodio::default_output_device().ok_or_else(|| {
GameError::AudioError(String::from(
"Could not initialize sound system (for some reason)",
))
})?;
Ok(AudioContext { device: device })
}
}
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<[u8]>);
impl SoundData {
pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
let path = path.as_ref();
let file = &mut context.filesystem.open(path)?;
SoundData::from_read(file)
}
pub fn from_bytes(data: &[u8]) -> Self {
SoundData(Arc::from(data))
}
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<Arc<[u8]>> for SoundData {
#[inline]
fn from(arc: Arc<[u8]>) -> Self {
SoundData(arc)
}
}
impl From<Vec<u8>> for SoundData {
fn from(v: Vec<u8>) -> Self {
SoundData(Arc::from(v))
}
}
impl From<Box<[u8]>> for SoundData {
fn from(b: Box<[u8]>) -> Self {
SoundData(Arc::from(b))
}
}
impl AsRef<[u8]> for SoundData {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
pub struct Source {
data: io::Cursor<SoundData>,
sink: rodio::Sink,
repeat: bool,
}
impl Source {
pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
let path = path.as_ref();
let data = SoundData::new(context, path)?;
Source::from_data(context, data)
}
pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
let sink = rodio::Sink::new(&context.audio_context.device);
let cursor = io::Cursor::new(data);
Ok(Source {
sink,
data: cursor,
repeat: false,
})
}
pub fn play(&self) -> GameResult<()> {
use rodio::Source;
let cursor = self.data.clone();
let decoder = rodio::Decoder::new(cursor)?;
if self.repeat {
let repeating = decoder.repeat_infinite();
self.sink.append(repeating);
} else {
self.sink.append(decoder);
}
Ok(())
}
pub fn set_repeat(&mut self, repeat: bool) {
self.repeat = repeat;
}
pub fn repeat(&self) -> bool {
self.repeat
}
pub fn pause(&self) {
self.sink.pause()
}
pub fn resume(&self) {
self.sink.play()
}
pub fn stop(&self) {
self.sink.stop()
}
pub fn stopped(&self) -> bool {
self.sink.empty()
}
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() && !self.stopped()
}
}
impl fmt::Debug for Source {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Audio source: {:p}>", self)
}
}