1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::{
engine::Engine,
graphics::{ RendererTextureHandle },
resources::{ ResourceStorage, Resource, ResourceLoadType, Material },
ecs::{ DeferredUpdateManagerPointer, AudioSourceComponent, SoundType, AudioManagerComponent },
config::*,
};
use pill_core::{ PillSlotMapKey, PillTypeMapKey, PillStyle, get_type_name, EngineError };
use std::{
collections::HashSet,
io::{ BufRead, Read, Cursor},
path::{ Path, PathBuf },
fs::File,
};
use anyhow::{ Result, Context, Error };
use rodio::{ Source, source::Buffered, Decoder };
pill_core::define_new_pill_slotmap_key! {
pub struct SoundHandle;
}
#[readonly::make]
pub struct Sound {
#[readonly]
pub name: String,
#[readonly]
pub path: PathBuf,
pub(crate) sound_data: Option<SoundData>
}
impl Sound {
pub fn new(name: &str, path: PathBuf) -> Self {
Self {
name: name.to_string(),
path,
sound_data: None
}
}
}
impl PillTypeMapKey for Sound {
type Storage = ResourceStorage<Sound>;
}
impl Resource for Sound {
type Handle = SoundHandle;
fn initialize(&mut self, engine: &mut Engine) -> Result<()> {
let error_message = format!("Initializing {} {} failed", "Resource".gobj_style(), get_type_name::<Self>().sobj_style());
pill_core::validate_asset_path(&self.path, &["mp3", "wav"]).context(error_message.clone())?;
let sound_data = SoundData::new(&self.path).context(error_message.clone())?;
self.sound_data = Some(sound_data);
Ok(())
}
fn get_name(&self) -> String {
self.name.clone()
}
fn destroy<H: PillSlotMapKey>(&mut self, engine: &mut Engine, self_handle: H) -> Result<()> {
for (scene_handle, scene) in engine.scene_manager.scenes.iter_mut() {
for (entity_handle, audio_source_component) in scene.get_one_component_iterator_mut::<AudioSourceComponent>()? {
if let Some(sound_handle) = audio_source_component.sound_handle {
if sound_handle.data() == self_handle.data() {
audio_source_component.remove_sound();
}
}
}
}
Ok(())
}
}
pub struct SoundData {
pub(crate) source_buffer: Vec<u8>
}
impl SoundData {
pub fn new(path: &PathBuf) -> Result<Self> {
let mut sound_file = match File::open(path) {
Err(err) => return Err(Error::new(EngineError::InvalidAssetPath(path.clone().into_os_string().into_string().unwrap()))),
file => file?
};
let mut sound_data = Vec::new();
sound_file.read_to_end(&mut sound_data).unwrap();
let sound_data = SoundData {
source_buffer: sound_data
};
Ok(sound_data)
}
pub fn get_source_sound(&self) -> Decoder<Cursor<Vec<u8>>> {
let mut sound_source = Vec::<u8>::new();
for buffer in self.source_buffer.iter() {
sound_source.push(buffer.clone());
}
Decoder::new(Cursor::new(sound_source)).unwrap()
}
}