General soundtrack stuff

What do you want to see in Armagetron soon? Any new feature ideas? Let's ponder these ground breaking ideas...
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6714
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

I think I had these same problems when I first wrote the kill code for the admin command. How to get from an ePlayerNetID to the gCycle... If you can do that, doesn't the camera attach to the cycle?
Image
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Hmmm, not sure if it's the same problem. :)

When you go Local Game, the first thing you see if your cycle, and everybody else spawns. I think the same thing happens when you host a game. How do I get a pointer to the eGameObject that is this player? And how do I focus on one specific player in a multi-viewport configuration?

I have it switching players later on with no problem. The camera knows what eGameObject it's associated with, or something like that. Anyway, the sound mixer knows when you switch, so after you die, while you're watching someone else, you'll hear their sounds. But this same mechanism doesn't identify the first player in a new game, as in local game. It might also break down on a multi-viewport configuration, I don't know, I haven't tested that. Hmmm.....

Anyway, I'm kinda stuck. I could probably go ahead and start adding the directional stuff to the mixer and just test it on internet servers rather than local game, I suppose. So I'm not totally stuck, but you know, I also have real work I should be doing instead. ;) Heh.

Edit: Got it! Turns out the camera gets a viewport when it's created, so all I needed to do was check if it got a viewport (rather than NULL), and then see if the viewport it got was also viewport 0. The camera knows what eGameObject it's watching. ;)
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Haha. So, based on z-man's response to a thread about making a math model, I figured he had some file somewhere that conveniently included all the math we'd ever need to do with eCoords. But I couldn't find such a beast! Anyone know if there is one, and if so, what is it? Or should I just do it the hard way?

(If we don't have one, I'll be happy to write one)

This is probably something worthy of being documented on the wiki.... <hint>
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Code check. :) This isn't getting the result I'm looking for.

In this code, bearingInt should be an int from 0 to 360, where 0 points forward in relation to sound, and you go clockwise. So 90 degrees is to the right. The angles coming out of atan2 are supposed to be in radians. This code doesn't appear to be sounding the explosion in the right direction some of the time. Sometimes it's dead right, and sometimes it's not sounded at all.

Code: Select all

    // theta is the heading of the sound position
    // beta is the home's heading
    // The bearing to the sound should be theta-beta
    // We get it in radians and need to convert to degrees because SDL_mixer is lame
    double theta = atan2( soundPos.y-home.y, soundPos.x-home.x );
    double beta = atan2( homeDirection.y, homeDirection.x );
    double bearing = theta - beta;

    int bearingInt = (int) floor(bearing * 180.0/M_PI);

    Mix_SetPosition(m_ChannelID, bearingInt, 0);
Edit: Figured out the first problem, I needed the angle from home, which is the eCoord that is the eGameObject's position that is used as the home for all sounds. I got the soundPosition's angle from the origin. At first. :) Then I wasn't using the direction the eGameObject is pointing, I was using the angle of his position from the origin. Dumb, eh?

After fixing that, I get no sound for the home object's explosion, and close explosions I don't hear. I suspect SDL_mixer actually behaves backwards from what it's documented. I'll investigate that. ;)
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Ah well, I've committed my latest. Including the new samples I'm working with. I'd like someone to take a look at it and see what's happening. Explosions are being played a bunch of times, some other things. Stuff I'm too sleepy to troubleshoot right this minute. :(

But it's all there. Still needs to use the distance calculation to figure out the distance from the sound, and still needs more sounds added. Hm, there's still a cycle motor sound effect missing. So that's still needed, otherwise the rest of the stuff is there, just needs to be made to work well.

Edit: Weird behavior. In local game, the explosions seem to be working fine. When I play on an internet server, I don't get explosions when they're supposed to sound, and I get explosions at seemingly random intervals sounding. Maybe the code I picked to sound the explosion happens to run at different times on the client in a network game than in local game?

Edit2: Anyway, I can't tell if the directional code is working right. It seems to be, in local game where the explosions sound when they're supposed to. Can't tell at all in a network game. I could really use someone looking at it, someone who actually knows how sound and explosions are currently handled. ;)
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

The code looks fine, except that bearingInt can be anything from -360 to +360 and not 0 to 360 as SDL_Mixer expects. Both beta and theta go from 0 to 2 pi. Maybe SDL_Mixer does not take it modulo 360?

IMHO, all the math you'll ever need for eCoords is in eCoord.h :) You have the vector operations (+,-,*), getting lengths (.Norm()), symmetric (eCoord::F) and antisymmetric (eCoord::operator *) bilinear product, reflection on the x-axis (.Conj()), and complex multiplication (.Turn()). The names are shit, but everything is there. Of course, should you really NEED an angle (like SDL_Mixer requires), you need atan2. But you only need it once:

Code: Select all

eCoord dirRelative = (soundPos-home).Turn( homeDirection.Conj() );
double bearing = atan2( dirRelative.y, dirRelative.x);
The right place to trigger an explosion sound is in the gExplosion constructor. The previous code had explosions sounds generated via the sound mixing code of that class, just like the engine sound for the cycles.

While you're at it, generate new sounds for the turning :) It can be generated from the explosion by speeding up the explosion by a factor of five.

The behavior for splitscreen players up to now is that not a single microphone is used, but every player has his own, and all sounds are just mixed together.

I'll have a look at the results, but it may take a while. My laptop loses sound everytime I suspend it, and recently it has trouble cold starting, so I'm reluctant to turn it off.

I hope I did not forget an important comment, just bump open questions.
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

I can certainly get that behavior with the new engine, just make a list of microphones and whenever a directional sound is called for, play it for each microphone. Of course, that means I'll need a microphone class (like you said :) ).

Done for the turn sound. Just fired up audacity and did it. I'll commit it when I get to doing it. I take it the turn sound should be sounded from within gCycle, where the turn is actually processed? (So I have it on disc right now already generated, that sentence wasn't clear)

So, one thing that always disoriented me before was that the cycle sound for *my* cycle would shift from left to right when I turned, finally centering after the turn. I'm planning on changing that... ;) (If people still want that, I can certainly make it configurable)

on eCoord and math: Yeah, I guess I just didn't understand what I read. By the time I got that far, my mind was on its way to bed already. Heh. My body still hasn't followed.

SDL_mixer claims to take any number and clamp it to the range [0,360). I don't understand why they don't use radians, to tell the truth. Seems like you could divide out pi and get a number you can directly and easily apply to the balance. Maybe I'm just on crack (or too focused on 2 speakers).

Two (possibly three) questions. :) Did you build it and run it? I'm wondering if you were able to notice whether or not the 3d effect on explosions actually worked as planned or if you were able to notice why they didn't, having already written code to do exactly this thing. (the second sentenced phrased as a sentence to avoid counting against my self-imposed question limit)

Do you happen to have a formula I could use to determine a volume modifier for sounds (distance)? I'm wanting something in the range [0,1] that I can use as a multiplier. I can fake one, and probably will if I don't have one when I get to implementing distance. You had mentioned you wanted to change this part from the old code, so I'm thinking I shouldn't be digging the old code to get it....

Do you happen to have a doppler shift formula? I'm not quite there yet, but it would be worthwhile if you happen to know one (Mr. Math Ph(u)D guy) that I could throw in a code comment so it'll be there when it's time to add the doppler effect.

Um, ok, one more question. Do people really want noises for the UI? Like when you switch from one menu item to the next, or enter a new menu, or something like that? And does anyone happen to have a sample of the spawning noise for the ebonstar in the old amiga game called Ebonstar? I'd like to use that noise for the winzone. ;)
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Heh. Found more stuff.

So, I've got a cycle turn added, and moved the explosion trigger to the gExplosion constructor. The directional thing works as it should now, with two caveats:

The turns seem to alternate between speakers when they're from your own cycle. Shouldn't they be centered? That's what I was trying to get, anyway. Explosions do it too when it's your own cycle. Maybe I hit a division by 0 calculation somewhere that atan2 is smoothing out for me? Seems likely, now that I think about it.

The other thing is that the more something is shifted to your side, the less loud it is, because balance is done by reducing the volume in the opposite side. So both speakers are at max volume in the middle, but one speaker is at max volume when the sound is coming from 90 or 270 degrees. I'm thinking I can interpret the volume given as a target volume and multiple it by 1/cos(angletosound) to smooth that out. Is that about right (maybe a vertical shift is called for too, so when cos=0 you don't get "no volume")?
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

I did build it. It does not run all that well without a playlist. Loading it goes into an infinite loop (I fixed that) and the first call to GetNextSong() form eSoundMixer.cpp lets everything crash. How about some error handling ? :) I preliminarily added one non-working song in case the playlist is empty. Also, the function that finds a free channel could use some, I added a dummy return value in case no channel is found. But it's likely to be a disaster if that is ever executed.
Unfortunately, there is a huge delay between the issuing of a sound and the moment I hear it. That's always been the case on this machine, I'll try it in Windows, and make the build work there, while I'm at it. SDL_Mixer is already included, so it should be a matter of adding the new files.

I'll look at the own sounds from strange directions once I have everything running.

SDL_Mixer gives another function to set the direction a sound is coming from. It just takes the left and right volumes, and AFAIK the angle-taking function does not do anything else than that. So if the function you are now using is crap, we can just fallback to the other. As a bonus, math gets easier if you set the two volumes directly.

The realistic distance to amplitude formula is simple: Amplitude is 1/distance. But that produces a) too fast a falloff at big distances, sounds get unhearable quickly b) wakes up the neighbors if distance is 0, like on the engine sound. Some tweaking is required.

A simple doppler shift formula:

Code: Select all

eCoord source; // source position relative to microphone
eCoord sourceSpeed; // source velocity relative to microphone
REAL realFrequency; // the real frequency of the source sound
REAL speedOfSound = 300; // speed of sound
REAL frequencyShift = -eCoord::F(source, sourceSpeed)/speedOfSound; // the doppler shift, measured relative to the real frequency
REAL frequency = realFrequency * ( 1 + ( frequencyShift > -1 ? frequencyShift : -1 ) ); // frequency the sound is heard with
That's not really accurate. For real sound, the source and listener speeds go in in different ways. But it's good enough, I guess. If not, it can be tweaked later.
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Umm, Ok, things sound really weird in Windows. Perhaps our SDL_Mixer there does not support ogg? And the turn sound's intensity varies far more than I would have expected from your description. I'm too tired to look at this in detail now, sorry.

I'd be cool if you could make the server compile again :) A couple of #ifndefs should do it, but you'll know best where you have to put them.
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

It should support ogg, but the only ogg sound effects right now are the announcer. If those aren't working, I can render them to wav, no biggie.

Um, server still doesn't build. ;)

Code: Select all

if g++ -DHAVE_CONFIG_H -I. -I../../../armagetronad/src -I..   -I/usr/include/libxml2   -I../../../armagetronad/src/tools  -I../../../armagetronad/src/render -I../../../armagetronad/src/ui -I../../../armagetronad/src/thirdparty/shttpd -I. -I..  -Os -Wno-long-long -I/usr/include/libxml2 -MT libui_a-uInput.o -MD -MP -MF ".deps/libui_a-uInput.Tpo" -c -o libui_a-uInput.o `test -f 'ui/uInput.cpp' || echo '../../../armagetronad/src/'`ui/uInput.cpp; \
then mv -f ".deps/libui_a-uInput.Tpo" ".deps/libui_a-uInput.Po"; else rm -f ".deps/libui_a-uInput.Tpo"; exit 1; fi
../../../armagetronad/src/ui/uInput.cpp:44: error: size of array 'sdlk_dynnames' is negative
make[3]: *** [libui_a-uInput.o] Error 1
I don't know what that does, but this was after I fixed a missing #ifndef NOJOYSTICK. I was stumped on this.

So, I got most of the soundmixer stuff fixed for the server, but there may be one or two more after this file that I didn't manage to get. It's a simple matter of when you see a particular construct or type of call, you can wrap it like so:

Here's the construct to watch for:

Code: Select all

eSoundMixer* mixer = eSoundMixer::GetMixer();
mixer->PushButton(WHATEVER);
Just wrap it in an ifdef, easy copy and paste version provided here:

Code: Select all

#ifdef HAVE_LIBSDL_MIXER
I don't think there are any files left after make goes into the ui directory that use it, so you should be fine. gGame, gCycle, and gExplosion are all done before ui is done. ;) (I think those are the only ones I messed with, and gArmagetron, to initialize and delete the mixer, of course).
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

cvs tags. Maybe I screwed up when I added binary files to cvs? ;)

I used:

cvs add -kb thisfile.wav thatfile.wav

Um, did I do it wrong? :( Test it with the title track I'm committing. There will be a music directory now, and a file in it called titletrack.ogg that is a placeholder I made. (Thought I'd throw together some placeholders for the different tracks so you guys can actually test it all reasonably)

Edit: I google it and it looked right, but you might still try the samples in a media player and see if it is right.
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

I worked around the array problem. Looks like you're not the only one who does not check server compilation :) Not all problems are fixed with simple #ifdef HAVE_LIBSDL_MIXER wrappers, eSoundMixer is not defined explicitly for the dedicated server. For testing, I removed the check for SDL_Mixer from configure for the dedicated server (the new one you added). Then, the dedicated server now compiles again, but it fails to link, because now it is missing the old sound stuff that is no longer compiled.
Perhaps you should rethink the preprocessor logic? You're getting us straight into cpp hell. Testing HAVE_LIBSDL_MIXER all over the place is bad: we require it now, so it should never be missing (only on the server, of course). And users of the sound classes should not have to care whether it uses SDL_Mixer or anything else.
In the old sound stuff, I took this approach: I left the interface active all the time, and only disabled the implementation. Whenever I was too lazy to remove a reference to an SDL object from a header, I just defined a replacement dummy object for it on the server. Most of them reside in rSDL.h, our include wrapper.

In different news, I get a division by zero (the number of channels) on my work PC. I'll dig a bit deeper before I blame you for it ;).
Edit: looks like the experimental configure change was responsible. I reverted it and now things work.

The good news is that the files are in CVS in the correct format: all binary. Playing them back with the MS media player produced the expected results.
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Memory leak! Do you want to hunt it yourself? Just compile with DEBUGLEVEL=3 and run the app twice, the second time in the debugger. You'll get a breakpoint where the leaking memory is allocated.
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Hmm, the #ifdefs are temporary, this is intended to supersede the old sound implementation when it can do everything the old one does. Or reasonably close, anyway. Not necessarily bug free, you know the drill. So, they're supposed to be there just so if the new sound engine is broke, people working on other things don't have to deal with it, they can just build with the old one. :) So I'm intending, after it's up and running on all platforms, to go through and just slash out the old stuff. (some of it'll get refactored into the new stuff, and I'm reading through it a lot in building the new stuff, so it's not like it'll be thrown away or anything) Naturally that'll mean we either depend on SDL_mixer always, or we need to write a new backend that's free of sdl_mixer. You guys were already headed towards depending on sdl_mixer always anyway (and with no option to build without sound, which we can certainly add), so no problem, right?

After that's done, then we'll be back at regular DEDICATED preprocessor logic, and I'll be happy to ifdef out the implementations instead. But I must admit I'd like to have a better solution for building the dedicated server than sprinkling ifdefs all over the place. ;) We'll get it sooner or later, I guess.
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
Post Reply