diff --git a/game/kernel/common/kmachine.cpp b/game/kernel/common/kmachine.cpp index a243de1ef2..c17dd169fd 100644 --- a/game/kernel/common/kmachine.cpp +++ b/game/kernel/common/kmachine.cpp @@ -113,65 +113,182 @@ u64 CPadOpen(u64 cpad_info, s32 pad_number) { -void playMP3(u32 filePathu32, u32 volume) -{ - - // Spawn a new thread to play the music. - std::thread thread([=]() { - std::string filePath = Ptr(filePathu32).c()->data(); - std::cout << "Playing MP3: " << filePath << std::endl; - sf::Music music; - if (!music.openFromFile(filePath)) +// Define a vector to store references to the active music instances. +std::vector> activeMusics; + +// Index to store the main music in the vector. +const size_t MAIN_MUSIC_INDEX = 0; + +// Function to stop all currently playing sounds. +void stopAllSounds() +{ + for (auto& pair : activeMusics) { - std::cout << "Failed to load: " << filePath << std::endl; - return; + pair.first->stop(); } - music.setVolume(volume); - music.play(); - while (music.getStatus() == sf::Music::Playing) + activeMusics.clear(); +} + +// Function to get the names of currently playing files. +std::vector getPlayingFileNames() +{ + std::vector playingFileNames; + for (const auto& pair : activeMusics) + { + playingFileNames.push_back(pair.second); + } + return playingFileNames; +} + +std::mutex activeMusicsMutex; // Mutex to synchronize access to activeMusics + +void playMP3(u32 filePathu32, u32 volume) { + std::thread thread([=]() { + std::string filePath = Ptr(filePathu32).c()->data(); + std::cout << "Playing MP3: " << filePath << std::endl; + + sf::Music* music = new sf::Music; + if (!music->openFromFile(filePath)) { + std::cout << "Failed to load: " << filePath << std::endl; + delete music; + return; + } + music->setVolume(volume); + music->play(); + { + std::lock_guard lock(activeMusicsMutex); + activeMusics.push_back(std::make_pair(music, filePath)); + } + + while (music->getStatus() == sf::Music::Playing) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } - music.stop(); + { + std::lock_guard lock(activeMusicsMutex); + activeMusics.erase(std::remove_if(activeMusics.begin(), activeMusics.end(), + [music](const auto& pair) { return pair.first == music; }), activeMusics.end()); + } + + delete music; }); - // Detach the thread so it can run independently. thread.detach(); } -// void playMP3(u32 filePathu32, u32 volume) -// { -// std::string filePath = Ptr(filePathu32).c()->data(); -// std::cout << "Playing MP3: " << filePath << std::endl; -// sf::Music music; +// Declare a mutex for synchronizing access to mainMusicInstance +std::mutex mainMusicMutex; + +// Define a structure to hold music data +struct MusicData { + sf::Music* music; + std::string filePath; + u32 volume; + bool isPaused; // Added flag to track pause/resume state +}; + +// Define a vector to hold the music instances +std::vector musicInstances; +std::string mainMusicFilePath; // Global variable to store the main music file path + +// Function to stop the Main Music. +void stopMainMusic() { + std::cout << "Trying to stop Main Music: " << mainMusicFilePath << std::endl; + auto it = musicInstances.begin(); + while (it != musicInstances.end()) { + std::cout << "Looking for Main Music: " << mainMusicFilePath << std::endl; + if (it->filePath == mainMusicFilePath) { + std::cout << "FOUND!!! Main Music: " << mainMusicFilePath << std::endl; + it->music->stop(); + delete it->music; + it = musicInstances.erase(it); // 'erase' will automatically move to the next element + } else { + ++it; + } + } +} -// std::ifstream file(filePath); -// if (!file) -// { -// std::cout << "Invalid file path: " << filePath << std::endl; -// return; -// } +// Function to play the Main Music. +void playMainMusic(u32 filePathu32, u32 volume) { + std::string filePath = Ptr(filePathu32).c()->data(); + std::cout << "Playing Main Music: " << filePath << std::endl; + mainMusicFilePath = filePath; + //stopMainMusic(); + // Stop and clean up any existing music instances for this file path + for (auto it = musicInstances.begin(); it != musicInstances.end();) { + if (it->filePath == filePath) { + it->music->stop(); + delete it->music; + it = musicInstances.erase(it); + } else { + ++it; + } + } + + // Create a new instance of sf::Music for the new Main Music. + sf::Music* mainMusic = new sf::Music; + if (!mainMusic->openFromFile(filePath)) + { + std::cout << "Failed to load: " << filePath << std::endl; + delete mainMusic; + return; + } + mainMusic->setVolume(volume); + // Set looping to true to make the track loop + mainMusic->setLoop(true); + + mainMusic->play(); + + // Store the Main Music instance in the vector. + MusicData musicData = { mainMusic, filePath, volume, false }; // Initialize isPaused to false + musicInstances.push_back(musicData); +} + + + +void pauseMainMusic() { + mainMusicMutex.lock(); + for (auto& musicData : musicInstances) { + if (musicData.music && !musicData.isPaused) { + if (musicData.music->getStatus() == sf::SoundSource::Playing) { + musicData.music->pause(); + musicData.isPaused = true; + } + } + } + mainMusicMutex.unlock(); +} + +void resumeMainMusic() { + mainMusicMutex.lock(); + for (auto& musicData : musicInstances) { + if (musicData.music && musicData.isPaused) { + if (musicData.music->getStatus() == sf::SoundSource::Paused) { + musicData.music->play(); + musicData.isPaused = false; + } + } + } + mainMusicMutex.unlock(); +} -// if (!music.openFromFile(filePath)) -// { -// printf("Failed to load: %s\n", filePath.c_str()); -// std::cout << "Failed to load: " << filePath << std::endl; -// return; -// } -// music.setVolume(volume); -// music.play(); -// while (music.getStatus() == sf::Music::Playing) -// { -// sf::sleep(sf::milliseconds(100)); -// sf::sleep(sf::milliseconds(100)); -// } -// } +// Function to change the volume of the Main Music. +void changeMainMusicVolume(u32 volume) { + mainMusicMutex.lock(); + for (auto& musicData : musicInstances) { + if (musicData.music) { + musicData.music->setVolume(volume); + musicData.volume = volume; + } + } + mainMusicMutex.unlock(); +} /*! @@ -1025,7 +1142,19 @@ void init_common_pc_port_functions( make_func_symbol_func("pc-mkdir-file-path", (void*)pc_mkdir_filepath); //Play sound file - make_func_symbol_func("play-rand-sound", (void*)playMP3); + make_func_symbol_func("play-sound-file", (void*)playMP3); + + //Stop sound file + make_func_symbol_func("stop-sound-file", (void*)stopAllSounds); + + //Main music stuff + make_func_symbol_func("play-main-music", (void*)playMainMusic); + make_func_symbol_func("pause-main-music", (void*)pauseMainMusic); + make_func_symbol_func("stop-main-music", (void*)stopMainMusic); + make_func_symbol_func("resume-main-music", (void*)resumeMainMusic); + + make_func_symbol_func("main-music-volume", (void*)changeMainMusicVolume); + // discord rich presence make_func_symbol_func("pc-discord-rpc-set", (void*)set_discord_rpc); diff --git a/goal_src/jak1/engine/mods/mod-common-functions.gc b/goal_src/jak1/engine/mods/mod-common-functions.gc index c802e4f625..181b12db94 100644 --- a/goal_src/jak1/engine/mods/mod-common-functions.gc +++ b/goal_src/jak1/engine/mods/mod-common-functions.gc @@ -375,6 +375,27 @@ if the result of rand-vu-int-range is 1, then DANCE! if it is not 1, then Don't ) ) +(defun music-manager () + (stop-main-music) + (case (-> (level-get-target-inside *level*) name) + (('test-zone) + (if (> (knuth-rand-int-range 0 15) (+ 8 5)) + (play-main-music "SND/music-test-zone.mp3" (the int (-> *setting-control* default music-volume))) + (play-main-music "SND/music-test-zone-track2.mp3" (the int (-> *setting-control* default music-volume)))) + ) + ;;Add more cases here for each level + (else + (play-main-music "" (the int (-> *setting-control* default music-volume))) + ;;(stop-main-music) This function is broken but playing a invalid sound does the same thing + ) + ) +(none) +) + +(defbehavior music-manager-proc process () + (music-manager) + (none) +) ;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Jak Color functions ;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/goal_src/jak1/engine/mods/mod-custom-code.gc b/goal_src/jak1/engine/mods/mod-custom-code.gc index 73734253b6..0e7a7bdebe 100644 --- a/goal_src/jak1/engine/mods/mod-custom-code.gc +++ b/goal_src/jak1/engine/mods/mod-custom-code.gc @@ -108,7 +108,10 @@ ) (defun runs-on-jak-spawn () - ;; Code here runs every time jak spawns (loading a file new game or death) + ;; Code here runs every time jak spawns (loading a file new game or death) + + ;;uncomment this to use custom music for custom levels - the function is in mod-common-functions.gc + ;;(process-spawn-function process music-manager-proc) (none) ) diff --git a/goal_src/jak1/kernel-defs.gc b/goal_src/jak1/kernel-defs.gc index aab74485a8..0aa3593726 100644 --- a/goal_src/jak1/kernel-defs.gc +++ b/goal_src/jak1/kernel-defs.gc @@ -384,7 +384,16 @@ (define-extern pc-discord-rpc-set (function int none)) -(define-extern play-rand-sound (function string int none)) +;;main music start +(define-extern play-main-music (function string int none)) +(define-extern pause-main-music (function none)) +(define-extern stop-main-music (function none)) +(define-extern resume-main-music (function none)) +(define-extern main-music-volume (function int none)) +;;main music end + +(define-extern play-sound-file (function string int none)) +(define-extern stop-sound-file (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/jak2/kernel-defs.gc b/goal_src/jak2/kernel-defs.gc index 434a9f0358..77d753e3ce 100644 --- a/goal_src/jak2/kernel-defs.gc +++ b/goal_src/jak2/kernel-defs.gc @@ -209,8 +209,19 @@ (declare-type discord-info structure) (define-extern pc-discord-rpc-update (function discord-info none)) (define-extern pc-discord-rpc-set (function int none)) -(define-extern play-rand-sound (function string int none)) +(define-extern play-sound-file (function string int none)) (define-extern pc-init-autosplitter-struct (function none)) + +;;main music start +(define-extern play-main-music (function string int none)) +(define-extern pause-main-music (function none)) +(define-extern stop-main-music (function none)) +(define-extern resume-main-music (function none)) +(define-extern main-music-volume (function int none)) +;;main music end + +(define-extern play-sound-file (function string int none)) +(define-extern stop-sound-file (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/out/build/Release/bin/decompiler.exe b/out/build/Release/bin/decompiler.exe index 82fa38e4fd..a6b393df7c 100644 Binary files a/out/build/Release/bin/decompiler.exe and b/out/build/Release/bin/decompiler.exe differ diff --git a/out/build/Release/bin/extractor.exe b/out/build/Release/bin/extractor.exe index e72147856b..5f62a095cc 100644 Binary files a/out/build/Release/bin/extractor.exe and b/out/build/Release/bin/extractor.exe differ diff --git a/out/build/Release/bin/gk.exe b/out/build/Release/bin/gk.exe index efea968b6c..9ecebc6d1a 100644 Binary files a/out/build/Release/bin/gk.exe and b/out/build/Release/bin/gk.exe differ diff --git a/out/build/Release/bin/goalc.exe b/out/build/Release/bin/goalc.exe index 92d33ce762..5230d306da 100644 Binary files a/out/build/Release/bin/goalc.exe and b/out/build/Release/bin/goalc.exe differ