use rodio::Decoder;
use rodio::{OutputStream, OutputStreamHandle, Sink};
use std::{cell::RefCell, collections::HashMap};
use strum::Display;
use strum::EnumIter;
use crate::filesystem::Filesystem;
#[derive(EnumIter, Display, PartialEq, Eq, Clone, Copy, Hash)]
#[allow(clippy::upper_case_acronyms)]
pub enum Source {
BGM,
BGS,
ME,
SE,
}
pub struct Audio {
inner: RefCell<Inner>,
}
struct Inner {
outputstream: (OutputStream, OutputStreamHandle),
sinks: HashMap<Source, Sink>,
}
impl Default for Audio {
fn default() -> Self {
let outputstream = OutputStream::try_default().unwrap();
Self {
inner: RefCell::new(Inner {
outputstream,
sinks: HashMap::new(),
}),
}
}
}
impl Audio {
pub fn play(
&self,
filesystem: &Filesystem,
path: &str,
volume: u8,
pitch: u8,
source: &Source,
) {
let mut inner = self.inner.borrow_mut();
let sink = Sink::try_new(&inner.outputstream.1).expect("Failed to create sink");
let bufreader = filesystem.bufreader(path);
match source {
Source::SE | Source::ME => {
sink.append(Decoder::new(bufreader).expect("Failed to create decoder"))
}
_ => {
sink.append(Decoder::new_looped(bufreader).expect("Failed to create decoder"))
}
}
sink.set_speed(pitch as f32 / 100.);
sink.set_volume(volume as f32 / 100.);
sink.play();
if let Some(s) = inner.sinks.insert(*source, sink) {
s.stop();
};
}
pub fn set_pitch(&self, pitch: u8, source: &Source) {
let mut inner = self.inner.borrow_mut();
if let Some(s) = inner.sinks.get_mut(source) {
s.set_speed(pitch as f32 / 100.);
}
}
pub fn set_volume(&self, volume: u8, source: &Source) {
let mut inner = self.inner.borrow_mut();
if let Some(s) = inner.sinks.get_mut(source) {
s.set_volume(volume as f32 / 100.);
}
}
pub fn stop(&self, source: &Source) {
let mut inner = self.inner.borrow_mut();
if let Some(s) = inner.sinks.get_mut(source) {
s.stop();
}
}
}