Sound engine dilemma
by Vern Jensen · in Torque Game Builder · 12/31/2006 (6:21 pm) · 4 replies
First, let me describe the problem: if alxPlay() is called for the *same* sound multiple times, and all calls are within a very close time span of one another, then what ends up happening is that you essentially hear one copy of the sound played, but it's amplified greatly.
Consider for example a game like Bejeweled, where gems fall from the top of the screen. Let's say that you make a call to alxPlay() each time a gem lands. So if 3 rows fall at once, then you have at least 3 calls to alxPlay at pretty much the exact same time, resulting in a much-louder-than-normal "gem landed" sound.
You'd think the solution would be to use alxIsPlaying(%handle) to determine if a given sound is already playing, and not call alxPlay() the 2nd and 3rd time if it is. But this results in *no* "gem landed" sound for gems that hit the ground a second or two later than the first gem, due to being a different heights. The original "gem hit ground" sound is still playing, but is nearly completed, but alxIsPlaying() only knows that the sound is *playing* -- it doesn't know how far along it is -- whether it has just started, or has been going for some time.
I can't use alxGetStreamPosition, because this is for streams, not ordinary sounds. Otherwise, it would be perfect to solve my dilemma.
So I'm left with having to solve it using some sort of a wrapper class. I'm thinking of this: record, in milliseconds, the "global time in milliseconds" that a given sound is started. When when my wrapper class is given a request to play that same exact sound again, it either cancels the request if the same sound is already playing AND it has recently just begun playing, OR it plays the sound, if the existing version of that sound hadn't started too recently.
Should solve my problem. So here's the question: is there some sort of a "running global millisecond count" in torque? Most computers have a global millisecond count since system startup. Is there a way to access this in Torque? Or do I need to resort to using Torque's schedule() command?
Or, if anyone else has any better ideas for solving my sound problem, I'm all ears.
Consider for example a game like Bejeweled, where gems fall from the top of the screen. Let's say that you make a call to alxPlay() each time a gem lands. So if 3 rows fall at once, then you have at least 3 calls to alxPlay at pretty much the exact same time, resulting in a much-louder-than-normal "gem landed" sound.
You'd think the solution would be to use alxIsPlaying(%handle) to determine if a given sound is already playing, and not call alxPlay() the 2nd and 3rd time if it is. But this results in *no* "gem landed" sound for gems that hit the ground a second or two later than the first gem, due to being a different heights. The original "gem hit ground" sound is still playing, but is nearly completed, but alxIsPlaying() only knows that the sound is *playing* -- it doesn't know how far along it is -- whether it has just started, or has been going for some time.
I can't use alxGetStreamPosition, because this is for streams, not ordinary sounds. Otherwise, it would be perfect to solve my dilemma.
So I'm left with having to solve it using some sort of a wrapper class. I'm thinking of this: record, in milliseconds, the "global time in milliseconds" that a given sound is started. When when my wrapper class is given a request to play that same exact sound again, it either cancels the request if the same sound is already playing AND it has recently just begun playing, OR it plays the sound, if the existing version of that sound hadn't started too recently.
Should solve my problem. So here's the question: is there some sort of a "running global millisecond count" in torque? Most computers have a global millisecond count since system startup. Is there a way to access this in Torque? Or do I need to resort to using Torque's schedule() command?
Or, if anyone else has any better ideas for solving my sound problem, I'm all ears.
#2
01/01/2007 (7:47 am)
I created a playSound() function that stores the time of each sound that was played, and if it's been longer than some duration (like 30 milliseconds) the sound will play, otherwise it won't. This avoids the "loudness" problem but still feels right most of the time. You can also set the default volume for a sound in its datablock and this function will honor that. It behaves like alxPlaySound(), returning the handle being played (or nothing).function playSound( %datablock )
{
%now = GetSimTime();
%diff = %now - $sounds[%datablock];
if ( %diff > 30 ) // don't play sounds closer than 0.03 seconds apart
{
$sounds[%datablock] = %now;
%handle = alxPlay( %datablock );
if ( %datablock.volume !$= "" )
alxSourcef( %handle, "AL_GAIN", %datablock.volume );
}
return %handle;
}
#3
Jason -- I'm trying to understand your code -- how you can use %datablock as an index for an array. I guess %datablock is just an integer value? (Like all objects in Torque? I'm still getting used to this concept.)
And this must be the C programmer in me who wants to initialize everything before using it, but your function accesses
$sounds[%datablock]
to compute %diff, and it does this before that value is ever even initialized. What happens in this case?
Thanks again.
01/01/2007 (1:43 pm)
Thanks, to both of you.Jason -- I'm trying to understand your code -- how you can use %datablock as an index for an array. I guess %datablock is just an integer value? (Like all objects in Torque? I'm still getting used to this concept.)
And this must be the C programmer in me who wants to initialize everything before using it, but your function accesses
$sounds[%datablock]
to compute %diff, and it does this before that value is ever even initialized. What happens in this case?
Thanks again.
#4
It takes some getting used to, and I was probably more sloppy here than I should have been. But it still works. :)
01/01/2007 (7:40 pm)
Quote:...how you can use %datablock as an index for an array. I guess %datablock is just an integer value?That's correct.
Quote:...it does this before that value is ever even initialized. What happens in this case?If that array index doesn't exist, it will return 0 (since this is a math expression, otherwise it would return an empty string). So, the time difference will be well above the 30 milliseconds and guarantee that the sound will play (at which point the array index for that datablock will be created and stamped with the current time for any subsequent call).
It takes some getting used to, and I was probably more sloppy here than I should have been. But it still works. :)
Torque Owner Maurice Ribble