annotate python/src/audio.rs @ 796:d876ac2ccfe1 default tip

Pass audio only once to GameRunner This prevents it being recreated every stage change, and playing music over the previous stages’ music.
author Link Mauve <linkmauve@linkmauve.fr>
date Sun, 28 Jun 2026 14:27:03 +0200
parents ec1e06402a97
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
783
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
1 use kira::sound::static_sound::StaticSoundData;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
2 use kira::sound::streaming::{StreamingSoundData, StreamingSoundHandle};
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
3 use kira::sound::FromFileError;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
4 use kira::{AudioManager, AudioManagerSettings, Tween};
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
5 use pyo3::prelude::*;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
6 use std::collections::HashMap;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
7 use std::io::Cursor;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
8 use std::path::PathBuf;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
9
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
10 #[pyclass(module = "libtouhou")]
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
11 pub struct Audio {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
12 loader: Py<super::Loader>,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
13 manager: AudioManager,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
14 cache: HashMap<String, StaticSoundData>,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
15 bgms: [Option<(String, String)>; 4],
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
16 current_music: Option<StreamingSoundHandle<FromFileError>>,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
17 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
18
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
19 #[pymethods]
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
20 impl Audio {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
21 #[new]
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
22 fn new(loader: Py<super::Loader>, bgms: [Option<(String, String)>; 4]) -> Audio {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
23 let manager =
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
24 AudioManager::<kira::DefaultBackend>::new(AudioManagerSettings::default()).unwrap();
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
25 let cache = HashMap::new();
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
26 Audio {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
27 loader,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
28 manager,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
29 cache,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
30 bgms,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
31 current_music: None,
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
32 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
33 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
34
796
d876ac2ccfe1 Pass audio only once to GameRunner
Link Mauve <linkmauve@linkmauve.fr>
parents: 783
diff changeset
35 fn load_bgms(&mut self, bgms: [Option<(String, String)>; 4]) {
d876ac2ccfe1 Pass audio only once to GameRunner
Link Mauve <linkmauve@linkmauve.fr>
parents: 783
diff changeset
36 self.bgms = bgms;
d876ac2ccfe1 Pass audio only once to GameRunner
Link Mauve <linkmauve@linkmauve.fr>
parents: 783
diff changeset
37 }
d876ac2ccfe1 Pass audio only once to GameRunner
Link Mauve <linkmauve@linkmauve.fr>
parents: 783
diff changeset
38
783
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
39 fn play_bgm(&mut self, py: Python, number: usize) {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
40 let Some((_name, filename)) = &self.bgms[number] else {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
41 eprintln!("Unspecified bgm number {number}");
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
42 return;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
43 };
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
44
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
45 // Load the loop points corresponding to this bgm.
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
46 let mut filename = PathBuf::from(filename);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
47 filename.set_extension("pos");
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
48 let loader = self.loader.borrow(py);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
49 let loop_points = loader
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
50 .get_loop_points(filename.file_name().unwrap().to_str().unwrap())
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
51 .unwrap();
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
52
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
53 // Then try to open the music file.
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
54 filename.set_extension("*");
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
55 let path = loader
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
56 .game_dir
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
57 .clone()
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
58 .and_then(|dir| Some(dir.join(&filename)))
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
59 .unwrap_or(filename);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
60 let mut music = None;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
61 for path in glob::glob(path.to_str().unwrap())
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
62 .unwrap()
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
63 .map(Result::unwrap)
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
64 .map(PathBuf::from)
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
65 {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
66 match StreamingSoundData::from_file(&path) {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
67 Ok(sound) => {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
68 music = Some(sound);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
69 break;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
70 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
71 Err(err) => {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
72 eprintln!("Error while opening {path:?} as a music file: {err:?}");
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
73 continue;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
74 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
75 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
76 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
77 let Some(music) = music else {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
78 eprintln!("Unable to find bgm, let’s keep the previous one playing…");
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
79 return;
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
80 };
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
81
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
82 // Stop the previous playing one.
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
83 if let Some(current_music) = &mut self.current_music {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
84 current_music.stop(Tween::default());
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
85 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
86
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
87 // And now we can start playing the new one!
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
88 let mut current_music = self.manager.play(music).unwrap();
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
89 // TODO: Fetch the sample rate from the file, instead of hardcoding it.
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
90 current_music.set_loop_region(
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
91 (loop_points.start as f64 / 44100.0)..(loop_points.end as f64 / 44100.0),
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
92 );
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
93 self.current_music = Some(current_music);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
94 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
95
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
96 fn play(&mut self, py: Python, name: &str) {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
97 let sound = self.cache.entry(name.to_string()).or_insert_with(|| {
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
98 let loader = self.loader.borrow(py);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
99 let bytes = loader.get_file_internal(name).unwrap();
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
100 let cursor = Cursor::new(bytes);
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
101 StaticSoundData::from_cursor(cursor).unwrap()
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
102 });
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
103 self.manager.play(sound.clone()).unwrap();
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
104 }
ec1e06402a97 Replace SDL2_mixer with the kira crate
Link Mauve <linkmauve@linkmauve.fr>
parents:
diff changeset
105 }