use std::mem;
use libc::c_void;
use std::vec::Vec;
use openal::{ffi, al};
use sndfile::{SndFile, SndInfo};
use sndfile::OpenMode::Read;
use internal::OpenAlData;
use audio_tags::{Tags, AudioTags, get_sound_tags};
pub struct SoundData {
sound_tags: Tags,
snd_info: SndInfo,
nb_sample: i64,
al_buffer: u32
}
impl SoundData {
pub fn new(path: &str) -> Result<SoundData, String> {
check_openal_context!(Err("Invalid OpenAL context.".into()));
let mut file = match SndFile::new(path, Read) {
Ok(file) => file,
Err(err) => {
return Err(format!("Error while loading sound file: {}", err));
}
};
let infos = file.get_sndinfo();
let nb_sample = infos.channels as i64 * infos.frames;
let mut samples = vec![0i16; nb_sample as usize];
file.read_i16(&mut samples[..], nb_sample as i64);
let mut buffer_id = 0;
let len = mem::size_of::<i16>() * (samples.len());
let format = match al::get_channels_format(infos.channels) {
Some(fmt) => fmt,
None => {
return Err("Unrecognized sound format.".into());
}
};
al::alGenBuffers(1, &mut buffer_id);
al::alBufferData(buffer_id,
format,
samples.as_ptr() as *mut c_void,
len as i32,
infos.samplerate);
if let Some(err) = al::openal_has_error() {
return Err(format!("Internal OpenAL error: {}", err));
};
let sound_data = SoundData {
sound_tags: get_sound_tags(&file),
snd_info: infos,
nb_sample: nb_sample,
al_buffer: buffer_id
};
file.close();
Ok(sound_data)
}
}
pub fn get_sndinfo<'r>(s_data: &'r SoundData) -> &'r SndInfo {
&s_data.snd_info
}
#[doc(hidden)]
pub fn get_buffer(s_data: &SoundData) -> u32 {
s_data.al_buffer
}
impl AudioTags for SoundData {
fn get_tags(&self) -> Tags {
self.sound_tags.clone()
}
}
impl Drop for SoundData {
fn drop(&mut self) -> () {
unsafe {
ffi::alDeleteBuffers(1, &mut self.al_buffer);
}
}
}
#[cfg(test)]
mod test {
#![allow(non_snake_case)]
#[allow(unused_variables)]
use sound_data::SoundData;
#[test]
#[ignore]
fn sounddata_create_OK() -> () {
#![allow(unused_variables)]
let snd_data = SoundData::new("res/shot.wav").unwrap();
}
#[test]
#[ignore]
#[should_panic]
fn sounddata_create_FAIL() -> () {
#![allow(unused_variables)]
let snd_data = SoundData::new("toto.wav").unwrap();
}
}