Portability | portable |
---|---|
Stability | stable |
Maintainer | [email protected] |
Safe Haskell | Safe-Infered |
Sound.OpenAL.AL.Source
Contents
Description
This module corresponds to sections 4.1 (Basic Listener and Source Attributes) and 4.3 (Source Objects) of the OpenAL Specification and Reference (version 1.1).
Sources specify attributes like position, velocity, and a buffer with sample data. By controlling a source's attributes the application can modify and parameterize the static sample data provided by the buffer referenced by the source. Sources define a localized sound, and encapsulate a set of attributes applied to a sound at its origin, i.e. in the very first stage of the processing on the way to the listener. Source related effects have to be applied before listener related effects unless the output is invariant to any collapse or reversal of order. OpenAL also provides additional functions to manipulate and query the execution state of sources: the current playing status of a source, including access to the current sampling position within the associated buffer.
- data Source
- sourcePosition :: Source -> StateVar (Vertex3 ALfloat)
- sourceVelocity :: Source -> StateVar (Vector3 ALfloat)
- sourceGain :: Source -> StateVar Gain
- data SourceRelative
- sourceRelative :: Source -> StateVar SourceRelative
- data SourceType
- = Undetermined
- | Static
- | Streaming
- sourceType :: Source -> GettableStateVar SourceType
- data LoopingMode
- loopingMode :: Source -> StateVar LoopingMode
- buffer :: Source -> StateVar (Maybe Buffer)
- buffersQueued :: Source -> GettableStateVar ALint
- buffersProcessed :: Source -> GettableStateVar ALint
- gainBounds :: Source -> StateVar (Gain, Gain)
- referenceDistance :: Source -> StateVar ALfloat
- rolloffFactor :: Source -> StateVar ALfloat
- maxDistance :: Source -> StateVar ALfloat
- pitch :: Source -> StateVar ALfloat
- direction :: Source -> StateVar (Vector3 ALfloat)
- coneAngles :: Source -> StateVar (ALfloat, ALfloat)
- coneOuterGain :: Source -> StateVar Gain
- secOffset :: Source -> StateVar ALfloat
- sampleOffset :: Source -> StateVar ALint
- byteOffset :: Source -> StateVar ALint
- queueBuffers :: Source -> [Buffer] -> IO ()
- unqueueBuffers :: Source -> [Buffer] -> IO ()
- data SourceState
- sourceState :: Source -> GettableStateVar SourceState
- play :: [Source] -> IO ()
- pause :: [Source] -> IO ()
- stop :: [Source] -> IO ()
- rewind :: [Source] -> IO ()
The Source Type
The abstract buffer type.
Source Attributes
Basic Source Attributes
sourcePosition :: Source -> StateVar (Vertex3 ALfloat)Source
sourcePosition
contains the current location of the source in the world
coordinate system. Any 3-tuple of valid float values is allowed.
Implementation behavior on encountering NaN and infinity is not defined. The
initial position is (Vertex3
0 0 0).
sourceVelocity :: Source -> StateVar (Vector3 ALfloat)Source
sourceVelocity
contains current velocity (speed and direction) of the
source in the world coordinate system. Any 3-tuple of valid float values is
allowed, and the initial velocity is (Vector3
0 0 0). sourceVelocity
does
not affect sourcePosition
. OpenAL does not calculate the velocity from
subsequent position updates, nor does it adjust the position over time based
on the specified velocity. Any such calculation is left to the application.
For the purposes of sound processing, position and velocity are independent
parameters affecting different aspects of the sounds.
sourceVelocity
is taken into account by the driver to synthesize the
Doppler effect perceived by the listener for each source, based on the
velocity of both source and listener, and the Doppler related parameters.
sourceGain :: Source -> StateVar GainSource
sourceGain
contains a scalar amplitude multiplier for the given source.
The initial value 1 means that the sound is unattenuated. A sourceGain
value of 0.5 is equivalent to an attenuation of 6dB. The value zero equals
silence (no output). Driver implementations are free to optimize this case
and skip mixing and processing stages where applicable. The implementation is
in charge of ensuring artifact-free (click-free) changes of gain values and
is free to defer actual modification of the sound samples, within the limits
of acceptable latencies.
A sourceGain
larger than 1 (amplification) is permitted. However, the
implementation is free to clamp the total gain (effective gain per source
times listener gain) to 1 to prevent overflow.
Source Positioning
data SourceRelative Source
The entity to which the source attributes sourcePosition
,
sourceVelocity
and direction
are to be interpreted.
Instances
sourceRelative :: Source -> StateVar SourceRelativeSource
If sourceRelative
contains Listener
, it indicates indicates that the
values specified by sourcePosition
, sourceVelocity
and direction
are to
be interpreted relative to the listener position. The initial value is
World
, indicating that those source attributes are to be interpreted
relative to the world, i.e. they are considered absolute.
Source Type
data SourceType Source
When first created, a source will be in the Undetermined
state. If a
buffer is then attached using buffer
, then the source will enter the
Static
state. If the first buffer attached to a source is attached using
queueBuffers
, then the source will enter the Streaming
state. A source of
either state will be reset to state Undetermined
by setting its buffer
to
Nothing
, and attaching any buffer to a streaming source will change the
state to Static
. Attempting to queue a buffer on a static source will
result in an ALInvalidOperation
error.
Constructors
Undetermined | |
Static | |
Streaming |
Instances
sourceType :: Source -> GettableStateVar SourceTypeSource
sourceType
indicates whether a source is ready to queue buffers, ready to
use a static buffer, or is in an undetermined state where it can be used for
either streaming or static playback.
Buffer Looping
data LoopingMode Source
Specifies what should happen when the end of a buffer queue is reached.
Instances
loopingMode :: Source -> StateVar LoopingModeSource
If loopingMode
contains Looping
, it indicates that the source will not
be in the Stopped
state once it reaches the end of last buffer in the
buffer queue. Instead, the source will immediately promote to Initial
and
Playing
. The initial value is OneShot
. loopingMode
can be changed on a
source in any execution state. In particular, it can be changed on a
Playing
source.
Current Buffer
buffer :: Source -> StateVar (Maybe Buffer)Source
buffer
contains the current buffer object. Setting buffer
to Just
a
buffer object makes it the head entry in the source's queue. Setting
buffer
for a source in the Stopped
or Initial
state empties the entire
queue, then appends the one buffer specified (or none at all if Nothing
was specified).
For a source in the Playing
or Paused
state, setting buffer
will result
in the ALInvalidOperation
error state being set. buffer
can be applied only
to sources in the Initial
and Stopped
states. Specifying an invalid
buffer name (either because the buffer name doesn't exist or because that
buffer can't be attached to the specified source) will result in an
ALInvalidValue
error while specifying an invalid source name results in an
ALInvalidName
error. Setting buffer
to Nothing
is a legal way to release
the current buffer queue on a source in the Initial
or Stopped
state,
whether the source has just one entry (current buffer) or more. Setting
buffer
to Nothing
still causes an ALInvalidOperation
for any source in
the Playing
or Paused
state, consequently it cannot be used to mute or
stop a source. The initial value is Nothing
.
Queue State Queries
buffersQueued :: Source -> GettableStateVar ALintSource
buffersQueued
contains the number of buffers in the queue of a given
source. This includes those not yet played, the one currently playing, and
the ones that have been played already. It will contain 0 if buffer
has
been set to Nothing
.
buffersProcessed :: Source -> GettableStateVar ALintSource
buffersProcessed
contains the number of buffers that have been played
by a given source. Indirectly, this gives the index of the buffer currently
playing. It can be used to determine how much slots are needed for unqueuing
them. On a source in the Stopped
state, all buffers are processed. On a
source in the Initial
state, no buffers are processed, all buffers are
pending. It will contain 0 if buffer
has been set to Nothing
.
Bounds on Gain
gainBounds :: Source -> StateVar (Gain, Gain)Source
gainBounds
contains two scalar amplitude thresholds between 0 and 1
(included): The minimum guaranteed gain for this source and the maximum gain
permitted, with initial values 0 and 1, respectively At the end of the
processing of various attenuation factors such as distance based attenuation
and sourceGain
, the effective gain calculated is compared to these values:
If the effective gain is lower than the minimum gain, the minimum gain is
applied. This happens before the listenerGain
is applied. If a zero minimum
gain is set, then the effective gain will not be corrected.
If the effective gain is higher than the maximum gain, the maximum gain is
applied. This happens before the listenerGain
is applied. If the
listenerGain
times the maximum gain still exceeds the maximum gain the
implementation can handle, the implementation is free to clamp. If a zero
maximum gain is set, then the source is effectively muted. The implementation
is free to optimize for this situation, but no optimization is required or
recommended as setting sourceGain
to zero is the proper way to mute a
source.
Distance Model Attributes
referenceDistance :: Source -> StateVar ALfloatSource
referenceDistance
is used for distance attenuation calculations based on
inverse distance with rolloff. Depending on the distance model it will also
act as a distance threshold below which gain is clamped. See
Sound.OpenAL.AL.Attenuation for details. The initial value is 1.
rolloffFactor :: Source -> StateVar ALfloatSource
rolloffFactor
is used for distance attenuation calculations based on
inverse distance with rolloff. For distances smaller than maxDistance
(and,
depending on the distance model, larger than referenceDistance
), this will
scale the distance attenuation over the applicable range. See
Sound.OpenAL.AL.Attenuation for details how the attenuation is computed as
a function of the distance. The initial value is 1.
In particular, rolloffFactor
can be set to zero for those sources that are
supposed to be exempt from distance attenuation. The implementation is
encouraged to optimize this case, bypassing distance attenuation calculation
entirely on a persource basis.
maxDistance :: Source -> StateVar ALfloatSource
maxDistance
is used for distance attenuation calculations based on
inverse distance with rolloff, if the inverse clamped distance model is
used. In this case, distances greater than maxDistance
will be clamped to
maxDistance
. maxDistance
based clamping is applied before minimum gain
clamping (see gainBounds
), so if the effective gain at maxDistance
is
larger than the minimum gain, the minimum gain will have no effect. No
culling is supported. The initial value is the largest representable
ALfloat
.
Frequency Shift by Pitch
pitch :: Source -> StateVar ALfloatSource
pitch
contains the desired pitch shift, where 1 (the initial value)
equals identity. Each reduction by 50 percent equals a pitch shift of -12
semitones (one octave reduction). Each doubling equals a pitch shift of 12
semitones (one octave increase). Zero is not a legal value. Implementations
may clamp the actual output pitch range to any values subject to the
implementation's own limits.
Direction and Cone
Each source can be directional, depending on the settings for coneAngles
.
There are three zones defined: the inner cone, the outside zone, and the
transitional zone in between. The angle-dependent gain for a directional
source is constant inside the inner cone, and changes over the transitional
zone to the value specified outside the outer cone. sourceGain
is applied
for the inner cone, with an application selectable coneOuterGain
factor to
define the gain in the outer zone. In the transitional zone
implementation-dependent interpolation between sourceGain
and sourceGain
times coneOuterGain
is applied.
direction :: Source -> StateVar (Vector3 ALfloat)Source
If direction
does not contain the zero vector (Vector3
0 0 0), the
source is directional. The sound emission is presumed to be symmetric around
the direction vector (cylinder symmetry). Sources are not oriented in full 3
degrees of freedom, only two angles are effectively needed.
The zero vector is the initial value, indicating that a source is not directional. Specifying a non-zero vector will make the source directional. Specifying a zero vector for a directional source will effectively mark it as nondirectional.
coneAngles :: Source -> StateVar (ALfloat, ALfloat)Source
coneAngles
contains the inner and outer angles of the sound cone, in
degrees. The default of 360 for the inner cone angle means that it covers the
entire world, which is equivalent to an omni-directional source. The default
of 360 for the outer cone angle means that it covers the entire world. If the
inner angle is also 360, then the zone for angle-dependent attenuation is
zero.
coneOuterGain :: Source -> StateVar GainSource
coneOuterGain
contains the factor with which sourceGain
is multiplied
to determine the effective gain outside the cone defined by the outer angle.
The effective gain applied outside the outer cone is sourceGain
times
coneOuterGain
. Changing sourceGain
affects all directions, i.e. the
source is attenuated in all directions, for any position of the listener. The
application has to change coneOuterGain
as well if a different behavior is
desired.
Offset
secOffset :: Source -> StateVar ALfloatSource
secOffset
contains the playback position, expressed in seconds (the value
will loop back to zero for looping sources).
When setting secOffset
on a source which is already playing, the playback
will jump to the new offset unless the new offset is out of range, in which
case an ALInvalidValue
error is set. If the source is not playing, then the
offset will be applied on the next play
call.
The position is relative to the beginning of all the queued buffers for the source, and any queued buffers traversed by a set call will be marked as processed.
This value is based on byte position, so a pitch-shifted source will have an exaggerated playback speed. For example, you can be 0.5 seconds into a buffer having taken only 0.25 seconds to get there if the pitch is set to 2.
sampleOffset :: Source -> StateVar ALintSource
sampleOffset
contains the playback position, expressed in samples (the
value will loop back to zero for looping sources). For a compressed format,
this value will represent an exact offset within the uncompressed data.
When setting sampleOffset
on a source which is already playing, the
playback will jump to the new offset unless the new offset is out of range,
in which case an ALInvalidValue
error is set. If the source is not playing,
then the offset will be applied on the next play
call. A stop
, rewind
,
or a second play
call will reset the offset to the beginning of the buffer.
The position is relative to the beginning of all the queued buffers for the source, and any queued buffers traversed by a set call will be marked as processed.
byteOffset :: Source -> StateVar ALintSource
byteOffset
contains the playback position, expressed in bytes (the value
will loop back to zero for looping sources). For a compressed format, this
value may represent an approximate offset within the compressed data buffer.
When setting byteOffset
on a source which is already playing, the playback
will jump to the new offset unless the new offset is out of range, in which
case an ALInvalidValue
error is set. If the source is not playing, then the
offset will be applied on the next play
call. A stop
, rewind
, or a
second play
call will reset the offset to the beginning of the buffer.
The position is relative to the beginning of all the queued buffers for the source, and any queued buffers traversed by a set call will be marked as processed.
Queuing Buffers with a Source
OpenAL does not specify a built-in streaming mechanism. There is no mechanism to stream data into a buffer object. Instead, the API has a more flexible and versatile mechanism to queue buffers for sources. There are many ways to use this feature, with streaming being only one of them.
Streaming is replaced by queuing static buffers. This effectively moves any multi-buffer caching into the application and allows the application to select how many buffers it wants to use, the size of the buffers, and whether these are re-used in cycle, pooled, or thrown away.
Looping (over a finite number of repetitions) can be implemented by
explicitly repeating buffers in the queue. Infinite loops can (theoretically)
be accomplished by sufficiently large repetition counters. If only a single
buffer is supposed to be repeated infinitely, using the respective source
attribute loopingMode
is recommended.
Loop Points for restricted looping inside a buffer can in many cases be replaced by splitting the sample into several buffers and queuing the sample fragments (including repetitions) accordingly.
Buffers can be queued, unqueued after they have been used, and either be deleted, or refilled and queued again. Splitting large samples over several buffers maintained in a queue has distinct advantages over approaches that require explicit management of samples and sample indices.
queueBuffers :: Source -> [Buffer] -> IO ()Source
The application can queue up one or multiple buffer names using
queueBuffers
. The buffers will be queued in the sequence in which they
appear in the list.
This command is legal on a source in any playback state (to allow for
streaming, queuing has to be possible on a Playing
source).
All buffers in a queue must have the same format and attributes. An attempt
to mix formats or other buffer attributes will result in a failure and an
ALInvalidValue
error will be thrown. If the queue operation fails, the source
queue will remain unchanged (even if some of the buffers could have been
queued).
unqueueBuffers :: Source -> [Buffer] -> IO ()Source
Once a queue entry for a buffer has been appended to a queue and is pending
processing, it should not be changed. Removal of a given queue entry is not
possible unless either the source is stopped (in which case then entire queue
is considered processed), or if the queue entry has already been processed
(Playing
or Paused
source). A playing source will enter the Stopped
state if it completes playback of the last buffer in its queue (the same
behavior as when a single buffer has been attached to a source and has
finished playback).
The unqueueBuffers
command removes a number of buffers entries that have
finished processing, in the order of appearance, from the queue. The
operation will fail with an ALInvalidValue
error if more buffers are
requested than available, leaving the destination arguments unchanged.
Managing Source Execution
The execution state of a source can be queried. OpenAL provides a set of functions that initiate state transitions causing sources to start and stop execution.
data SourceState Source
Each source can be in one of four possible execution states: Initial
,
Playing
, Paused
, Stopped
. Sources that are either Playing
or Paused
are considered active. Sources that are Stopped
or Initial
are considered
inactive. Only Playing
sources are included in the processing. The
implementation is free to skip those processing stages for sources that have
no effect on the output (e.g. mixing for a source muted by zero gain, but not
sample offset increments). Depending on the current state of a source certain
(e.g. repeated) state transition commands are legal NOPs: they will be
ignored, no error is generated.
Instances
sourceState :: Source -> GettableStateVar SourceStateSource
Contains the current execution state of the given source. The initial state
of any source is Initial
.
Note that the Initial
state is not necessarily identical to the initial
state in which a source is created, because the other source attributes are
not automatically reset to their initial values. Initial
merely indicates
that the source can be executed using the play
command. A Stopped
or
Initial
source can be reset into the default configuration by using a
sequence of source commands as necessary. As the application has to specify
all relevant state anyway to create a useful source configuration, no reset
command is provided.
play :: [Source] -> IO ()Source
play
applied to an Initial
source will promote the source to Playing
,
thus the data found in the buffer will be fed into the processing, starting
at the beginning. play
applied to a Playing
source will restart the
source from the beginning. It will not affect the configuration, and will
leave the source in Playing
state, but reset the sampling offset to the
beginning. play
applied to a Paused
source will resume processing using
the source state as preserved at the pause
operation. play
applied to a
Stopped
source will propagate it to Initial
then to Playing
immediately.
stop :: [Source] -> IO ()Source
stop
applied to an Initial
source is a legal NOP. stop
applied to a
Playing
source will change its state to Stopped
. The source is exempt
from processing, its current state is preserved. stop
applied to a Paused
source will change its state to Stopped
, with the same consequences as on a
Playing
source. stop
applied to a Stopped
source is a legal NOP.
rewind :: [Source] -> IO ()Source
rewind
applied to an Initial
source is a legal NOP. rewind
applied to
a Playing
source will change its state to Stopped
then Initial
. The
source is exempt from processing: its current state is preserved, with the
exception of the sampling offset, which is reset to the beginning. rewind
applied to a Paused
source will change its state to Initial
, with the
same consequences as on a Playing
source. rewind
applied to an Stopped
source promotes the source to Initial
, resetting the sampling offset to the
beginning.