Created
February 28, 2019 00:30
-
-
Save ndarilek/3239c2e659626d2f8a1818553071e3d3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cell::RefCell; | |
use std::collections::HashMap; | |
use std::io::Cursor; | |
use std::sync::{Arc, Mutex}; | |
use alto::{Alto, Buffer, Context, Mono, Stereo, Source, SourceState, StaticSource}; | |
use amethyst::{ | |
Error, | |
assets::{Asset, AssetStorage, Handle, ProcessingState, Processor, SimpleFormat}, | |
core::{ | |
bundle, | |
transform::Transform, | |
}, | |
ecs::prelude::*, | |
}; | |
use lewton::inside_ogg::OggStreamReader; | |
use serde::{Deserialize, Serialize}; | |
#[derive(Clone, Debug)] | |
pub struct Audio { | |
bytes: Vec<i16>, | |
sample_rate: i32, | |
channels: u8, | |
} | |
pub type AudioHandle = Handle<Audio>; | |
impl Asset for Audio { | |
const NAME: &'static str = "audio::Source"; | |
type Data = Self; | |
type HandleStorage = VecStorage<AudioHandle>; | |
} | |
impl From<Audio> for Result<ProcessingState<Audio>, Error> { | |
fn from(audio: Audio) -> Result<ProcessingState<Audio>, Error> { | |
Ok(ProcessingState::Loaded(audio)) | |
} | |
} | |
#[derive(Clone)] | |
pub struct OggFormat; | |
impl SimpleFormat<Audio> for OggFormat { | |
const NAME: &'static str = "OGG"; | |
type Options = (); | |
fn import(&self, bytes: Vec<u8>, _: ()) -> Result<Audio, Error> { | |
let mut reader = OggStreamReader::new(Cursor::new(bytes))?; | |
let sample_rate = reader.ident_hdr.audio_sample_rate as i32; | |
let channels = reader.ident_hdr.audio_channels; | |
let mut decoded: Vec<i16> = Vec::new(); | |
while let Some(mut samples) = reader.read_dec_packet_itl()? { | |
decoded.append(&mut samples); | |
} | |
Ok(Audio { | |
bytes: decoded, | |
sample_rate, | |
channels, | |
}) | |
} | |
} | |
#[derive(Clone, Debug, Deserialize, Serialize)] | |
pub enum AudioFormat { | |
Ogg, | |
} | |
impl SimpleFormat<Audio> for AudioFormat { | |
const NAME: &'static str = "AudioFormat"; | |
type Options = (); | |
fn import(&self, bytes: Vec<u8>, options: ()) -> Result<Audio, Error> { | |
match *self { | |
AudioFormat::Ogg => SimpleFormat::import(&OggFormat, bytes, options), | |
} | |
} | |
} | |
#[derive(Default)] | |
pub struct AudioListener; | |
impl Component for AudioListener { | |
type Storage = NullStorage<Self>; | |
} | |
pub struct AudioEmitter { | |
context: Context, | |
sources: RefCell<HashMap<String, Arc<StaticSource>>>, | |
} | |
impl AudioEmitter { | |
pub fn new(context: Context) -> Self { | |
AudioEmitter { | |
context, | |
sources: RefCell::new(HashMap::new()), | |
} | |
} | |
pub fn insert<S: Into<String>>(&mut self, name: S, audio: Audio) { | |
let buffer = match &audio.channels { | |
1 => { | |
Arc::new(self.context.new_buffer::<Mono<i16>, _>(&audio.bytes, audio.sample_rate).unwrap()) | |
}, | |
2 => { | |
Arc::new(self.context.new_buffer::<Stereo<i16>, _>(&audio.bytes, audio.sample_rate).unwrap()) | |
}, | |
_ => panic!("Unsupported channel count"), | |
}; | |
let source = Arc::new(self.context.new_static_source().unwrap()); | |
source.set_buffer(buffer); | |
let sources = self.sources.borrow_mut(); | |
sources.insert(name.into(), source); | |
} | |
pub fn play<S: Into<String>>(&mut self, name: S) -> Result<(), Error> { | |
let mut sources = self.sources.borrow_mut(); | |
let source = sources.get_mut(&name.into()) | |
.expect("Source not found"); | |
source.play(); | |
Ok(()) | |
} | |
pub fn stop<S: Into<String>>(&mut self, name: S) -> Result<(), Error> { | |
let mut sources = self.sources.borrow_mut(); | |
let source = sources.get_mut(&name.into()) | |
.expect("Source not found"); | |
source.stop(); | |
Ok(()) | |
} | |
pub fn insert_and_play<S: Into<String>>(&mut self, name: S, audio: Audio) -> Result<(), Error> { | |
let name = name.into(); | |
self.insert(name.clone(), audio); | |
self.play(name.clone())?; | |
Ok(()) | |
} | |
pub fn set_loop<S: Into<String>>(&mut self, name: S, should_loop: bool) -> Result<(), Error> { | |
let mut sources = self.sources.borrow_mut(); | |
let mut source = sources.get_mut(&name.into()) | |
.expect("Source not found"); | |
source.set_looping(should_loop); | |
Ok(()) | |
} | |
pub fn set_gain<S: Into<String>>(&mut self, name: S, gain: f32) -> Result<(), Error> { | |
let mut sources = self.sources.borrow_mut(); | |
let mut source = sources.get_mut(&name.into()) | |
.expect("Source not found"); | |
source.set_gain(gain); | |
Ok(()) | |
} | |
} | |
/*impl Component for AudioEmitter { | |
type Storage = DenseVecStorage<Self>; | |
}*/ | |
/*#[derive(Default)] | |
struct AudioSystem( | |
HashMap<(Entity, String), StaticSource>, | |
HashMap<AudioHandle, Arc<Buffer>>, | |
); | |
impl<'s> System<'s> for AudioSystem { | |
type SystemData = ( | |
Entities<'s>, | |
Read<'s, AssetStorage<Audio>>, | |
ReadStorage<'s, Transform>, | |
ReadExpect<'s, Context>, | |
ReadStorage<'s, AudioListener>, | |
WriteStorage<'s, AudioEmitter>, | |
); | |
fn run( | |
&mut self, | |
(entities, assets, transforms, context, listener, mut emitters): Self::SystemData | |
) { | |
if let Some((_, entity)) = (&listener, &*entities).join().next() { | |
if let Some(transform) = transforms.get(entity) { | |
let translation = transform.translation(); | |
context.set_position([translation[0], translation[1], translation[2]]).unwrap(); | |
// context.set_orientation(([0.0, 0.0, 1.0], [0.0, 1.0, 0.0])).unwrap(); | |
} else { | |
context.set_position([0.0, 0.0, 0.0]).unwrap(); | |
context.set_orientation(([0.0, 0.0, 1.0], [0.0, 1.0, 0.0])).unwrap(); | |
} | |
} else { | |
context.set_position([0.0, 0.0, 0.0]).unwrap(); | |
context.set_orientation(([0.0, 0.0, 1.0], [0.0, 1.0, 0.0])).unwrap(); | |
} | |
for (entity, emitter) in (&entities, &mut emitters).join() { | |
} | |
} | |
fn setup(&mut self, res: &mut Resources) { | |
Self::SystemData::setup(res); | |
let alto = Alto::load_default().unwrap(); | |
let device = alto.open(None).unwrap(); | |
let context = device.new_context(None).unwrap(); | |
res.insert(context); | |
} | |
} | |
pub struct AudioBundle; | |
impl<'a, 'b> bundle::SystemBundle<'a, 'b> for AudioBundle { | |
fn build(self, builder: &mut DispatcherBuilder<'a, 'b>) -> amethyst::Result<()> { | |
builder.add(AudioSystem::default(), "audio_system", &[]); | |
builder.add(Processor::<Audio>::new(), "audio_processor", &[]); | |
Ok(()) | |
} | |
}*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment