OpenAL Tutorial
(by Brian Matzon <brian@matzon.dk>)

1.0 OpenAL Basics
Before embarking on our little OpenAL adventure, some tools are needed.

1.0.1 Ingredients
Head on over to Creatives site and snag a copy of the OpenAL specification along with a copy of the Programmers reference.
If you haven't already done so, get a copy of the OpenAL runtime environment too (and install it).

1.1 OpenAL theory
Uhm... I'm not going to write this... In all honesty reading the specification would be a good thing before continuing - but it isn't required...

1.2 Basic setup
Lets start out by creating a skeleton class for some very basic sound. We'll start of by creating the required OpenAL objects

import org.lwjgl.openal.AL;
import org.lwjgl.openal.ALC;
import org.lwjgl.openal.ALCcontext;
import org.lwjgl.openal.ALCdevice;
import org.lwjgl.openal.ALUT;

public class PlayTest {
   
  /** OpenAL instance */
  protected AL al;
   
  /** OpenAL Context instance */
  protected ALC alc;
   
  /** OpenAL Util library instance */
  protected ALUT alut;
   
  /** OpenAL context */
  protected ALCcontext context;
   
  /** OpenAL device */
  protected ALCdevice device;  
   
  /**
   * Creates an instance of PlayTest
   */
  public PlayTest() {
    try {
           al      = new AL();
      alc     = new ALC();
      alut    = new ALUT();

      al.create();
      alc.create();
      alut.create();
   } catch (Exception e) {
      e.printStackTrace();
    }

  }
}

We need instances of the following classes:
1.3 OpenAL initialization
Now that we have created a basic class containing instances of the relevant OpenAL classes, lets start of by initializing OpenAL - that is create a device and a context:

  /**
   * Initializes OpenAL
   */
  protected void alInitialize() {     
    //get default device
    device = alc.openDevice(null);
       
    //create context (no attributes specified)
    context = alc.createContext(device, 0);
       
    //make context current
    alc.makeContextCurrent(context);
  }

Start of by opening a device using the openDevice method. openDevice takes a String as argument, containing the name of the device to open. If no name is supplied, the default device will be used (OpenAL currently doesn't support enumeration of devices available).

Having opened a device, create a context to that device using createContext. createContext takes two arguments: device to use and a list of attributes (see specification for list of attributes). Since we're going by default context, we just specify 0 for attributes.

Finish of by making the created context current. Do this by calling makeContextCurrent, supplying just created context as argument.

1.4 Buffer and Source creation
Now that we have opened a device and gotten a context, we need to create two things to actually get some sound. We need to create a buffer to hold sounddata, and a source that is to play the sounddata.
Lets start of by creating one source, and one buffer:

  //create one IntBuffer as buffer and one as source
  IntBuffer buffers = createIntBuffer(1);
  IntBuffer sources = createIntBuffer(1);

  //generate buffers and sources
  al.genBuffers(1, Sys.getDirectBufferAddress(buffers));
  al.genSources(1, Sys.getDirectBufferAddress(sources));

There, all set for actually loading some sounddata into the buffer.

1.5 Loading sounddata and setting up a buffer
Now that we have a buffer, we need to load some sound data into this buffer. This is done using the al.bufferData method. In our example we will cheat a bit, by using the ALUT method loadWAVFile to load a wave file, and copy this into the buffer:

  //load wave data
  ALUTLoadWAVData file = alut.loadWAVFile("myfile.wav");
        
  //copy to buffer
  al.bufferData(buffers.get(0), file.format, file.data, file.size, file.freq);
        
  //unload file again
  alut.unloadWAV(file.format, file.data, file.size, file.freq);        

Having loaded the data, we pass it to bufferData. Once the buffer has been filled with sounddata, we unload it from the system using alut.unloadWAV. Don't worry about deleting it this soon - the sounddata has been copied to the buffer.

1.6 Associating sources and buffers
To associate a source to a buffer we set the integer BUFFER attribute on the source, and assign it a value of the buffer to play:

  //set up source input
  al.sourcei(sources.get(0), AL.BUFFER, buffers.get(0));

1.7 Setting source properties
Having set up the source, it is time to set some attributes on the source - there are many that can be set, but in this example we only set the looping attribute to true by doing the following:

  //loop source
  al.sourcei(sources.get(0), AL.LOOPING, AL.TRUE);

1.8 Sound...
There, ready to play the sound, do this using the sourcePlay method of the AL class. to stop and pause use sourcePause and sourceStop respectively, and supply the source to affect:

  //play source 0
  al.sourcePlay(sources.get(0));
       
  //wait 5 secs
  try {
    System.out.println("Waiting 5 seconds for sound to complete");
    Thread.sleep(5000);
  } catch (InterruptedException inte) {
  }
       
  //stop source 0
  al.sourceStop(sources.get(0));

1.9 Cleaning up
Having had loads of fun playing a sound (!), it is now time to do some house chores. We need to clean up what we have created, this amounts to:
 - deleting source and buffer
 - deleting context
 - closing devce
as is shown here:

  //delete buffers and sources
  al.deleteSources(1, Sys.getDirectBufferAddress(sources));
  al.deleteBuffers(1, Sys.getDirectBufferAddress(buffers));
        
  //shutdown
  alc.makeContextCurrent(null);
  alc.destroyContext(context);
  alc.closeDevice(device);

There, all set. Now you should be able to play some basic sound!
This tutorial is rather short, and the above examples feature no error checking. For the complete source code, look at:
org.lwjgl.openal.BasicTest in the repository.