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