Mercurial > touhou
view python/src/audio.rs @ 783:ec1e06402a97
Replace SDL2_mixer with the kira crate
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Fri, 21 Nov 2025 10:21:59 +0100 |
| parents | |
| children |
line wrap: on
line source
use kira::sound::static_sound::StaticSoundData; use kira::sound::streaming::{StreamingSoundData, StreamingSoundHandle}; use kira::sound::FromFileError; use kira::{AudioManager, AudioManagerSettings, Tween}; use pyo3::prelude::*; use std::collections::HashMap; use std::io::Cursor; use std::path::PathBuf; #[pyclass(module = "libtouhou")] pub struct Audio { loader: Py<super::Loader>, manager: AudioManager, cache: HashMap<String, StaticSoundData>, bgms: [Option<(String, String)>; 4], current_music: Option<StreamingSoundHandle<FromFileError>>, } #[pymethods] impl Audio { #[new] fn new(loader: Py<super::Loader>, bgms: [Option<(String, String)>; 4]) -> Audio { let manager = AudioManager::<kira::DefaultBackend>::new(AudioManagerSettings::default()).unwrap(); let cache = HashMap::new(); Audio { loader, manager, cache, bgms, current_music: None, } } fn play_bgm(&mut self, py: Python, number: usize) { let Some((_name, filename)) = &self.bgms[number] else { eprintln!("Unspecified bgm number {number}"); return; }; // Load the loop points corresponding to this bgm. let mut filename = PathBuf::from(filename); filename.set_extension("pos"); let loader = self.loader.borrow(py); let loop_points = loader .get_loop_points(filename.file_name().unwrap().to_str().unwrap()) .unwrap(); // Then try to open the music file. filename.set_extension("*"); let path = loader .game_dir .clone() .and_then(|dir| Some(dir.join(&filename))) .unwrap_or(filename); let mut music = None; for path in glob::glob(path.to_str().unwrap()) .unwrap() .map(Result::unwrap) .map(PathBuf::from) { match StreamingSoundData::from_file(&path) { Ok(sound) => { music = Some(sound); break; } Err(err) => { eprintln!("Error while opening {path:?} as a music file: {err:?}"); continue; } } } let Some(music) = music else { eprintln!("Unable to find bgm, let’s keep the previous one playing…"); return; }; // Stop the previous playing one. if let Some(current_music) = &mut self.current_music { current_music.stop(Tween::default()); } // And now we can start playing the new one! let mut current_music = self.manager.play(music).unwrap(); // TODO: Fetch the sample rate from the file, instead of hardcoding it. current_music.set_loop_region( (loop_points.start as f64 / 44100.0)..(loop_points.end as f64 / 44100.0), ); self.current_music = Some(current_music); } fn play(&mut self, py: Python, name: &str) { let sound = self.cache.entry(name.to_string()).or_insert_with(|| { let loader = self.loader.borrow(py); let bytes = loader.get_file_internal(name).unwrap(); let cursor = Cursor::new(bytes); StaticSoundData::from_cursor(cursor).unwrap() }); self.manager.play(sound.clone()).unwrap(); } }
