Sound/Animation tutorials

This forum is for the Lua scriptable clone of DM/CSB called Dungeon Strikes Back by Sophia. Use DSB to build your own highly customised games.

Moderator: Sophia

Forum rules
Please read the Forum rules and policies before posting.
Post Reply
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Sound/Animation tutorials

Post by Gambit37 »

Can we please have a tutorial on how to create ambient sounds and music?

1) How would I create and lay down items in the dungeon to make a rushing river sound that gets louder/quieter as you move nearer/further away?
2) How can I make sounds that play at the same volume throughout the level (cavern ambience, birds singing, etc)?
3) How to play music on a specific level and a way of stopping/re-starting it?

Do playing sounds get saved in the save game file? So they continue when you resume? That's a nice feature in RTC...

Could we also have some example code for doing animations:

1) From a series of individual bitmaps
2) From a single strip image containing multiple equal sized frames
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

Gambit37 wrote:How would I create and lay down items in the dungeon to make a rushing river sound that gets louder/quieter as you move nearer/further away?
Use an "ambient_sound" object. There is an example of this in the test dungeon. Just send it an activate message when you want the sound to start, and a deactivate to shut it up. (It's probably a good idea to deactivate the sound when you get really far out of range, as otherwise FMOD continues to tie up resources, albeit very slight ones)
Gambit37 wrote:How can I make sounds that play at the same volume throughout the level (cavern ambience, birds singing, etc)?
Right now the only way is the same way as "music" below. However, this is the kind of thing that wouldn't be difficult to add if needed, because, in the base code, it'd just be a call to dsb_sound, which plays a sound everywhere, as opposed to dsb_3dsound, which plays a sound centered at specific dungeon coordinates.
Gambit37 wrote:How to play music on a specific level and a way of stopping/re-starting it?
Instead of a sound exvar, specify a music exvar in your ambient_sound object. The other difference is that the music name must be not a snd table entry but an actual symbolic filename (i.e., "MUSIC") because music is streamed directly off the disk. Right now, dsb_music only supports the old pathless, extensionless notation for referencing files. If this bothers you greatly, I can probably come up with a hack to work around this.
Gambit37 wrote:Do playing sounds get saved in the save game file? So they continue when you resume?
Yes they do.
Gambit37 wrote:Could we also have some example code for doing animations
The basic syntax for using a strip of images is: dsb_animate(gfx.bitmap, number_of_frames, delay_between_frames)
DSB determines the width of each frame by dividing the total width of the image by number_of_frames, and then chops up the image appropriately. This makes a modification to gfx.bitmap directly; it is also returned by the function, but you don't actually need the return value in this case, because you already have it. Grabbing an animation from a strip has plenty of examples in base/graphics.lua so look there if you need more help. Grabbing an animation from a strip has plenty of examples in base/graphics.lua so please look there.

Grabbing an animation from a series of individual bitmaps is very similar, except that it uses a table to specify the source images, and you need to grab the return value, as dsb_animate generates a new bitmap in these cases.
gfx.animation = dsb_animate( { gfx.bmp1, gfx.bmp2, gfx.bmp3, ... }, 0, delay_between_frames)
The 0 is there because DSB automatically determines the number of frames, so you don't need to pass anything.
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Cool information, thank you very much.

I tried adding music to my title screen, but can't seem to. I added these lines in my startup.lua, into the sys_game_start function:

Code: Select all

snd.music_title = dsb_get_sound("title.ogg")
sndhandle_titlemusic = dsb_sound(snd.music_title,1)
But DSB outputs errors into the logfile:

Code: Select all

LUA ERROR: ...\_dsb49\test_dungeon_me/startup.lua:143: dsb_get_sound can only be used in initialization files
LUA ERROR: ...\_dsb49\test_dungeon_me/startup.lua:144: Sound is nil
In addition, you mentioned about path problems with dsb_music. Is that an actual function? It's not listed on the Wiki.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

Yes, dsb_music is an actual function, and what you should probably be using to play large files like mp3 or ogg, because DSB will attempt to stream it from disk rather than grabbing and decompressing it at load time. It works just like dsb_sound except it takes an actual file.

You had the right idea, but what you really want is to streamline the whole operation like this:

Code: Select all

gt_sndhandle_titlemusic = dsb_music("TITLE", true)
The gt prefix is because it's a global variable that is temporary. This is just a convention I use in the DSB base code. Feel free to ignore it if you choose. Oh, and another random side note: Lua, like many other languages that don't force you to declare all your variables, assumes variables are global unless you specify that they're local, i.e., just using a random variable makes it global. I'm not sure why only PHP does it the (in my opinion much more) sane way of assuming a variable is local unless you tell it otherwise, but that's how it is.

When using short names, no extension is needed or wanted. DSB will figure it out. (Yes, I realize that's strange, but it fits better with how resources are stored inside of graphics.dsb)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Hmmm, ok. I can't get this to work.

I've put a file called "titlemusic.ogg" in my root dungeon folder.
I call it in a file "title.lua" which is the first file listed in my manifest list -- using the line you posted above:

Code: Select all

gt_sndhandle_titlemusic = dsb_music("TITLEMUSIC", true)
No sounds plays, and no errors are generated.

I'm stumped!
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

Are you calling dsb_music in a function, or just floating in title.lua?
It needs to be in some sort of function, like sys_game_start.

If it's just floating, it will get called as the file is being parsed, which is far too early. The bug here is that no error is generated. :)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Ah, right, yes it's just floating about. I've changed sys_game_start to this, but it still doesn't work?

Code: Select all

function sys_game_start(savegames)
	gt_sndhandle_title_music = dsb_music("TITLEMUSIC",1)
	return (title_screen(savegames))
end
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

For some reason FMOD doesn't like your music file, then. I tested the exact code you wrote and it worked fine for me. :(
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Weird. It plays fine in RTC which also uses FMOD. I'll try with some different types and see what I get.

EDIT: Yep, MP3 is fine. Strange! Thanks for helping pin down the problem :)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Another question: how would I create a fade out function? I tried this code, but the music simply stops playing without being faded out. Am I on the right lines?

Code: Select all

current_sound_vol = dsb_get_soundvol(gt_sndhandle_title_music)
	for d=current_sound_vol,1 do
		dsb_delay_func(4, dsb_set_soundvol(gt_sndhandle_title_music,d-1))
  	end
dsb_stopsound(gt_sndhandle_title_music)
How would I trace variables to screen or a log for debugging purposes?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

You can write to log.txt with __log("blah blah blah")
Or you can write to the onscreen console with dsb_write(color, "TEXT HERE")

Code: Select all

dsb_write(debug_color, "DEBUGGING INFORMATION")
Remember to use all caps because that's how the DM font works.

Anyway, the reason your music stops playing immediately is because dsb_stopsound is executed immediately. Lowering the volume is delayed, but that doesn't matter. Here's some code that might help.

Code: Select all

function fade_out_music(time_delay, handle)
   local vol = dsb_get_soundvol(handle)
   vol = vol - 1
   if (vol <= 0) then
      dsb_stopsound(handle) 
   else
      dsb_set_soundvol(handle, vol)
      dsb_delay_func(time_delay, function() fade_out_music(time_delay, handle) end)
   end
end
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Ah, right. Thank you! :-) So my for loop doesn't actually delay anything -- the processing is concurrent and it jumps ahead to the dsb_stopsound even before the loop is done?
EDIT: Of course, duh, silly me. If the for loop held up the entire program, nothing else would work! See, this is why I'm not a programmer, I think too linearly...
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

By the way, the looping parameter TRUE does not seem to work. At least, it's not working on my title screen music -- it plays once and never repeats.
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

Lua has a separate boolean datatype. If you're sending "1", you're sending the integer 1, which is not the same as a boolean true, and will not be parsed as telling it to loop.
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Ah, right, thanks :-)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

I've been playing with your fade function, and queuing up one music file after another. Either I'm misunderstanding how this should work or there's a problem:

My second music file should start playing while the previous one is being faded out. This doesn't happen -- the second file seems to stop the previous file and take control of the output. It's even weirder -- if you look at the code below, you'll see I have 2 unique handles.

But the second handle seems not to be used -- the second file gets faded out by the fade function that precedes it (which is supposed to be fading out the music on the first handle.)

Is there something screwy going on here, or is my code crap?

(BTW, I modified your fade function with an extra parameter, it now takes a step and a delay as well as the handle -- step is used by the "vol = vol - (step)" line; your original value of 1 takes far too long to fade out.)

Code: Select all

function sys_game_start(savegames)
	-- Default return values:
	-- 0 = Start New Game
	-- 1 = Load Game
	-- 2 = Quit Game
	-- 3 = Introduction
	gt_sndhandle_title_music = dsb_music("music_titlescreen",TRUE)
	start_action = title_screen(savegames)
	if (start_action == 999) then
		fade_out_music(5,1,gt_sndhandle_title_music)
		gt_sndhandle_selector_music = dsb_music("music_champion_selector",TRUE)
		start_action = dsb_fullscreen(champion_selector_draw, champion_selector, nil,true,true)
	end
	return start_action
end
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

The default behavior was to only allow a single music stream to be open at a time, so you could just dsb_music and DSB would automatically handle changing whatever was playing. I guess if you want to do fancy things like fading between them, then the underlying code would have to be more fancy as well.

So, the answer is, nothing "screwy" is going on; the system is just designed differently than you expect. The good news is that the data structure for currently playing music can be extended easily enough, so I should be able to come up with a workaround for this for you. :)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Right, gotcha, thanks for clarifying. I thought I was doing summat wrong ;-)
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

I've added a dsb_music_to_background() command. Its sole purpose is to "free" the specialized music stream, telling DSB you want it to handle the currently playing music more like a normal sound. This means you are responsible for stopping it yourself, and so on, but it also means a new call to dsb_music won't interrupt the playing stream any more.

For example, at the end of this code, only SONG2 will be playing.

Code: Select all

dsb_music("SONG1")
dsb_music("SONG2")
At the end of this code, on the other hand, SONG2 will be playing over SONG1, which will remain playing.

Code: Select all

dsb_music("SONG1")
dsb_music_to_background()
dsb_music("SONG2")
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Cool, that sounds great, thanks :-)
BTW, in my code above, I have the looping option set to true, but the sounds don't loop...?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

No, you don't have looping set to true. You have it set to TRUE, which (unless you've defined it) evaluates to nil in Lua. :mrgreen:
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Gah! Picky little thing this Lua, ain't she? ;)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

I've noticed something odd: Music in DSB does not sound good at all.

Play the music in various external players and they sound great. They also sound equally great in RTC. But in DSB they sound sort of tinny and compressed, and only in Mono too. Is FMOD doing something weird to music in DSB?
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

Hmm. I never noticed a problem, but I think I see what was up. If I'm right, I've fixed it. :)

The sound only coming out in mono was an important clue. I think the problem may have been that dsb_music's output was being forced through the same 3D sound handler as the normal dungeon sounds, which is resulted in a lot of unnecessary 3D processing being done, as well as forcing all of the output to mono because 3D introduces its own panning that takes precedence.
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Cool. I like being able to help you debug things. Sometimes I'm not sure if you want me to though ;-) I think GG got sick of all my bug reports in RTC!
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

No, I don't mind the bug reports. It's better to know something's broken (even if I can't fix it right now) than to think everything's fine.
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

How do I get an ambient background sound to play on entering the game for the first time?

I'm using sys_enter_level(level) to check the level number and play different ambience using dsb_music() -- but this doesn't work until the first time the player changes to another level.

Is there a way of doing this using ESB mech, or would I need to write a one-time function to play the first ambience and attach it to a trigger on the party entrance tile? (actually, I don't think works either as I tried triggers on party start tile and they don't seem to update unless you step off then step on again).
User avatar
Sophia
Concise and Honest
Posts: 4240
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Sound/Animation tutorials

Post by Sophia »

No, using sys_enter_level is the right way to do it; that's how I would do it, too.
Unfortunately, right now, the order that the DSB startup sequence is executed means that it doesn't work properly.

I'll fix this. :)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Sound/Animation tutorials

Post by Gambit37 »

Cool, thanking you kindly :-) BTW, this method of doing background sound is so much nicer than the billions of triggers that would have been required in RTC. :-)
Post Reply