Page 1 of 1

Controlling Looping Sounds System

Posted: Thu Dec 13, 2012 9:09 pm
by Batty
Looping sounds ("sounds" in this post) have the following problems:
  • 1. Can't be stopped
    2. Disappear when player loads savegame
    3. Disappear when party changes level
    4. Audible on every level in square they're played
I use door objects to produce sounds instead of playSoundAt() and it works well. The definition looks like this:

Code: Select all

cloneObject{
	name = "sound_wind",
	baseObject = "dungeon_wall_grating",
	--class = "Door",
	model = "mod_assets/models/vertex.fbx",
	openSound = "silence",
	closeSound = "silence",
	lockSound = "wind",
	openVelocity = 100,
	--closeVelocity = 0,
	--closeAcceleration = -10,
	--sparse = true,
	--placement = "wall",
	editorIcon = 88,
}
The door is invisible & is spawned then immediately opened thus producing the lockSound which is your defined sound. This fixes problem #4 as door produced sound does not occur on every level as playSoundAt() does. The sound can be stopped at anytime by simply destroying the door which fixes problem #1. The door never blocks anything as it's opened the moment it's spawned at a velocity of 100.

Note the following:
  • openSound & closeSound are silent, you need your own silent .wav because you can't have the standard door sounds playing.
  • You must make the door model disappear. There are several ways to do this, I use a null model (very small), I leave that up to you.
  • openVelocity must be set high. I use 100, a nice round number, it opens the door instantaneously.
  • You define one "sound door" for every defined sound. Easy to do, 2 steps only: change the name and set the lockSound as your defined sound.
Problem #2 was solved in this thread. That leaves #3 and overall sound management so I have this function:

Code: Select all

function detectParty(obj)
	if obj.level == party.level then
		current = party.level
		if notAtStart then
			if not findEntity("loopy") then
				spawn("fx", 2, 25, 9, 0, "loopy"):setLight(0, 0, 0, 0, 0, 1800000, false)
				restoreSound(current)		
			end		
		end	
		notAtStart = true
		if previous and current ~= previous then
			restoreSound(current)	
		end
		previous = current	
	end
end
I have a timer on every level set to same interval (0.5 seconds 8-)) calling this function. This function detects when the player loads a savegame and when a level change occurs and then calls restoreSound() to restart the sounds only on the current party level.

Note the following:
  • The if not findEntity("loopy") section is the check for a loaded savegame, again, covered in this thread.
  • Current & previous handle when the party changes level. This works well. In testing, I noticed that the level change registers before you arrive (e.g. midpoint down a pit) so there is no interruption in sound as they are restored before you arrive.
  • The check for if notAtStart and if previous are required to handle the special case of the player first starting the game. I don't want restoreSound() called at game start, notAtStart & previous will only be nil once, at start, the first time the function is called. They will have values from then on and their respective tests will pass for all following function calls thus calling restoreSound().
Remaining functions:

Code: Select all

function restoreSound(current)		
	local l, x, y
	for sound, state in pairs(sounds[current]) do
		if state == "on" then
			l = findEntity(sound).level
			x = findEntity(sound).x
			y = findEntity(sound).y		
			for entity in entitiesAt(l, x, y) do		
				if entity.name == findEntity(sound).name then		
					entity:setDoorState("closed")
					entity:open()			
				end			
			end	
		end		
	end
end

sounds = { [1] = { },
		     [2] = { },
		     [3] = { } }
		
function soundStateOn(id, l)
	sounds[l][id] = "on"
end

function soundStateOff(id, l)
	sounds[l][id] = "off"
end

function startSound(sound, l, x, y, f, id)
	spawn(sound, l, x, y, f, id):open()
	soundStateOn(id, l)	
end

function stopSound(id)
	soundStateOff(id, findEntity(id).level)
	findEntity(id):destroy()
end
The restoreSound() function iterates through the sounds on the current party level & if it finds them, restarts them. Note how sounds are restarted by setting the door state to closed, then opening it again thus restarting the lockSound (your defined sound).

The sounds table stores references to all the sound doors. The example is a 3 level dungeon, you would add tables within the sounds table, one each for each level of your dungeon. Level 7 would be [7] = { },

startSound(sound, l, x, y, f, id) is called with the exact same parameters as spawn() (that's what it does, after all). Sound is the name of the sound door, not the defined sound.
stopSound(id) simply pass it the unique ID of the sound door.

Important: Door object produced sound emanates from the edge of the square (between squares). This doesn't change no matter where you place the door. You may want this, in which case, you're fine. However, if you want the sound to emanate "centrally" from the entire square you must do this:

Code: Select all

startSound("sound_wind", 1, 27, 4, 0, "sw_1_27_4_0")
startSound("sound_wind", 1, 27, 4, 2, "sw_1_27_4_2")
Two sound doors are spawned at opposite facings in the same square. You need to lower the volume ~50% of your defined sound since it is played twice. This works surprisingly well when compared to a single sound with playSoundAt(), no significant distortion.

Disclaimer: We may get a nice sound object from AH making this all for naught. There may be other ways, better ways, there usually is. Nevertheless, this system is working well for me (could be bugged, of course). You can implement these sound doors any way you want, my system is here for example. :D

Re: Controlling Looping Sounds System

Posted: Thu Dec 13, 2012 9:49 pm
by Komag
nice work! This is quite the workaround! I hope (in a good way) that ultimately it's a wasted effort due to AH fixing the bug properly, but at least it's possible to deal with in the mean time :)

Re: Controlling Looping Sounds System

Posted: Thu Dec 13, 2012 9:55 pm
by Phitt
Nice idea! Didn't think of that. Also hope AH will fix it eventually, but definitely better than the playSoundAt approach. Thanks!

EDIT: ...
EDIT2: Nevermind, pits/trapdoors don't have a sound you can define, thought I remembered something like that.
EDIT3: Maybe a spell without particle effect/light/screen effect and with 0 damage?
EDIT4: Nope, spells also play their sound on all levels.

Re: Controlling Looping Sounds System

Posted: Thu Dec 13, 2012 10:23 pm
by Batty
Thanks guys. Before I used doors to produce sound, I tried a few other objects (forget which, blockage was one) & attached looping sounds to them. Destroying them destroyed the object but the sound kept going. Doors were the first object that allowed me to stop sounds. So, there may be others, I haven't tried them all.

The thing with the doors is that they normally have sounds that are played for different durations depending on open/close velocity and are, I guess, hardcoded to be stopped so the next sound (lock, close) can be played. I *think* this may be unique to the doors, but again, I only tried a few objects.

Re: Controlling Looping Sounds System

Posted: Thu Dec 13, 2012 11:01 pm
by Komag
I think the door movement sounds are simply the right length, not that they stop per se

Re: Controlling Looping Sounds System

Posted: Tue Apr 16, 2013 1:31 am
by zimberzimber
question:
Where do I put the:

Code: Select all

cloneObject{
   name = "sound_wind",
   baseObject = "dungeon_wall_grating",
   --class = "Door",
   model = "mod_assets/models/vertex.fbx",
   openSound = "silence",
   closeSound = "silence",
   lockSound = "wind",
   openVelocity = 100,
   --closeVelocity = 0,
   --closeAcceleration = -10,
   --sparse = true,
   --placement = "wall",
   editorIcon = 88,
}
I tried looking at the post but I found nothing about where to place this, ad how.
maybe its just me being stupidly blind, but hey...

Re: Controlling Looping Sounds System

Posted: Tue Apr 16, 2013 2:27 am
by Komag
In the original game the base thing is in objects.lua so that is a good place for your mod version. But honestly it can go anywhere.

Re: Controlling Looping Sounds System

Posted: Thu Apr 18, 2013 4:51 pm
by AdrTru
Super idea. THX
I using it in new version of MultiAlcoveManager for Torch burning sound.
(This new version will be published soon :) )

Re: Controlling Looping Sounds System

Posted: Tue Feb 04, 2014 12:34 pm
by Eightball
Thank you! I had thought the sound bug was my fault and spend a few hours looking for the non-existent error. But making invisible doors? This is going to take me a while. Time to invest, uh, time in a session of graphic editing forums to make that tiny door "model". Wish AH had made the fix, but as of yet still hasn't, I guess. Must be all that work on Grim2.