/****************************************************************************
PROGRAM: audioenv.cpp
DESCRIPTION: audio object class code
****************************************************************************/
#include "audioenv.h"
// constructor
AudioEnv::AudioEnv ()
{
nextBuffer = 0;
nextSource = 0;
}
// destructor
AudioEnv::~AudioEnv ()
{
}
// init
void AudioEnv::Init ()
{
/* tsao:
alutInit, or alcCreateContext, is required to initialize the
OpenAL library. As the alut functions are not well specified at
the moment, it is probably better form to use the following
initialization technique:
void *context_id = alcCreateContext(NULL);
if(context_id == NULL) {
return;
}
alcMakeContextCurrent(context_id);
As you can see, alutInit provides no provision for reporting a
failed initialization, and for this reason alone it's not as
robust as the technique described above.
*/
#ifdef ALFUNCTIONS
alutInit (NULL, 0); // init OpenAL
#endif
}
// init
void AudioEnv::ListenerPosition (ALfloat* position, ALfloat* angle)
{
/* tsao:
alListenerfv is used to set those Listener attributes which take
a float vector form. These include position, orientation, and
velocity.
The Listener in OpenAL is the person who hears things. By
changing the Listener's position and orientation, the application
essentially places the user in the scene created by the other
calls.
*/
alListenerfv(AL_POSITION, position);
alListenerfv(AL_ORIENTATION, angle);
}
// LoadFile
int AudioEnv::LoadFile (char *filename, bool loop)
{
int i;
/* tsao:
XLDEMO creates Sources and Buffers as needed, with a one-to-one
mapping, for each sample desired. This isn't necessary, as one
can have many Sources referring to the same Buffer.
The application must associate a sound file with a Buffer and
associate a Buffer with a Source before the sound file can be
played. The usual course of events goes something like this:
alGenSources(1, &sid);
alGenBuffers(1, &bid);
...load PCM data ...
alBufferData(bid, format, data, size, freq);
alSourcei(sid, AL_BUFFER, bid);
The call alBufferData is needed to associate a chunk of PCM data
with a Buffer ID. The format parameter is one of
AL_FORMAT_MONO8, AL_FORMAT_MONO16, AL_FORMAT_STEREO8, or
AL_FORMAT_STEREO16, although implementations are free to add
additional formats as extensions for things like compressed audio
formats.
size corresponds to the length of the data in bytes, and freq
corresponds to the sampling rate of the data.
The proposed 1.0 spec specifies that functions that cannot completely
fulfill a requested allocation/deallocation request fail, setting
an error, and not perform partial allocation. The Linux
implementation follows this guideline which is why there is no
return from alGenSources or alGenBuffers, and instead alGetError
is checked.
Buffers are not played, Sources are, although they get their
sound data from Buffers. Attributes such as position, pitch,
gain, etc are set for Sources, not Buffers.
*/
// tsao: Linux OpenAL follows spec in that alGenBuffers
// and alGenSources don't return.
// create Buffer
alGetError(); /* clear */
alGenBuffers(1, &buffer[nextBuffer]);
if(alGetError() != AL_NO_ERROR) {
return 0;
}
// create Source
alGetError(); /* clear */
alGenSources(1, &source[nextSource]);
if(alGetError() != AL_NO_ERROR) {
return 0;
}
/* tsao:
The alut functions, being unspecified, are different between the
implementations at the moment. This is why we need seperate
defines for this section.
alut functions are meant to be utility functions not reliant on
the main library proper. Here, alutLoadWAV is used to open a
wave file and extract (or convert to) a chunk of PCM data,
setting format, data, size, and frequency for use in a call to
alBufferData. The bits field, while present in the Linux
implementation of the call, is unused.
*/
// load data into Buffer
#ifdef LINUX
ALsizei size, freq, bits;
ALenum format;
ALvoid *data;
ALboolean err;
err = alutLoadWAV(filename, &data, &format, &size, &bits, &freq);
if(err == AL_FALSE) {
fprintf(stderr, "Could not load %s\n", filename);
return 0;
}
alBufferData (buffer[nextBuffer], format, data, size, freq);
#endif
/* tsao:
Here is where the Buffer above is associated with the source
just created.
In addition, looping is either turned on or off (default) based
on a passed parameter. The proposed 1.0 spec has a more
flexible loop mechanism, based on AL_PLAY_COUNT, which allows
for repitition counts on a playing Source. A backwards
compatitibility token is also present for infinite loop counts.
*/
// setup Source
alSourcei(source[nextSource], AL_BUFFER, buffer[nextBuffer]);
alSourcei(source[nextSource], AL_LOOPING, loop);
nextBuffer++;
nextSource++;
return nextBuffer;
}
// Playfile
int AudioEnv::PlayFile (char *filename, bool loop)
{
int loadhandle;
loadhandle = LoadFile(filename, loop);
if (loadhandle != 0) {
Play(loadhandle);
} else
{
return 0;
}
return loadhandle;
}
//SetSourcePosition
void AudioEnv::SetSourcePosition (int handle, float *position)
{
/* tsao:
In order to place sounds in an environment, the Source's position
must be set.
alSourcefv is used to set Source attributes with a float vector
form, such as position, velocity, direction.
*/
alSourcefv(source[handle-1], AL_POSITION, position);
}
// Play
void AudioEnv::Play(int handle)
{
/* tsao:
Sources must be played to be heard. alSourcePlay (and
alSourcePlayv, the vector form) can be used to play Sources.
*/
alSourcePlay(source[handle-1]);
}
// Stop
void AudioEnv::Stop(int handle)
{
/* tsao:
Non-looping Sources will stop of their own accord when they reach
the end of their PCM data, but occasionally the application will
want to stop a Source prematurely, and alSourceStop (or
alSourceStopv, the vector form) is the way to do it.
Because of the introduction of the play count attribute in the
proposed 1.0 spec, it is possible to have a Source which loops
for a specified number of iterations and then stops of its own
accord, although using the backward compatibility token for
infinite looping will require an explicit stop of the Source if
the application expects the Source to end at any point.
*/
alSourceStop(source[handle-1]);
}