audio: implement random SFX output
This commit is contained in:
+81
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user