There is a method of removing specific sounds using only Lua, as long as there is an event or function that happens in the same frame. It's a method I discovered (independently, not sure if I'm the first) which I use in my Decliner addon to block the guild invite sound since it's internal and not declared in Blizzard's public code. I then used it to block all invite sounds my addon handles so I can avoid replacing Blizzard code and causing taints. I'll share my method later when I'm at home.
- - - Updated - - -
Alright, so the way I block regular UI sounds (anything that uses "PlaySound" in the public code) is I hook PlaySound itself, check for what sound name was passed against a table, play a sound to get the "handle", then immediately stop that sound and use handle-1 to stop the first sound. The handle ID, which is the second return from PlaySound, is an incremental number for every sound played. If you were to use "print(handle)" for every sound played, your chat window would be spammed in the same way looping "print(i) i=i+1" would.
So far, from the limited testing I did, every single sound in the default UI uses "PlaySound", including sounds not declared in public code, since every single sound played increments the handle ID. This means that the handle ID is screaming higher and higher during things like raids. File and KitID seems to only exist for addons, but they also increment the handle ID. Using this info, you can stop any sound you want as long as you get the handle ID immediately after that sound, as in the same frame, and then stop both. I originally did this with the guild invite sound, but it is unreliably delayed so I just cut off the SFX for just one frame, so you can do that for sounds without a reliable same-frame event or function to hook to.
Here's the basic layout of the handle-1 method:
Code:
hooksecurefunc('PlaySound',silence)
-- change block in whatever function you would use to decide whether or not to play the sound
-- if you are copying this code to use and plan on changing "block", make sure to remove this line
local block=true
-- sound name with its KitID equivalent
-- these sounds are just what i block in my addon
local sound={
igCharacterInfoClose=840,
igCharacterInfoOpen=839,
igMainMenuClose=851,
igMainMenuOpen=850,
igPlayerInvite=880,
igQuestListClose=876,
igQuestListOpen=875,
}
local function silence(name)
if sound[name] then
-- sound ID "64" is one of the button sounds from the login screen, i chose it because its the number 64
local _,handle=PlaySoundKitID(64,'Master',false)
if handle then
StopSound(handle) -- this stops "64"
StopSound(handle-1) -- this stops the sound we want to filter
-- this single frame delay is the filter, which plays the sound we just stopped if block==false
-- local f=CreateFrame('frame')
-- f:SetScript('OnUpdate',function()
-- if not block then PlaySoundKitID(sound[name]) end
-- f:SetScript('OnUpdate',nil)
-- end)
end
end
end
I use 'Master' to ensure the sound plays, "false" to let the sound play over other copies of itself (otherwise, 64 won't play if too many filtered sounds happen close to each other), and check for "handle" since all three PlaySound functions fail and return nothing when the entire game is muted. One of the neat ideas I thought about doing with this is a pure addon that silences Rhonin, instead of the empty sound files, which would use CHAT_MSG to watch for his yells and then just stop his voice. I never got around to doing that.
And here's the somewhat known one-frame sfx mute:
Code:
local f=CreateFrame('frame')
f.sfx=GetCVar('Sound_EnableSFX')
SetCVar('Sound_EnableSFX','0')
f:SetScript('OnUpdate',function()
SetCVar('Sound_EnableSFX',f.sfx)
f:SetScript('OnUpdate',nil)
end)
This saves the current status (1/on or 0/off) of the sfx, turns sfx off, then uses the saved value. If sfx was on before, it turns back on. If sfx was off, it stays off. I didn't discover this method, I found it somewhere on WoWInterface forums. This "swallows" the sound. If a sound plays with sfx off, it doesn't play, so a long sound will not be playing when the sfx turns back on a frame later. The four second long guild invite sound (which is the level up sound) is completely muted within this one frame, and since a standard frame is 0.016 seconds long, the player never knows the sfx turned off.