Skip to content

Instantly share code, notes, and snippets.

@ndarilek
Created February 28, 2019 00:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndarilek/3239c2e659626d2f8a1818553071e3d3 to your computer and use it in GitHub Desktop.
Save ndarilek/3239c2e659626d2f8a1818553071e3d3 to your computer and use it in GitHub Desktop.
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