use fxhash::FxHashMap;
use rodio::cpal::FromSample;
use rodio::Sample;
use rodio::{source::Source, Decoder, OutputStream};
use std::fs::File;
use std::io::BufReader;
use ABC_ECS::Resource;
pub struct AudioFile {
pub(crate) file: Decoder<BufReader<File>>,
}
impl AudioFile {
pub fn new(path: &str) -> Self {
let file = File::open(path).expect("Failed to open file");
let source = Decoder::new(BufReader::new(file)).expect("Failed to decode file");
AudioFile { file: source }
}
}
#[derive(Clone)]
pub struct AudioBus {
parent: Option<String>,
name: String,
volume: f32,
speed: f32,
}
impl AudioBus {
pub fn new(name: &str) -> Self {
Self {
parent: None,
name: name.to_string(),
volume: 1.0,
speed: 1.0,
}
}
pub fn set_volume(&mut self, volume: f32) {
self.volume = volume;
}
pub fn get_volume(&self, audio_handle: &AudioHandle) -> f32 {
match self.parent {
Some(ref parent) => {
let parent = audio_handle
.buses
.get(parent)
.expect(format!("Parent: {} not found for {}", parent, self.name).as_str());
self.volume * parent.get_volume(audio_handle)
}
None => self.volume,
}
}
pub fn get_volume_without_parent(&self) -> f32 {
self.volume
}
pub fn set_speed(&mut self, speed: f32) {
self.speed = speed;
}
pub fn get_speed(&self, audio_handle: &AudioHandle) -> f32 {
match self.parent {
Some(ref parent) => {
let parent = audio_handle
.buses
.get(parent)
.expect(format!("Parent: {} not found for {}", parent, self.name).as_str());
self.speed * parent.get_speed(audio_handle)
}
None => self.speed,
}
}
pub fn get_name(&self) -> &str {
&self.name
}
pub fn set_name(&mut self, name: &str) {
self.name = name.to_string();
}
pub fn set_parent(&mut self, parent: &str) {
self.parent = Some(parent.to_string());
}
pub fn get_parent(&self) -> Option<&String> {
self.parent.as_ref()
}
pub fn get_full_name(&self, handle: &AudioHandle) -> String {
let mut full_name = self.name.clone();
if let Some(parent) = &self.parent {
let parent = handle.buses.get(parent).expect("Parent not found");
*&mut full_name += &parent.get_full_name(handle);
}
full_name.to_string()
}
}
struct ParellelSink {
sinks: Vec<rodio::Sink>,
volume: f32,
speed: f32,
}
impl ParellelSink {
pub fn new() -> Self {
Self {
sinks: Vec::new(),
volume: 1.0,
speed: 1.0,
}
}
fn append<S>(&mut self, source: S, handle: &rodio::OutputStreamHandle)
where
S: Source + Send + 'static,
f32: FromSample<S::Item>,
S::Item: Sample + Send,
{
self.append_without_cleanup(source, handle);
self.clean_up();
}
fn append_without_cleanup<S>(&mut self, source: S, handle: &rodio::OutputStreamHandle)
where
S: Source + Send + 'static,
f32: FromSample<S::Item>,
S::Item: Sample + Send,
{
for sink in &self.sinks {
if sink.empty() {
sink.append(source);
return;
}
}
let sink = rodio::Sink::try_new(handle).expect("Failed to create audio sink");
sink.set_volume(self.volume);
sink.set_speed(self.speed);
sink.append(source);
self.sinks.push(sink);
}
fn clean_up(&mut self) {
self.sinks.retain(|sink| !sink.empty());
}
fn set_volume(&mut self, volume: f32) {
for sink in &mut self.sinks {
sink.set_volume(volume);
}
self.volume = volume;
}
fn set_speed(&mut self, speed: f32) {
for sink in &mut self.sinks {
sink.set_speed(speed);
}
self.speed = speed;
}
fn pause(&mut self) {
for sink in &mut self.sinks {
sink.pause();
}
}
fn play(&mut self) {
for sink in &mut self.sinks {
sink.play();
}
}
}
pub struct AudioHandle {
pub(crate) handle: rodio::OutputStreamHandle,
_stream: OutputStream,
master_volume: f32,
master_speed: f32,
sink: ParellelSink,
sinks: FxHashMap<String, ParellelSink>, buses: FxHashMap<String, AudioBus>,
}
impl AudioHandle {
pub(crate) fn new() -> Self {
let (_stream, handle) = rodio::OutputStream::try_default().expect("Failed to open stream");
Self {
handle: handle.clone(),
_stream,
master_volume: 0.1,
master_speed: 1.0,
sink: ParellelSink::new(),
sinks: FxHashMap::default(),
buses: FxHashMap::default(),
}
}
pub fn play_one_shot(&mut self, audio_file: AudioFile) {
self.sink.set_volume(self.master_volume);
self.sink.set_speed(self.master_speed);
self.sink
.append(audio_file.file.convert_samples::<f32>(), &self.handle);
}
pub fn play_sounds_in_sequence(&mut self, audio_files: Vec<AudioFile>) {
for audio_file in audio_files {
self.sink
.append(audio_file.file.convert_samples::<f32>(), &self.handle);
}
}
pub fn play_infinitely(&mut self, audio_file: AudioFile) {
self.sink.append(
audio_file.file.convert_samples::<f32>().repeat_infinite(),
&self.handle,
);
}
pub fn set_master_volume(&mut self, volume: f32) {
self.master_volume = volume * 0.1;
self.sink.set_volume(volume);
for sink in self.sinks.values_mut() {
sink.set_volume(volume);
}
}
pub fn get_master_volume(&self) -> f32 {
self.master_volume / 0.1
}
pub fn set_master_speed(&mut self, speed: f32) {
self.master_speed = speed;
self.sink.set_speed(speed);
for sink in self.sinks.values_mut() {
sink.set_speed(speed);
}
}
pub fn get_master_speed(&self) -> f32 {
self.master_speed
}
pub fn play_sound_on_bus(&mut self, audio_file: AudioFile, name: &str) {
let (volume, speed) = self.get_volume_and_speed_of(name);
let sink = self
.sinks
.entry(name.to_string())
.or_insert_with(|| ParellelSink::new());
sink.set_volume(volume * self.master_volume);
sink.set_speed(speed * self.master_speed);
sink.append(audio_file.file.convert_samples::<f32>(), &self.handle);
}
pub fn play_sounds_in_sequence_on_bus(&mut self, audio_files: Vec<AudioFile>, name: &str) {
let (volume, speed) = self.get_volume_and_speed_of(name);
let sink = self
.sinks
.entry(name.to_string())
.or_insert_with(|| ParellelSink::new());
sink.set_volume(volume * self.master_volume);
sink.set_speed(speed * self.master_speed);
for audio_file in audio_files {
sink.append(audio_file.file.convert_samples::<f32>(), &self.handle);
}
}
fn get_volume_and_speed_of(&self, name: &str) -> (f32, f32) {
let bus = self
.buses
.get(name)
.expect("Bus not found, call add_bus first");
(bus.get_volume(self), bus.get_speed(self))
}
pub fn play_infinitely_on_bus(&mut self, audio_file: AudioFile, name: &str) {
let (volume, speed) = self.get_volume_and_speed_of(name);
let sink = self
.sinks
.entry(name.to_string())
.or_insert_with(|| ParellelSink::new());
sink.set_volume(volume * self.master_volume);
sink.set_speed(speed * self.master_speed);
sink.append(
audio_file.file.convert_samples::<f32>().repeat_infinite(),
&self.handle,
);
}
pub fn add_bus(&mut self, bus: AudioBus) {
self.buses.insert(bus.name.clone(), bus);
}
pub fn get_bus(&self, bus: &str) -> Option<&AudioBus> {
self.buses.get(bus)
}
pub fn get_bus_mut(&mut self, bus: &str) -> Option<&mut AudioBus> {
self.buses.get_mut(bus)
}
pub fn get_or_make_bus(&mut self, bus: &str) -> &AudioBus {
self.buses
.entry(bus.to_string())
.or_insert_with(|| AudioBus::new(bus))
}
pub fn get_or_make_bus_mut(&mut self, bus: &str) -> &mut AudioBus {
self.buses
.entry(bus.to_string())
.or_insert_with(|| AudioBus::new(bus))
}
pub fn add_bus_to_bus(&mut self, mut new_bus: AudioBus, parent_bus: &str) {
new_bus.parent = Some(parent_bus.to_string());
self.buses.insert(new_bus.name.clone(), new_bus.clone());
}
pub fn drop_all_sounds(&mut self) {
self.sink.sinks.clear();
self.sinks.clear();
}
pub fn pause(&mut self) {
self.sink.pause();
for sink in self.sinks.values_mut() {
sink.pause();
}
}
pub fn play(&mut self) {
self.sink.play();
for sink in self.sinks.values_mut() {
sink.play();
}
}
}
impl Resource for AudioHandle {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
}