     START-INFO-DIR-ENTRY
     * OpenAL: (openal).         The Programmer's Guide to 3d Positional Audio
     END-INFO-DIR-ENTRY

OpenAL
******

This document describes the OpenAL API, design goals and Loki's OpenAL implementation.

Introduction
************

The idea behind OpenAL is a 3d positional spatialized sound library analogous to OpenGL: instead of micromanaging each aspect of sound playback and effect, the application writer may limit themselves to placing the sounds in the scene and letting the native OpenAL implementation determine the correct amount of pitch alteration, gain attenuation, phase shift, etc, required to render the sounds correctly.

That's the goal, anyway.

Here are some of the most Frequently Asked Questions, and their answers.

Configure openal with configure --enable-esd.  make, then install. Then, place the following in your ~/.openalrc file:

     	(define devices '(esd))

Dollars-to-donuts your driver doesn't implemented the select call properly.  You can see messages from native_blitbuffer complaining about select timeouts when this is a problem.

If you suffer from an unimplemented select call in your driver, put the following in your ~/.openalrc file:

     	(define native-use-select #f)

This will tell OpenAL that it shouldn't rely on select for information about when to write to a file descriptor.

Use alAttenuationScale_LOKI.  For more info, please see Built In.

Goals
*****

  * 3d audio

  * World Domination

  * Fame

  * Fortune

The OpenAL API
**************

This is the OpenAL API.  Sort of.

al calls, either implicitly or explicitly, act upon opaque objects of the kind Buffers, Sources, Contexts, or Listeners.  Of these types, the generation and deletion of Buffers, Sources, and Contexts are explicit and must be handled by the application.

To give a brief overview:

Buffers

     Buffers contain PCM audio data, and the parameters associated with the data (length, frequency, sample width etc).  Buffers cannot be played, a Source must be associated with them, and the Source is then played.

     Buffers are created with a call to alGenBuffers, which creates a set of buffer ids and binds them to buffers.  The buffer id is the only mechanism by which an application may refer to a buffer.  After its useful lifetime is over, buffer ids should be deleted via the call alDeleteBuffers.

Sources

     Sources are independent objects, which, when played, make sound. Sources need to be associated with a Buffer before they can be played.

     Sources are created with a call to alGenSources, which creates a set of source ids and binds them to sources.  The source id is the only mechanism by which an application may refer to a source.  After its useful lifetime is over, source ids should be deleted via the call alDeleteSources.

Contexts

     A Context abstracts the audio device from the rest of the library (and the application).  You generally only need one.  Calling most al functions before creating a context via alcCreateContext will result in either an error or a segfault.

     When you're about to quit, call alcDestroyContext to destroy the context and don't make any other al calls.

OpenAL types
============

ALboolean
     OpenAL bool type.

ALbyte
     OpenAL 8bit signed byte.

ALubyte
     OpenAL 8bit unsigned byte.

ALshort
     OpenAL 16bit signed short integer type.

ALushort
     OpenAL 16bit unsigned short integer type.

ALuint
     OpenAL 32bit unsigned integer type.

ALint
     OpenAL 32bit signed integer type.

ALfloat
     OpenAL 32bit floating point type.

ALdouble
     OpenAL 64bit double point type.

ALsizei
     OpenAL 32bit type.

OpenAL main functions
=====================

Here are the al functions, grouped according to object they affect.

Listener functions

     Listener is the sample position for a given context.  The multi-channel (usually stereo) output stream generated by the mixer is parametrized by this Listener object: its position and velocity relative to Sources, within occluder and reflector geometry.

     void alListenerf( ALenum pname, ALfloat param )
          Listener Gain:  default 1.0f.

     void alListener3f( ALenum pname, ALfloat param1, ALfloat param2, ALfloat param3 )

          Listener Position. Listener Velocity.

     void alListenerfv( ALenum pname, ALfloat *param )
          Listener Position:        ALfloat[3]
          Listener Velocity:        ALfloat[3]
          Listener Orientation:     ALfloat[6]  (forward and up vector).

     void alGetListeneri( ALenum pname,  ALint *value )
          Retrieve listener integer parameter.

     void alGetListenerf( ALenum pname,  ALfloat *values )
          Retrieve listener float parameter.

     void alGetListenerfv( ALenum pname, ALfloat *values )
          Retrieve listener float vector parameter.

Source functions

     Source objects are by default localized. Sources take the PCM data provided in the specified Buffer, apply Source-specific modifications, and then submit them to be mixed according to spatial arrangement etc.

     void alGenSources( ALsizei n, ALuint* sources )

          Create Source objects.

     void alDeleteSources( ALsizei n, ALuint* sources )
          Delete Source objects.

     ALboolean alIsSource( ALuint sid )
          Verify a handle is a valid Source.

     void alSourcei( ALuint sid, ALenum param, ALint value )
          Set an integer parameter for a Source object.

     void alSourcef( ALuint sid, ALenum param, ALfloat value )
          Set an integer parameter for a Source object.

     void alSource3f( ALuint sid, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3)

          Set an 3 float parameter for a Source object.

     void alSourcefv( ALuint sid, ALenum param, ALfloat* values )
          Set a float vector parameter for a Source object.

     void alGetSourcei( ALuint sid,  ALenum pname, ALint* value )
          Get an integer parameter for a Source object.

     void alGetSourcef( ALuint sid,  ALenum pname, ALfloat* value )
          Get a float parameter for a Source object.

     void alGetSourcefv( ALuint sid, ALenum pname, ALfloat* values )
          Get a float vector parameter for a Source object.

     void alSourcePlayv( ALuint ns, ALuint *ids )
          Play a set of ns sources.

     void alSourceStopv( ALuint ns, ALuint *ids )
          Stop a set of ns sources.

     void alSourcePlay( ALuint sid )
          Activate a source, start replay.

     void alSourcePause( ALuint sid )
          Pause a source.

     void alSourceStop( ALuint sid )
          Stop a source, and reset its internal state to pre-Play.  To remove a Source completely, it has to be deleted following Stop, or before Play.

Buffers
     Buffer objects are storage space for sample data.  Buffers are referred to by Sources. There can be more than one Source using the same Buffer data. If Buffers have to be duplicated on a per-Source basis, the driver has to take care of allocation, copying, and deallocation as well as propagating buffer data changes.

     void alGenBuffers( ALsizei n, ALuint *samples )
          Buffer object generation.

     void alDeleteBuffers( ALsizei n, ALuint *samples )
          Buffer object destruction.

     ALboolean alIsBuffer( ALuint buffer )
          Buffer object query.

     void alBufferData( ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq )
          Specify the data to be filled into a buffer.

     ALsizei alBufferAppendData( ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq )

          Specify data to be filled into a looping buffer.  This takes the current position at the time of the call, and returns the number of samples written.

     void alGetBufferi( ALuint buffer, ALenum param, ALint *value )
          Query Buffer integer attribute.

     void alGetBufferf( ALuint buffer, ALenum param, ALfloat* value )
          Query Buffer float attribute.

Extension Support

     Extension support.

     ALboolean alIsExtensionPresent( const ALubyte* fname )

          Obtain the address of a function (usually an extension) with the name fname. All addresses are context-independent.

     void *alGetProcAddress( const ALubyte* fname )

          Obtain the address of a function (usually an extension) with the name fname. All addresses are context-independent.

     ALenum alGetEnumValue( const ALubyte* ename )

          Obtain the integer value of an enumeration (usually an extension) with the name ename.

Misc

     Misc functions that don't act directly upon an object and don't fit well anywhere else.

     OpenAL Maintenance Functions State Management and Query.

     void alEnable( ALenum capability )

          Renderer State management.

     void alDisable( ALenum capability )

          Renderer State management.

     ALboolean alIsEnabled( ALenum capability )

          Is capability enabled?

     void alHint( ALenum target, ALenum mode )
          Application preferences for driver performance choices.

     ALboolean alGetBoolean( ALenum param )
          State retrieval.

     ALint alGetInteger( ALenum param )
          State retrieval.

     ALfloat alGetFloat( ALenum param )
          State retrieval.

     ALdouble alGetDouble( ALenum param )
          State retrieval.

     void alGetBooleanv( ALenum param, ALboolean* data )
          State retrieval.

     void alGetIntegerv( ALenum param, ALint* data )
          State retrieval.

     void alGetFloatv( ALenum param, ALfloat* data )
          State retrieval.

     void alGetDoublev( ALenum param, ALdouble* data )

          State retrieval.

     const ALubyte *alGetString( ALenum param )
          Get string representation of param.

OpenAL context management functions
===================================

You can't do anything really good in OpenAL without creating at least one context.

void *alcCreateContext( ALint* attrlist )

     Create a context, returning a unique identifier for the context, or NULL on error.  If this is the first context created, it becomes the default context.

     attrlist is usually NULL, but you can pass it an integer array terminated by ALC_INVALID in alc enum / integer pairs:

          	int attrlist[] = { ALC_SYNC, AL_TRUE,
          			   ALC_SOURCES, 100,
          			   ALC_FREQUENCY, 44100,
          			   ALC_INVALID };

          	void *context = alcCreateContext(attrlist);

ALCenum alcMakeContextCurrent( ALvoid *alcHandle )

     There is no current context, as we can mix several active contexts. But al* calls only affect the current context.

void *alcUpdateContext( ALvoid *alcHandle )
     For synchronous operation (where the context specified by alcHandle was created using the ALC_SYNC context creation flag), this commits all the changes needed and writes the result to the audio backend.  In asynchronous operation, this is a NOP.

ALCenum alcDestroyContext( ALvoid *alcHandle )

     Destroy the context associated with alcHandle, freeing all associated memory.

ALCenum alcGetError( ALvoid );

     Get the last alc error set.

const ALubyte *alcGetErrorString(ALenum param);
     Get the string representation of the last alc error set.

OpenAL utility functions
========================

Description of OpenAL utility functions goes here.

OpenAL kludgey functions
========================

alkludge.h is a repository for stuff that need to either be discarded, rewritten, or thought out.  You should not rely on functions in alkludge.h, although it is unlikely that functions will be removed from it without some form of equivalent functionality being introduced in the regular library.

There are two types of errors in OpenAL: alc errors and al errors.  al errors are context specific and one deep.  Only the first occurring error will be recorded, subsequent errors will not be recorded.  Errors may be retrieved via the alGetError call, after which the error in the current context will be set to AL_NO_ERROR, and subsequent errors will again alter the context's error state.

alc errors are not context specific, and may be retrieved via the alcGetError call.  After a call to alcGetError, the context-global error variable is set to ALC_NO_ERROR.

Loki's high-quality implementation of the OpenAL API
****************************************************

While we may be a bit biased, we are partial to the Loki OpenAL implementation.  Loki's implementation is currently an all-software library with support for multiple filters, configuration, and extension support via plugins.

If you retrieve the library via cvs, be sure to run the autogen.sh script provided.  It will build configure and config.h.in.

After that, run configure with the options you want.  Run configure --help for available options.

Loki Openal Filters
*******************

The openal configuration file
*****************************

Users can give openal hints as to optimal defaults for various parameters via the openal configuration file.  The openal configuration file should be placed in either /etc or in one's home directory, being named openalrc in the first location or .openalrc in the second location.

The configuration language is meant to be lisp-like.  This does not mean that it supports lisp constructs, only that it looks something like lisp.  This hideous language is referred to within the openal sources as ALRC (for openAL Resource Configuration language).

ALRC supports a very small number of primitives required to give the user a very small amount of control over OpenAL.  Generally, the user can specific default values for things like listener position, source parameters, etc.

Primitives are responsible for evaluation their own arguments, unlike expressions or functions.  Therefore, an argument passed to a primitive may never be evaluated.

The primitives are:

and

          (and predicate-1 predicate-2 ... )

     Performs a logical and on parameters, using short circuit evaluation.  Evaluates to true if none of the parameters evaluate to false.

or

          (or predicate-1 predicate-2 ... )

     Performs a logical or on parameters, stopping at the first true evaluation.  Evaluates to true if any of the parameters evaluate to true.

define

          (define identifier value)

     define evaluates value, and if identifier is not already in the symbol table, creates a new symbol named identifier with the evaluated value.  If identifier is already defined, define sets it to the the evaluated value.

load-extension

          (load-extension "/absolute/pathname/plugin.so")

     load-extension informs openal of the presence of a plugin which conforms to the extension format described in see Making your own.

By setting certain variables, a user can change the behavior of OpenAL without resorting to wholesale recompilations.  Loki's OpenAL implementation respects on certain variables and checks for them. Usually, the values are used to set default values (such as the default gain for a source (usually 1.0).

There are some, but I haven't listed them here.

devices

     devices is a list of tokens (either strings or unquoted symbols) that OpenAL checks for in order to determine the sequence and types of devices that should be used to render audio to.

     The list of available devices at the time of this writing is:

     native   Standard OSS (/dev/dsp) backend on linux.
     sdl   Simple DirectMedia Layer backend.
     arts   aRTs backend
     esd   esound daemon backend.
     alsa   ALSA backend.
     waveout   WAVE file output.

     ...please note that this does not mean that the backends work without fail, but that support either is included or is planned.

     A typical invocation look like:

          (define devices '(sdl native))

     ...which indicates to OpenAL that it should try to render audio to the SDL backend (if available), and failing that to try the native audio method for the platform in question, which usually means using the OSS drivers and /dev/dsp.  If each device specified in devices fails, then the default behavior (native) is tried.  If that fails, OpenAL will return a NULL context.

Symbol values have associated type information.  Users should be acquainted with the following types in ALRC:

  * ALRC_INVALID

     This is the type of a value that is either false or for some reason invalid.  No evaluation or assignment should be attempted with this type.

  * ALRC_LIST

     This type contains other types.  If not quoted, it is evaluated as an expression with the first item specifying the function name, which is probably not what you want.

          '(0.0 0.0 0.0)          ; list which is not an expression
          (define blah 'blah) 	; list which is an expression

  * ALRC_SYMBOL

     Things which, when evaluated, are not themselves.

  * ALRC_INTEGER

     Integer numbers.

  * ALRC_FLOAT

     Floating point numbers.

  * ALRC_STRING

     A series of characters enclosed by '"'.

How to extend Loki's OpenAL
***************************

Loki's OpenAL implementation include some functions which are specific to the implementation.  These functions all have the suffix _LOKI to distinguish them.

In order to use these extensions, the application will need to query their existence via IsExtensionPresent, and then use GetProcAddress to resolve the address of the extension.  The result of GetProcAddress will need to be cast to the appropriate function type.

     Some of the Loki specific functionality is expressed in terms of Loki specific enumerate tokens passed to otherwise standard calls.

AL_BYTE_LOKI

     AL_BYTE_LOKI is used as a getter to alGetSourcei, and reports a source's position, in bytes, into the buffer, or -1 in the case of a non playing source.  There are no guarentees about the internal representation of data so the value returned using this token may not correspond with the equivilant offset in the user supplied data.

AL_SOURCE_LOOPING_LOKI

     AL_SOURCE_LOOPING_LOKI is used as a setter/getter to al{Get}Sourcei, and sets/gets the infinite loop flag on a source.

Here's a list of extensions which are built into the Loki OpenAL implementation.  The prefix is included in this section for clarify.

void alAttenuationScale_LOKI(ALfloat param)

     alAttenuationScale_LOKI scales the units of the simulation. Without a call to this function, it is very likely that your application will not sound correct.

     The default scaling factor in Loki's OpenAL is such that a listener placed at the origin will hear sounds attenuated until that point that the sounds are ALMAXDISTANCE units away.  ALMAXDISTANCE is an arbitrary constant defined when including AL/alkludge.h.

     It is almost assured that the default scaling factor will be incorrect for most applications.  That is why this call is so important.  Usage will generally follow:

                  /* create context, load data, and define some value radius
                   * to be the radius of your world simulation.
                   */

                  setScale = (void (*)(ALfloat ))
                                  alGetProcAddress("alAttenuationScale_LOKI");
                  if(setScale != NULL) {
                          setScale(radius / ALMAXDISTANCE);
                  }

     It is highly recommended you explicitly use this function, and do not assume that the default units will be useful to you.

ALfloat alcGetAudioChannel_LOKI(ALuint channel)

     alcGetAudioChannel_LOKI takes in a channel enumeration from the set AL_CHAN_MAIN_LOKI, AL_CHAN_PCM_LOKI, and AL_CHAN_CD_LOKI, and returns a normalized ALfloat, corresponding to the volume associated with the channel on whatever backend the library is using.

void alcSetAudioChannel_LOKI(ALuint channel, ALfloat volume)

     alcSetAudioChannel_LOKI takes a channel specification from the set AL_CHAN_MAIN_LOKI, AL_CHAN_PCM_LOKI, and AL_CHAN_CD_LOKI and a normalized volume, and sets the hardware channel associated with the channel argument to the volume (the volume mapped to the settings appropriate for the backend, that is).

void alMute_LOKI(ALvoid)

     alMute_LOKI returns nothing and takes no argument.  After a call to alMute_LOKI, the implementation ceased all audio output, while still updating state (so sources still play, you just can't hear them). The audio setting is preserved so that a subsequent call to alUnMute_LOKI will restore the volume to its value prior to the alMute_LOKI call.

     This isn't really useful, as you can do the same with by just querying and setting the listener gain.

void alUnMute_LOKI(ALvoid)

     alUnMute_LOKI performs the inverse operation of alMute_LOKI.  alUnMute_LOKI restores the volume of the simulation to that which is was before calling alMute_LOKI.

void alReverbScale_LOKI(ALuint sid, ALfloat param)

     alReverbScale_LOKI allows you to set a normalized value param, which represents the gain that is used when reverberating.  Don't use it.  It will be removed as soon as the IASIG extension is completed.

void alReverbDelay_LOKI(ALuint sid, ALfloat param)

     alReverbScale_LOKI allows you to set the delay associated with a reverberating source.  Don't use this.  It will be removed as soon as the IASIG extension is completed.

ALboolean alBufferPitchHack_LOKI(ALuint bid, ALfloat pitch)
     Don't use this.  You don't want it.

ALboolean alutBufferAndConvertData_LOKI(ALuint bid, void *data,
     ALboolean should_use, ALuint size)

     alutBufferAndConvertData_LOKI is like alBufferData, but it infers the format / frequency information from the data itself.  This is useful for when the application is handed a chunk of data that it would like to use for a buffer, but cannot readily determine the type of data.

     alutBufferAndConvertData_LOKI accepts data in the form of entire sound files, in their native format.  It does not accept raw PCM data. The should_use argument is used to inform OpenAL that the data in question should be used, as opposed to OpenAL making a copy.  I don't suggest you even set it to AL_TRUE.

     alutBufferAndConvertData_LOKI returns AL_TRUE when the conversion and alBufferData was successful, AL_FALSE otherwise.  Unless you specify the should_use flag, in which case alutBufferAndConvertData_LOKI will return AL_FALSE in the additional case that it could not use the original data (ie, in-place conversion would be impossible without overflow).

void alBombOnError_LOKI(void)

     alBombOnError_LOKI, when called, will cause the implementation to abort on error, instead of just setting the per-context error and continuing.  This is useful only for debugging.  alc errors are not handled.

void alBufferSyncData_LOKI( ALuint bid, ALenum format, ALvoid *data,
     ALsizei size, ALsizei freq );

     alBufferSyncData_LOKI is like alBufferData, but will use the passed data instead of creating a copy.  Not recommended for general use.

void alBufferi_LOKI( ALuint bid, ALenum param, ALint value )

     alBufferi_LOKI can be used to set a buffer's attributes.  Not recommended unless you know what you're doing.  Usually, you can use this to enable a "multichannel" buffer.

void alBufferDataWithCallback_LOKI( ALuint bid, ALint (*callback)(ALuint sid, ALuint bid, ALshort *data, ALenum format, ALuint samples))

     alBufferDataWithCallback_LOKI can be used to specify that the buffer bid should, instead of using a static chunk of data specified by alBufferData, call the callback callback to fill a chunk of data as needed.

     The parameters for callback are as such:

          	ALuint sid
          	The source id that this request is associated with.  Since many
          	sources may share the same buffer, this sid allows the application
          	to keep track of offsets and other state associated with each
          	source instance.

          	ALuint bid
          	The buffer id that the callback is associated with.

          	ALshort *data
          	The memory area that the callback should populate

          	ALenum format
          	The format the the output data should be in.

          	ALuint samples
          	The number of samples required.

It is possible to extend the functionality of Loki's implementation of OpenAL via plugins (combined with some configuration mojo).

"Plugins" are actually just shared libraries which contain, as an available symbol, a table which contains function name/address pairs. Code necessary for library initialization and exit should be placed in _init, _fini as described in dlopen(3).

The table containing the function name/address pairs should correspond to the following format:

     struct {
             ALubyte *name;
             void *addr;
     } alExtension_03282000 [] = {
         { "alutLoadGIF", (void *) alutLoadGIF },
         { NULL, NULL }
     };

Right now, the end { NULL, NULL } pair is needed, and the table needs to be named alExtension_03282000.  This format is likely to change in the future, in order to avoid a badly written plugin from crashing each application linked against openal.

In order to take advantage of the extension, openal will have to be informed of its location via the configuration file see Configuration.

To avoid potential compatibility problems with initialization code, Loki's OpenAL implementation checks for the presence of the functions alExtInit_03282000 and alExtFini_03282000.  These functions are executed at dlopen and dlclose time, respectively.

Includes and typedefs
=====================

Basics
======

Getting Symbol Information
==========================

Adding Filters
==============

OpenAL examples
***************

Here are some examples.

Trivial Example
===============

     #include <AL/al.h>
     #include <AL/alc.h>
     #include <AL/alkludge.h>
     #include <AL/alut.h>

     #include <time.h>
     #include <stdio.h>
     #include <stdlib.h>
     #include <sys/time.h>
     #include <sys/types.h>
     #include <unistd.h>

     #define DATABUFFERSIZE (10 * (512 * 3) * 1024)

     static void iterate(void);
     static void init(void);
     static void cleanup(void);

     static ALuint moving_source = 0;

     static time_t start;
     static void *data = (void *) 0xDEADBEEF;

     static void *context_id;

     static void iterate( void ) {
             /* sleep for a bit */
             micro_sleep(500000);
     }

     static void init( void ) {
             FILE *fh;
             ALfloat zeroes[] = { 0.0f, 0.0f,  0.0f };
             ALfloat back[]   = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
             ALfloat front[]  = { 0.0f, 0.0f,  1.0f, 0.0f, 1.0f, 0.0f };
             ALuint stereo;
             ALsizei size;
             ALsizei bits;
             ALsizei freq;
             ALsizei format;
             int filelen;

             data = malloc(DATABUFFERSIZE);

             alListenerfv(AL_POSITION, zeroes );
             alListenerfv(AL_ORIENTATION, front );

             alGenBuffers( 1, &stereo);

             fh = fopen("sample.wav", "rb");
             if(fh == NULL) {
                     fprintf(stderr, "Couldn't open sample.wav\n");
                     exit(1);
             }

             filelen = fread(data, 1, DATABUFFERSIZE, fh);
             fclose(fh);

             talutBufferAndConvertData(stereo, data, AL_TRUE, filelen);

             alGenSources(1, &moving_source);

             alSource3f( moving_source, AL_POSITION, 0.0, 0.0, 4.0 );
             alSourcefv( moving_source, AL_VELOCITY, zeroes );
             alSourcei(  moving_source, AL_BUFFER, stereo );
             alSourcei(  moving_source, AL_SOURCE_LOOPING, AL_FALSE);

             /* Scale world to 0.7 * ALMAXDISTANCE */
             talAttenuationScale(0.7);

             return;
     }

     static void cleanup(void) {
             free(data);
             alcDestroyContext(context_id);
     }

     int main( int argc, char* argv[] ) {
             int attrlist[] = { ALC_FREQUENCY, 22050,
                                ALC_INVALID };
             time_t shouldend;
             ALint state = AL_INITIAL;

             /* Initialize ALUT. */
             context_id = alcCreateContext(attrlist);
             if(context_id == NULL) {
                     return 1;
             }

             /*
              * Setup LOKI extensions
              */
             fixup_function_pointers();

             init( );

             alSourcePlay( moving_source );
             do {
                     iterate();

                     shouldend = time(NULL);
                     if((shouldend - start) > 10) {
                             /* After 10 seconds, we end */
                             alSourceStop(moving_source);
                     }

                     alSourcei(moving_source, AL_SOURCE_STATE, &state);
             } while(state == AL_ACTIVE);

             cleanup();

             return 0;
     }

Error Handling
==============

Error Handling goes here.

Context Management
==================

Context Management goes here.

Panning
=======

Panning example goes here.

Positional
==========

Positional example goes here.

Doppler
=======

Doppler example goes here.

Reverb
======

     #include <AL/al.h>
     #include <AL/alc.h>
     #include <AL/alkludge.h>
     #include <AL/alut.h>

     #include <time.h>
     #include <stdio.h>
     #include <unistd.h>

     static void init( void );

     static ALuint reverb_sid = 0;

     static void *wave = NULL;

     static void init( void ) {
     	ALfloat zeroes[] = { 0.0f, 0.0f,  0.0f };
     	ALfloat back[]   = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
     	ALfloat front[]  = { 0.0f, 0.0f,  1.0f, 0.0f, 1.0f, 0.0f };
     	ALuint boom;
     	ALsizei size;
     	ALsizei bits;
     	ALsizei freq;
     	ALsizei format;

     	alListenerfv(AL_POSITION, zeroes );
     	alListenerfv(AL_VELOCITY, zeroes );
     	alListenerfv(AL_ORIENTATION, front );

             alGenBuffers( 1, &boom );

     	alutLoadWAV( "l2.wav", &wave, &format, &size, &bits, &freq);

     	alBufferData( boom, format, wave, size, freq );
     	free(wave); /* openal makes a local copy of wave data */

     	alGenSources( 1, &reverb_sid);

     	alSource3f(reverb_sid, AL_POSITION, 2.0, 0.0, 4.0);
     	alSourcefv(reverb_sid, AL_VELOCITY, zeroes);
     	alSourcefv(reverb_sid, AL_ORIENTATION, back);
     	alSourcei (reverb_sid, AL_BUFFER, boom);

     	alReverbScale(reverb_sid, 0.6);
     	alReverbDelay(reverb_sid, 0.3);

     	alAttenuationScale(0.3);
     }

     int main(int argc, char *argv[]) {
     	alutInit( &argc, argv );

     	init( );

     	alSourcePlay(reverb_sid);
     	sleep(10);

     	alutExit();

     	return 0;
     }

Streaming
=========

Support for streaming sounds rises from the API specification surrounding alBufferAppendData.  Streaming sources are understood to be sources whose AL_BUFFER parameter is a streaming buffer.  A streaming buffer is a buffer created by a call to alGenStreamingBuffer, and can only be fed data using alBufferAppendData.

Streaming sources have restrictions associated with them, and for the time being require special creation procedures.  Further specifications may remove some of these restrictions, but until further notice streaming sources will always be synchronized, and some of the filters may not apply to them.

     insert code example

Foo!