Skip to content

Add client-side world sound replacement functions - #5330

Open
iManGaaX wants to merge 37 commits into
multitheftauto:masterfrom
iManGaaX:feature/world-sound-replacement
Open

Add client-side world sound replacement functions#5330
iManGaaX wants to merge 37 commits into
multitheftauto:masterfrom
iManGaaX:feature/world-sound-replacement

Conversation

@iManGaaX

@iManGaaX iManGaaX commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds four new client-side functions that let resources replace GTA world sounds (weapon shots, bullet impacts, explosions, vehicle, environment sounds and etc..) directly, without the usual workarounds:

bool replaceWorldSound ( string filePathOrRawData, int group [, int index = -1 [, float minDistance = 0 [, float maxDistance = 0 ]]] )
bool restoreWorldSound ( int group [, int index = -1 ] )
bool restoreAllWorldSounds ( )
bool isWorldSoundReplaced ( int group [, int index = -1 ] )

Example:

addEventHandler("onClientResourceStart", resourceRoot, function()
    replaceWorldSound("sounds/water.wav", 32, -1, 5, 50)
end)

addEventHandler("onClientResourceStop", resourceRoot, function()
    restoreAllWorldSounds()
end)

Behavior highlights:

  • The replacement plays at the original sound's position and respects its audible distance (optional minDistance/maxDistance overrides per call).
  • Follows moving emitters (vehicles, peds) frame-by-frame while they play.
  • Honors the game's SFX volume (audio sfx CVar) and mute_sfx_when_minimized, matching the original sound exactly.
  • replaceWorldSound validates the audio file and the distance arguments at call time; unreadable/corrupt files and inverted distances return false and log a script-debugging warning.
  • Replacing a sound silences the original; restoring removes the replacement. isWorldSoundReplaced queries the current state.

Video (Make sure to unmute the video):

2026-09-06.21-36-01.mp4

Motivation

Currently, replacing an internal GTA world sound (e.g. a weapon shot) requires disabling the original with setWorldSoundEnabled, cancelling onClientWorldSound, and manually re-playing a new sound via playSound3D with tracked positions. That loses the original sound's position and distance behavior, is tedious to write, and is error-prone.

This PR lets a resource replace any world sound with a single call, keeping GTA's original trigger, position and distance semantics.

Closes #4908.

Test plan

  1. Compile the client changes with the new pool scanning implementation.
  2. Tested all the functions, and they are all working smoothly without any issues.
  3. Fire from far away and confirm the replacement fades like the original did (or per a custom minDistance/maxDistance).
  4. Fire from a moving vehicle and confirm the sound tracks it.
  5. Set audio sfx to 0 and minimize the game; the replacement must go silent, same as the original.
  6. Pass a missing/corrupt file and an inverted distance pair; both must return false and log a warning.

Checklist

  • Your code should follow the coding guidelines.
  • Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.

@FileEX

FileEX commented Sep 6, 2026

Copy link
Copy Markdown
Member

This isn't actually replacing the sounds, and in my opinion these functions shouldn't be named that way. You're not replacing the actual sound in the audio banks; you're muting the original sounds and playing your own instead. This will mean that, for example, engine sounds won't be modulated based on the vehicle's gear and will instead remain at a constant sound.

@iManGaaX

iManGaaX commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

This isn't actually replacing the sounds, and in my opinion these functions shouldn't be named that way. You're not replacing the actual sound in the audio banks; you're muting the original sounds and playing your own instead. This will mean that, for example, engine sounds won't be modulated based on the vehicle's gear and will instead remain at a constant sound.

But naming it engineReplaceWorldSound is completely consistent with MTA. Ex, engineReplaceModel doesn't alter the original DFF file inside gta3.img either; it suppresses the original entity and substitutes it in runtime memory. in GTA SA, true bank patching at runtime is unstable and doesn't support custom external formats easily.

Anyway, let me think of a better approach and update the files.

@iManGaaX

iManGaaX commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

@FileEX ,
Review the files and let me know ur thoughts on this implementation and if u have any further suggestions?

@FileEX

FileEX commented Sep 6, 2026

Copy link
Copy Markdown
Member

Could you record a video showing the engine sound being replaced and reacting to how the vehicle is being driven?

@iManGaaX

iManGaaX commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Could you record a video showing the engine sound being replaced and reacting to how the vehicle is being driven?

Sure, i will record a quick video demonstrating the replaced engine sound, then share it here, give me some time

@iManGaaX

iManGaaX commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Could you record a video showing the engine sound being replaced and reacting to how the vehicle is being driven?

The engine pitch and sound modulate smoothly with the rpm, speed, and gear shifts, sorry for the short video; GitHub doesn't allow video/image uploads over 10MB

2026-09-07.02-48-01.mp4

@iManGaaX

iManGaaX commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Example:

replaceWorldSound("ak1.wav", 5, 31, 5, 25)
replaceWorldSound("ak2.wav", 5, 32, 5, 25)
replaceWorldSound("ak3.wav", 5, 33, 5, 25)
2026-09-07.03-05-16.mp4

@FileEX

FileEX commented Sep 7, 2026

Copy link
Copy Markdown
Member

The engine pitch and sound modulate smoothly with the rpm, speed, and gear shifts, sorry for the short video; GitHub doesn't allow video/image uploads over 10MB

2026-09-07.02-48-01.mp4

This sound really weird...

@FileEX FileEX added the enhancement New feature or request label Sep 7, 2026
Comment thread Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp Outdated
Comment thread Client/mods/deathmatch/logic/luadefs/CLuaAudioDefs.cpp Outdated
@Fernando-A-Rocha

Copy link
Copy Markdown
Contributor

Can u replace vehicle horn sounds with this? Got a video/audio demo? :D

@iManGaaX

iManGaaX commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Can u replace vehicle horn sounds with this? Got a video/audio demo? :D

xD

2026-09-07.20-45-33.mp4

@Fernando-A-Rocha

Copy link
Copy Markdown
Contributor

lmao I meant a realistic horn sound that sounds as good as the originals

@starfleet001

Copy link
Copy Markdown

Wouldn't it be more efficient to replace audio chunks in internal data bunks?

Your solution basically acts like a replacement for playSound3D (which is inefficient and will not produce native behavior)

@iManGaaX

iManGaaX commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Wouldn't it be more efficient to replace audio chunks in internal data bunks?

Your solution basically acts like a replacement for playSound3D (which is inefficient and will not produce native behavior)

It already does that; index-specific replacements patch the PCM buffer inside the game's loaded sound bank (CAEAudioHardware::PatchSoundBuffer), so the engine plays it natively with full pitch/RPM behavior. The playSound3D-style overlay only kicks in as a fallback when the bank isn't loaded yet, the clip is bigger than the fixed bank slot, or the replacement is group-wide (index = -1)

@iManGaaX

iManGaaX commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

@Fernando-A-Rocha here's exactly what u wanted to see regarding the vehicle horn; and @FileEX here are the engine sounds just as u wanted to hear them. the only thing is i don't have the ideal audio files yet; i just found a few decent ones to test with for now. also, using the function properly requires someone who knowns the function's group and index numbers

2026-09-07.23-16-14.mp4

@FileEX

FileEX commented Sep 7, 2026

Copy link
Copy Markdown
Member

It already does that; index-specific replacements patch the PCM buffer inside the game's loaded sound bank (CAEAudioHardware::PatchSoundBuffer), so the engine plays it natively with full pitch/RPM behavior.

If you're replacing a sound in the sound bank, you don't need PlaySound3D; just let GTA play the sound itself.

@iManGaaX

iManGaaX commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

It already does that; index-specific replacements patch the PCM buffer inside the game's loaded sound bank (CAEAudioHardware::PatchSoundBuffer), so the engine plays it natively with full pitch/RPM behavior.

If you're replacing a sound in the sound bank, you don't need PlaySound3D; just let GTA play the sound itself.

np, just let me know exactly what u would like me to do and i will handle it. list all ur suggestions/required changes

@FileEX

FileEX commented Sep 8, 2026

Copy link
Copy Markdown
Member

Generally, it should work so that the specified sound in the given audio bank is actually replaced, but the game still plays it normally, modifies its pitch, frequency, etc., without cancelling onClientWorldSound and playing our own sound through playSound. GTA itself should continue playing the sound from the audio bank normally.

It's the same as with engineReplaceModel - we don't hide the original model and render our own. We replace the original model with a new data stream. Exactly the same thing should happen with sounds. They should be literally replaced, not muted and simulated through playSound.

@iManGaaX

iManGaaX commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Generally, it should work so that the specified sound in the given audio bank is actually replaced, but the game still plays it normally, modifies its pitch, frequency, etc., without cancelling onClientWorldSound and playing our own sound through playSound. GTA itself should continue playing the sound from the audio bank normally.

It should be doing this now. i also added a new function, getWorldSoundBankSlotInfo ( int group [, int index = -1 ] ), which returns two values: maxBytes (the bank slot sound size in bytes) and sampleRate (the sample rate), or false if the bank is not loaded or values are out of range, now replaceWorldSound function is supposed to perform an in-memory replacement inside the bank, featuring auto-trimming for non-looping sounds (at full quality), downsampling for looping ones, and issuing warnings/errors in debugscript

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add to replace GTA world sounds directly

4 participants