1use std::{io::Cursor, sync::Arc};
2
3use anyhow::Result;
4use collections::HashMap;
5use gpui::{AppContext, AssetSource};
6use rodio::{
7 source::{Buffered, SamplesConverter},
8 Decoder, Source,
9};
10
11type Sound = Buffered<SamplesConverter<Decoder<Cursor<Vec<u8>>>, f32>>;
12
13pub struct SoundRegistry {
14 cache: Arc<parking_lot::Mutex<HashMap<String, Sound>>>,
15 assets: Box<dyn AssetSource>,
16}
17
18impl SoundRegistry {
19 pub fn new(source: impl AssetSource) -> Arc<Self> {
20 Arc::new(Self {
21 cache: Default::default(),
22 assets: Box::new(source),
23 })
24 }
25
26 pub fn global(cx: &AppContext) -> Arc<Self> {
27 cx.global::<Arc<Self>>().clone()
28 }
29
30 pub fn get(&self, name: &str) -> Result<impl Source<Item = f32>> {
31 if let Some(wav) = self.cache.lock().get(name) {
32 return Ok(wav.clone());
33 }
34
35 let path = format!("sounds/{}.wav", name);
36 let bytes = self.assets.load(&path)?.into_owned();
37 let cursor = Cursor::new(bytes);
38 let source = Decoder::new(cursor)?.convert_samples::<f32>().buffered();
39
40 self.cache.lock().insert(name.to_string(), source.clone());
41
42 Ok(source)
43 }
44}