HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Sound doesn't play first time

04-21-2009, 07:41 PM#1
marshall
I have a sound that doesn't play the first time I call it. I get the idea that the sound has to be loaded first, however I have tried preloading and that doesn't help.
In the below code, the first sound (s3start) does not play the first time. The second sound (s3loop) does play the first time, although that might have something to do with the fact that the sound loops.

Collapse JASS:
if GetSpellAbilityId() == 'A039'then
        set uCaster = GetTriggerUnit()
        set iSound = GetSoundHandle()
        call SetUnitInvulnerable(uCaster, true)
        set iUnit = StoreAlphaUnit(uCaster)
        call UpdateAlphaUnit(iUnit, 255, 255, 0, -1, 0, true)
        call ConditionalTriggerExecute(gg_trg_UpdateAlphaUnits)
        //start sound
        set udg_SoundHandle[iSound] = CreateSound("war3mapImported\\s3start.wav", false, true, false, 10, 10, "DefaultEAXON")
        call SetSoundDuration(udg_SoundHandle[iSound], 681)
        call SetSoundChannel(udg_SoundHandle[iSound], 0)
        call SetSoundVolume(udg_SoundHandle[iSound], 127)
        call SetSoundPitch(udg_SoundHandle[iSound], 1.0)
        call SetSoundDistances(udg_SoundHandle[iSound], 600.0, 1024.0)
        call SetSoundDistanceCutoff(udg_SoundHandle[iSound], 1536.0)
        call SetSoundConeAngles(udg_SoundHandle[iSound], 0.0, 0.0, 127)
        call SetSoundConeOrientation(udg_SoundHandle[iSound], 0.0, 0.0, 0.0)
        call AttachSoundToUnit(udg_SoundHandle[iSound], uCaster)
        call StartSound(udg_SoundHandle[iSound])
        call KillSoundWhenDone(udg_SoundHandle[iSound])
        call PolledWaitMx(0.6)
        //looping sound
        set udg_SoundHandle[iSound] = CreateSound("war3mapImported\\s3loop.wav", true, true, false, 10, 10, "DefaultEAXON")
        call SetSoundDuration(udg_SoundHandle[iSound], 5684)
        call SetSoundChannel(udg_SoundHandle[iSound], 0)
        call SetSoundVolume(udg_SoundHandle[iSound], 127)
        call SetSoundPitch(udg_SoundHandle[iSound], 1.0)
        call SetSoundDistances(udg_SoundHandle[iSound], 600.0, 1024.0)
        call SetSoundDistanceCutoff(udg_SoundHandle[iSound], 1536.0)
        call SetSoundConeAngles(udg_SoundHandle[iSound], 0.0, 0.0, 127)
        call SetSoundConeOrientation(udg_SoundHandle[iSound], 0.0, 0.0, 0.0)
        call AttachSoundToUnit(udg_SoundHandle[iSound], uCaster)
        call StartSound(udg_SoundHandle[iSound])
        //wait and remove effects
        call PolledWaitMx(28.4)
        call StopSound(udg_SoundHandle[iSound], true, true)
        call ClearSoundHandle(iSound)
        ...

Any thoughts on why the sound won't play first time / how I can get it to play first time?
Thanks.
04-21-2009, 08:44 PM#2
Michael Peppers
You're using the same array global for two different sounds: "udg_SoundHandle[iSound]"

Are you sure that the first sound being played doesn't get overwritten by modifying the value of that variable? Give it a check...
04-21-2009, 10:02 PM#3
marshall
Hmmm... I don't think that's an issue because the idea is that the start sound plays, and then the loop sound plays. When the loop sound plays I no longer need the start sound. If a second instance arrises then a different SoundHandle element will be returned.

The problem is that the sound doesn't play only on the first time I try to play it. All subsequent plays are fine.
This suggests that it is a loading/caching issue, but preload doesn't fix the problem (preload during initialisation a problem?). I could have a function that duplicates this code and run it 1 second after initialisation but that seems a rather poor work-around (plus I don't want to have to do that for every sound)...
04-21-2009, 10:24 PM#4
Vexorian
As far as I know it has always been like this.

What we do is either to a) ignore the issue or b) "play" the sound at map init.
04-22-2009, 07:11 AM#5
marshall
I've added basic code to my InitSounds trigger to just play the sound at zero volume, and changed the trigger to fire at 0.01 seconds instead of init. Now it's working. Thanks.
04-22-2009, 12:57 PM#6
Fledermaus
If the sound wont actually play the first time you "play" it, why bother setting the volume to 0?
04-22-2009, 01:20 PM#7
marshall
Good point, but better safe than sorry.
04-22-2009, 02:46 PM#8
Captain Griffen
Preloading it always made it work fine for me.
04-22-2009, 04:31 PM#9
Ammorth
I found that as long as the sound wasn't created in the same thread it was to be played in, it would work the first time. Aka, use a timer or an execute function to play the sound after you create it.
04-22-2009, 06:40 PM#10
Captain Griffen
Isn't KillSoundWhenDone buggy in some way?
04-22-2009, 08:57 PM#11
Vexorian
KillSoundWhenDone == DestroySound

Blizz just used that name not to give the impression that it would stop current reproductions of the sound.
04-23-2009, 01:27 PM#12
marshall
Hmm... this was working for me, but tried it just now and the sound is once again not playing in the first call.

Is KillSoundWhenDone buggy in some way? My understanding was that it only destroyed the instance of the sound so that I don't end up with hundreds of instances loaded in memory, but if it unloads the WAV as well then that's not good...

Quote:
as long as the sound wasn't created in the same thread it was to be played in
If ^this refers to the sound object rather than the WAV then this could be my problem...
04-23-2009, 02:42 PM#13
Ammorth
Collapse JASS:
set soundFile = CreateSound()
call PlaySound(soundFile)

vs.

Collapse JASS:
set soundFile = CreateSound()
call ExecuteFunc("PlayMySound")

..

function PlayMySound takes nothing returns nothing
call PlaySound(soundFile)
endfunction

I have never tried with execute function, but I know a 0 second timer works.
04-23-2009, 08:51 PM#14
marshall
I've done pretty much what Ammorth suggested (but dressed up with a slew of other functionality)... and it now works perfectly. No need to preload either.

Just one more question regarding TriggerWaitForSound. Does this native actually do anything at all? I was expecting call TriggerWaitForSound(mysound, 0) to pause execution of the thread until the sound finished but it acted as though the call wasn't even there. Unless it's supposed to work like "wait for sound to play to offset" but if that's the case then it's useless because you'd have to know in advance how long your sound is.

EDIT:
Okay, it STILL isn't working. I thought it was, but now I've discovered that it doesn't play the first time in a given session of Warcraft 3. Meaning, I have the problem, play the sound once (which doesn't work), quit back to the menu, start another game, now the sound will play first time.
I am presently preloading the file, playing it 3 seconds after map load, but STILL it doesn't play when I try to play it with my spell (first time). Playing it 3 seconds after map load should have solved it at least, but it hasn't. I can't figure out why because it calls the same function that my spell trigger does. Aaaggghh!

EDIT2:
Found a post where someone mentioned that KillSoundWhenDone can sometimes stop the sound. That appears to be the case here. When I comment that out of my play sound function the problem goes away.
But how am I supposed to kill the sound when done? I don't wanna have to set up a timer for every sound!
04-24-2009, 03:04 AM#15
midiway
what I know about KillSoundWhenDone() is that you CAN'T call it before StartSound(), else the sound won't play. So the correct order would be:
Collapse JASS:
call StartSound( s )
call KillSoundWhenDone( s )

I've created a library that feets my needs of making spells, it's preaty basic since it only have two methods of playing a sound: play it globally, so anyone will hear it no matter where the player camera is positioned; play the sound attached to an unit.
Expand JASS:

How to use it? first declare a global witch is used to reference the sound:
Collapse JASS:
globals
    soundSX snd_launch
    soundSX snd_hit
    soundSX snd_thunder
endglobals

At some place in your map inicialization, initialize the sounds globals, you need to pass the sound .wav file path, and the duration in miliseconds:
Collapse JASS:
function Init takes nothing returns nothing
    set snd_launch = soundSX.NewSound( "Abilities\\Spells\\Orc\\LightningBolt\\LightningBolt.wav", 2136 )
    set snd_hit = soundSX.NewSound( "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldTarget.wav", 3878 )
    set snd_thunder = soundSX.NewSound( "Sound\\Interface\\GlueScreenEarthquake1.wav", 3237 )
endfunction

and finally you call the method PlayNormal() or PlayAttachUnit() to play it
Collapse JASS:
local unit u

call snd_launch.PlayNormal()
call snd_hit.PlayAttachUnit( u )