changeset 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 2d60a14f4816
children
files python/src/audio.rs python/src/lib.rs python/src/main.rs pytouhou/ui/gamerunner.pyx
diffstat 4 files changed, 43 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/python/src/audio.rs
+++ b/python/src/audio.rs
@@ -32,6 +32,10 @@ impl Audio {
         }
     }
 
+    fn load_bgms(&mut self, bgms: [Option<(String, String)>; 4]) {
+        self.bgms = bgms;
+    }
+
     fn play_bgm(&mut self, py: Python, number: usize) {
         let Some((_name, filename)) = &self.bgms[number] else {
             eprintln!("Unspecified bgm number {number}");
--- a/python/src/lib.rs
+++ b/python/src/lib.rs
@@ -336,6 +336,23 @@ impl Prng {
     }
 }
 
+#[pyclass(module = "libtouhou")]
+pub struct DummyAudio;
+
+#[pymethods]
+impl DummyAudio {
+    #[new]
+    fn new() -> DummyAudio {
+        DummyAudio
+    }
+
+    fn load_bgms(&mut self, _bgms: [Option<(String, String)>; 4]) {}
+
+    fn play_bgm(&mut self, _number: usize) {}
+
+    fn play(&mut self, _name: &str) {}
+}
+
 #[pymodule]
 mod libtouhou {
     #[pymodule_export]
@@ -348,6 +365,9 @@ mod libtouhou {
     use super::Prng;
 
     #[pymodule_export]
+    use crate::DummyAudio;
+
+    #[pymodule_export]
     use crate::audio::Audio;
 
     #[cfg(feature = "glide")]
--- a/python/src/main.rs
+++ b/python/src/main.rs
@@ -54,16 +54,6 @@ enum Backend {
     Sdl,
 }
 
-impl Backend {
-    const fn to_str(&self) -> &'static str {
-        match self {
-            Backend::OpenGL => "opengl",
-            Backend::Glide => "glide",
-            Backend::Sdl => "sdl",
-        }
-    }
-}
-
 #[derive(Debug, Clone, ValueEnum)]
 enum GlFlavor {
     Core,
@@ -248,6 +238,16 @@ fn main() -> PyResult<()> {
 
         let libtouhou = PyModule::import(py, "libtouhou").unwrap();
         let Prng = libtouhou.getattr("Prng").unwrap();
+        let Audio = libtouhou.getattr("Audio").unwrap();
+        let DummyAudio = libtouhou.getattr("DummyAudio").unwrap();
+
+        let audio;
+        if !args.no_sound {
+            let bgms = [Some(("赤より紅い夢", "th06_01.mid")), None, None, None];
+            audio = Audio.call1((resource_loader.clone(), bgms)).unwrap();
+        } else {
+            audio = DummyAudio.call0().unwrap();
+        }
 
         let mut stage_num;
         let story;
@@ -338,7 +338,7 @@ fn main() -> PyResult<()> {
         } else {
             None
         };
-        let runner = GameRunner.call1((window.clone(), renderer, common.clone(), resource_loader.clone(), args.skip_replay, con, args.no_sound)).unwrap();
+        let runner = GameRunner.call1((window.clone(), renderer, common.clone(), resource_loader.clone(), audio, args.skip_replay, con)).unwrap();
         let window_set_runner = window.getattr("set_runner").unwrap();
         window_set_runner.call1((runner.clone(),)).unwrap();
 
--- a/pytouhou/ui/gamerunner.pyx
+++ b/pytouhou/ui/gamerunner.pyx
@@ -17,31 +17,23 @@ cimport cython
 from pytouhou.lib.gui cimport EXIT, PAUSE, SCREENSHOT, RESIZE, FULLSCREEN
 
 from .window cimport Window, Runner
-from libtouhou import Audio
+from libtouhou import Audio, DummyAudio
 from pytouhou.game.game cimport Game
 
 
-class DummyAudio:
-    def play(self, name):
-        pass
-
-    def play_bgm(self, track):
-        pass
-
-
 cdef class GameRunner(Runner):
-    cdef object background, con, resource_loader, keys, replay_level, common
+    cdef object audio, background, con, resource_loader, keys, replay_level, common
     cdef Game game
     cdef Window window
     cdef list save_keystates
-    cdef bint skip, audio
+    cdef bint skip
 
     # Since we want to support multiple renderers, don’t specify its type.
     #TODO: find a way to still specify its interface.
     cdef object renderer
 
-    def __init__(self, Window window, renderer, common, resource_loader,
-                 bint skip=False, con=None, bint audio=True):
+    def __init__(self, Window window, renderer, common, resource_loader, audio,
+                 bint skip=False, con=None):
         self.renderer = renderer
         self.common = common
         self.resource_loader = resource_loader
@@ -74,12 +66,9 @@ cdef class GameRunner(Runner):
 
         self.save_keystates = save_keystates
 
-        if self.audio:
-            game.music = Audio(self.resource_loader, bgms)
-        else:
-            game.music = DummyAudio()
-        if bgms is not None:
-            game.music.play_bgm(0)
+        game.music = self.audio
+        game.music.load_bgms(bgms)
+        game.music.play_bgm(0)
 
         game.sfx_player = game.music if not self.skip else DummyAudio()