3D Sound System

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

Previous topic - Next topic

paulscode

Sound System, Minor Updates

Sound System jPCT
Sound System

JavaSound library pluggin
LWJGL OpenAL library pluggin

WAV codec pluggin
JOgg codec pluggin
JOrbis codec pluggin

- Fixed problem with second constructor for SoundSystem class where derived classes would not automatically load their default libraries and codecs.
- Removed all refrences to "println" and "printStackTrace" from the codec classes.  Using the logger to handle all messages instead.
- Corrected four potential "null pointer exception" lines in the LibraryJavaSound and LibraryLWJGLOpenAL classes.


fireside

I take it SoundSystemJpct comes with the tutorial?  I'm still not ready to work on sound in my game, but I'm glad you got everything worked out so it's ready.
click here->Fireside 7 Games<-

paulscode

I'm working on a tutorial for SoundSystemJPCT.  Currently, there is only a tutorial for the core SoundSystem library.

paulscode

Miscellaneous updates and bug fixes
Descriptions for each item can be found on page one of this thread.

Sound System jPCT
Sound System

JavaSound library pluggin
LWJGL OpenAL library pluggin
JOAL library pluggin

WAV codec pluggin
JOgg codec pluggin
JOrbis codec pluggin

JavaDoc
3D Sound with SoundSystem  (example programs)
Guide to SoundSystemJPCT  (example programs)


What's new?

- Finished writing the long-awaited tutorial guide for SoundSystemJPCT.
- Corrected a thread synchronization problem that caused occasional NulPointerExceptions when temporary (quickPlay) sources were bound to Object3Ds.
- Fixed a bug in the JavaSound library plug-in where ambient sources were 3D panning between left and right speaker rather than being ambient.
- Fixed a problem in bindListener where the listener did not initially match the camera until tick() was called for the first time.
- Eliminated a long pause that was being added to the end of streaming sources when using the Wav and J-Ogg codec plug-ins.
- Added a new library plug-ins for JOAL.
- Fixed a class-name mistype in error messages logged by library pluggins.
- Fixed a potential logic error in the LibraryLWJGLOpenAL class channel-initialization code.


JavaMan

Its great how you continue to update this. I don't need it yet, but I will definitely check it out in the future.

paulscode

At the request of a couple of users, I added the ability to manipulate pitch.  This is a useful feature, because making slight random pitch changes when playing sound effects can help reduce the repetitiveness and make a game's sound effects more believable.  Also, this could potentially be used to create a "Doppler effect" for moving sources.

There are two new methods in the SoundSystem class:
getPitch( String sourcename )
setPitch( String sourcename, float newPitch )

Possible values for pitch are 0.5f - 2.0f (where 1.0f is normal pitch).  Changing the pitch also changes the playback speed.  I uploaded the updated SoundSystem core and library pluggins.  The links in my initial post are still the same.

Since there are already several people using SoundSystem in their projects, I don't want to break the existing quickPlay method by adding in a parameter for initial pitch if it isn't necessary.  The following can be used instead:
soundSystem.setPitch( soundSystem.quickPlay( ... ), initialPitch );

This works fine on my computer, but if there winds up being latency problems with this method on slower machines, I will go back and change the quickPlay method.

paulscode

At the request of a user, I added a new 'loadSound( String identifier, URL url )' method and uploaded the updated library.  This allows you to use a URL instance rather than specifying a String filename parameter.  The links on my original post are still the same.  Changes were applied to the SoundSystem core and all library plug-ins.  The 'String identifier' parameter must end in the file's extension (example "whatever.ogg"), so SoundSystem knows what codec to use when reading from the URL.  This identifier can be used for the 'String filename' parameter in the newSource and quickPlay methods.

paulscode

Over the weekend I discovered some delay problems whenever there are more than 20 or so sources playing at around the same time in the Helicopter demo applet I wrote some time ago.  I spent a great deal of time looking into the issue.

I haven't been able to solve this problem yet, but I have discovered a couple of interesting things.  Firstly, the problem only appears when running jPCT via the LWJGL Applet Loader, and only for the LibraryLWJGLOpenAL plug-in (LibraryJavaSound works fine, even when loaded via the Applet Loader).  In other words, I can only replicate the problem when mixing the LibraryLWJGLOpenAL plug-in with jPCT in an applet.  Since jPCT relies on the LWJGL, as does the LibraryLWJGLOpenAL plug-in, I suspect there is a thread synchronization problem in my code related to the LWJGL that is conflicting with jPCT.  The confusing thing is that the problem only appears in applets and not applications (due to limited resources, perhaps?)

I am currently working on porting the helicopter demo applet to the JMonkey Engine so I can mix OpenAL and OpenGL in an applet without the LWJGL Applet Loader.  This should either strengthen or refute my theory that the problem is a thread synchronization issue related to the LWJGL.  If the problem exists there as well, then I will start looking at other possible causes, such as memory leaks and the like.  I will post further information as I progress.

EgonOlsen

When using the AWTGLRenderer, rendering happens in the AWT event dispatch thread. And there are some synchronizations in jPCT to make this possible but nothing of this is related to LWJGL directly. I assume you are using this renderer in the demo?

You may want to try two things: Try to compile the objects in the scene to shift some load from the CPU to the GPU and try the JOGL renderer instead. For both, you'll need the latest beta of 1.18: http://www.jpct.net/download/beta/jpctapi_118pre3.zip

paulscode

I am almost positive there is a thread synchronization problem somewhere.  The random-delay behavior looks identical to what was happening in a target-shooter applet I started working on a while back, which turned out to be an awt event thread issue.  I think what I'll do is use a much simpler test applet rather than trying to make the helicopter demo work (there are too many things going on in that demo to rule out a problem in the applet's source).  Instead I'll make an test-case applet that simply adds a bunch of primitives to the world and starts playing sounds to see if I can replicate the problem.  If I can replicate the problem, then I'll give your suggestions a shot to see if there is any difference.  If I am unable to replicate the problem, I'll try rewriting the helicopter applet from scratch.  I wrote that one when I was new to Java and jPCT, so it may just be poorly written / not thread-safe.

paulscode

#325
I thought I would share a recent conversation I had with a developer, in case anyone else was having a similar issue.

Quote from: Howardhey Paul,

I extended your Sound System and added this class/function. My goal is to load all sounds on startup and associate them with a string identifier for play/pause/stop later. I'm not really sure what ManageSources really does but it only works with the QUICK_PLAY option. The question is, is the below correct for what I'm trying to do?

Also, I noticed a minor problem. Sometimes when a sound starts to play, a split second into that sound, the sound starts again. This happens randomly but every so often. It's very slight so you really have to listen for it. After running a bunch of tests I can only assume the CommandThread is going to sleep right after the sound just starts to play and then when the thread is awaken, it finishes off what it started. I don't know. Your thoughts please.

Any help would be greatly appreciated.

howie
public class NinjaSound extends SoundSystem
{

    public void loadSound( String sourcename, String filename,
                           boolean toStream, boolean toLoop )
    {
        if( toStream )
        {
            newStreamingSource( true, sourcename, filename, toLoop, 0, 0, 0,
                                SoundSystemConfig.ATTENUATION_NONE, 0 );
        }

        ManageSources( new CommandObject( CommandObject.QUICK_PLAY, true,
                           true, toLoop, sourcename, filename, 0, 0, 0,
                           SoundSystemConfig.ATTENUATION_NONE, 0, false ) );

        if( !toStream )
        {
            loadSound( filename );
        }
    }
}
Quote from: Howardnever mind. I figured it out. I was basing my code on your backgroundMusic function. The newStreamingSource and ManageSources basicly do that same thing so you end up with two calls in the sourceMap.

    public void backgroundMusic( String sourcename, String filename,
                                 boolean toLoop )
    {
        newStreamingSource( true, sourcename, filename, toLoop, 0, 0, 0,
                            SoundSystemConfig.ATTENUATION_NONE, 0 );
        // Queue a command to quick stream this new source:
        ManageSources( new CommandObject( CommandObject.QUICK_PLAY, true,
                           true, toLoop, sourcename, filename, 0, 0, 0,
                           SoundSystemConfig.ATTENUATION_NONE, 0, false ) );
        CommandQueue( new CommandObject( CommandObject.PLAY, sourcename) );
       
        commandThread.interrupt();
    }


here's my new function for loading sound.

public class NinjaSound extends SoundSystem
{

    public void loadSound( String sourcename, String filename,
                           boolean toStream, boolean toLoop )
    {
        CommandNewSource( false, toStream, toLoop, sourcename,
                          filename, 0, 0, 0,
                          SoundSystemConfig.ATTENUATION_NONE, 0 );

        commandThread.interrupt();
    }
}


Quote from: PaulHoward,

Yes, I can see how this part of the code might be confusing.  I originally made it so quickPlay and backgroundMusic both created a temporary source and then immediately played it (seems logical).  All commands, including these two, were processed in order from the "CommandQueue" method via the Command Thread.

However, I later wanted the ability to "cull" and "activate" sources.  This feature is so that developers can extend the SoundSystem and manage which sources should play and which shouldn't based on their own rules.  For example, one might create a game where there are hundreds of simultaneously playing sources, and they only want the closest ones to play on whatever channels are available.

This seemingly simple update ended up requiring a significant change to the CommandQueue infrastructure.  All source creation, deletion, cull, and activate commands now needed to be processed first before play commands could be processed (this is the only way to ensure that only the active sources would play and not the culled ones).  So I created a new method called ManageSources, which is basically the same as CommandQueue, except it is called before CommandQueue is called.  This method processes the creation, deletion, cull, and activate commands that needed to be processed first.  The Command Thread processes all commands in the ManageSources queue first, then those in the CommandQueue.  Additionally, the ManageSources method is used in extended classes to sort the sources (by distance, for example), and to cull and activate the proper ones.  After all of those commands in the ManageSources queue are done, the commands in the CommandQueue are processed.

This change also required me to change the quickPlay and backgroundMusic methods, because I could no longer have these methods automatically play the new source (cull and activate stuff had to be figured out first via ManageSources).  So I changed it so quickPlay and backgroundMusic queues one command to create the source (via ManageSources), and a second command to play the source (via CommandQueue).

Now, I have tested this new infrastructure quite a bit since I wrote it, but I will go back and take another look to make sure two calls to "play" are not happening from the quickPlay and backgroundMusic methods.  I should also add in more comments to that section of the code to explain what is going on and why there are two methods that look virtually the same.

Thanks for the insight!

-Paul
Quote from: PaulHoward,

After reviewing the source, you are correct - there is a bug in the backgroundMusic method (not in the quickPlay method, though) -- I am creating two sources with the exact same information.  Nice catch!  I will have this corrected in the next release.

-Paul

paulscode

Today I finished a major update to the SoundSystem.  I wrote a new class to make switching between String filename/identifier and URL on the fly very easy.  I worked it into all the streaming methods and the MIDI channel stuff (as well as reworking the loadSound method to use this new setup), so now either URLs or filenames can be used with all types of sources (MIDI, normal, and streaming).  Everything seems to be working after running several quick tests.  However, since the change was rather extensive (I ended up editing almost every class), I need to spend some time doing more extreme testing to make sure the library is still stable and all features work.  I also have a couple more small additions I want to add before the next release.

paulscode

Sound System, Cumulative Updates/Bug-Fixes

Sound System jPCT
Sound System
Sound System Utils

JavaSound library pluggin
LWJGL OpenAL library pluggin
JOAL library pluggin

JOrbis codec pluggin

-Made it so initializing OpenAL plug-ins will notify when AL_PITCH is not supported
-Fixed vorbis-header compatability issue with OGG files generated by Audacity
-Improved error-handling in multiple classes
-Updated and added multiple classes to allow user to specify either String filenames or URL instances
-Added new class to associate filename/identifier with URL
-Improved MIDIChannel class - searches for alternate sequencer/synthesizer if defaults don't work
-Added a new method for feeding raw audio data directly to a channel through streaming sources
-Added a new source-creation method to produce streams that can be fed directly with raw audio data
-Added a new SoundSystemUtils library which includes an XML loader
-Corrected problem in LibraryJavaSound plug-in where sources would only play once
-Corrected channel-source association bug which caused rare odd behaviors


paulscode

Something I changed seems to have broken Command synchronization.  I am currently looking into the problem, so please stand by.

paulscode

Ok, I solved the problem.  This logic error has actually been in the code for a very long time, but it never manafested itself until now.  I had to change the CommanQueue/ManageSources infrastructure to correct it, so any legacy code that extends the SoundSystem class for customized source management models will most likely now be broken.  If this causes problems for anyone, please refer to the JavaDoc for the proper new way to do custom source management, or post questions here for help.  Sorry any inconvenience this causes.

Updated packages:
Sound System
Sound System jPCT
Sound System Utils