3D Sound System

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

Previous topic - Next topic

zammbi

Ok thanks.
For now then I'll use the old sound lib I was using and try to repair what I can and then move to yours once yours is ready.

paulscode

I finally got JOrbis up and running.  It is an extremely low-level library - it takes about sixteen lines of code to simply read the header (not counting comments,if,try,case,break,while,etc), compared to JOgg which only required one line of code to do the same.  Great news, though - JOrbis is extremely compatible.  I haven't found a single .ogg file so far that it wasn't able to load, including very short-duration sounds!  And no more random clicking during any of them either!  I am very happy with this library - definitely worth having to deal with the whole LGPL issue.

I will now begin work on the new IDecoder infrastructure.  I have changed the basic concept a little, so that it will be possible to decode more than one file at a time (for example streaming multiple .ogg files simultaneously).  There will be an ICodec infrastructure, which will return IDecoder instances.  Each ICodec will have its own internal derivitive class of IDecoder.  The codec will return a decoder instance when asked for one.  That way there will be only one single codec instance for each audio format, but multiple decoder instances - one for each file that is being read from.  Each decoder instance will be shut down and discarded when it is no longer needed (i.e. when a file has finished pre-loading, a stream has been stopped, etc.)

zammbi

That's great that you got it working.
Can't wait to test. Just want to get rid of this current sound lib I'm using.

paulscode

Progress update:  I finished writing the new Codec/Decoder infrastructure into SoundSystem, and it is working beautifully in JavaSound - both regular and streaming sources, applets and applications.  When playing under OpenAL, on the other hand, there are serious bugs.  I get skipping, clicks, and random freezing, and the problems are worse in an applet vs. an application.  I'm in the process of trying to track down the source(s) of these problems, but haven't had any luck yet.  So far I have only written the codec for the JOrbis library, so when I get it working properly I still need to write codecs for the JOgg library and for unencoded pcm (.wav files) and debug those as well.

paulscode

I finally figured out what is causing all the problems with streaming in OpenAL.  The JOrbis library is much slower at decoding .ogg files than JOgg is (JOrbis seems to be decoding the data at about the same speed as playing the sound - I don't know if this is intentional or just a coincidence).  Since the default number of stream buffers is 2, what happens is that one buffer finishes being processed, and another begins loading to replace it.  It takes so long to load that next buffer that the remaining queued buffer sometimes finishes playing first.  As you would expect, when this happens you hear a skip or click.  The problem is, in OpenAL when there is no data being fed in to the stream, it sometimes crashes.  This of course highlights an underlying bug with the OpenAL library that I will need to track down.

In the mean time, simply increasing the number of streaming buffers to 3 seems to have fixed the problem.

You might be wondering why there wasn't any clicking or skipping in JavaSound also.  The reason is that the JavaSound library starts reading the next buffer when the first one begins processing rather than after it has finished processing like in OpenAL, so it has time to finish decoding the next buffer before the stream runs out of data.

I was also thinking, the "no data, stream crashes" bug could potentially be a big problem if, for example, you were streaming background music from an online url and the user happened to have a really slow internet connection.  Of course one would expect there to be problems with streaming in that case, but the stream should not crash because of it.  I will try and figure out a way to prevent this from happening or at least detecting when the stream has crashed and resetting it.

Also, the slow decoding speed of JOrbis could be a really big concern.  For example, in a project where you wanted to pre-load a whole bunch of .ogg sound effects, the load time could be significantly long.  Also, I doubt it will be possible to stream more than one .ogg file at a time with JOrbis (since all simultaneous streams are handled by a single "StreamThread").  I'm looking into this problem further to see if maybe I am using the decoder incorrectly (maybe there is a setting or something that is making it decode at playback speed).

paulscode

After a lot of searching on google and discussing the issue on various forums, it doesn't appear that there is any way to speed up the JOrbis decoder.  It looks like this is just a limitation that users will have to accept when using JOrbis instead of JOgg.  JOrbis is much more compatible, but JOgg is much faster.

I am proceeding on to code the JOgg and .wav codec pluggins.

paulscode

I have finished implementing the new ICodec/IDecoder infrastructure and I've written codecs for .wav, JOrbis, and JOgg.  All tests have been stable with no problems.  As mentioned in my previous posts, both JOrbis and JOgg have there own benefits and drawbacks, so the user now has the flexability to decide what they want to use in their project.

I actually like this setup I'm using for codecs so much that I think I will change how I am doing the individual libraries (lwjgl binding of OpenAL, JavaSound, and "no sound"), and make them stand-alone pluggins as well.  Instead of having three versions of SoundSystem out there, instead there will be a SoundSystemCore (equivalent to the current SoundSystemSmall) which will be completely stripped down - not have any of the redundancy of the current SoundSystem class.  This core library would only be capable of playing MIDI files, but the library and codec pluggins could be added as desired to increase functionality.  So for example, a user may only want to use OpenAL and Jorbis, and he will be able to eliminate the overhead of the other libraries and codecs that he isn't using (a major benefit for use in applets where memory is a concern).  The SoundSystemCore would be extended into the SoundSystem class (OpenAL, JavaSound, .wav, and JOgg pluggins included plus all the redundant methods in the current SoundSystem class).  The SoundSystemCore would also be extended into SoundSystemJPCT (with OpenAL, Javasound, .wav, and JOgg pluggins plus the jPCT-specific methods, like binding Listener to Camera, auto-conversion of SimpleVectors into the SoundSystem coordinate system, etc.)

I am going to begin working on this concept tomorrow, and I'll see how it goes.  If it is going to be a major hassle, I'll probably release an updated version of SoundSystem as it is now, before implementing the new infrastructure.

zammbi

Glad everything is going well, can't wait to test and remove the current sound lib I'm using.

paulscode

#308
Seperating the libraries from SoundSystem was a lot easier than I expected it to be (I think because I always had a sense when I was programming them that they were seperate entities from the core library).  It really just required making a couple of big changes to the SoundSystemConfig class and several minor changes in other random classes.

I have decided to do a couple of things differently than before.

The first thing I'm going to do differently is that I am just going to call the library core class "SoundSystem" rather than "SoundSystemCore" (as mentioned before this will be the stripped-down customizable version).  I will not post any equivalent of the old "full SoundSystem" class here.  Rather, I will post only the core SoundSystem class, and the SoundSystemJPCT extention (since this is the jPCT forum, after all).

Another thing I changed today is that I combined the ICodec and IDecoder classes into a single ICodec class (made more sense because all that the ICodec was doing before was returning instances of IDecoder).  The method for assigning a codec to a particular file type now works like this:
SoundSystemConfig.setCodec( "ogg", CodecJOrbis.class ); // takes a Class parameter, not an instance parameter any more
Internally, when SoundSystem needs to decode the audio data, it grabs an instance of the class using:
SoundSystemConfig.getCodec( "myfilename.ogg" );
Adding libraries now works in a similar manner:
SoundSystemConfig.addLibrary( LibraryLWJGLOpenAL.class );
I removed the old method for setting library priorities (this was used by SoundSystem's built-in compatibility checking).  Now, the order you add the libraries using the above "addLibrary" method is the order SoundSystem will try to load them (if the first one fails, it tries the second one, etc).

I am also working to ensure that even though the SoundSystem core is stripped down and more flexible, it is still easy to use.  I feel like I have been able to accomplish that.  Here is an example - say you were using the SoundSystem core in a project.  You wanted it to have support for .wav files only, and you wanted it to try OpenAL first, then JavaSound as a backup option.  To do this, you would first link with the required jars:
SoundSystem.jar
LibraryLWJGLOpenAL.jar
LibraryJavaSound.jar
CodecWav.jar
(lwjgl.jar, jpct.jar, etc)

Then you would do a couple of extra steps in your program before instantiating the SoundSystem:
SoundSystemConfig.setCodec( "wav", CodecWav.class );
SoundSystemConfig.addLibrary( LibraryLWJGLOpenAL.class );
SoundSystemConfig.addLibrary( LibraryJavaSound.class );
SoundSystem soundSystem = new SoundSystem();

As you can see, it's still not too much of a hassle to use.

Anyway, most of the changes are going to be completely internal to SoundSystem, and as long as you use SoundSystemJPCT rather than the SoundSystem core by itself, your program is not likely to be affected at all by the change.  The only change that may affect you is if you are using the SoundSystem.switchLibrary method.  The reason this method has changed is that I have completely removed all the "global library identifiers" from the SoundSystemConfig class (for example, SoundSystemConfig.LIBRARY_JAVASOUND).  All class methods that used to take one of these identifiers as a parameter will now take the library class as a parameter instead.  Example:
mySoundSystem.switchLibrary( LibraryJavaSound.class );
I fell this is a very minor change, and it shouldn't take too much effort to fix anything that breaks because of it.

So far all of my tests have gone smoothly, so I should be ready to post a new release soon.

fireside

Sounds good.  I may be experimenting with it soon.  Once I get a few more things worked out in my game.
click here->Fireside 7 Games<-

paulscode

I ran some more extreme tests today in preparation for releasing the new version of SoundSystem.  I have uncovered a couple of serious bugs that I need to track down.  (This is pretty normal for me - a major update like this never goes off without a hitch).

The first bug is when streaming with the JOgg codec.  It seems that if I rapidly play and stop a streaming source it will eventually crash.  I don't recall if I ever ran a test like this on previous versions of SoundSystem, so I will first make sure that this bug wasn't happening before.  If not, then it is most likely a problem with the new CodecJOgg class.

The second bug is when using quickPlay in JavaSound to rapidly play a whole bunch of sources at once.  Eventually all normal sources stop playing and I receive a message "Error in class 'ChannelJavaSound', Buffer missing audio data in method 'attachBuffer'".  MIDI and streaming sources do not appear to be affected by this problem, and they continue to work normally after the problem occurs.  This is a new bug I have never seen before, and at the moment I have no idea where it is coming from.  I will check to see if this bug is present in the newest version of SoundSystem right before I disconnected the Libraries from SoundSystem to make them external pluggins.  This will let me know if the problem came from the new "Codec pluggin" infrastructure.  If the problem does not exist there, then it most likely appeared as a result of the new "Library pluggin" infrastructure.

At the moment I do not have a clear idea of what might be causing these two bugs, so I really can't speculate on how long it might take for me to track them down.  I will post further information as I learn more.

paulscode

Ok, I managed to track down the "Buffer missing audio data" problem today.  The problem turned out to be related to a new class called SoundBuffer, which I created for wrapping audio data buffers with the audio format in which the data is stored (I wrote this class for use with the new ICodec infrastructure to help me keep track of data from multiple sources in multiple formats).  On a whim, I had gone back and changed a few methods in the Library classes to use this more elegant class, and in the process I made a rather simple logic error which resulted in the bug (I forgot about the fact that multiple non-streaming sources can get their data from the same SoundBuffer, so I can't call a normal source's SoundBuffer cleanup() method from inside the Source cleanup() method - instead, it must be called from the Library cleanup() and unloadSound() methods).

So one bug is fixed.  I will now start looking at the other one.

paulscode

I fixed the bug.  It was another logic error (it was in some very old code - I'm surprised I hadn't noticed this bug before).  I will post the new release shortly after I package everything up with their corresponding license documents.  This has been a significant update, so I'm sure there are still bugs.  I'll try and fix problems as they surface.

paulscode

Sound System, major updates:
Please reference page one for more information.

Sound System jPCT
Sound System
JavaSound library pluggin
LWJGL OpenAL library pluggin
WAV codec pluggin
JOgg codec pluggin
JOrbis codec pluggin

JavaDoc

Tutorial (example programs)

What's new?

Added new transition methods for MIDI and streaming sources with the ability to queue next sounds and create fade in/out effects.
Created a new stripped-down customizable core SoundSystem library
Added a codec and library pluggin infrastructure, allowing the user to choose which sound libraries and codecs to use.


fireside

Great work.  Glad you have the tutorial there.  It will still be a little while for me before I become concerned with sound, but I'm looking forward to trying it out.
click here->Fireside 7 Games<-