From 2876f1e644c97fe75b8509ec68d79778fd24bccd Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sat, 1 Aug 2026 12:12:17 -0400 Subject: [PATCH 1/4] Deprecate LoadMusicStreamFromPhysFS --- README.md | 15 ++++++++++++++- examples/audio/audio_music_stream.c | 6 +++++- raylib-physfs.h | 11 ++++++++++- test/raylib-physfs-test.c | 27 +++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 40f9a0f..0916504 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,19 @@ int main() { } ``` +### Music + +`LoadMusicStreamFromPhysFS()` is deprecated, as raylib streams music directly from the file buffer, which this one-call API can never free. Instead, load the file data yourself, keep it alive while the music plays, and free it after unloading the music stream. + +``` c +int size; +unsigned char *data = LoadFileDataFromPhysFS("assets/music.ogg", &size); +Music music = LoadMusicStreamFromMemory(".ogg", data, size); +// ... play the music ... +UnloadMusicStream(music); +UnloadFileData(data); // Free the buffer only after unloading the music stream. +``` + ### API ``` c @@ -72,7 +85,7 @@ Image LoadImageAnimFromPhysFS(const char* fileName, int* frames); // Load an an Texture2D LoadTextureFromPhysFS(const char* fileName); // Load a texture from PhysFS Wave LoadWaveFromPhysFS(const char* fileName); // Load wave data from PhysFS Sound LoadSoundFromPhysFS(const char* fileName); // Load a sound from PhysFS -Music LoadMusicStreamFromPhysFS(const char* fileName); // Load music data from PhysFS +Music LoadMusicStreamFromPhysFS(const char* fileName); // Load music data from PhysFS (DEPRECATED: leaks the file buffer by design; use LoadFileDataFromPhysFS() with LoadMusicStreamFromMemory(), and UnloadFileData() after UnloadMusicStream()) Font LoadFontFromPhysFS(const char* fileName, int fontSize, int *fontChars, int charsCount); // Load a font from PhysFS Shader LoadShaderFromPhysFS(const char* vsFileName, const char* fsFileName); // Load shader from PhysFS void SetPhysFSCallbacks(void); // Set the raylib file loader/saver callbacks to use PhysFS diff --git a/examples/audio/audio_music_stream.c b/examples/audio/audio_music_stream.c index b56bd02..dcbe074 100644 --- a/examples/audio/audio_music_stream.c +++ b/examples/audio/audio_music_stream.c @@ -29,7 +29,10 @@ int main(void) InitPhysFS(); MountPhysFS("resources", "res"); - Music music = LoadMusicStreamFromPhysFS("res/country.mp3"); + // Load the music file data manually, as the buffer must stay valid while the music plays. + int musicDataSize = 0; + unsigned char *musicData = LoadFileDataFromPhysFS("res/country.mp3", &musicDataSize); + Music music = LoadMusicStreamFromMemory(".mp3", musicData, musicDataSize); PlayMusicStream(music); @@ -90,6 +93,7 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- UnloadMusicStream(music); // Unload music stream buffers from RAM + UnloadFileData(musicData); // Free the music file data after the stream is unloaded CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) diff --git a/raylib-physfs.h b/raylib-physfs.h index 42c0e95..feea7d1 100644 --- a/raylib-physfs.h +++ b/raylib-physfs.h @@ -72,7 +72,7 @@ RAYLIB_PHYSFS_DEF Image LoadImageAnimFromPhysFS(const char* fileName, int* frame RAYLIB_PHYSFS_DEF Texture2D LoadTextureFromPhysFS(const char* fileName); // Load a texture from PhysFS RAYLIB_PHYSFS_DEF Wave LoadWaveFromPhysFS(const char* fileName); // Load wave data from PhysFS RAYLIB_PHYSFS_DEF Sound LoadSoundFromPhysFS(const char* fileName); // Load a sound from PhysFS -RAYLIB_PHYSFS_DEF Music LoadMusicStreamFromPhysFS(const char* fileName); // Load music data from PhysFS +RAYLIB_PHYSFS_DEF Music LoadMusicStreamFromPhysFS(const char* fileName); // Load music data from PhysFS (DEPRECATED: leaks the file buffer by design; use LoadFileDataFromPhysFS() with LoadMusicStreamFromMemory(), and UnloadFileData() after UnloadMusicStream()) RAYLIB_PHYSFS_DEF Font LoadFontFromPhysFS(const char* fileName, int fontSize, int *fontChars, int charsCount); // Load a font from PhysFS RAYLIB_PHYSFS_DEF Shader LoadShaderFromPhysFS(const char* vsFileName, const char* fsFileName); // Load shader from PhysFS RAYLIB_PHYSFS_DEF void SetPhysFSCallbacks(void); // Set the raylib file loader/saver callbacks to use PhysFS @@ -498,10 +498,19 @@ Sound LoadSoundFromPhysFS(const char* fileName) { /** * Load module music from PhysFS. * + * @deprecated This function leaks the loaded file buffer by design: raylib's + * music decoders stream directly from the buffer, so it has to stay valid for + * as long as the music plays, and there is no way to free it afterwards. + * Instead, load the file with LoadFileDataFromPhysFS(), pass it to + * LoadMusicStreamFromMemory(), and free the buffer with UnloadFileData() + * after UnloadMusicStream(). + * * @param fileName The file name to load from the PhysFS mount paths. * * @return The Music object, or an empty Music object on failure. * + * @see LoadFileDataFromPhysFS() + * @see LoadMusicStreamFromMemory() * @see UnloadMusic() */ Music LoadMusicStreamFromPhysFS(const char* fileName) { diff --git a/test/raylib-physfs-test.c b/test/raylib-physfs-test.c index 8dc258a..d45c9f8 100644 --- a/test/raylib-physfs-test.c +++ b/test/raylib-physfs-test.c @@ -198,6 +198,33 @@ int main(int argc, char *argv[]) { AssertEqual(missingSound.stream.buffer, 0); } + // LoadFileDataFromPhysFS() with LoadMusicStreamFromMemory() + { + // The supported music pattern: the caller owns the file buffer, which + // must outlive the music stream, and is freed after UnloadMusicStream(). + for (int i = 0; i < 5; i++) { + int musicDataSize = 0; + unsigned char* musicData = LoadFileDataFromPhysFS("assets/sound.wav", &musicDataSize); + AssertNotEqual(musicData, 0); + Assert(musicDataSize > 0); + Music music = LoadMusicStreamFromMemory(".wav", musicData, musicDataSize); + AssertNotEqual(music.ctxData, 0); + UnloadMusicStream(music); + UnloadFileData(musicData); + } + } + + // LoadMusicStreamFromPhysFS() + { + // Deprecated, as it leaks the file buffer, but it should still load. + Music music = LoadMusicStreamFromPhysFS("assets/sound.wav"); + AssertNotEqual(music.ctxData, 0); + UnloadMusicStream(music); + + Music missingMusic = LoadMusicStreamFromPhysFS("MissingFile.wav"); + AssertEqual(missingMusic.ctxData, 0); + } + // LoadShaderFromPhysFS() { Shader missingShader = LoadShaderFromPhysFS("MissingFile.txt", "MissingFile.txt"); From 347b519d280dbaf4090562fa0335def68f5513f2 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sat, 1 Aug 2026 12:19:00 -0400 Subject: [PATCH 2/4] Remove LoadMusicStreamFromPhysFS --- README.md | 3 +-- raylib-physfs.h | 39 --------------------------------------- test/raylib-physfs-test.c | 11 ----------- 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/README.md b/README.md index 0916504..6b6a5c1 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ int main() { ### Music -`LoadMusicStreamFromPhysFS()` is deprecated, as raylib streams music directly from the file buffer, which this one-call API can never free. Instead, load the file data yourself, keep it alive while the music plays, and free it after unloading the music stream. +There is no `LoadMusicStreamFromPhysFS()`, as raylib streams music directly from the file buffer, which a one-call API could never free. Instead, load the file data yourself, keep it alive while the music plays, and free it after unloading the music stream. ``` c int size; @@ -85,7 +85,6 @@ Image LoadImageAnimFromPhysFS(const char* fileName, int* frames); // Load an an Texture2D LoadTextureFromPhysFS(const char* fileName); // Load a texture from PhysFS Wave LoadWaveFromPhysFS(const char* fileName); // Load wave data from PhysFS Sound LoadSoundFromPhysFS(const char* fileName); // Load a sound from PhysFS -Music LoadMusicStreamFromPhysFS(const char* fileName); // Load music data from PhysFS (DEPRECATED: leaks the file buffer by design; use LoadFileDataFromPhysFS() with LoadMusicStreamFromMemory(), and UnloadFileData() after UnloadMusicStream()) Font LoadFontFromPhysFS(const char* fileName, int fontSize, int *fontChars, int charsCount); // Load a font from PhysFS Shader LoadShaderFromPhysFS(const char* vsFileName, const char* fsFileName); // Load shader from PhysFS void SetPhysFSCallbacks(void); // Set the raylib file loader/saver callbacks to use PhysFS diff --git a/raylib-physfs.h b/raylib-physfs.h index feea7d1..53b884a 100644 --- a/raylib-physfs.h +++ b/raylib-physfs.h @@ -72,7 +72,6 @@ RAYLIB_PHYSFS_DEF Image LoadImageAnimFromPhysFS(const char* fileName, int* frame RAYLIB_PHYSFS_DEF Texture2D LoadTextureFromPhysFS(const char* fileName); // Load a texture from PhysFS RAYLIB_PHYSFS_DEF Wave LoadWaveFromPhysFS(const char* fileName); // Load wave data from PhysFS RAYLIB_PHYSFS_DEF Sound LoadSoundFromPhysFS(const char* fileName); // Load a sound from PhysFS -RAYLIB_PHYSFS_DEF Music LoadMusicStreamFromPhysFS(const char* fileName); // Load music data from PhysFS (DEPRECATED: leaks the file buffer by design; use LoadFileDataFromPhysFS() with LoadMusicStreamFromMemory(), and UnloadFileData() after UnloadMusicStream()) RAYLIB_PHYSFS_DEF Font LoadFontFromPhysFS(const char* fileName, int fontSize, int *fontChars, int charsCount); // Load a font from PhysFS RAYLIB_PHYSFS_DEF Shader LoadShaderFromPhysFS(const char* vsFileName, const char* fsFileName); // Load shader from PhysFS RAYLIB_PHYSFS_DEF void SetPhysFSCallbacks(void); // Set the raylib file loader/saver callbacks to use PhysFS @@ -495,44 +494,6 @@ Sound LoadSoundFromPhysFS(const char* fileName) { return sound; } -/** - * Load module music from PhysFS. - * - * @deprecated This function leaks the loaded file buffer by design: raylib's - * music decoders stream directly from the buffer, so it has to stay valid for - * as long as the music plays, and there is no way to free it afterwards. - * Instead, load the file with LoadFileDataFromPhysFS(), pass it to - * LoadMusicStreamFromMemory(), and free the buffer with UnloadFileData() - * after UnloadMusicStream(). - * - * @param fileName The file name to load from the PhysFS mount paths. - * - * @return The Music object, or an empty Music object on failure. - * - * @see LoadFileDataFromPhysFS() - * @see LoadMusicStreamFromMemory() - * @see UnloadMusic() - */ -Music LoadMusicStreamFromPhysFS(const char* fileName) { - int bytesRead; - unsigned char* fileData = LoadFileDataFromPhysFS(fileName, &bytesRead); - if (bytesRead == 0) { - Music output = { 0 }; - return output; - } - - // Load from the memory. - const char* extension = GetFileExtension(fileName); - Music music = LoadMusicStreamFromMemory(extension, fileData, bytesRead); - - // Unload the file data if the music failed to load. - if (music.ctxData == NULL) { - UnloadFileData(fileData); - } - - return music; -} - /** * Load font from PhysFS. * diff --git a/test/raylib-physfs-test.c b/test/raylib-physfs-test.c index d45c9f8..dfebe00 100644 --- a/test/raylib-physfs-test.c +++ b/test/raylib-physfs-test.c @@ -214,17 +214,6 @@ int main(int argc, char *argv[]) { } } - // LoadMusicStreamFromPhysFS() - { - // Deprecated, as it leaks the file buffer, but it should still load. - Music music = LoadMusicStreamFromPhysFS("assets/sound.wav"); - AssertNotEqual(music.ctxData, 0); - UnloadMusicStream(music); - - Music missingMusic = LoadMusicStreamFromPhysFS("MissingFile.wav"); - AssertEqual(missingMusic.ctxData, 0); - } - // LoadShaderFromPhysFS() { Shader missingShader = LoadShaderFromPhysFS("MissingFile.txt", "MissingFile.txt"); From 020012575bb04cf81a88f468333a0a59529b61e1 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sat, 1 Aug 2026 12:20:09 -0400 Subject: [PATCH 3/4] Trim music README note --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b6a5c1..ed4cb86 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ int main() { ### Music -There is no `LoadMusicStreamFromPhysFS()`, as raylib streams music directly from the file buffer, which a one-call API could never free. Instead, load the file data yourself, keep it alive while the music plays, and free it after unloading the music stream. +raylib streams music directly from the file buffer, so load the file data yourself, keep it alive while the music plays, and free it after unloading the music stream. ``` c int size; From 84ccdf1ae25d5fe9af7f9718d1d900d4ebee205b Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Sat, 1 Aug 2026 12:23:07 -0400 Subject: [PATCH 4/4] Apply suggestion from @RobLoach --- test/raylib-physfs-test.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/test/raylib-physfs-test.c b/test/raylib-physfs-test.c index dfebe00..8dc258a 100644 --- a/test/raylib-physfs-test.c +++ b/test/raylib-physfs-test.c @@ -198,22 +198,6 @@ int main(int argc, char *argv[]) { AssertEqual(missingSound.stream.buffer, 0); } - // LoadFileDataFromPhysFS() with LoadMusicStreamFromMemory() - { - // The supported music pattern: the caller owns the file buffer, which - // must outlive the music stream, and is freed after UnloadMusicStream(). - for (int i = 0; i < 5; i++) { - int musicDataSize = 0; - unsigned char* musicData = LoadFileDataFromPhysFS("assets/sound.wav", &musicDataSize); - AssertNotEqual(musicData, 0); - Assert(musicDataSize > 0); - Music music = LoadMusicStreamFromMemory(".wav", musicData, musicDataSize); - AssertNotEqual(music.ctxData, 0); - UnloadMusicStream(music); - UnloadFileData(musicData); - } - } - // LoadShaderFromPhysFS() { Shader missingShader = LoadShaderFromPhysFS("MissingFile.txt", "MissingFile.txt");