8.18
top
← prev up next →

OpenAL: Bindings for the OpenAL sound libraryπŸ”— i

gcr

libopenal-racket is a fork of (planet gcr/openal). 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.

1Example: Playing sound from a raw bufferπŸ”— i

In this example, we play an 8-bit sine wave generated from a bytestring.

(require libopenal-racket)
 
;;Oursounddata
(define sinewave
(for/list ([i(in-range 0(* 2pi )0.07)])
(+ 128
(* (sin i)64)))))))

First, we must open the sound device and create a context for it:

;;InitializeOpenAL(seetheOpenALguide)
(define device(open-device #f))
(define context(create-context device))

Once we have a device context, we must create a buffer to hold our sound data.

;;MakeourOpenALbuffer
(define buffer(car (gen-buffers 1)))
;;Copythebytestothisbuffer
(buffer-data buffer
sinewave
44100)

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 .

;;MakeourOpenALsource
(define source(car (gen-sources 1)))
 
;;Bindourbuffertothesource--8-bitmono
(set-source-buffer! sourcebuffer)

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.

;;Loopforever(withoutthis,thesourcewillplayjustonceandthenstop)
 
;;Startplaying
(play-source source)

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.

;;Waituntilwe'refisishedplaying
(sleep 5)
 
;;Cleanup
(delete-sources! (list source))
(delete-buffers! (list buffer))
(destroy-context! context)
(close-device! device)

2Example: Playing OGG Vorbis FilesπŸ”— i

OpenAL works great with the (planet gcr/libvorbisfile) package, and this is no accident. This example shows you how to stream a vorbis file straight to an OpenAL source without loading it into a buffer like we did above.

First, we must dig out the spellbook and incant the OpenAL Summoning Mantra:

(require libopenal-racket
(planet gcr/libvorbisfile))
 
;;InitializeOpenAL(seethedocsforlibopenal-racket)
(define device(open-device #f))
(define context(create-context device))

From here, it’s not rocket science to open a vorbis file and query basic information about it.

(define filename"/home/gcr/Music/Lights/Siberia/11FluxandFlow.ogg")
(printf "Playingfile~a\n"filename)
 
(define m(open-vorbis-filefilename))

To read the sound data, we use libvorbisfile’s make-vorbis-input-port function to create a port that decodes the sound data into binary bytes on-demand.

;;ToreadthePCMsamples,wemakeaportthatsuppliesuswith
;;thebinarydecompresseddata.
(define vorbis-binary(make-vorbis-input-portm021))
;;OpenALexpects:
;;0(Little-endian)
;;2(Wordsize;16bits)
;;1(Signed)

Now that we have a port that gives us raw sample data, we can stream it straight to an OpenAL source. This avoids reading the entire file into memory – each block of sound is decoded right as it’s needed.

;;MakeourOpenALsource
(define source(car (gen-sources 1)))
 
;;Startstreaming
(define stream-thread
(stream-port-to-source vorbis-binary
source
(vorbis-frequencym)))
 
;;Startplaying
(play-source source)
 
;;OpenAL'sstream-port-to-sourcereturnsathread,sowaituntilwe're
;;finishedplaying
(thread-wait stream-thread)

Once we’re done, we should clean up our OpenAL mess:

(destroy-context! context)
(close-device! device)

You should probably close the vorbis file when you’re finished.

(close-vorbis-file!m)

3ConstantsπŸ”— i

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.

4Device and context managementπŸ”— i

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.

procedure

( open-device devicename)any/c

devicename:(or/c string? #f)
Opens an OpenAL device. Pass #f to just use the default device.

procedure

( open-capture-device devicename
frequency
format
buffersize)any/c
devicename:(or/c string? #f)
frequency:integer?
buffersize:integer?
Opens an OpenAL capture device. Pass #f to just use the default device.

frequency is the frequency at which the device should record, usually 44100.

format is the requested capture buffer format.

buffersize is the size of the capture buffer.

procedure

( close-device! device)boolean?

device:any/c
Closes an OpenAL device.

procedure

( close-capture-device! device)boolean?

device:any/c
Closes an OpenAL capture device.

procedure

( create-context device)any/c

device:any/c
Creates an OpenAL device context using a device. You must use set-current-context to make it active.

procedure

( set-current-context context)any/c

context:any/c
Sets the context to be the current context for the device. You must do this before you can play any sound.

procedure

( get-current-context )any/c

Returns the current device context.

procedure

( get-device-from-context context)any/c

context:any/c
Returns the device that the given context applies to.

procedure

( destroy-context! context)any/c

context:any/c
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.

procedure

( start-capture device)void?

device:any/c
Begin a capture operation using device.

procedure

( stop-capture device)void?

device:any/c
Stop a capture operation on device.

procedure

( capture-samples devicebuffersamples)void?

device:any/c
buffer:bytes?
samples:integer?
Complete a capture operation, this does not block.

5BuffersπŸ”— i

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.

procedure

( gen-buffers num)(listof exact-integer? )

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.

procedure

( delete-buffers! buffers)any/c

Deletes the given buffers. Do not attempt to modify them after calling this function.

procedure

( buffer? buffer)boolean?

Returns whether buffer is an OpenAL buffer.

procedure

( buffer-data bufidformatdatafrequency)any/c

data:bytes?
frequency:exact-integer?
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.

5.1Buffer propertiesπŸ”— i

5.1.1C-level buffer getters and settersπŸ”— i

procedure

( alBufferf bufferparamvalue)any/c

value:real?
Sets the given param of the given buffer to the given value.

procedure

( alBuffer3f bufferparamvalue1value2value3)any/c

value1:real?
value2:real?
value3:real?
Sets the given param of the given buffer to the given values.

procedure

( alBufferfv bufferparamvalues)any/c

values:(listof real? )
Sets the given param of the given buffer to the given values.

procedure

( alBufferi bufferparamvalue)any/c

Sets the given param of the given buffer to the given value.

procedure

( alBuffer3i bufferparamvalue1value2value3)any/c

Sets the given param of the given buffer to the given values.

procedure

( alBufferiv bufferparamvalues)any/c

Sets the given param of the given buffer to the given values.

procedure

( alGetBufferf bufferparam)real?

Gets the given param of the given buffer.

procedure

( alGetBuffer3f bufferparam)(list/c real? real? real? )

Gets the given param of the given buffer.

procedure

( alGetBufferfv bufferparam)(listof real? )

Gets the given param of the given buffer.

procedure

( alGetBufferi bufferparam)exact-integer?

Gets the given param of the given buffer.

Gets the given param of the given buffer.

procedure

( alGetBufferiv bufferparam)(listof exact-integer? )

Gets the given param of the given buffer.

5.1.2Friendly buffer getters and settersπŸ”— i

procedure

( buffer-frequency buffer)exact-integer?

Retrieves the given buffer’s frequency, in Hz.

procedure

( buffer-bits buffer)exact-integer?

Retrieves the given buffer’s bit depth.

procedure

( buffer-channels buffer)exact-integer?

Retrieves the number of channels in buffer – 1 for mono, 2 for stereo.

procedure

( buffer-size buffer)exact-integer?

Retrieves the size of the buffer in bytes.

6SourcesπŸ”— i

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).

procedure

( gen-sources num-sources)(listof exact-integer? )

num-sources:exact-integer?
Generates a list of num-sources. Note that these will not be garbage-collected; you are responsible for freeing them yourself with delete-sources!

procedure

( delete-sources! sources)any/c

Stops and removes the listed sources. Do not attempt to use them after calling this function.

procedure

( play-source source)any/c

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.

procedure

( pause-source source)any/c

Stops playing the source.

procedure

( stop-source source)any/c

Stops the source. Like pause-source , but this function rewinds it back to the beginning of its buffer.

procedure

( rewind-source source)any/c

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.

6.1Source propertiesπŸ”— i

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.

6.1.1C-like source getters and settersπŸ”— i

procedure

( alSourcef sourceparamvalue)any/c

value:real?
Sets the given param of the given source to the given value.

procedure

( alSource3f sourceparamvalue1value2value3)any/c

value1:real?
value2:real?
value3:real?
Sets the given param of the given source to the given values.

procedure

( alSourcefv sourceparamvalues)any/c

values:(listof real? )
Sets the given param of the given source to the given values.

procedure

( alSourcei sourceparamvalue)any/c

Sets the given param of the given source to the given value.

procedure

( alSource3i sourceparamvalue1value2value3)any/c

Sets the given param of the given source to the given values.

procedure

( alSourceiv sourceparamvalues)any/c

Sets the given param of the given source to the given values.

procedure

( alGetSourcef sourceparam)real?

Gets the given param of the given source.

procedure

( alGetSource3f sourceparam)(list/c real? real? real? )

Gets the given param of the given source.

procedure

( alGetSourcefv sourceparam)(listof real? )

Gets the given param of the given source.

procedure

( alGetSourcei sourceparam)exact-integer?

Gets the given param of the given source.

Gets the given param of the given source.

procedure

( alGetSourceiv sourceparam)(listof exact-integer? )

Gets the given param of the given source.

6.1.2Friendly source getters and settersπŸ”— i

procedure

( set-source-pitch! sourcevalue)any/c

value:real?

procedure

( source-pitch source)real?

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.

procedure

( set-source-gain! sourcevalue)any/c

value:real?

procedure

( source-gain source)real?

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! }

procedure

( set-source-rolloff-factor! sourcevalue)any/c

value:real?

procedure

( source-rolloff-factor source)real?

Gets or sets the rolloff rate of the source. See the Distance models section for more details.

procedure

value)any/c
value:real?

procedure

( source-reference-distance source)real?

Gets or sets the source’s reference distance, used for calculating the gain. See the Distance models section for more details.

procedure

( set-source-min-gain! sourcevalue)any/c

value:real?

procedure

( source-min-gain source)real?

procedure

( set-source-max-gain! sourcevalue)any/c

value:real?

procedure

( source-max-gain source)real?

procedure

( set-source-max-distance! sourcevalue)any/c

value:real?

procedure

( source-max-distance source)real?

Gets or sets the source’s minimum and maximum gain and distance. See the Distance models section for more details.

procedure

( set-source-cone-outer-gain! sourcevalue)any/c

value:real?

procedure

( source-cone-outer-gain source)real?

procedure

( set-source-cone-inner-angle! sourcevalue)any/c

value:real?

procedure

( source-cone-inner-angle source)real?

procedure

( set-source-cone-outer-angle! sourcevalue)any/c

value:real?

procedure

( source-cone-outer-angle source)real?

Gets or sets the parameters of an oriented sound cone around the source. See the OpenAL Programmer’s Guide

procedure

( set-source-position! sourcexyz)any/c

x:real?
y:real?
z:real?

procedure

( source-position source)(list/c real? real? real? )

procedure

( set-source-direction! sourcexyz)any/c

x:real?
y:real?
z:real?

procedure

( source-direction source)(list/c real? real? real? )

procedure

( set-source-velocity! sourcexyz)any/c

x:real?
y:real?
z:real?

procedure

( source-velocity source)(list/c real? real? real? )

Gets or sets the source’s position, velocity, and direction in 3D space.

procedure

( set-source-source-relative! sourcevalue)any/c

value:(or/c 01)

procedure

( source-source-relative source)(or/c 01)

Sets whether the source’s position is relative to the listener or an absolute position.

Returns the source’s type – AL_STATIC for buffered sources, AL_STREAMING for sources with buffer queues, and AL_UNDETERMINED for sources with unknown type.

procedure

( set-source-looping! sourcevalue)any/c

value:(or/c 01)

procedure

( source-looping source)(or/c 01)

Gets or sets whether buffered sources should loop back to the beginning of the buffer upon completion. May misbehave on streaming sources.

procedure

( set-source-buffer! sourcebuffer)any/c

procedure

( source-buffer source)exact-integer

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! source0).

Returns the state of a source. Use play-source , stop-source , pause-source to change.
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.

procedure

( source-sec-offset source)real?

Returns how many seconds the source is in its buffer.

procedure

( source-sample-offset source)exact-integer?

Returns how many samples the source is in its buffer.

procedure

( source-byte-offset source)exact-integer?

Returns how many bytes the source is in its buffer.

7Listener propertiesπŸ”— i

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.

7.1C-like listener getters and settersπŸ”— i

procedure

( alListenerf paramvalue)any/c

value:real?
Sets the given param of the listener to the given value.

procedure

( alListener3f paramvalue1value2value3)any/c

value1:real?
value2:real?
value3:real?
Sets the given param of the listener to the given values.

procedure

( alListenerfv paramvalues)any/c

values:(listof real? )
Sets the given param of the listener to the given values.

procedure

( alListeneri paramvalue)any/c

Sets the given param of the listener to the given value.

procedure

( alListener3i paramvalue1value2value3)any/c

Sets the given param of the listener to the given values.

procedure

( alListeneriv paramvalues)any/c

Sets the given param of the listener to the given values.

procedure

( alGetListenerf param)real?

Gets the given param of the listener.

procedure

( alGetListener3f param)(list/c real? real? real? )

Gets the given param of the listener.

procedure

( alGetListenerfv param)(listof real? )

Gets the given param of the listener.

procedure

( alGetListeneri param)exact-integer?

Gets the given param of the listener.

Gets the given param of the listener.

procedure

( alGetListeneriv param)(listof exact-integer? )

Gets the given param of the listener.

7.2Friendly listener getters and settersπŸ”— i

procedure

( set-listener-gain! value)any/c

value:real?

procedure

( listener-gain )real?

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.

8Streaming soundπŸ”— i

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.

procedure

( source-queue-buffers! sourcebuffers)any/c

buffers:(listof/cexact-integer? )
Adds the given buffers to the end of the source’s buffer queue. You can check how many buffers are on the queue with source-buffers-queued and find how many buffers finished playing with source-buffers-processed .

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.

procedure

( source-unqueue-buffers! sourcebuffers)any/c

buffers:(listof/cexact-integer? )
Removes the given buffers from source’s buffer queue. You can check how many buffers are on the queue with source-buffers-queued , and you can see how many buffers finished playing with source-buffers-processed .

procedure

source
format
frequency
[ at-end-of-loop
num-buffers
buffer-size
poll-interval
cleanup])thread?
port:port?
frequency:exact-integer?
at-end-of-loop:(-> boolean? )=(λ ()#f)
num-buffers:exact-integer? =5
buffer-size:exact-integer? =(* 40968)
poll-interval:real? =0.1
cleanup:(-> any/c )=(λ ()(void ))
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.

9Distance modelsπŸ”— i

OpenAL defines several models that select how sound is attenuated (softened) over distance.

Sets the OpenAL distance model.

According to the OpenAL Programmer’s Guide, the inverse distance model works with this formula:

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.

procedure

( set-doppler-factor! value)any/c

value:real?
Sets the doppler factor. The default is 1.0. Use this to accentuate or reduce the doppler effect.

procedure

( set-speed-of-sound! value)any/c

value:real?
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.

10LicenseπŸ”— i

The code in this package and this documentation is under the zlib license, reproduced below. Keep in mind that OpenAL itself has many different implementations – some of which are proprietary to Creative Labs and some of which LGPL-licensed.

Copyright (c) 2012 gcr

This software is provided 'as-is', without any express or implied

warranty. In no event will the authors be held liable for any damages

arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,

including commercial applications, and to alter it and redistribute it

freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not

claim that you wrote the original software. If you use this software

in a product, an acknowledgment in the product documentation would be

appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be

misrepresented as being the original software.

3. This notice may not be removed or altered from any source

distribution.

top
← prev up next →

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /