WoWInterface - View Single Post - Queue ready sound -> play at 100% volume?
View Single Post
01-11-18, 07:10 PM   #6
A Molten Giant
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 503
  1. My apologies, I did some testing this time.
  2. I was wrong, it really is levelup2.ogg. Damn Blizzard spaghetti code.
  3. The second code didn't work because apparently PlaySoundFile doesn't actually work exactly like PlaySound does, despite my assumption. It only has file and channel for arguments, no new fourth argument and I could've sworn it had noDupe but it doesn't. Good thing to know now lol.
  4. The first code didn't work because the UI plays sounds with no duplicates by default and apparently StopSound doesn't release that "lock" in the same frame you try to play the sound again. So, I had to use an OnUpdate script to play the sound a frame later. You won't notice the frame skip. There was also an issue with honoring no duplicates, the sound would start over if the UI or anything else using the sound wanted no duplicates and tried to play it again. While accounting for both of these issues, I went further and allowed the sound to play at 100% on any channel requested, master by default. Other code can even overlap the sound, the volume will go back down once the last duplicate is done. I think I went a bit overboard, but I'm satisfied with how it turned out.

I can now guarantee the following code works, keep your custom sound in the levelup2.ogg file path. If the sound ever changes in the future, just change the number at the very top along with finding the new file path. I doubt that would happen though.

Lua Code:
  1. local readycheck=8960 -- Sound\\Interface\\levelup2.ogg
  2. local pool,f={},CreateFrame('frame') f.handle={} f.last={}
  3. function f.pool(t,i)
  4.     if i then pool[i]:SetScript('OnUpdate',nil) pool[i].t=nil return end
  5.     for i=1,#pool do
  6.         if pool[i] and not pool[i].t then pool[i].t={i=i,t=t} return i end
  7.     end
  8.     tinsert(pool,CreateFrame('frame')) i=#pool pool[i].t={i=i,t=t} return i
  9. end
  10. f:SetScript('OnEvent',function(_,_,handle)
  11.     if f.nodupe==handle then f.nodupe=nil end
  12.     if f.handle[handle] then
  13.         if f[f.handle[handle]] and f.last[f.handle[handle]]==handle then
  14.             SetCVar(f.handle[handle],f[f.handle[handle]])
  15.             f[f.handle[handle]]=nil
  16.         end
  17.         f.handle[handle]=nil
  18.     end
  19. end)
  20. f:RegisterEvent('SOUNDKIT_FINISHED')
  21. hooksecurefunc('PlaySound',function(id,channel,nodupe,_,_,_,_,own)
  22.     if id==readycheck and not f.nodupe and not own then
  23.         local _,handle=PlaySound(64,'Master',false)
  24.         if handle then
  25.             StopSound(handle) StopSound(handle-1)
  26.             channel=(not channel and 'Master') or (strlower(channel)=='sfx' and 'SFX') or strlower(channel):gsub('^%a',strupper)
  27.             local cvar='Sound_'..channel..'Volume'
  28.             pool[f.pool({id,channel,nodupe,cvar})]:SetScript('OnUpdate',function(self)
  29.                 local _,handle=PlaySound(self.t.t[1],self.t.t[2],self.t.t[3],true,nil,nil,nil,true)
  30.                 if handle then
  31.                     if self.t.t[3]~=false then f.nodupe=handle end
  32.                     f.last[self.t.t[4]]=handle
  33.                     f.handle[handle]=self.t.t[4]
  34.                     if not f[self.t.t[4]] then
  35.                         f[self.t.t[4]]=GetCVar(self.t.t[4])
  36.                         if f[self.t.t[4]] then SetCVar(self.t.t[4],1) end
  37.                     end
  38.                 end
  39.                 f.pool('',self.t.i)
  40.             end)
  41.         end
  42.     end
  43. end)

Some tests you can run:

 -- exactly what the UI does, will play on master at 100%, using it again will do nothing while the sound is playing
/run PlaySound(8960)

 -- each line will still only play one sound, the last one in each line chooses the channel (which is weird, one would think the first one would go first)
/run PlaySound(8960,'master')PlaySound(8960,'sfx')PlaySound(8960,'dialog')
/run PlaySound(8960,'sfx')PlaySound(8960,'dialog')PlaySound(8960,'master')
/run PlaySound(8960,'dialog')PlaySound(8960,'master')PlaySound(8960,'sfx')

 -- plays two overlapping sounds at 100% on master
/run PlaySound(8960,nil,false)PlaySound(8960,nil,false)

 -- (WARNING: LOUD) will play five overlapping sounds using all five channels, all at 100%
/run PlaySound(8960,'master',false)PlaySound(8960,'ambience',false)PlaySound(8960,'dialog',false)PlaySound(8960,'music',false)PlaySound(8960,'sfx',false)

Last edited by Kanegasi : 01-11-18 at 07:15 PM.
  Reply With Quote