audio: implement random SFX output

This commit is contained in:
2026-06-22 13:54:42 +02:00
parent 85fa485833
commit 74a823d1c2
6 changed files with 335 additions and 20 deletions
+81
View File
@@ -0,0 +1,81 @@
use rand::seq::IteratorRandom;
use symphonia::core::{formats::{TrackType, probe::Hint}, io::MediaSourceStream};
use crate::audio::AudioOutStream;
#[derive(Debug)]
pub enum SfxRequest {
RandomAmbient
}
#[derive(Debug)]
pub struct SfxControl {
sink: tokio::sync::mpsc::Sender<SfxRequest>
}
impl SfxControl {
pub async fn play_ambient(&mut self) -> Result<(), tokio::sync::mpsc::error::SendError<SfxRequest>> {
self.sink.send(SfxRequest::RandomAmbient).await
}
}
pub async fn start_sfx(audio_sink: AudioOutStream) -> SfxControl {
let (event_sink, mut event_src) = tokio::sync::mpsc::channel(32);
tokio::spawn(async move {
let sfx_dir = std::path::Path::new("./sfx");
loop {
while let Some(event) = event_src.recv().await {
match event {
SfxRequest::RandomAmbient => {
let avail_files = std::fs::read_dir(sfx_dir).unwrap();
let chosen_file = avail_files.choose(&mut rand::rng()).unwrap().unwrap();
log::debug!("Queuing ambient sound playback with {:?}", chosen_file);
let sfx_fd = std::fs::File::open(chosen_file.path()).unwrap();
let mss = MediaSourceStream::new(Box::new(sfx_fd), Default::default());
let meta_opts = Default::default();
let fmt_opts = Default::default();
let mut hint = Hint::new();
hint.with_extension(".mp3");
let mut format = symphonia::default::get_probe()
.probe(&hint, mss, fmt_opts, meta_opts)
.expect("Unsupported audio format");
let track = format.default_track(TrackType::Audio).expect("No audio track");
let dec_opts = Default::default();
let mut decoder = symphonia::default::get_codecs()
.make_audio_decoder(
track.codec_params.as_ref().expect("codec params missing").audio().unwrap(),
&dec_opts
).expect("Unsupported audio codec");
log::debug!("Starting stream");
loop {
let packet = match format.next_packet() {
Ok(Some(packet)) => packet,
Ok(None) => break,
Err(err) => panic!()
};
match decoder.decode_ref(&packet.as_packet_ref()) {
Ok(samples) => {
let mut channel_bufs: Vec<f32> = vec![];
samples.copy_to_vec_interleaved(&mut channel_bufs);
let audio_out_buf: Vec<f32> = channel_bufs.windows(samples.byte_len_per_plane()).map(|channels| {
let total_volume = channels.iter().cloned().reduce(|a, b| a + b).unwrap_or_default();
total_volume / (channels.len() as f32)
}).collect();
audio_sink.sink.send(audio_out_buf).await.unwrap();
},
Err(err) => panic!()
}
}
log::debug!("Playback complete");
}
}
}
}
});
SfxControl {
sink: event_sink
}
}