OpenAL: Bindings for the OpenAL sound library
This library provides low-level bindings for the OpenAL sound library.
Because these bindings are low-level, you may want to look at the
OpenAL Programmer’s Guide to get a sense of how it works.
1 Example: Playing sound from a raw buffer
In this example, we play an 8-bit sine wave generated from a
bytestring.
First, we must open the sound device and create a context for it:
Once we have a device context, we must create a buffer to hold our
sound data.
In this example, each unsigned byte of sinewave is a separate
8-bit sound sample. Realistically, a real-world application would want
to use 16-bit samples, but this grainy, ugly example is fine for us.
Once our data is safe in an OpenAL buffer, we make a source and play
it. Note that OpenAL internally copies that data – we are free to mutate it however we like after the call to buffer-data.
OpenAL allows us to define several simultaneously playing sources.
Though a single source can only have one buffer, note that a buffer
can be bound to several sources at the same time to save space.
Now that we have a source and a sound buffer to play, we can set our
source to play the data from the sound buffer.
OpenAL uses a separate OS-level thread to play sounds. The
play-source call will exit instantly and our sound will
continue to play in the background until we choose to stop it.
2 Constants
All constants defined in al.h and alc.h are re-exported
under their usual names. See the OpenAL Programmer’s Guide for
information about what each constant means.
3 Device and context management
With OpenAL, we must manage our own devices and our device contexts.
It’s good practice to close all devices at the end of your program –
some platforms may get confused.
Opens an OpenAL device. Pass #f to just use the default device.
Closes an OpenAL device.
Creates an OpenAL device context using a device. You must use
set-current-context to make it active.
Sets the context to be the current context for the device.
You must do this before you can play any sound.
Returns the current device context.
Returns the device that the given context applies to.
Removes context from the device. Do not play any sounds after
using this without reinstating another device context.
Returns (and clears) OpenAL’s last error. Will be 0 if there are no errors.
4 Buffers
OpenAL buffers hold sound data. They are kept in completely separate
memory outside Racket’s garbage collection pool, so you must free
buffers yourself when you’re finished with them to avoid memory leaks.
Generates num buffers, and returns a list of the buffer IDs.
Once you have a buffer, you must load data with buffer-data,
bind it to a source with set-source-buffer!, and then play
the source with play-source. See the Example: Playing sound from a raw buffer section.
Deletes the given buffers. Do not attempt to modify them
after calling this function.
Returns whether buffer is an OpenAL buffer.
Loads the data in data to the given buffer with ID
bufid.
Format should be an OpenAL constant signifying the format of the
samples in data. For 8-bit formats, a value of 128 means no
DC offset, with 0 and 255 being the extreme DC offsets. For 16-bit
formats, samples are signed little-endian 16-bit integers. Stereo
formats include interleaved samples, left first.
The frequency of the data is how many samples per second the
source should play, usually 44100.
Note that data is automatically copied, not referenced – you
can reuse or mutate data however you like after this call.
4.1 Buffer properties
4.1.1 C-level buffer getters and setters
Sets the given param of the given buffer to the given value.
Sets the given param of the given buffer to the given values.
Sets the given param of the given buffer to the given values.
Sets the given param of the given buffer to the given value.
Sets the given param of the given buffer to the given values.
Sets the given param of the given buffer to the given values.
Gets the given param of the given buffer.
Gets the given param of the given buffer.
Gets the given param of the given buffer.
Gets the given param of the given buffer.
Gets the given param of the given buffer.
Gets the given param of the given buffer.
4.1.2 Friendly buffer getters and setters
Retrieves the given buffer’s frequency, in Hz.
Retrieves the given buffer’s bit depth.
Retrieves the number of channels in buffer – 1 for mono, 2
for stereo.
Retrieves the size of the buffer in bytes.
5 Sources
Sources are actual playing sounds in the world. Each source can either
be bound to a single buffer or can contain a buffer queue that
continuously streams sound data.
Sources have a 3D position and velocity in space. This means that
OpenAL can optionally apply certain effects such as attenuation
(softening far-away sounds) and pitch shifting (the doppler effect).
Generates a list of
num-sources. Note that these will not
be garbage-collected; you are responsible for freeing them yourself
with
delete-sources!Stops and removes the listed sources. Do not attempt to
use them after calling this function.
Begins playing the
source. Note that this function does not
block – playback occurs in a separate OS-level thread. Use
source-source-state to see whether a source is finished
playing.
Stops playing the source.
Stops the
source. Like
pause-source, but this
function rewinds it back to the beginning of its buffer.
Like
stop-source, but additionally sets the source’s state to
AL_INITIAL. Your program can use this property to distinguish
between sources that played and ended normally versus sources that
stopped because of this function.
5.1 Source properties
These bindings define two “levels” of functions that set and
retrieve properties. First, there are the low-level “C-like”
functions like alSourcef that allow you to get and set
individual properties of sources defined by an OpenAL constant.
Alternatively, there are the friendlier functions like
set-source-looping! that offer a simpler interface for
setting the same properties.
5.1.1 C-like source getters and setters
Sets the given param of the given source to the given value.
Sets the given param of the given source to the given values.
Sets the given param of the given source to the given values.
Sets the given param of the given source to the given value.
Sets the given param of the given source to the given values.
Sets the given param of the given source to the given values.
Gets the given param of the given source.
Gets the given param of the given source.
Gets the given param of the given source.
Gets the given param of the given source.
Gets the given param of the given source.
Gets the given param of the given source.
5.1.2 Friendly source getters and setters
Gets or sets the source’s pitch, a number greater
than 0. The default is 1.0. A value of 2.0 will make the
sound play twice as fast and one octave higher; a value of 0.5 will make
the sound go twice as slow and one octave lower.
Gets or sets the
source’s gain (volume), a number greater
than 0. The default is 1.0. Note that values higher than 1 may cause
clipping. Gain can also be set globally with
set-listener-gain!
}
Gets or sets the rolloff rate of the source. See the
Distance models section for more details.
Gets or sets the source’s reference distance, used for calculating the
gain. See the
Distance models section for more details.
Gets or sets the source’s minimum and maximum gain and distance. See the
Distance models section for more details.
Gets or sets the source’s position, velocity, and direction in 3D space.
Sets whether the source’s position is relative to the listener or an
absolute position.
Gets or sets whether buffered sources should loop back to the
beginning of the buffer upon completion. May misbehave on streaming sources.
Binds a source to a given buffer. This does not begin to play the
source yet – use
play-source to start.
If you want to build a streaming buffer, don’t use
set-source-buffer! or else it may misbehave. You can,
however, clear any queued buffers by running
(set-source-buffer! source 0).
For streaming sources, returns how many buffers are in the source’s
buffer queue. Includes both processed and yet-to-be-processed buffers.
For streaming sources, returns how many buffers in the source’s
buffer queue were processed.
Returns how many seconds the source is in its buffer.
Returns how many samples the source is in its buffer.
Returns how many bytes the source is in its buffer.
6 Listener properties
The listener is the single entity in the world that listens for sound
from all the sources. When the listener “hears” a source, it sends
the output to the current sound device. The volume is adjusted based
on the distance between the source and listener, and the sound’s pitch
is adjusted based on the velocity and orientation thanks to the
doppler effect.
6.1 C-like listener getters and setters
Sets the given param of the listener to the given value.
Sets the given param of the listener to the given values.
Sets the given param of the listener to the given values.
Sets the given param of the listener to the given value.
Sets the given param of the listener to the given values.
Sets the given param of the listener to the given values.
Gets the given param of the listener.
Gets the given param of the listener.
Gets the given param of the listener.
Gets the given param of the listener.
Gets the given param of the listener.
Gets the given param of the listener.
6.2 Friendly listener getters and setters
Gets and sets the global gain (master volume). Note that value
should be a number greater than 0, with 1.0 being the default, 0.5
being half as loud, and so forth. Beware – numbers greater than 1
may cause clipping.
Sets the listener’s position, velocity, and orientation in 3D space.
7 Streaming sound
Each source usually has one buffer attached to it. If this were the
only possible way of playing your sound, you would have to either load
the entire sound into memory (imagine loading 90 minutes of raw sample
data) or manage buffers yourselves, suffering through the inevitable
clicks and hisses when OpenAL drains the buffer just before you can
replace it.
Thankfully, OpenAL allows you to assign several buffers to a source
using a queue of buffer objects. The sound will continue to play as
long as there is a buffer left to play from. From time to time, your
program should un-queue old buffers, refill them, and queue them at
the end of the source’s queue.
You can either manage each source’s low-level buffer queue yourself or
use the higher-level port streaming facilities to stream sounds
straight from a Racket binary port.
If you intend to build a streaming source with a buffer queue, don’t
call set-source-buffer!. Likewise, don’t use this function if
you only want an ordinary source backed by a single buffer.
Begins a background thread that streams the binary bytes from
port to the given OpenAL source. This function does
not block.
Every poll-interval seconds, the background thread will
ensure that the source has num-buffers unprocessed
buffers of at most buffer-size bytes each, and the thread
will refill processed buffers as necessary to ensure gapless playback.
The port should yield bytes suitable for OpenAL playback,
with the given format, and sample rate of frequency
(typically 44100).
Just after the last buffer is queued, the thread will run the
at-end-of-loop procedure which returns #t if the
thread should continue or #f if it should stop once the last
buffer finishes. You might use the at-end-of-loop function to
seek the port back to the beginning of the file to seamlessly start
playing back at the beginning of the file when reaching the end.
The thread will run the cleanup function just before exiting.
Use this function to delete the allocated source, close the port, or
perhaps to transition to a different screen in your application. Note
that this may run up to poll-interval seconds after the sound
actually finishes.
If you want to terminate the thread early, just run
kill-thread on it. Cleanup will be run automatically.
8 Distance models
OpenAL defines several models that select how sound is attenuated
(softened) over distance.
Sets the OpenAL distance model.
gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + |
AL_ROLLOFF_FACTOR * |
(distance – AL_REFERENCE_DISTANCE)); |
Similarly, the Inverse Clamped Distance model works with this formula:
distance = max(distance,AL_REFERENCE_DISTANCE); |
distance = min(distance,AL_MAX_DISTANCE); |
gain = AL_REFERENCE_DISTANCE / (AL_REFERENCE_DISTANCE + |
AL_ROLLOFF_FACTOR * |
(distance – AL_REFERENCE_DISTANCE)); |
By contrast, the Linear Distance Model works according to the
following formula:
distance = min(distance, AL_MAX_DISTANCE) // avoid negative gain |
gain = (1 – AL_ROLLOFF_FACTOR * (distance – |
AL_REFERENCE_DISTANCE) / |
(AL_MAX_DISTANCE – AL_REFERENCE_DISTANCE)) |
And the Clamped Linear Distance Model works according to this formula:
distance = max(distance, AL_REFERENCE_DISTANCE) |
distance = min(distance, AL_MAX_DISTANCE) |
gain = (1 – AL_ROLLOFF_FACTOR * (distance – |
AL_REFERENCE_DISTANCE) / |
(AL_MAX_DISTANCE – AL_REFERENCE_DISTANCE)) |
The Exponential Distance Model works like this:
gain = (distance / AL_REFERENCE_DISTANCE) ^ |
(- AL_ROLLOFF_FACTOR) |
The Clamped Exponential Distance model works like this:
distance = max(distance, AL_REFERENCE_DISTANCE) |
distance = min(distance, AL_MAX_DISTANCE) |
gain = (distance / AL_REFERENCE_DISTANCE) ^ |
(- AL_ROLLOFF_FACTOR) |
Without any distance model, the gain remains fixed at 1.
Sets the doppler factor. The default is 1.0. Use this to accentuate or
reduce the doppler effect.
Sets the speed of sound for doppler effect calculations. The default
is 343.3, which is good for units of meters and air as the propagation
medium. Note that this does not delay sounds, OpenAL only uses this to
calculate the doppler effect.