From 83780421ec1a56ee6612cb4c55b99e4228236941 Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Tue, 16 Jun 2026 22:18:41 -0300 Subject: [PATCH] added new custom audio functions for j2/j3 added: `is-any-sound-playing?`; `is-sound-playing?`; `pause-all-sounds`; `resume-all-sounds` --- game/kernel/common/kmachine.cpp | 151 ++++++++++++++++++++- goal_src/jak2/engine/debug/default-menu.gc | 8 ++ goal_src/jak2/engine/game/main.gc | 9 ++ goal_src/jak2/engine/scene/scene.gc | 17 +++ goal_src/jak2/kernel-defs.gc | 8 ++ goal_src/jak3/engine/debug/default-menu.gc | 8 ++ goal_src/jak3/engine/game/main.gc | 9 ++ goal_src/jak3/engine/scene/scene.gc | 17 +++ goal_src/jak3/kernel-defs.gc | 9 ++ 9 files changed, 234 insertions(+), 2 deletions(-) diff --git a/game/kernel/common/kmachine.cpp b/game/kernel/common/kmachine.cpp index a3c0a45c07..207adba054 100644 --- a/game/kernel/common/kmachine.cpp +++ b/game/kernel/common/kmachine.cpp @@ -195,6 +195,10 @@ std::mutex activeMusicsMutex; // Declare a mutex for synchronizing access to mainMusicInstance std::mutex mainMusicMutex; +// Mutex to synchronize access to sounds +std::mutex soundMutex; +bool isPaused = false; // flag to check whether the custom sounds are paused or not + // Function to stop all instances of specific sound by filepath void stopMP3(u32 filePathu32) { std::string filePath = Ptr(filePathu32).c()->data(); @@ -219,6 +223,39 @@ void stopMP3(u32 filePathu32) { // Function to stop all currently playing sounds. void stopAllSounds() { + std::lock_guard lock(activeMusicsMutex); + + std::cout << "Stopping all sounds..." << std::endl; + + // Stop all sounds before removing them + for (auto& pair : maSoundMap) { + for (auto& sound : pair.second) { + if (MiniAudioLib::ma_sound_is_playing(&sound)) { + MiniAudioLib::ma_sound_stop(&sound); + } + } + } + + // Wait a short period of time to make sure the sounds have stopped + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + // Release memory and remove the sounds from the map + for (auto it = maSoundMap.begin(); it != maSoundMap.end();) { + auto& soundList = it->second; + + for (auto& sound : soundList) { + MiniAudioLib::ma_sound_uninit(&sound); + } + + soundList.clear(); + it = maSoundMap.erase(it); + } + + std::cout << "All sounds stopped successfully!" << std::endl; +} + +// Function to force sounds to stop after playing. +void forceStopSounds() { for (auto& pair : maSoundMap) { // stop all instances of this sound for (auto sound : pair.second) { @@ -281,9 +318,36 @@ u64 playMP3_internal(u32 filePathu32, u32 volume, bool isMainMusic) { maSoundMap[filePath].push_back(sound); } - // sleep/loop until we're no longer main music, or non-looping sound is stopped/ends - while (mainMusicSound == &sound || MiniAudioLib::ma_sound_is_playing(&sound)) { + // Loop to check the state of the sound without freezing the main thread + bool isPlaying = true; + while (isPlaying) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + // Check if the game is paused + if (isPaused) { + // pause sound + //std::cout << "Sounds paused, stopping playback..." << std::endl; + MiniAudioLib::ma_sound_stop(&sound); // stop the sound when paused + + // Wait until the game is resumed + while (true) { + { + std::lock_guard lock(soundMutex); + if (!isPaused) + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + // Resume the sound after the pause + //std::cout << "Resuming sound: " << filePath << std::endl; + MiniAudioLib::ma_sound_start(&sound); + } + + // Check if the sound is still playing + if (!MiniAudioLib::ma_sound_is_playing(&sound)) { + isPlaying = false; + } } MiniAudioLib::ma_sound_stop(&sound); @@ -295,6 +359,7 @@ u64 playMP3_internal(u32 filePathu32, u32 volume, bool isMainMusic) { if (maSoundMap.find(filePath) != maSoundMap.end()) { maSoundMap[filePath].remove_if( [&](MiniAudioLib::ma_sound l_sound) { return &sound == &l_sound; }); + forceStopSounds(); // Force sounds to stop. For some reason, without this `isAnySoundPlaying` will always return true even if the sound finished playing. } } }); @@ -353,6 +418,80 @@ void changeMainMusicVolume(u32 volume) { mainMusicMutex.unlock(); } +// Function to check if any custom audio is being played or not. This will return true or false. +u64 isAnySoundPlaying() { + bool anyPlaying = false; // Flag to track whether any sound is currently playing + + std::lock_guard activeLock(activeMusicsMutex); + + // Iterate over all entries in maSoundMap + for (auto it = maSoundMap.begin(); it != maSoundMap.end();) { + auto& soundList = it->second; // Get the list of sounds for the current file + + // Remove sounds that have finished playing + soundList.remove_if([](MiniAudioLib::ma_sound& sound) { + if (!MiniAudioLib::ma_sound_is_playing(&sound)) { // Check if the sound has stopped + MiniAudioLib::ma_sound_stop(&sound); // Stop the sound to free resources + MiniAudioLib::ma_sound_uninit(&sound); // Uninitialize to clean up memory + return true; // Remove this sound from the list + } + return false; // Keep this sound in the list if it's still playing + }); + + // If the list still contains sounds, set anyPlaying to true + if (!soundList.empty()) { + anyPlaying = true; + } + + // If the list is empty after removing finished sounds, erase it from the map + if (soundList.empty()) { + it = maSoundMap.erase(it); // Remove the entry and move iterator to the next valid element + } else { + ++it; // Move to the next element in the map + } + } + + /*if (anyPlaying) { + std::cout << "Some sound is being played!" << std::endl; + } else { + std::cout << "No sound is being played!" << std::endl; + }*/ + + return bool_to_symbol(anyPlaying); +} + +// Function to check if the custom audio passed as an argument is being played or not. This will return true or false. +u64 isSoundPlaying(u32 filePathu32) { + + std::string filePath = Ptr(filePathu32).c()->data(); + + //Get the list of files that are currently being played + std::vector playingFiles = getPlayingFileNames(); + + // Checks if the file is in the list of files being played + if (std::find(playingFiles.begin(), playingFiles.end(), filePath) != playingFiles.end()) { + //std::cout << "The sound: (" << filePath << ") is being played!" << std::endl; + return bool_to_symbol(true); + } + + return bool_to_symbol(false); +} + +// Function to pause custom sounds +void pauseAllSounds() { + std::lock_guard lock(soundMutex); + //std::cout << "Pausing all sounds..." << std::endl; + isPaused = true; // pause sounds +} + +// Function to resume custom sounds +void resumeAllSounds() { + std::lock_guard lock(soundMutex); + //std::cout << "Resuming all sounds..." << std::endl; + isPaused = false; // resume sounds + //std::cout << "All sounds have resumed!" << std::endl; +} + /*! * Not checked super carefully for jak 2, but looks the same */ @@ -1410,6 +1549,14 @@ void init_common_pc_port_functions( make_func_symbol_func("main-music-volume", (void*)changeMainMusicVolume); + // Check if any custom audio is being played or not + make_func_symbol_func("is-any-sound-playing?", (void*)isAnySoundPlaying); + make_func_symbol_func("is-sound-playing?", (void*)isSoundPlaying); + + // Pause/Resume all sounds + make_func_symbol_func("pause-all-sounds", (void*)pauseAllSounds); + make_func_symbol_func("resume-all-sounds", (void*)resumeAllSounds); + // discord rich presence make_func_symbol_func("pc-discord-rpc-set", (void*)set_discord_rpc); diff --git a/goal_src/jak2/engine/debug/default-menu.gc b/goal_src/jak2/engine/debug/default-menu.gc index 7417f05540..41d9878060 100644 --- a/goal_src/jak2/engine/debug/default-menu.gc +++ b/goal_src/jak2/engine/debug/default-menu.gc @@ -6054,6 +6054,10 @@ (debug-menu-context-send-msg *popup-menu-context* (debug-menu-msg activate) (debug-menu-dest activation)) (debug-menu-context-send-msg *debug-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) (debug-menu-context-send-msg *editable-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ((and (cpad-hold? 1 start) *editable*) (debug-menu-context-send-msg *editable-menu-context* (debug-menu-msg activate) (debug-menu-dest activation)) @@ -6064,6 +6068,10 @@ (debug-menu-context-send-msg *debug-menu-context* (debug-menu-msg activate) (debug-menu-dest activation)) (debug-menu-context-send-msg *popup-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) (debug-menu-context-send-msg *editable-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ) ) diff --git a/goal_src/jak2/engine/game/main.gc b/goal_src/jak2/engine/game/main.gc index a1daeb73ef..96e7733910 100644 --- a/goal_src/jak2/engine/game/main.gc +++ b/goal_src/jak2/engine/game/main.gc @@ -140,6 +140,10 @@ (set! *pause-lock* #f) (sound-group-pause (sound-group sfx music dialog sog3 ambient dialog2 sog6 sog7)) (set! (-> *game-info* pause-start-time) (-> *display* real-clock frame-counter)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) (('freeze) (logior! (-> *setting-control* user-default process-mask) (process-mask freeze)) @@ -164,10 +168,15 @@ ) ) (set! (-> *game-info* pause-start-time) (-> *display* real-clock frame-counter)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) (('game) (logclear! (-> *setting-control* user-default process-mask) (process-mask freeze pause menu)) (sound-group-continue (sound-group sfx music dialog sog3 ambient dialog2 sog6 sog7)) + (resume-all-sounds) ;; mod-base-change - resume all custom audios ) ) diff --git a/goal_src/jak2/engine/scene/scene.gc b/goal_src/jak2/engine/scene/scene.gc index cc25b1393f..0e0d77d176 100644 --- a/goal_src/jak2/engine/scene/scene.gc +++ b/goal_src/jak2/engine/scene/scene.gc @@ -1133,6 +1133,10 @@ (if (and (-> self scene) (-> self scene save)) (auto-save-user) ) + ;; mod-base-change - if there are custom audios playing, then, stop them + (if (is-any-sound-playing?) + (stop-all-sounds) + ) ) ) @@ -1422,6 +1426,10 @@ (-> self clock time-adjust-ratio) ) ) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ((cpad-hold? 0 l1) (if (cpad-pressed? 0 square) @@ -1434,6 +1442,10 @@ (-> self clock time-adjust-ratio) ) ) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ((cpad-hold? 0 x) (when (cpad-pressed? 0 x) @@ -1457,6 +1469,10 @@ (cond ((= (-> self cur-speed) -1000.0) (format *stdcon* "scene paused~%") + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) (when (!= (-> self targ-speed) -1000.0) (sound-continue (-> gp-7 id)) (when *sound-player-enable* @@ -1467,6 +1483,7 @@ (set! (-> v1-186 params mask) (the-as uint 2)) (-> v1-186 id) ) + (resume-all-sounds) ;; mod-base-change - resume all custom audios ) (set! (-> self targ-speed) 0.0) (set! (-> self cur-speed) 0.0) diff --git a/goal_src/jak2/kernel-defs.gc b/goal_src/jak2/kernel-defs.gc index a67cce0a80..e771b1c5db 100644 --- a/goal_src/jak2/kernel-defs.gc +++ b/goal_src/jak2/kernel-defs.gc @@ -270,6 +270,14 @@ (define-extern stop-sound-file (function string none)) (define-extern stop-all-sounds (function none)) +;;check if any custom audio is being played or not +(define-extern is-any-sound-playing? (function symbol)) +(define-extern is-sound-playing? (function string symbol)) + +;;pause/resume all sounds +(define-extern pause-all-sounds (function none)) +(define-extern resume-all-sounds (function none)) + (define-extern pc-filepath-exists? (function string symbol)) (define-extern pc-mkdir-file-path (function string none)) (define-extern pc-sound-set-flava-hack (function int none)) diff --git a/goal_src/jak3/engine/debug/default-menu.gc b/goal_src/jak3/engine/debug/default-menu.gc index 9f5b25bc47..bb2b8ceadc 100644 --- a/goal_src/jak3/engine/debug/default-menu.gc +++ b/goal_src/jak3/engine/debug/default-menu.gc @@ -6851,6 +6851,10 @@ (debug-menu-context-send-msg *popup-menu-context* (debug-menu-msg activate) (debug-menu-dest activation)) (debug-menu-context-send-msg *debug-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) (debug-menu-context-send-msg *editable-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ((and (cpad-hold? 1 start) *editable*) (debug-menu-context-send-msg *editable-menu-context* (debug-menu-msg activate) (debug-menu-dest activation)) @@ -6861,6 +6865,10 @@ (debug-menu-context-send-msg *debug-menu-context* (debug-menu-msg activate) (debug-menu-dest activation)) (debug-menu-context-send-msg *popup-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) (debug-menu-context-send-msg *editable-menu-context* (debug-menu-msg deactivate) (debug-menu-dest activation)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ) ) diff --git a/goal_src/jak3/engine/game/main.gc b/goal_src/jak3/engine/game/main.gc index 5838eca40a..de4479affc 100644 --- a/goal_src/jak3/engine/game/main.gc +++ b/goal_src/jak3/engine/game/main.gc @@ -160,6 +160,10 @@ (set! *pause-lock* #f) (sound-group-pause (the-as sound-group #xffffffff)) (set! (-> *game-info* pause-start-time) (-> *display* real-clock frame-counter)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) (('freeze) (logior! (-> *setting-control* user-default process-mask) (process-mask freeze)) @@ -183,10 +187,15 @@ ) ) (set! (-> *game-info* pause-start-time) (-> *display* real-clock frame-counter)) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) (('game) (logclear! (-> *setting-control* user-default process-mask) (process-mask freeze pause menu)) (sound-group-continue (the-as sound-group #xffffffff)) + (resume-all-sounds) ;; mod-base-change - resume all custom audios ) ) (apply-settings *setting-control*) diff --git a/goal_src/jak3/engine/scene/scene.gc b/goal_src/jak3/engine/scene/scene.gc index 0730b59b0c..bca8e8f692 100644 --- a/goal_src/jak3/engine/scene/scene.gc +++ b/goal_src/jak3/engine/scene/scene.gc @@ -1319,6 +1319,10 @@ ) (script-eval (-> self scene on-complete)) ) + ;; mod-base-change - if there are custom audios playing, then, stop them + (if (is-any-sound-playing?) + (stop-all-sounds) + ) ) ) @@ -1720,6 +1724,10 @@ (-> self clock time-adjust-ratio) ) ) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ((cpad-hold? 0 l1) (if (cpad-pressed? 0 square) @@ -1732,6 +1740,10 @@ (-> self clock time-adjust-ratio) ) ) + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) ) ((cpad-hold? 0 x) (when (cpad-pressed? 0 x) @@ -1757,6 +1769,10 @@ ) ((= (-> self cur-speed) -1000.0) (format *stdcon* "scene paused~%") + ;; mod-base-change - if there are custom audios playing, then, pause them + (if (is-any-sound-playing?) + (pause-all-sounds) + ) (when (!= (-> self targ-speed) -1000.0) (sound-continue (-> gp-7 id)) (when *sound-player-enable* @@ -1767,6 +1783,7 @@ (set! (-> v1-190 params mask) (the-as uint 2)) (-> v1-190 id) ) + (resume-all-sounds) ;; mod-base-change - resume all custom audios ) (set! (-> self targ-speed) 0.0) (set! (-> self cur-speed) 0.0) diff --git a/goal_src/jak3/kernel-defs.gc b/goal_src/jak3/kernel-defs.gc index 5fb7930171..ee9db4216d 100644 --- a/goal_src/jak3/kernel-defs.gc +++ b/goal_src/jak3/kernel-defs.gc @@ -281,6 +281,15 @@ (define-extern play-sound-file (function string int symbol)) (define-extern stop-sound-file (function string none)) (define-extern stop-all-sounds (function none)) + +;;check if any custom audio is being played or not +(define-extern is-any-sound-playing? (function symbol)) +(define-extern is-sound-playing? (function string symbol)) + +;;pause/resume all sounds +(define-extern pause-all-sounds (function none)) +(define-extern resume-all-sounds (function none)) + (define-extern pc-init-autosplitter-struct (function none)) (define-extern pc-filepath-exists? (function string symbol)) (define-extern pc-mkdir-file-path (function string none))