use {log, fmod, nsys};
use key_vec::KeyVec;
use crate::Tree;
use crate::tree::NodeId;
use crate::interface::{view, View};
use super::{Audio, Presentation};
pub mod remote;
pub use self::remote::Remote;
#[derive(Debug)]
pub struct Fmod {
pub audition : nsys::fmod::Audition,
pub channel_group : fmod::ChannelGroup,
pub sfx : KeyVec <NodeId, nsys::fmod::voice::Id>
}
impl Fmod {
fn create_sfx (&mut self, node_id : NodeId) {
log::trace!("create sfx...");
let voice_id = self.audition.new_voice();
self.sfx.insert (node_id, voice_id);
log::trace!("...create sfx");
}
fn update_sfx (&mut self, sfx : view::component::Sfx, node_id : NodeId) {
log::trace!("update sfx...");
let voice_id = self.sfx.get (&node_id).unwrap();
let voice = &mut self.audition.voices[voice_id.0 as usize];
if let Some ((sound_id, state)) = sfx.playback {
use view::component::sfx::State;
let sample_id = sound_id.into();
let mut sample = self.audition.sampler.get (sample_id).unwrap().clone();
let channel_group = Some (self.channel_group.clone());
match state {
State::Ready => voice.cue (&mut sample, channel_group),
State::Play => voice.play (&mut sample, channel_group),
State::Loop => voice.loop_ (&mut sample, channel_group),
State::PlayFrom (position) => voice.play_from (&mut sample,
channel_group, position),
State::LoopFrom (position) => voice.loop_from (&mut sample,
channel_group, position)
}
} else {
voice.stop();
}
log::trace!("...update sfx");
}
fn display_value (&mut self, node_id : NodeId, display : view::Display) {
match display {
view::Display::Create (
View { component: view::Component::Sfx (sfx), .. },
node_id,
..
) => {
self.create_sfx (node_id.clone());
self.update_sfx (sfx, node_id);
}
view::Display::Update (view::Update::View (view)) => {
if let Some (sound_id) = view.appearance.sound {
let sample_id = sound_id.into();
let mode = Some (fmod::Mode::LOOP_OFF | fmod::Mode::_2D);
let _ = self.audition.sampler
.play (sample_id, mode, Some (&mut self.channel_group));
}
match view.component {
view::Component::Sfx (sfx) => {
if self.sfx.get (&node_id).is_none() {
self.create_sfx (node_id.clone());
}
self.update_sfx (sfx, node_id);
}
_ => {}
}
}
view::Display::Update (view::Update::FocusTop) |
view::Display::Create (_, _, _) => { }
view::Display::Destroy => {
if let Some (voice_id) = self.sfx.remove (&node_id) {
let _ = self.audition.remove_voice (voice_id).unwrap();
}
}
}
}
}
impl Default for Fmod {
fn default() -> Self {
let mut audition = nsys::fmod::Audition::default();
let channel_group = audition.system.create_channel_group (Some ("gui")).unwrap();
let sfx = KeyVec::new();
Fmod { audition, channel_group, sfx }
}
}
impl Audio for Fmod { }
impl Presentation for Fmod {
fn with_root (root : View, root_id : NodeId) -> Self {
let mut fmod = Fmod::default();
match &root.component {
view::Component::Sfx (sfx) => {
fmod.create_sfx (root_id.clone());
fmod.update_sfx (sfx.clone(), root_id);
}
_ => {}
}
fmod
}
fn get_input (&mut self, _ : &mut Vec <view::Input>) { }
fn display_view <V : AsRef <View>> (&mut self,
_view_tree : &Tree <V>,
display_values : std::vec::Drain <(NodeId, view::Display)>
) {
log::trace!("display view...");
for (node_id, display) in display_values {
self.display_value (node_id, display);
}
self.audition.update();
log::trace!("...display view");
}
}
impl From <view::Sound> for nsys::fmod::sampler::Id {
fn from (sound : view::Sound) -> Self {
nsys::fmod::sampler::Id (sound.0)
}
}