3D Sound System

Hey!  I thought of a way to do a loadSound( URL ) method.  It would look like this:



loadSound( String identifier, URL url );



This would require you to come up with your own unique identifier for each sound file.  Then you could use that identifier later in the quickPlay() and newSource() methods.  It wouldn't require me to break any of the existing methods.



Would this work for your situation?



–EDIT–

I added the above 'loadSound( String identifier, URL url )' method and uploaded the updated library.  The links on my original post are still the same.  Changes were applied to the SoundSystem core and all library plug-ins.  I didn't have time to run tests today, so let me know if there are any problems.  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.  The identifier can be used for the 'String filename' parameter in the newSource and quickPlay methods.

PaulLamb said:

No, for maximum compatibility (which is really the whole point of using JavaSound instead of OpenAL), I use the "Java Sound Audio Engine" mixer.  Not only is this the most compatible Mixer, it ensures there are volume and pan controls available for use in simulating 3D sound, and that there are up to 32 possible simultaneously open Clips/SourceDataLines.

The problem is that on my machine, the Java Sound Audio Engine was unable to play some of my sounds, I had to switch to another mixer. If you always use this, some people will have to tinker your library to choose another mixer by default.

In your method loadSound( String identifier, URL url ), is the parameter "identifier" useful to play a sound later? I want to preload some sounds that are often used at the beginning of the game to avoid lags.
gouessej said:

The problem is that on my machine, the Java Sound Audio Engine was unable to play some of my sounds, I had to switch to another mixer. If you always use this, some people will have to tinker your library to choose another mixer by default.

I don't want SoundSystem to try to pick a mixer to use, because I know I can't expect to find something that works on every computer every time.  However, I could add "getMixer" and "setMixer" methods to the LibraryJavaSound class, which would give you the option of picking a different mixer in your program before creating any sources.  I did something similar in the LibraryJOAL pluggin (I created a getAL() method, allowing direct access to JOAL if needed), and AL10 in the LibraryLWJGLOpenAL pluggin is already used in a static context and directly accessible.  Providing control over the JavaSound mixer just makes sense (not sure why I haven't done this already).  I'll add this capability later today when I have a little time.

Ultimately, your best bet might be to allow the user to chose between OpenAL and JavaSound (and possibly choose what mixer they want to use) in the program (with some sort of "sound menu").  SoundSystem lets you easily switch between library pluggins on the fly using the switchLibrary method, and if I add in a setMixer method to LibraryJavaSound, you could also easily switch between mixers, allowing you to create some kind of interface to give the user control.  Then you would start out with "most likely to work" settings, and the few users that it doesn't work for could change it.

gouessej said:

In your method loadSound( String identifier, URL url ), is the parameter "identifier" useful to play a sound later? I want to preload some sounds that are often used at the beginning of the game to avoid lags.

Yes, the "identifier" parameter is used as the "filename" in the newSource and quickPlay methods.  This is used to identify what sound effect you want to use.  Yes, to avoid lags it is best to preload your sounds with the loadSound method at the beginning of the game.  The audio data will be placed into a hashmap with "identifier" used as the key for easy access by SoundSystem when you create your sources.

BTW, thanks for all the suggestions.  I probably wouldn't have thought of these myself.
PaulLamb said:

Ok, I added in the new getMixer and setMixer methods, and uploaded the updates.  Changes were applied to the LibraryJavaSound plug-in and to the SoundSystem core (changed a couple of 'private' varriables to 'protected' in the Library class).  These new methods are static, and should be thread safe.  It should also be possible to switch between Mixers on the fly.  I haven't run many tests yet, so let me know if you have any problems.  I'll have time to run more extensive tests this weekend.

Have you put some tests or try/catch clauses into your code in the case I change the mixer? For example, if I change the mixer and this one has less available controls, what happens if I use an available control? Is there any exception? Does it do nothing?

You're fast. Thank you very much  :D

Good point, I should do something when a control isn't available.  I'll make the setMixer method throw a SoundSystemException, and I'll add a couple more identifiers to the SoundSystemException class so you can use it to check what the problem was.  I'll upload the updates when I get that finished.

Ok, the setMixer method now throws a SoundSystemException.  There are also several int identifiers available in the SoundSystemException class that can be used to find out what went wrong:

JAVASOUND_MIXER_NOT_FOUND
JAVASOUND_MIXER_NO_GAIN_CONTROL
JAVASOUND_MIXER_NO_PAN_CONTROL
JAVASOUND_MIXER_NO_SAMPLE_RATE_CONTROL



I've uploaded the updates.  The changes applied to the LibraryJavaSound plug-in and the SoundSystem core.
PaulLamb said:

Ok, the setMixer method now throws a SoundSystemException.  There are also several int identifiers available in the SoundSystemException class that can be used to find out what went wrong:

JAVASOUND_MIXER_NOT_FOUND
JAVASOUND_MIXER_NO_GAIN_CONTROL
JAVASOUND_MIXER_NO_PAN_CONTROL
JAVASOUND_MIXER_NO_SAMPLE_RATE_CONTROL



I've uploaded the updates.  The changes applied to the LibraryJavaSound plug-in and the SoundSystem core.

Why don't you use enums instead of int identifiers? In JME 2, we use them and it is cleaner.

Enums would be another way to do it, but in programming, there is always more than one way to skin a cat.  Whether enums are "cleaner" is a matter of opinion.  Personally, I think int identifiers are more logical (but that's just my programming style).  There have been plenty of lengthy debates on the subject, so not to get off topic I won't defend my position any more than that.

PaulLamb said:

Enums would be another way to do it, but in programming, there is always more than one way to skin a cat.  Whether enums are "cleaner" is a matter of opinion.  Personally, I think int identifiers are more logical (but that's just my programming style).  There have been plenty of lengthy debates on the subject, so not to get off topic I won't defend my position any more than that.

Ok. I prefer using enums to avoid people to pass stupid values to my methods, it is more restrictive. Do as you wish.

I compiled a couple of demo applets to post for reference.  In one of them, though, I noticed some delay problems whenever there are more than 20 or so sources playing at around the same time (The same demo using an older version of SoundSystem didn't have this problem).  I am currently attempting to find where the delay is coming from (I suspect it is a thread synchronization problem).  I will post an update when I get this fixed.

PaulLamb said:

The same demo using an older version of SoundSystem didn't have this problem

Which version exactly?

Yes, I want to have extensions of the SoundSystem core tailored for each of the the popular Java 3D engines - jPCT, JME, 3DzzD, and Xith3D.  Obviously, I am still working out the kinks with the jPCT version, but JME is next on my list as soon as I am comfortable with using the engine.  I'll probably start with some simple JME applications and applets to become familiar with how to deal with things like positions and orientations for the camera and objects, aquiring "world" coordinates, etc.  Porting the demo applet should be a good way for me to learn most of this.

On one user's computer, an exception was thrown stating that AL_PITCH was not supported.  Those of you who have used pitch changes with OpenAL before, how common is it for AL_PITCH to not work on computers, and is there an easy way to check if a particular system doesn't support it?  The way I thought of would be to create a test source and attempt to change the pitch on it.  Is there a more elegant solution?

I have not seen that exception before. Saying that, I don't know how it's implemented in the JME sound system either.

thanks for this great sound api.



now a quite "noobic" question follows:

how can i load audio files which are not stored in the compiled jar or on a remote server?

in my case i need to load audio files which are stored in a "data" folder next to the "src" folder in my java project. the SoundSystem jar and several codecs are already added to the project (as libraries).

thanks for everything!

regarding AL_PITCH: most implementations support values from 0.5 to 2.0, and I have  read that going above the limit will produce an error and going below will sometimes just screw it up without throwing an error. Also, these limits are with doppler effect included. So if you set pitch to 2.0 and use positional audio with velocity, doppler might take it above that threshold. I suggest you make sure that is not what is happening here.



Also, did that user run it with the software implementation of OpenAL? (software impl is more reliable)




kalaffkalasch said:

how can i load audio files which are not stored in the compiled jar or on a remote server?
in my case i need to load audio files which are stored in a "data" folder next to the "src" folder in my java project. the SoundSystem jar and several codecs are already added to the project (as libraries).
thanks for everything!

I did not include a direct method for accessing files stored locally outside of the JAR (I could not think of any reliable way to distinguish between a filename inside the JAR and one outside).  However, it should be possible to use the new loadSound( String identifier, URL file ) by simply creating a URL instance pointing to your local sound file.

Tobias said:

regarding AL_PITCH: most implementations support values from 0.5 to 2.0, and I have  read that going above the limit will produce an error and going below will sometimes just screw it up without throwing an error. Also, these limits are with doppler effect included. So if you set pitch to 2.0 and use positional audio with velocity, doppler might take it above that threshold. I suggest you make sure that is not what is happening here.

I see.  This should not happen naturally with the SoundSystem library, since I did not implement velocity.  However it is possible that this was the user's problem if he were manually accessing AL and doing both velocity changes and pitch changes.  I will ask him about this.

Tobias said:

Also, did that user run it with the software implementation of OpenAL? (software impl is more reliable)

No, he was using the hardware implementation.  However, even if running with the software implementation were to fix the problem, I do not personally see that as an acceptable bug-fix, since I do not want to force people to change their OpenAL implementation unless they want to.  I need to make the library handle this problem gracefully.

I don't think the end-user needs to install openal-soft or anything, the developer just ships the appropriate native library. Anyway, there are several problems with the hardware implementation, at least on linux, so the software one is always preferred in my opinion.

Tobias said:

I don't think the end-user needs to install openal-soft or anything, the developer just ships the appropriate native library. Anyway, there are several problems with the hardware implementation, at least on linux, so the software one is always preferred in my opinion.

I see.  Well, since the natives are completely seperate from my library plug-ins, I will just leave that decision up to the developer.  I will simply check for AL_PITCH compatability, and if it's not compatable I'll throw a SoundSystemException.  This is basically what I do for the LibraryJavaSound plug-in when a particular control is not available.  The developer can decide if they need AL_PITCH or not and either switch to a different Library plug-in or just use OpenAL without it.

Sounds good