3D Sound System

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

Previous topic - Next topic

paulscode

-- This slot is reserved for the most recent working releases --

Downloads:

Sound System  Version date:  October 23, 2010
The core SoundSystem library, independent from 3rd-party libraries.  It is stripped down to the bare essentials, and designed to be easily customizable with various sound library and codec plug-ins.  If memory is a concern (such as in an applet) this may be a good option, because it allows you to choose as many or as few plug-ins as you require for your project.  NOTE: The core SoundSystem library without any plug-ins is only capable of playing MIDI files.  Additional plug-ins should be added for more capabilities.  The source code and license are included in the .zip file.

Sound System jPCT  Version date:  October 23, 2010
The jPCT-friendly 3D sound library.  The SoundSystemJPCT class overrides the core SoundSystem libray, and provides a number of methods to make adding 3D sound to any jPCT project easy.  It includes methods for binding Listener to Camera and Sources to Object3Ds, as well as using SimpleVector parameters.  SoundSystemJPCT utilizes the LWJGL binding of OpenAL (with JavaSound as a backup option), and the J-Ogg library for .ogg support.  NOTE: The core SoundSystem library, source code, and all relevant licenses are included in the .zip file.

SoundSystem Utils  Version date:  August 8, 2009
Includes a SoundSystem loader, and an example XML file.


Plug-ins:

JavaSound library plug-in  Version date:  October 23, 2010
Interface to the Java Sound API.  More compatable than OpenAL, but not as high quality and fewer features.  This plug-in utilizes JavaSound's panning and volume control methods to simulate an reasonable-quality 3D sound system.  Known bug: quickPlaying sounds will begin playing them at full volume for a split second, before switching to the correct volume.  This is a bug with the Java Sound API itself, and therefore beyond my control to correct.  An easy workaround is to add 0.02 seconds of silence to the beginning of each sound effect (the free Audacity sound editor works well for this).

LWJGL OpenAL library plug-in  Version date:  August 24, 2010
Interface to the LWJGL binding of OpenAL.  The LWJGL library (http://www.lwjgl.org) is required for this plug-in to work.  This library sounds much better than Java Sound, but is not as compatable.  I recommend using the JavaSound library plug-in as a backup option.  NOTE: Please read the included LWJGL license.

JOAL library plug-in  Version date:  August 29, 2011
Interface to the JOAL binding of OpenAL.  The JOAL library (http://jogamp.org) is required for this plug-in to work.  As mentioned previously, this library sounds much better than Java Sound, but is not as compatable.  I recommend using the JavaSound library plug-in as a backup option.  NOTE: Please read the included JOAL license.

WAV codec plug-in  Version date:  October 23, 2010
Adds support for .wav files.

JOgg codec plug-in  Version date:  August 24, 2010
Adds support for .ogg files using the J-Ogg library.  This codec is less compatible than the JOrbis codec, but the license is less restrictive.  Sometimes running incompatable .ogg files through a converter will make them compatable.  NOTE: Please read the included JOgg license.

JOrbis codec plug-in  Version date:  November 23, 2010
Adds support for .ogg files using the JOrbis library.  More compatible than the JOgg codec, but reads data more slowly (it may not be possible to stream more than one file simultaneously when using this codec).  This plug-in is licensed by the LGPL.  NOTE: Please read the included LGPL document.

IBXM codec plug-in  Version date:  August 24, 2010
Adds support for Protracker, Fast Tracker 2, and Scream Tracker 3 (.s2m, .mod, and .xm) files using the IBXM library.  File sizes for these formats tend to be quite small, so this may be a good option for background music.  This plug-in is based on or using the IBXM library, which is bound by the BSD License.  NOTE: Please read the included license document.

JSpeex codec plug-in  Version date:  August 24, 2010
Adds support for .ogg or .wav files encoded with Speex (a compression optimized for human voice).  See http://www.speex.org/ for more information.


Documentation:

JavaDoc  Version date:  October 23, 2010
Also includes the JavaDocs for SoundSystemJPCT and all library and codec plug-ins, and the utils library.

3D Sound with SoundSystem  PDF (download the example programs)
A tutorial-style guide to using the core SoundSystem library (last updated: April 14, 2009).

Guide to SoundSystemJPCT  PDF (download the example programs)
Another tutorial-style guide to using SoundSystemJPCT. (last updated: April 14, 2009).


Demos:
(last updated: August 21, 2010)

Sound Effects Player  (download the Source Code)
Demonstrates library switching on the fly, streaming background music, playing MIDI, and playing multiple sources simultaneously.

Bullet / Target Collision  (download the Source Code)
Demonstrates the LibraryJavaSound plug-in.

Holy Bouncing Helicopter Balls!  (download the Source Code)
Currently uses the SoundSystem core -- I'm currently working on a version for SoundSystemJPCT, which will be much simpler.  Demonstrates moving through a world with multiple sources.


What's new?

- Fixed JOAL package name from the old net.java.games.joal to the new com.jogamp.openal
- Updated CodecWav link to current version
- Improved LibraryJavaSound performance slightly in non-Sun Java versions
- Handled rare pan-control exception
- Fixed fadeOutIn bug which caused fade-in effect to be silent
- Fixed a bug where certain types of .ogg files created in versions of Audacity were cut off just before the end of the sample

paulscode

#1
Project Overview:

This project began as a problem in the Support section, about OpenAL being extremely complicated, and that there needs to be a 3D sound library that is easy to understand and use.  I decided to create a class that does all the tedious stuff and simplifies OpenAL.  I have since added the ability to switch between OpenAL and JavaSound, using a common interface.  I also added automatic compatibility checking, to make life even easier for the programmer.  And of course, I extended the base library to make a version that is easily compatible with jPCT.

Now as you know, jPCT uses the Lightweight Java Game Library (lwjgl) for hardware rendering (http://www.lwjgl.org), so chances are, your projects are already loading those libraries.  Cool thing is, lwjgl has a binding to OpenAL too, so that is what SoundSystem uses to interface with OpenAL.

This project was originally called "Sound Manager", and the thread title was "3D Sound using lwjgl binding of Open AL".  Somewhere along the way the library name changed to "Sound System", and I also decided to change the thread name.  Just thought I would point that out in case anyone decides to read through the old posts, so you won't be confused.

For a while I was regularly updating an extension of the SoundSystem class called "SoundManager", which used two different source management models for dealing intelligently with cases where more than 32 sources were playing at once.  It has since been discontinued, since there there doesn't seem to be any interest in it.  The way SoundSystem manages too many simultaneously playing sources is quite sufficient for most projects.

If anyone has any ideas for improving the library, let me know!

fireside

click here->Fireside 7 Games<-

paulscode

#3
New version of SoundManager is out today.

JAR:
http://www.paulscode.com/libs/SoundSystem/11MAR2008/SoundManager.jar

Source:
http://www.paulscode.com/source/SoundSystem/11MAR2008/SoundManagerSource.zip

Here's what's new about this version:

1) SoundManager now supports attenuation (how a sound "fades" with distance).  Available types:
    No Attenuation: The sound will play at constant volume regardless of distance
    Linear Attenuation: lets you specify a distance at which a sound volume
                              will become completely silent.
                              (works for both mono and stereo sounds!)
     Logrithmic Attenuation (or Rolloff): More realistic - uses a rolloff factor
                                                    Smaller values for rolloff fade at
                                                    longer distances.  If rolloff is 0,
                                                    then the sound will not fade.
                                                    (only works for mono sounds)
     There are also a few varriables you can change to redefine the default attenuation settings.  Or you can just leave them alone and let SoundManager use the default settings:
         SoundManager.DEFAULT_ATTENUATION_MODEL
         SoundManager.DEFAULT_ROLLOFF_FACTOR
         SoundManager.DEFAULT_FADE_DISTANCE
2) You can now create multiple sources from the same sound file.  The method for creating a source is "newSource".  It is no longer necessary to call the "load" method.  SoundManager will automatically call "load" before creating a source if the sound file hasn't been loaded yet.  There are several ways to call "newSource", depending on how much information you want to supply.  SoundManager will use default values for any value you don't specify when creating your source.
    The least amount of information required to create a source is:
    newSource( sourcename, filename, toLoop );
          sourcename: A unique identifier for this source
                          (two sources may not use the same sourcename)
          filename:   The name of the sound file to play at this source
                          (if the sound file has not been loaded yet,
                              then SoundManager will load it for you)
          toLoop:     Should this source loop, or play the sound only once         
    Optional information you can specify when creating a new source:
    newSource( sourcename, filename, toLoop, x, y, z, attmodel, distORroll );
          (x, y, z):  Location in 3D space for this source.
                      Default location is the origin ( 0, 0, 0 )
          attmodel:   Attenuation model to use.  Possible values are
                              SoundManager.ATTENUATION_NONE
                              SoundManager.ATTENUATION_ROLLOFF
                              SoundManager.ATTENUATION_LINEAR
          distORroll: Either the fading distance or rolloff factor,
                      depending on the value of "attmodel".
3) .ogg files are supported.  They can be either streamed or played normally.  There are some varriables you can change to redefine how streaming is handled.  Or you can just leave them alone and let SoundManager use the default settings:
    SoundManager.STREAMING_BUFFER_SIZE   (size of each data "block")
    SoundManager.STREAMING_NUM_BUFFERS   (number of buffers to use when streaming)
4) There is also a method called "newStreamingSource".  A streaming source differs from a normal source, in that it has multiple, dynamic buffers.  Use newStreamingSource to create a source that will be streaming a sound.  newStreamingSource takes the same parameters as newSource.

To have support for .ogg files, the above jar is compiled with the source code from the j-ogg library, located at http://www.j-ogg.de.  If you want to alter the SoundManager class, you will need need to include that library before you will be able to compile.  The source files for the j-ogg library are also inside the zip file refrenced above.

JavaMan

Wow, I don't need it now, but I will check this out in the future! Looks super easy to use.  ;D Which I um, like.
Jman

fireside

Does the sound file need to be added to the jar?  I haven't tried it yet, just asking beforehand.  To tell the truth I have no experience with jar files at all other than putting them in a classpath.
click here->Fireside 7 Games<-

paulscode

Quote from: fireside on March 14, 2008, 03:52:10 AM
Does the sound file need to be added to the jar?  I haven't tried it yet, just asking beforehand.  To tell the truth I have no experience with jar files at all other than putting them in a classpath.
Yes, for now they need to be in the jar.  You can either put them in a package called "Sounds/", or you can change the global varriable:
SoundManager.SOUNDFILES_LOCATION
It needs to be a String containing the "/" separated path to the package containing your sound files, and must end with "/".

I am adding two more ways to load files - from a URL and from an external path.  I should hopefully be finished with this and a few other things I am working on, in the next couple of days.

fireside

O.K.  I'll have to read up on jars a little and get back.
click here->Fireside 7 Games<-

paulscode

#8
New version of SoundManager is out today.
JAR:
http://www.paulscode.com/libs/SoundSystem/15MAR2008/SoundManager.jar

Source:
http://www.paulscode.com/source/SoundSystem/15MAR2008/SoundManagerSource.zip

SoundManager has changed quite a bit, so I decided to write a basic guide:

Guide to the SoundManager class

The simplest way to use SoundManager in your jPCT project:
Create the SoundManager object when you initialize things:
    soundManager = new SoundManager();
Bind the listener to the Camera after creating one:
    soundManager.bindListener( camera );
Create some sound sources:
    soundManager.newStreamingSource( "music", "deckthehalls.ogg", true );
    soundManager.newSource( "meow", "cat.wav", false );
    soundManager.newSource( "purr", "motor.wav", true );
Bind sound sources to Object3D's:
    soundManager.bindSource( "meow", my3DCat );
    soundManager.bindSource( "purr", my3DCat );
Call tick() in your main game loop:
    soundManager.tick();
Play the sounds any time you like:
    soundManager.play( "music" );
    soundManager.play( "meow" );
Call cleanup() at the end of your project:
    soundManager.cleanup();


Common Terms:
ATTENUATION:  How a sound "fades" with distance.
    If there is no attenuation, a sound will play at constant volume regardless of distance
FADE DISTANCE:  The distance at which a sound volume will become completely silent
    Used in Linear Attenuation
    (works for both mono and stereo sounds)
LINEAR ATTENUATION:  A sound's volume is inverse to it's distance
    A sound half fade-distance away will play at half volume
LOGRITHMIC ATTENUATION:  A sound's volume is a logrithmic function of it's distance
    A more realistic attenuation model - uses a rolloff factor
    (only works for mono sounds)
ROLLOFF:  A value used in logrithmic attenuation.
    Smaller values for rolloff fade away at longer distances
    If rolloff is 0, then the sound will not fade
STREAMING:  Using multiple buffers to break long sound files, (like background music) up
     into smaller pieces, so you can start playing immediately, rather than waiting to load.


Global References:
Attenuation models:
    public int ATTENUATION_NONE    = 0;  // no attenuation
    public int ATTENUATION_ROLLOFF = 1;  // logrithmic attenuation
    public int ATTENUATION_LINEAR  = 2;  // linear attenuation

Global Varriables (can be changed to fit your preference):
Package where the sound files are located:
    public String SOUNDFILES_LOCATION = "Sounds/";   
Attenuation model to use if not specified (one of the references listed above):
    public int DEFAULT_ATTENUATION_MODEL = ATTENUATION_ROLLOFF;
Default value to use for rolloff model when value isn't specified:
    public float DEFAULT_ROLLOFF_FACTOR = 0.03f;
Default fade distance for linear model if value isn't specified:
    public float DEFAULT_FADE_DISTANCE = 500.0f;   
Number of bytes to load at a time when streaming:
    public int STREAMING_BUFFER_SIZE = 4096*16;
The number of buffers used for each streaming sorce:
    public int STREAMING_NUM_BUFFERS = 2;   
The approximate size of a normal .ogg file:
    private int OGG_NORMAL_SIZE = 1048575;


Easy Interfacing with jPCT
When using these methods, don't forget to call tick() in the main game loop:
    bindListener( Camera c )
        Listener will automatically follow and align with the Camera object

   bindSource( Object3D o )
       A source will automatically follow an Object3D



Method Descriptions:

public void cleanUp()
    Stops all sounds and clears up any used resources

public boolean bindListener( Camera c )
    Orientates the listener to match the Camera orientation

public boolean bindSource( String sourcename, Object3D obj )
    Associates a sound source with an Object3D to follow

Releases a source from it's associated Object3D
    public void releaseSource( String sourcename )

public void releaseAllSources( Object3D obj )
    Releases all sources bound to this Object3D
    (Usually called before deleting an Object3D with sources attached to it, but not required)

public void tick()
    Re-aligns the listner to the camera, and keeps sources folowing the Object3D's they are bound to
    Should be called within the game loop
    (only required if you are using bindListener or bindSource)

public boolean load( String filename )
    Load the specified file (only used for non-streaming sources).
    It is not necessary for you to call this method in your program, but you can if you want to.
    (For example, you could load all the sounds at once and show a progress bar)
    SoundManager will automatically call this method if necessary when creating a source
    If "filename" is a url, it must begin with "http://"
    Returns "true" if there were no problems loading the file
   
public boolean newSource( String sourcename, String filename, boolean toLoop )
public boolean newSource( String sourcename, String filename, boolean toLoop, int attmodel )
public boolean newSource( String sourcename, String filename, boolean toLoop, int attmodel, float distORroll )
public boolean newSource( String sourcename, String filename, boolean toLoop, float x, float y, float z, int attmodel )
public boolean newSource( String sourcename, String filename, boolean toLoop, float x, float y, float z, int attmodel, float distORroll )
public boolean newStreamingSource( String sourcename, String filename, boolean toLoop )
public boolean newStreamingSource( String sourcename, String filename, boolean toLoop, int attmodel )
public boolean newStreamingSource( String sourcename, String filename, boolean toLoop, int attmodel, float distORroll )
public boolean newStreamingSource( String sourcename, String filename, boolean toLoop, float x, float y, float z, int attmodel )
public boolean newStreamingSource( String sourcename, String filename, boolean toLoop, float x, float y, float z, int attmodel, float distORroll )
    Create a new normal or streaming source.  A streaming source differs from a normal source, in that it has multiple, dynamic buffers.
    SoundManager will use default values for any value you don't specify when creating your source.
    sourcename: A unique identifier for this source (two sources may not use the same sourcename)
    filename: The name of the sound file to play at this source.  If "filename" is a url, it must begin with "http://"
        (if the sound file has not been loaded yet, then SoundManager will load it for you)
    toLoop: Should this source loop, or play the sound only once
    (x, y, z):  Location in 3D space for this source.  Default location is the origin ( 0, 0, 0 )
    attmodel:   Attenuation model to use.  Default is the value in DEFAULT_ATTENUATION_MODEL
    distORroll: Either the fading distance or rolloff factor, depending on the value of "attmodel".

public boolean deleteSource( String sourcename )
    Deletes the specified source

public boolean setPos( String sourcename, SimpleVector pos )
public boolean setPos( String sourcename, float x, float y, float z )
    Moves the named sound to the specified location.

public boolean play( String sourcename )
public boolean stop( String sourcename )
public boolean pause( String sourcename )
public boolean rewind( String sourcename )
    Controls for playing, stopping, pausing, and rewinding a source

public boolean playing( String sourcename )
    Returns true if the source is playing

public void moveListener( float xStep, float zStep )
public void moveListener( SimpleVector step )
public void moveListener( float xStep, float yStep, float zStep )
    Moves the listener, relative to their current position.

public void setListenerPos( float xNew, float zNew )
public void setListenerPos( SimpleVector posNew )
public void setListenerPos( float xNew, float yNew, float zNew )
    Positions the listener at the coordinates provided.

public void turnListener( float angle )
    Turns the listener counterclockwise by "angle" radians, relative to their current orientation.

public void setListenerOrientation( float angle )
    Sets the listener's orientation (counterclockwise rotation in radians along the y-axis)

public void setListenerOrientation( SimpleVector look, SimpleVector up )
public void setListenerOrientation( float lookX, float lookY, float lookZ, float upX, float upY, float upZ )
    Sets the listener's orientation based on a look-at point and an up-direction

public void recalculateDistances()
    Recalculates the distances between each source and the listener, and recalculates the gain if a
    source is using linear attenuation.  It is not necessary for you to use this method.
    SoundManager will automatically call this method when the listener moves or rotates, or a source moves.


Here's a rough overview of what's new about this version:

1) I moved the SoundManager class from package "Sounds" to a package called "paulscode.sound"

2) Sounds can now be loaded from either the jar, or from a url.  When loading from a url, the filename must begin with "http://" (that is how SoundManager determines wheter to look in the jar or go to a URL to load a file).  I didn't add the ability to load files from a harddrive directory (I figure it is just as easy to load them from the jar).

3) I corrected a math error in the setListenerOrientation( float angle ) method.

4) I added looping for streaming .ogg sources, and corrected a problem where the last block of data was getting cut off.

5) I rewrote the methods for handling streaming threads, to correct an exception I was getting when trying to clear buffer memory on exit.  Buffers are now all being cleared correctly when SoundManager.cleanUp() gets called.

6) I added in two new functions to make using SoundManager with jPCT a breeze.  They are designed to let you focus on the graphics, and not have to wory about sound. The functions are:
    a) bindListener( Camera c )
        Called after creating the camera.  The SoundManager will automatically translate and rotate the listener to match the camera any time the camera's position or orientation changes.  After calling this method, you don't have to even think about translations and rotations to keep the listener and camera in-sinc - SoundManager does it for you.
    b) bindSource( String sourcename, Object3D obj )
        Called after creating a new source and an Object3D.  Similar to bindListener, except it binds a sound source to an Object3D.  You can attach as many sources as you want to an object, and they can be regular, streaming, looping, whatever.  Again, after calling this method, you don't have to worry about moving your source to match the object - SoundManager takes care of it.

The only thing you have to remember when using either of the two "bind" methods, is you have to call SoundManager.tick() from inside your main game loop (that is the method where SoundManager checks if anything has moved).

I created a simple applet to demonstrate the bind features, which you can see at:
LINK NO LONGER EXISTS

Rotate the camera with the left and right arrow keys, and move the gear's depth with the up and down arrow keys.  You can get the source code for this applet at:
LINK NO LONGER EXISTS

One potential bug I am looking into is the fading between left and right speakers only seems to work when the source is close to the listener.  I haven't determined if it is a limitation with my soundcard, or a bug in the code.  I am looking into this further.  It would be helpful if a few people could run the above applet and see if they experience the same thing.  Thanks in advance!

fireside

Cool applet.  I'm going to have to look at the source. 
click here->Fireside 7 Games<-

paulscode

One thing you may have noticed if you've tried to create a lot of sources (depending on your sound card), at some point the sources will just not play - ie there is a maximum number of sources that can be played at one time.  Unfortunately, it seems that a source's distance from the listener has no bearing on which sources OpenAL decides to play when you have too many.  This would pose a serious problem in a 3D game where you could potentially have hundreds or thousands of sound sources.

So what I've decided to do, is make SoundManager smart enough to cull unnecessary sources.  Basically, there would be a "maximum source number".  Sources will have a priority based on their distance from the listener, closer sources having priority over further away sources.  Sources will be culled down to the maximum source number based on their priority.  Here is an illustration to demonstrate what I am talking about:



In this example, the maximum source number is four.  The green circle is the listener.  The four red circles are sources which are allowed to play, while the grey circles are sources that would be culled.  Which sources are culled will change dynamically as the listener or sources move, or when non-looping sounds stop playing.

I will keep you posted on how progress goes for this concept.


fireside

I was wondering about that very thing.  Mostly because it seemed like it would be a waste of resources. 
click here->Fireside 7 Games<-

paulscode

I have finished adding the infrastructure for source culling.  It is late here in Maryland, so I'm going to bed - I will debug the code more thoroughly tomorrow and post the source.  A couple of basic initial tests have been promising, though - no exceptions, error messages, or lag ( always a good sign ;D ).  I am going to run some more "extreme" cases and see if I can get the class to break down.  I'll try and release the code tomorrow after running more tests and creating a nice demo applet to showcase the new source-culling.  Good night all!

paulscode

#13
New version of SoundManager is out today.
JAR:
http://www.paulscode.com/libs/SoundSystem/25MAR2008/SoundManager.jar

Source:
http://www.paulscode.com/source/SoundSystem/25MAR2008/SoundManagerSource.zip

I finished the code for source culling, and I have run a number of tests.  I have found that in cases when there are thousands of sources, there is a noticable lag.  I am looking into this to see if I can streamline things a bit more.  For now, using around 500 sources or so runs well (and sounds really cool ;D)

There is a logic error somewhere I am having trouble locating, related to remembering to replay looping sources when they are reactivated.  For now I put a hack in that replays every source when it is reactivated (obviously not the correct behavior, but it let me debug the rest of the code).

I created an applet to demonstrate the new source culling, which you can see at:
LINK NO LONGER EXISTS

Move through the world with the arrow keys.  You can get the source code for this applet at:
LINK NO LONGER EXISTS

Let me know if you have any problems with the above applet.

fireside

The applet seemed to run fine for me.  Nice job.
click here->Fireside 7 Games<-