Mercurial > touhou
view python/src/audio.rs @ 792:11bc22bad1bf default tip
python: Replace the image crate with png
We weren’t using any of its features anyway, so the png crate is exactly what
we need, without the many heavy dependencies of image.
https://github.com/image-rs/image-png/pull/670 will eventually make it even
faster to build.
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Sat, 17 Jan 2026 22:22:25 +0100 |
| parents | ec1e06402a97 |
| 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(); } }
