3D Sound System

Started by paulscode, March 11, 2008, 02:38:51 AM

Previous topic - Next topic

paulscode

#90
Yeh, I think you're right.  I'll leave OpenAL as it is.

BTW, I finally got an answer on the lwjgl formus for why the panning in OpenAL only works for really close sources.  Apparently, it is because the sources are omni-directional instead of directional.  I have been advised to use directional sources instead.  That seems rather unrealistic to me.  Many sources in real life are omnidirectional, but if a sound is to you right, regardless of how far away it is, you're going to hear it out of your right ear louder than your left one.

I guess I will try and make every source directional, pointed at the listener and see if that fixes the problem.  Just one more thing to complicate matters.

paulscode

Today I created a test applet to try and explain the panning problem to someone who had asked me a stupid question.  Turned out I was the one who ended up looking dumb, because, to my amazement, the applet works exactly the way it is supposed to (true 3D fading between left and right speaker, regardless of distance). :o

So the whole omnidirectional source thing is not what is causing the problem.  So far, I have not been able to track down exactly where the bug is, but I'll keep looking.

The thing that amazes me is that I've started from scratch on SoundManager three times, but apparantly I made the same mistake every time ???  Now I just have to figure out what that mistake is so I can correct it!

paulscode

I'm making great progress on the SoundSystem.  I have moved the CommandQueue stuff over to this class to ensure everything is done on a single thread, and I retested the system for thread conflicts, finding none.  I made a sound library template class called (you guessed it) SoundLibraryTemplate.  This class is to be extended with the specific libraries.

The way the system works is, the SoundSystem class takes care of thread issues, and it passes commands on to the active sound library.  Since all (both) sound libraries extend the template class, they have common interface methods, making the process simpler.

I am about 90% finished with the OpenAL extension of SoundLibraryTemplate (called SoundLibraryOpenAL, of course ;D).  I just need to add in some stuff for shutting down when switching between libraries, and copying sources over from one library to another.  There will be two switch methods, one that copies sources over (so the user won't have to recreate all sources every time he switches between OpenAL and Javasound), and one that just starts fresh.  The user can chose whatever works best for his application.

I have also created some test applets, and the 3D fading appears to be working the way it should.  I never did find the problem with previous versions of SoundManager, so I copied and pasted from the applet I mentioned in my last post.  Fortunately, that seems to have paid off.

I am hoping to finish SoundSystem this weekend, if I don't run into any serious problems.  In case you are wondering, I am going to spend some time studying this weekend for my test as well.

EgonOlsen

Good news. Maybe i should start to look out for some sounds to use in my project... ;D

paulscode

#94
Progress Update

I backtracked a little bit today to change the way sources are handled in the OpenAL part of the SoundSystem (back to the basics, really).  Puts me a little behind schedule, but it should improve the library in the long run.

Ever since I implemented source culling in the SoundManager class, the way I have handled sources is to delete the culled sources, and recreate the non-culled ones if necessary.  This method works, but after a discussion on Egon's thread about his Bomberman-inspired game, I am changing this concept.

The way it is going to work, is that when OpenAL is initialized, it will grab all available channels (or however many you specify) and create a permanant source for each.

Ok, terminology is biting me in the butt right now.  From now on, let me refer to those permanant sources as "channels".  As far as OpenAL is concerned, these are the only "sources" that exist.  So when I use the term "source" from now on, I am referring to the peripheral information about a source (sound filename, position, gain, etc) rather than an actual "OpenAL source".  Hopefully you can understand the distinction.  When I use the term "cull", I mean "stop a channel", and when I use the term "reactivate" I mean "transfer a source over to one of the channels and play it".

With the new method, when a source is to be culled, another source will be given that channel.  The speed benefit should be significant when dealing with large numbers of sources.  Also, this is going to simplify things when I finish SoundSystem and get back to the SoundManager and source management.  By grabbing up all the available channels in the beginning, I will no longer need to recheck if the soundcard has channels available every time a source is reactivated.

-- EDIT --
This new method of dealing with sources is now in place in the SoundSystem library.  I have tested it, and it works beautifully (at least for monotone sounds).  I have it iterating through the channels when a call to "play()" is made.  This makes SoundSystem even more useful, because you could use it as-is, even without a source-management system like SoundManager, and still get acceptable behavior in situations where you are not playing a huge number of sources simultaneously.  The only thing I need to figure out is how to handle stereo sounds (each stereo sound uses two "soundcard-channels", but it has only one "OpenAL-source").

-- UPDATE --
I ran some tests with stereo sounds.  Unfortunately, it seems that when OpenAL runs out of soundcard-channels, it decides to silently override others that are in-use, and not give any errors, warnings, or messages of any kind to alert you.  Same situation if you start a different application with sound in it after you reserve your soundcard-channels.  Either application can override the other application's playing sounds when soundcard-channels run out.  Only way I can see around this is to determine the number of available soundcard-channels and divide that number by two, using only that many.  The problem would still exist in a situation where the user had multiple applications open that were playing too many sounds.  As far as I can see, there's not much I can do in that situation.  Guess I just won't worry about it..

-- EDIT --
Stereo sounds now work the way they should, and tests do not seem to indicate any problems.  I'll now get back to finishing the SoundSystem library.

paulscode

Well the OpenAL panning problem has reared its ugly head once again.  Turns the reason it seemed to be fixed was that I had mis-diagnosed the problem.  My assumtion had been that it was a source-related problem, but it turns out that it is in fact a listener-related problem.  It has something to do with when the listener moves, its orientation gets thrown off.  The code I'm using for this is directly out of a book I bought, and it seems to be written correctly.  I've been googling and wracking my brains for hours, but I can not figure out what the problem is!  I've posted a question on the lwjgl forum, so hopefully someone over there can point me in the right direction.  I'll post the code here, as well, in case any of you guys can see anything obvious like a math or logic error:

Create the Listener:

    private synchronized void initListener()
    {
        // Listener is at the origin, facing along the z axis, no velocity:
        listenerPosition = BufferUtils.createFloatBuffer( 3 ).put(
            new float[] { 0.0f, 0.0f, 0.0f } );
        listenerOrientation = BufferUtils.createFloatBuffer( 6 ).put (
            new float[] { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f } );
        listenerVelocity = BufferUtils.createFloatBuffer( 3 ).put (
            new float[] { 0.0f, 0.0f, 0.0f } );
       
        // Flip the buffers, so they can be used:
        listenerPosition.flip();
        listenerOrientation.flip();
        listenerVelocity.flip();
       
        AL10.alListener( AL10.AL_POSITION, listenerPosition );
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
        AL10.alListener( AL10.AL_VELOCITY, listenerVelocity );
    }


Move the listener:

    private void moveListener( float x, float y, float z )
    {
        float xOffset = x - listenerPosition.get( 0 );
        float yOffset = y - listenerPosition.get( 1 );
        float zOffset = z - listenerPosition.get( 2 );
       
        listenerPosition.put( 0, x );
        listenerPosition.put( 1, y );
        listenerPosition.put( 2, z );
       
        AL10.alListener( AL10.AL_POSITION, listenerPosition );
       
        // Keep the listener facing the same direction by
        // moving the "look at" point by the offset values:
        listenerOrientation.put( 0, listenerOrientation.get( 0 ) + xOffset );
        listenerOrientation.put( 1, listenerOrientation.get( 1 ) + yOffset );
        listenerOrientation.put( 2, listenerOrientation.get( 2 ) + zOffset );
       
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
    }


And turn the listener:

    public void setListenerAngle( float angle )
    {
        float xOffset = -1.0f * (float) Math.sin( angle );
        float zOffset = -1.0f * (float) Math.cos( angle );
        listenerOrientation.put( 0, listenerPosition.get( 0 ) + xOffset);
        listenerOrientation.put( 2, listenerPosition.get( 2 ) + zOffset);
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
    }


paulscode

Problem solved (hopefully for good this time).  You must use coordinates that represent normalized vectors for both look-at point and up-direction (contradictory to what my book says.  Geez, you think they would have tested their code before publishing).  I mean the book even has a big diagram and a paragraph about how when you move the listener, his orientation changes, so you have to also change the look-at point to match the offset, blah, blah, blah.  WHAT A BUNCH OF BOLOGNA!

I can't believe it took me so long to figure this out (I mean, I already knew the up-direction was normalized).  Wasted all evening yesterday and half the morning today on this.

Ok, NOW I'll get back to finishing the SoundSystem library!   :D

paulscode

I did a little more work on SoundSystem today, but I had to take a break from the computer for most of the day to study for my test.  Because of the couple of hang-ups mentioned previously, I haven't finished SoundSystem this weekend like I'd hoped.  What I do have seems to be running well, and I have finished working out all the kinks with switching between sound libraries on the fly.  Sources and listener information are preserved.  I can see this being easily used in some kind of menu system where a player could change sound libraries at will, at any time during the game.

All I really have left is to figure out streaming sources in Javasound, and a couple of minor logic errors I need to track down related to the 3D panning stuff I wrote for Javasound.  When I get those things working, I will release SoundSystem.

This library has become a bit larger than I expected - I am currently at 12 different classes (not counting all the ogg-related stuff).  That is quite a lot when you are talking about something complicated like 3D sound.  Thankfully I have commented things pretty well, because it is getting harder to keep track of everything.  This is really turning out to be a fun project!

fireside

How big is it?  Size gets to be a premium on an online game. 
click here->Fireside 7 Games<-

paulscode

Quote from: fireside on May 28, 2008, 06:03:35 PM
How big is it?  Size gets to be a premium on an online game. 

The JAR for SoundSystem is currently around 200 KB

EgonOlsen

Quote from: paulscode on May 29, 2008, 12:32:26 AM
The JAR for SoundSystem is currently around 200 KB
Only the compiled classes? Is that thing zipped? 200K doesn't matter to me, but i'm surprised that it turned out quite huge. I expected it to be much smaller. jPCT itself isn't much bigger than that.

paulscode

Quote from: EgonOlsen on May 29, 2008, 11:51:30 PM
Only the compiled classes? Is that thing zipped? 200K doesn't matter to me, but i'm surprised that it turned out quite huge. I expected it to be much smaller. jPCT itself isn't much bigger than that.

That is the compiled JAR containing only the classes, not zipped.  It will be a bit larger than that if I ever get around to finishing it.  Hopefully I'll get some time to work on it Saturday.  My schedule has been crazy this week.

paulscode

Well, I finished my promotion test, and I am leaving for vacation tomorrow morning.  I won't be able to get back to this project for a couple of weeks, so sorry to anyone who is waiting for the next release.  I was hoping to finish it before I left, but that didn't work out.  Oh, well..  Talk to you all when I get back!

JavaMan


fireside

click here->Fireside 7 Games<-