State and State Requests
The majority of &AL; state is associated with individual &AL; objects,
and has to be set and queried referencing the objects. However, some
state - e.g. processing errors - is
defined context specific. &AL; has global state that affects all
objects and processing equally. This state is set using a variety
of functions, and
can be queried using query functions. The majority of queries
has to use the interface described in "Simple Queries".
Querying &AL; State
Simple Queries
Like &OGL;, &AL; uses a simplified interface for querying global
state. The following functions accept a set of enumerations.
void GetBooleanv
&enum; paramName
&bool;* dest
void GetIntegerv
&enum; paramName
∫* dest
void GetFloatv
&enum; paramName
&float;* dest
void GetDoublev
&enum; paramName
&double;* dest
Legal values are e.g. DOPPLER_FACTOR, DOPPLER_VELOCITY, DISTANCE_MODEL.
NULL destinations are quietly ignored. INVALID_ENUM is the
response to errors in specifying paramName. The amount of memory
required in the destination depends on the actual state requested.
Usually, state variables are returned in only one or some of the
formats above.
To query state controlled by Enable/Disable there is an additional
IsEnabled function defined (see "Controlling &AL; Execution").
Data Conversions
If a Get command is issued that returns value types different from
the type of the value being obtained, a type converswion is
performed. If GetBooleanv is called, a floating-point or integer
value converts to FALSE if and only if it is zero (otherwise
it converts to TRUE). If GetIntegerv is called, a boolean value
is interpreted as either 1 or 0, and a floating-point value is
rounded to the nearest integer. If GetFloatv is called, a boolean
value is interpreted as either 1.0 or 0.0, an integer is
coerced to floating point, and a double-presicion foating-point
value is converted to single precision. Analogous conversions are
carried out in the case of GetDoublev. If a value is so large
in magnitude that it cannot be represented with the requested
type, then the nearest value is representable using the requested
type is returned.
Annotation (Query of Modes)
Modes (e.g. the current distance model) can be queried
using the respective tokens. The recommended query
command is GetIntegerv.
]]>
String Queries
The application can retrieve state information global to the current
&AL; Context. GetString will return a pointer to a constant string.
Valid values for param are VERSION, RENDERER, VENDOR, and EXTENSIONS,
as well as the error codes defined by &AL;. The application can
use GetString to retrieve a string for an error code.
const &ubyte;* GetString
&enum; paramName
Time and Frequency
By default, &AL; uses seconds and Hertz as units for
time and frequency, respectively.
A float or integral value of one
for a variable that specifies quantities like duration,
latency, delay, or any other parameter measured as time,
specifies 1 second.
For frequency, the basic unit is 1/second, or Hertz.
In other words, sample frequencies and frequency
cut-offs or filter parameters specifying frequencies
are expressed in units of Hertz.
RFC: Query and Factor?
Will time be an &AL; state that can be queried and scaled?
&AL; usually (always) implements a real-time
process with the constraint that it has to be
synchronized with the time as experienced by the user.
Do the units used with respect to time and frequency have
a fixed meaning?
]]>
RFC: Setting Time/Long
Given a frequency range from a few Hz to 50kHz or more,
we need a temporal resolution of 20 microseconds or less.
For simplicity that means we either resolve Milliseconds
and loose precision, or we resolve microseconds.
Applications might run hours or days, which is 10E5 seconds
or more. If we cover 12 orders of magnitude (10E6 to 10E-6)
32bit unsigned integer will not suffice. Do we introduce
a 64 signed integer for the purpose of specifying time
over a duration of several days at microseconds resolution,
or do we use two 32bit integers, and how do we split them?
]]>
RFC: Duration Query
The application might want to cull Sources based on
how many milliseconds are left for their current buffer
or queue (either to stop those that will stop soon
anyway, or to stop those that will take too long,
depending).
We need to divorce sample (memory) count from duration,
because of compression and differences between
internal and external sample format.
Duration can be queried in microsecond resolution in
case we want to account for O(10Khz) sampling
frequencies properly, or milliseconds if we
do not anticipate the need to go beyond typical
operating system time resolution.
We need query as double, float, and possibly
long (as of now an undefined data type).
We might need an INVALID_RANGE error on the getter,
especially if large reptition counters can be set.
For paused source, the remainder will be the same
as for playing sources. The application can query
the Source State to find out the additional
information. INFINITE is not needed,
no is UNKNOWN as we operate on known
queues.
]]>
Annotation (Buffer vs. Queue Duration)
Sourcel( sName , REMAINDER, &rem ) queries the remainder
for the current buffer (zero if the Source is STOPPED,
duration of the first buffer if the source is INITIAL).
Sourcel( sName, REMAINDER_QUEUE, &rem ) queries the remainder
of the entire queue.
A STOPPED Source has remainder==0.
An INITIAL Source has full remainder.
]]>
Annotation (DURATION vs. REMAINDER)
DURATION is a buffer attribute independent of
execution state. REMAINDER is a Source attribute
that encapsulates part of the execution state.
Sources and Buffers should not share these attributes:
there is no Buffer REMAINDER and no Source DURATION.
]]>
]]>
Space and Distance
&AL; does not define the units of measurement for distances.
The application is free to use meters, inches, or parsecs.
&AL; provides means for simulating the natural attenuation
of sound according to distance, and to exagerate or reduce
this effect. However, the resulting effects do not depend on
the distance unit used by the application to express source
and listener coordinates. &AL; calculations are scale
invariant.
The specification assumes Euclidean calculation of
distances, and mandates that if two Sources are
sorted with respect to the Euclidean metric, the
distance calculation used by the implementation has
to preserve that order.
Annotation (No DistanceFactor)
&AL; does not provide a global, per Context DISTANCE_FACTOR,
as all calculations are scale invariant.
]]>
Annotation (Distance Calculations)
The specification does not enforce that distances
are calculated using the euclidean norm, to permit
using computationally cheaper approximations.
Implementations that opt to use approximations
might cause audible artifacts. The specification does
not enforce any upper limits on distance calculation
errors yet.
]]>
RFC: Limiting Errors
Do we limit permissible errors on distance or gain
calculations? How much quality
and accuracy do we expect from conformant implementations?
]]>
Annotation (DS3D DistanceFactor)
The DS3D documentation explicitely states that the default
unit is 1 meter. &AL; does not specify any units.
&AL; calculations are scale invariant. The main purpose
of the DS3D DistanceFactor (modifying Doppler Shift
by scaling velocity but not reference velocity) is
accomplished using DOPPLER_VELOCITY in &AL;. &AL;
does not have an equivalent to A3D's SetUnitsPerMeter
either.
]]>
Attenuation By Distance
Samples usually use the entire dynamic range of the
chosen format/encoding, independent of their real world
intensity. In other words, a jet engine and a clockwork
both will have samples with full amplitude. The application
will then have to adjust Source GAIN accordingly to account
for relative differences.
Source GAIN is then attenuated by distance.
The effective attenuation of a Source depends on many
factors, among which distance attenuation and source
and Listener GAIN are only some of the contributing
factors. Even if the source and Listener GAIN exceed 1.0
(amplification beyond the guaranteed dynamic range),
distance and other attenuation might ultimately limit
the overall GAIN to a value below 1.0.
&AL; currently supports three modes of operation
with respect to distance attenuation. It supports
two distance-dependent attenuation models, including one
that is similar to the IASIG I3DL2 (and DS3D) model.
The application chooses one of these two models (or
chooses to disable distance-dependent attenuation)
on a per-context basis.
void DistanceModel
&enum; modelName
Legal arguments are NONE, INVERSE_DISTANCE, and
INVERSE_DISTANCE_CLAMPED. NONE bypasses all distance
attenuation calculation for all Sources. The implementation
is expected to optimize this situation. INVERSE_DISTANCE_CLAMPED
is the DS3D model, with REFERENCE_DISTANCE indicating both the
reference distance and the distance below which gain will
be clamped. INVERSE_DISTANCE is equivalent to the DS3D model
with the exception that REFERENCE_DISTANCE does not imply any
clamping. The &AL; implementation is still free to apply
any range clamping as necessary. The current distance model
chosen can be queried using GetIntegerv and DISTANCE_MODEL.
Annotation (Inverse Square Law)
The "inverse square law" used in physics applies to sound
intensity (energy), which is proportional to the square
of linear gain (amplitude). Thus the inverse distance model
describes a physically correct inverse square behavior
if ROLLOFF_FACTOR is set to 1.0.
]]>
Annotation (Enable/Disable Attenuation)
As ROLLOFF_FACTOR is a per-Source attribute, setting it to zero
can not be used to globally enable or disable distance
attenuation, which (e.g. when using tables) can be resource
intensive. Using Enable/Disable/IsEnabled with a DISTANCE_ATTENUATION
token is redundant with respect to the possibility that support
for different distance models might be desired at a later time.
]]>
Inverse Distance Rolloff Model
The following formula describes the distance attenutation
defined by the Rolloff Attenutation Model, as logarithmic
calculation.
G_dB = GAIN - 20*log10(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE );
G_dB = min(G_dB,MAX_GAIN);
G_dB = max(G_dB,MIN_GAIN);
The REFERENCE_DISTANCE parameter used here is a per-Source attribute
that can be set and queried using the REFERENCE_DISTANCE token.
REFERENCE_DISTANCE is the distance at which the Listener will
experience GAIN (unless the implementation had to clamp effective
GAIN to the available dynamic range).
ROLLOFF_FACTOR is per-Source parameter the application can use
to increase or decrease the range of a source by decreasing
or increasing the attenuation, respectively. The default value
is 1. The implementation is free to optimize for a
ROLLOFF_FACTOR value of 0, which indicates that the application
does not wish any distance attenuation on the respective Source.
Annotation (Linear Calculation)
The logarithmic formula above is equivalent to
G = gain_linear / ( 1 + ROLLOFF_FACTOR*((dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE) );
G = min(G,max_gain_linear);
G = max(G,min_gain_linear);
with linear gains calculated from the logarithmic GAIN,
MIN_GAIN, MAX_GAIN accordingly.
By means of explanation: linear GAIN is applied to the sample, which describes
an amplitude ultimately (DAC) converted into voltage. The actual power of the
signal is proportional to the square of the amplitude (voltage). Logarithmic
measurement is done by comparing the actual power with a reference value,
i.e. the power (e.g in Watt) at the reference distance. The original Bel unit
of measure (named after Alexander Graham Bell) was defined to account for the
logarithmic response of the human ear: our subjective impression of "loudness"
is not linear in the power of the acoustic signal. For practical purposes (range
of volumes the human ear can handle) the deciBel (dB) is a better unit:
dB = 10 * log( P/P0 ) = 10 * log( sqr(A/A0 ) = 20 * log( A/A0 )
Common power/amplitude ratios and attenuations per distance are:
Logarithmic Scale and Gain
Distance>
Attenuation>
Power Ratio>
Amplitude Ratio>
REF>
0dB >
1:1 >
1:1 >
2*REF >
-6dB >
1:4 >
1:2 >
4*REF >
-12dB >
1:16 >
1:4 >
8*REF >
-18dB >
1:64 >
1:8 >
0.5*REF >
6dB >
2:1 >
4:1 >
0.25*REF >
12dB >
4:1 >
16:1 >
The logarithmic gain will drop from zero (linear gain 1) to negative infinity
(approaching linear gain 0). A linear gain of zero can not be represented
logarithmically. Any doubling of the reference distance will add another
-6dB (i.e. 6dB of attenuation). This approximates an inverse square law falloff
of signal power with distance, as long as the distance exceeds the reference
distance.
]]>
Annotation (Rolloff quantization)
Implementations that use lookup tables to speed up
distance attenuation calculation may opt to map
ROLLOFF_FACTOR to a limited set of internally used
values, to minimize expense of per-Source calculations
and setup/memory costs.
]]>
Annotation (Gain Clamping)
In the absence of user MIN_GAIN and MAX_GAIN selections,
clamping is implied by implementation constraints, and
clamping behavior might change.
The &AL; implementation should not clamp intermediate
values of effective gain to unit range.
Any clamping, if necessary, should be applied at the latest
possible stage. In other words, GAIN>1 is perfectly
valid as the implementation is free to clamp the value as
needed for maximum mixing accuracy and to account for the
actual dynamic range of the output device.
]]>
Annotation (Extended Dynamic Range)
For applications that
change GAIN but do not want to adjust ROLLOFF_FACTOR
and REFERENCE_DISTANCE to account for different ranges,
the separation in this distance model might allow for
more intuitive adjustments:
If we put a damper on the jet engine by lowering GAIN,
we still want the listener to perceive the full volume,
but now at a closer distance, without changing the
reference distance.
]]>
Inverse Distance Clamped Model
This is essentially the Inverse Distance model,
extended to guarantee that for distances below
REFERENCE_DISTANCE, gain is clamped. This mode
is equivalent to the IASIG I3DL2 (and DS3D) distance
model.
dist = max(dist,REFERENCE_DISTANCE);
dist = min(dist,MAX_DISTANCE);
G_dB = GAIN - 20*log10(1 + ROLLOFF_FACTOR*(dist-REFERENCE_DISTANCE)/REFERENCE_DISTANCE )
G_dB = min(G_dB,MAX_GAIN);
G_dB = max(G_dB,MIN_GAIN);
Annotation (DS3D MIN_DISTANCE)
The DS3D attenuation model is extended by an explicit
clamping mechanism. REFERENCE_DISTANCE is equivalent
to DS3D MIN_DISTANCE if the INVERSE_DISTANCE_CLAMPED
mode is used.
]]>
Annotation (High Frequency Rolloff)
To simulate different atmospheric conditions, a frequency
dependent attenuation is used in A3D and EAX.
At this time &AL; does not have a mechanism to specify
lowpass filtering parameterized by distance.
]]>
Evaluation of Gain/Attenuation Related State
While amplification/attenuation commute (mulplication of
scaling factors), clamping operations do not. The order
in which various gain related operations are applied is:
Distance attenuation is calculated first, including
minimum (REFERENCE_DISTANCE) and maximum (MAX_DISTANCE)
thresholds. If the Source is directional (CONE_INNER_ANGLE
less than CONE_OUTER_ANGLE), an angle-dependent attenuation
is calculated depending on CONE_OUTER_GAIN, and multiplied
with the distance dependent attenuation.
The resulting attenuation factor for the given angle and
distance between Listener and Source is multiplied
with Source GAIN. The effective GAIN computed this way
is compared against MIN_GAIN and MAX_GAIN thresholds.
The result is guaranteed to be clamped to [MIN_GAIN, MAX_GAIN],
and subsequently multiplied by Listener GAIN which serves
as an overall volume control. The implementation is free
to clamp Listener GAIN if necessary due to hardware or
implementation constraints.
No Culling By Distance
With the DS3D compatible Inverse Clamped Distance Model,
&AL; provides a per-Source MAX_DISTANCE attribute
that can be used to define a distance beyond which the Source will
not be further attenuated by distance.
The DS3D distance attenuation model and its clamping of volume
is also extended by a mechanism to cull (mute) sources from proccessing,
based on distance. However, &AL; does not
support culling a Source from processing based on a distance
threshold.
At this time &AL; is not meant to support culling at all. Culling
based on distance, or bounding volumes, or other criteria, is best
left to the application. For example, the application might
employ sophisticated techniques to determine whether sources
are audible that are beyond the scope of &AL;. In particular,
rule based culling inevitably introduces acoustic artifacts.
E.g. if the Listener-Source distance is nearly equal to the
culling threshold distance, but varies above and below, there
will be popping artifacts in the absence of hysteresis.
Annotation (No MAX_DISTANCE plus MUTE)
&AL; does support the AUDIBLE mode with MAX_DISTANCE (clamping),
but does not support culling. Applications that employ this
DS3D feature will have to perform their own distance calculation
and mute the source (Source GAIN equals zero) as desired.
]]>
RFC: DS3D-like Extension
For ease of portability, should we define an Extension that
provides MAX_DISTANCE for MUTE mode?
]]>
NO Sound Propagation Speed
&AL; implementations can choose to model sound propagation with
limited speed for certain effects, e.g. early reflections.
In addition, the Doppler Effect is defined with respect to the
speed of sound in the predominant medium. The application can
set the speed of sound as a scalar value. The speed is defined
with respect to the scaled unit. If D I S T A N C E _ S C A L E is changed,
this will affect both the distance and the propagation speed,
leaving the propagation time unaffected.
void PropagationSpeed
&float; propSpeed
A negative scale will result in an INVALID_VALUE error, the
command is then ignored. The default value is 1. The current
setting can be queried using GetFloatv and PROPAGATION_SPEED.
]]>
Velocity Dependent Doppler Effect
The Doppler Effect depends on the velocities of Source and
Listener relative to the medium, and the propagation speed
of sound in that medium. The application might want to
emphasize or de-emphasize the Doppler Effect as physically
accurate calculation might not give the desired results. The
amount of frequency shift (pitch change) is proportional
to the speed of listener and source along their line of
sight. The application can increase or decrease that
frequency shift by specifying the scaling factor &AL;
should apply to the result of the calculation.
The Doppler Effect as implemented by &AL; is described
by the formula below. Effects of the medium (air, water)
moving with respect to listener and source are ignored.
DOPPLER_VELOCITY is the propagation speed relative to
which the Source velocities are interpreted.
VD: DOPPLER_VELOCITY
DF: DOPPLER_FACTOR
vl: Listener velocity (scalar, projected on source-listener vector)
vs: Source velocity (scalar, projected on source-listener vector)
f: Frequency of sample
f': effective Doppler shifted frequency
f' = DF * f * (VD-vl)/(VD+vs)
vl<0, vs>0 : source and listener approaching each other
vl>0, vs<0 : source and listener moving away from each other
The implementation has to clamp the projected Listener
velocity vl, if abs(vl) is greater or equal to VD. It similarly has to
clamp the projected Source velocity vs if abs(vs) is greater or equal
to VD.
There are two API calls global to the current context that provide
control of the two related parameters. DOPPLER_FACTOR is a simple
scaling to exaggerate or deemphasize the Doppler (pitch) shift
resulting from the calculation.
void DopplerFactor
&float; dopplerFactor
A negative value will result in an INVALID_VALUE error, the
command is then ignored. The default value is 1. The current
setting can be queried using GetFloatv and DOPPLER_FACTOR.
The implementation is free to optimize the case of DOPPLER_FACTOR
being set to zero, as this effectively disables the effect.
Annotation (No Enable)
There is currently no mechanism to switch on/off Doppler
calculation using e.g. a DOPPLER_SHIFT token and Enable/Disable.
For the time being, DopplerFactor(0) may be used to signal
to the implementation that no Doppler Effect calculation is
required.
]]>
DOPPLER_VELOCITY allows the application to change the
reference (propagation) velocity used in the Doppler Effect
calculation. This permits the application to use a velocity
scale appropriate to its purposes.
void DopplerVelocity
&float; dopplerVelocity
A negative or zero value will result in an INVALID_VALUE error, and the
command is ignored. The default value is 1.
The current setting can be queried using GetFloatv and DOPPLER_VELOCITY.
Annotation (No Sideeffects on Delay)
To permit independent control of Doppler Effect as opposed
to other, sound wave propagation related effects (delays,
echos, reverberation), DOPPLER_VELOCITY is not taken into
account for any other calculation than Doppler Shift.
]]>
Annotation (SetUnitsPerMeter)
DOPPLER_VELOCITY accomplishes the purposes of DS3D
scaling parameters in a straightforward way, without
introducing the undesirable connotations of real world
units.
]]>