1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077 |
- <chapter id="rendering">
- <title>Listener and Sources</title>
- <sect1 id="object-state">
- <title>Basic Listener and Source Attributes</title>
- <para>
- This section introduces basic attributes that can be set both for
- the Listener object and for Source objects.
- </para>
- <![ %RFC [
- <note id="rfc-bk000619-02"><title>RFC: attribute grouping</title><para>
- JM: "These attributes are of
- two types: non-positional and positional.
- Non-positional properties include gain control and Environment Name."
- </para><para>
- I said: (low pass) Filters are applied to the sound during processing
- at various stages. The exact sequence in which Filters are applied is
- determined based on the location of the Objects they are
- set for - spatial arrangement of Objects determines the
- sequence unless invariance is guaranteed, or invariance
- violation is permitted by the specification and current &AL;
- configuration state.
- </para><para>
- Is there a required order of application, i.e. a pipeline?
- </para><para>
- Filter Parameters vs. Non-positional properties.
- Spatialization vs. Positional properties.
- Spatial attributes?
- Let's postpone grouping of attributes.
- </para></note>
- ]]>
-
- <para>
- The &AL; Listener and Sources have attributes to describe
- their position, velocity and orientation in three dimensional space.
- &AL; like &OGL;, uses a right-handed Cartesian coordinate system (RHS),
- where in a frontal default view X (thumb) points right,
- Y (index finger) points up, and Z (middle finger) points towards
- the viewer/camera. To switch from a left handed coordinate system (LHS)
- to a right handed coordinate systems, flip the sign on the Z coordinate.
- </para>
- <para>
- <table>
- <title>Listener/Source Position</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>POSITION</>
- <entry>3fv, 3f</>
- <entry> any except NaN </>
- <entry> { 0.0f, 0.0f, 0.0f } </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- POSITION specifies the current location of the Object in the
- world coordinate system. Any 3-tuple of valid float/double values
- is allowed. Implementation behavior on encountering &NaN; and &Infty;
- is not defined. The Object position is always defined in the
- world coordinate system.
- </para>
- <![ %Annote [
- <note><title>Annotation (No Transformation)</title><para>
- &AL; does not support transformation operations on Objects.
- Support for transformation matrices is not planned.
- </para></note>
- ]]>
- <para>
- <table>
- <title>Listener/Source Velocity</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>VELOCITY</>
- <entry>3fv, 3f</>
- <entry> any except NaN </>
- <entry> { 0.0f, 0.0f, 0.0f } </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- VELOCITY specifies the current velocity (speed and direction) of
- the Object, in the world coordinate system. Any 3-tuple of valid
- float/double values is allowed. The Object VELOCITY does not affect
- its position.
- &AL; 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.
- </para><para>
- VELOCITY 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.
- </para>
- <para>
- <table>
- <title>Listener/Source Gain (logarithmic)</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>GAIN</>
- <entry>f</>
- <entry>0.0f, (0.0f, any</>
- <entry> 1.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- GAIN defines a scalar amplitude multiplier. As a Source attribute, it applies
- to that particular source only. As a Listener attribute, it effectively
- applies to all Sources in the current Context. The default 1.0 means
- that the sound is un-attenuated. A GAIN value of 0.5 is equivalent to
- an attenuation of 6 dB. 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.
- </para>
- <para>
- GAIN larger than 1 (amplification) is permitted for Source and
- Listener. However, the implementation is free to clamp the
- total gain (effective gain per source times listener gain)
- to 1 to prevent overflow.
- </para>
- <![ %Annote [
- <note><title>Annotation/ Effective Minimal Distance</title><para>
- Presuming that the sample uses the entire dynamic range of
- the encoding format, an effective gain of 1 represents the
- maximum volume at which a source can reasonably be played.
- During processing, the implementation combines the Source
- GAIN (or MIN_GAIN, if set and larger) with distance based
- attenuation. The distance at which the effective gain is 1
- is equivalent to the DirectSound3D MIN_DISTANCE parameter.
- Once the effective gain has reached the maximum possible
- value, it will not increase with decreasing distance anymore.
- </para></note>
- ]]>
-
- <![ %Annote [
- <note><title>Annotation (Muting a Context)</title><para>
- To mute the current context, simply set Listener GAIN to zero.
- The implementation is expected to optimize for this case,
- calculating necessary (offset) updates but bypassing the
- mixing and releasing hardware resources.
- The specification does not guarantee that the implementation
- will release hardware resources used by a muted context.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Muting a Source)</title><para>
- To mute a Source, set Source GAIN to zero. The &AL; implementation
- is encouraged to optimize for this case.
- </para></note>
- ]]>
- <![ %RFC [
- <para>
- <note id="rf-bk000503-01"><title>RFC: GAIN > 1?</title><para>
- GAIN could exceed 1 (to compensate attenuation elsewhere, or to account
- for grater dynamic range of the hardware? No guarantees are made with
- respect to range overflows? Precision loss? Culling by effective gain?
- Does &AL; clip values during processing, and when/at what stages?
- </para></note>
- <note id="rfc-bk000619-01"><title>RFC: Doppler</title><para>
- JM wrote: "VELOCITY is used by the driver
- to synthesize the Doppler effect perceived by the listener for each
- source, based on the relative velocity of this source with respect
- to the listener."
- Doppler is calculated using Source and Listener velocities measured
- with respect to the medium. Do we have to account for the medium
- to move (offsetting listener/source) in later revisions (air/water currents)?
- </para></note>
-
- <note id="rfc-bk000619-03"><title>RFC: </title><para>
- JM removed: "For the purposes of sound processing, position and
- velocity are independent parameters affecting different paths
- in the sound synthesis." I think the "different aspects of sounds"
- is ambiguous. Is there a problem with describing &AL; as a
- multichannel processing machine?
- </para></note>
- </para>
- ]]>
- </sect1>
- <sect1 id="object-listener">
- <title>Listener Object</title>
- <para>
- The Listener Object defines various properties that affect processing of
- the sound for the actual output. The Listener is unique for an &AL; Context,
- and has no Name. By controlling the listener, the application controls
- the way the user experiences the virtual world, as the listener defines
- the sampling/pickup point and orientation, and other parameters that
- affect the output stream.
- </para>
- <para>
- It is entirely up to the driver and hardware configuration, i.e.
- the installation of &AL; as part of the operating system and
- hardware setup, whether the output stream is generated for
- headphones or 2 speakers, 4.1 speakers, or other arrangements,
- whether (and which) HRTF's are applied, etc..
- </para>
-
- <![ %Annote [
- <note><title>Annotation (Listener Anatomy)</title><para>
- The API is ignorant with respect to the real world
- listener, it does not need to make assumptions on the
- listening capabilities of the user, its species or its
- number of ears. It only describes a scene and the position
- of the listener in this scene. It is the &AL; implementation
- that is designed for humans with ears on either side of the
- head.
- </para></note>
- ]]>
-
- <![ %Annote [
- <note><title>Annotation (Listener State Evaluation)</title><para>
- Some Listener state (GAIN) affects only the very last
- stage of sound synthesis, and is thus applied to the sound stream
- as sampled at the Listener position. Other Listener state is
- applied earlier. One example is Listener velocity as used to
- compute the amount of Doppler pitch-shifting applied to each source:
- In a typical implementation, pitch-shifting (sample-rate conversion)
- might be the first stage of the audio processing for each source.
- </para></note>
- ]]>
- <sect2>
- <title>Listener Attributes</title>
- <para>
- Several Source attributes also apply to Listener: e.g. POSITION, VELOCITY,
- GAIN. In addition, some attributes are listener specific.
- <table>
- <title>Listener Orientation</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>ORIENTATION</>
- <entry> fv </>
- <entry> any except NaN </>
- <entry> { { 0.0f, 0.0f, -1.0f }, { 0.0f, 1.0f, 0.0f } } </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- ORIENTATION is a pair of 3-tuples representing the 'at' direction vector
- and 'up' direction of the Object in Cartesian space. &AL; expects two
- vectors that are orthogonal to each other. These
- vectors are not expected to be normalized. If one or more vectors
- have zero length, implementation behavior is undefined. If the two
- vectors are linearly dependent, behavior is undefined.
- </para>
- <![ %RFC [
- <note id="rfc-bk000503-01"><title>RFC: Orientation Paranoia</title><para>
- Watch LHS vs. RHS (sign on 'at').
- Confirm sequence is (up, at) not vice versa.
- Do we want to allow for different representations down the road?
- </para></note>
- ]]>
- </sect2>
- <sect2>
- <title>Changing Listener Attributes</title>
- <para>
- Listener attributes are changed using the Listener group of commands.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> Listener{n}{sifd}{v} </function></funcdef>
- <paramdef> &enum; <parameter> paramName </parameter></paramdef>
- <paramdef> &type; <parameter> values </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- </sect2>
- <sect2>
- <title>Querying Listener Attributes</title>
- <para>
- Listener state is maintained inside the &AL; implementation and can be
- queried in full. See Querying Object Attributes. The valid values for
- paramName are identical to the ones for the Listener* command.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> GetListener{sifd}v </function></funcdef>
- <paramdef> &enum; <parameter> paramName </parameter></paramdef>
- <paramdef> &type;* <parameter> values </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- </sect2>
- </sect1>
- <sect1 id="object-sources">
- <title>Source Objects</title>
- <para>
- 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.
- </para>
- <para>
- &AL; also provides additional functions to manipulate and query the
- execution state of Sources: the current playing status of a
- source (started, stopped, paused), including access to the current
- sampling position within the associated Buffer.
- </para>
-
- <![ %RFC [
- <note id="rfc-briareos000629-01"><title>RFC: Mike on Source Types</title><para>
- AL_SOURCE_ABSOLUTE and AL_SOURCE_AMBIENT have been
- deprecated. AL_SOURCE_ABSOLUTE was simply the converse of the
- AL_SOURCE_RELATIVE pname, and as such was unnecessary. The
- effect of AL_SOURCE_AMBIENT is trivially emulated by either
- querying the Listener position and setting the Source position
- accordingly, or setting the Source position to (0,0,0) and the
- type to AL_SOURCE_RELATIVE, and is therefore also unnecessary.
- </para></note>
- ]]>
-
- <![ %RFC [
- <note id="rfc-bk000721-02"><title>RFC: Bernd on Source Types</title><para>
- Mike seems to miss a few problems here. W/o a converse we can't
- reset source attributes to ABSOLUTE. Ambient sounds are not
- necessarily trivial. A3D manual suggested some magic number
- to fake the effect of ambient (i.e. sound that ideally
- can't be localized by listener). If we can get away with such magic
- numbers in a tutorial in a driver-independent way, fine. If there is any
- risk that the impression of ambient sound requires driver specific
- hacks, then we need AMBIENT. As soon as we have a third localization
- type, ABSOLUTE and RELATIVE are needed as there is no unambiguous
- converse.
- From the A3D 2.0 Optimize.doc:
- "Adding some ambient background noise is a great way to fill in the gaps
- when the audio content is reduced. A great way to make an ambient sound
- seem like it is coming from everywhere is to load up two buffers with the
- same sound, and position them about 2 meters behind the listener at
- about 4 and 8 o\rquote clock. The waves have to be looping (make sure
- there is no beating when you play them back). Starting the sounds 180
- degrees out of phase can help, as will playing them with slightly different
- pitch-shift values."
- </para></note>
- ]]>
- <![ %RFC [
- <note id="rfc-bk000721-03"><title>RFC: Bernd on Source Types (2)</title><para>
- There is a point to be made in using POSITION_RELATIVE and
- VELOCITY_RELATIVE iff we do not have AMBIENT to consider.
- This makes it a call-by-call choice when setting Source3f{v}
- vectors, as it is applied when dereferencing.
- </para></note>
- ]]>
- <![ %RFC [
- <note id="rfc-bk000721-04"><title>RFC: Bernd on Source Types (3)</title><para>
- Semantically, AMBIENT has nothing to do with coordinate systems,
- it is a qualifier just like multichannel direct passthru.
- </para></note>
- ]]>
- <![ %RFC [
- <note id="rfc-bk000721-05"><title>RFC: Source Attenuation Clamping</title><para>
- Using AL_SOURCE_ATTENUATION_MIN and AL_SOURCE_ATTENUATION_MAX
- to specify the clamping values for the normalized attenuation
- factor (which is a function of distance) is in contradiction
- to the distance based model that Creative is pushing for
- (DirectSound). As driver-interall culling of source and other
- processing might be based on the effective (overall, ultimate)
- gain composed of amplifications and attenuations accumulated
- over the entire processing, I raise the question whether a sound
- designer might not want to control the effective GAIN ranges
- instead of the distance attenuation itself. Samples commonly
- use the entire dynamic range provided by the format, which is
- mapped to the entire dynamic range of the output device. An
- effective gain exceeding 1 does not make sense, an amplification
- during processing might.
- </para></note>
- ]]>
-
- <sect2>
- <title>Managing Source Names</title>
- <para>
- &AL; provides calls to request and release Source Names handles.
- Calls to control Source Execution State are also provided.
- </para>
- <sect3>
- <title>Requesting a Source Name</title>
- <para>
- The application requests a number of Sources using GenSources.
- <funcsynopsis><funcprototype>
- <funcdef> &void; <function> GenSources </function></funcdef>
- <paramdef> &sizei; <parameter> n </parameter></paramdef>
- <paramdef> &uint;* <parameter> sources </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- </sect3>
- <sect3>
- <title>Releasing Source Names</title>
- <para>
- The application requests deletion of a number of Sources
- by DeleteSources.
- <funcsynopsis><funcprototype>
- <funcdef> &void; <function> DeleteSources </function></funcdef>
- <paramdef> &sizei; <parameter> n </parameter></paramdef>
- <paramdef> &uint;* <parameter> sources </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- </sect3>
- <sect3>
- <title>Validating a Source Name</title>
- <para>
- The application can verify whether a source name is valid
- using the IsSource query.
- <funcsynopsis><funcprototype>
- <funcdef> &bool; <function> IsSource </function></funcdef>
- <paramdef> &uint; <parameter> sourceName </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- </sect3>
- </sect2>
- <sect2>
- <title>Source Attributes</title>
- <para>
- This section lists the attributes that are set per Source,
- affecting the processing of the current buffer. Some of
- these attributes can also be set for buffer queue entries.
- </para>
- <![ %Annote [
- <note><title>Annotation (No Priorities)</title><para>
- There are no per Source priorities, and no explicit priority
- handling, defined at this point. A mechanism that lets the
- application express preferences in case that the implementation
- provides culling and prioritization mechanisms might be added
- at some later time. This topic is under discussion for GL as
- well, which already has one exlicit priority API along with
- internally used MRU heuristics (for resident texture memory).
- </para></note>
- ]]>
-
- <sect3>
- <title>Source Positioning</title>
- <para>
- <table>
- <title>SOURCE_RELATIVE Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> SOURCE_RELATIVE </>
- <entry> &bool; </>
- <entry> FALSE, TRUE</>
- <entry> FALSE </>
- </row>
- </tbody>
- </tgroup>
- </table>
- SOURCE_RELATIVE set to TRUE indicates that the values
- specified by POSITION are to be interpreted relative
- to the listener position.
- </para>
- <![ %Annote [
- <note><title>Annotation (Position only)</title><para>
- SOURCE_RELATIVE does not affect velocity or orientation
- calculation.
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Buffer Looping</title>
- <para>
- <table>
- <title>Source LOOPING Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <colspec colname=c1>
- <colspec colname=c2>
- <colspec colname=c3>
- <colspec colname=c4>
- <spanspec spanname=hspan namest=c1 nameend=c4 align=left>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> LOOPING </>
- <entry> &uint; </>
- <entry> TURE, FALSE</>
- <entry> FALSE </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- LOOPING is a flag that indicates that the Source will not
- be in 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 default value is FALSE.
- LOOPING can be changed on a Source in any execution state.
- In particular, it can be changed on a PLAYING Source.
- </para>
- <![ %Annote [
- <note><title>Annotation (Finite Repetition)</title><para>
- Finite reptition is implemented by buffer queueing.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Loop Control)</title><para>
- To implement a 3 stage "loop point" solution, the
- application has to queue the FadeIn buffer first,
- then queue the buffer it wants to loop, and set
- LOOPING to TRUE once the FadeIn buffer has been
- processed and unqueued. To fade from looping, the
- application can queue a FadeOut buffer, then
- set LOOPING to false on the PLAYING source. Alternatively,
- the application can decide to not use the LOOPING
- attribute at all, and just continue to queue the buffer
- it wants repeated.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Rejected alternatives)</title><para>
- A finite loop counter was rejected because it is
- ambiguous with respect to persistent (initial counter)
- vs. transient (current counter). For similar reasons,
- a Play-equivalent command with a (transient) loop counter
- was rejected.
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Current Buffer</title>
- <para>
- <table>
- <title>Source BUFFER Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>BUFFER</>
- <entry> &uint; </>
- <entry> any valid bufferName </>
- <entry> &NONE; </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- Specifies the current Buffer object, making it the
- head entry in the Source's queue. Using BUFFER on a
- STOPPED or INITIAL Source empties the entire queue,
- then appends the one Buffer specified.
- </para>
- <para>
- For a PLAYING or PAUSED Source, using the Source command
- with BUFFER is an INVALID_OPERATION.
- It can be applied to INITIAL and STOPPED Sources only.
- Specifying an invalid bufferName will
- result in an INVALID_VALUE error while specifying an
- invalid sourceName results in an INVALID_NAME error.
- </para>
- <para>
- NONE, i.e. 0, is a valid buffer Name.
- Source( sName, BUFFER, 0 ) is a legal way to release the
- current buffer queue on an INITIAL or STOPPED Source,
- whether it has just one entry (current buffer) or more.
- The Source( sName, BUFFER, NONE) call still causes an
- INVALID_OPERATION for any source PLAYING or PAUSED,
- consequently it cannot be abused to mute or stop a source.
- </para>
- <![ %Annote [
- <note><title>Annotation (repeated Source+BUFFER does not queue) </title><para>
- Using repeated Source(BUFFER) calls to queue a buffer on
- an active source would imply that there is no way to
- release the current buffer e.g. by setting it to 0.
- On the other hand read-only queues do not allow for
- releasing a buffer without releasing the entire queue.
- We can not require BUFFER state to be transient and lost
- as soon as a Source is implicitely or explicitely stopped.
- This contradicts queue state being part of the Source's
- configuration state that is preserved through Stop()
- operations and available for Play().
- </para></note>
- ]]>
-
- </sect3>
- <sect3>
- <title>Queue State Queries</title>
- <para>
- <table>
- <title>BUFFERS_QUEUED Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> BUFFERS_QUEUED </>
- <entry> &uint; </>
- <entry> [0, any]</>
- <entry> none </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Query only. Query 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. This will return 0 if the current and
- only bufferName is 0.
- </para>
- <para>
- <table>
- <title>BUFFERS_PROCESSED Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> BUFFERS_PROCESSED </>
- <entry> &uint; </>
- <entry> [0, any]</>
- <entry> none </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Query only. Query the number of buffers that have
- been played by a given Source.
- Indirectly, this gives the index of the buffer
- currently playing. Used to determine how much
- slots are needed for unqueueing them.
- On an STOPPED Source, all buffers are processed.
- On an INITIAL Source, no buffers are processed,
- all buffers are pending.
- This will return 0 if the current and
- only bufferName is 0.
- </para>
- <![ %Annote [
- <note><title>Annotation (per-Source vs. Buffer State)</title><para>
- BUFFERS_PROCESSED is only defined within the scope of a given
- Source's queue. It indicates that the given number of buffer names
- can be unqueued for this Source. It does not guarantee that the
- buffers can safely be deleted or refilled, as they might still be
- queued with other Sources. One way to keep track of this is to
- store, per buffer, the Source for which a given buffer was most
- recently scheduled (this will not work if Sources sharing buffers
- might be paused by the application). If necessary an explicit
- query for a given buffer name can be added in later revisions.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (No Looping Queues)</title><para>
- Unqueueing requires nonzero BUFFERS_PROCESSED,
- which necessitates no looping on entire queues,
- unless we accept that no unqueueing is possible
- from Source looping over the entire queue.
- Currently not supported, as queueing is
- primarily meant for streaming, which implies
- unqueue-refill-requeue operations.
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Bounds on Gain</title>
- <para>
- <table>
- <title>Source Minimal Gain</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MIN_GAIN</>
- <entry>f</>
- <entry>0.0f, (0.0f, 1.0f]</>
- <entry>0.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- MIN_GAIN is a scalar amplitude threshold. It indicates the minimal GAIN
- that is always guaranteed for this Source. At the end of the processing
- of various attenuation factors such as distance based attenuation and
- Source GAIN, the effective gain calculated is compared to this value.
- If the effective gain is lower than MIN_GAIN, MIN_GAIN is applied.
- This happens before the Listener GAIN is applied. If a zero MIN_GAIN
- is set, then the effective gain will not be corrected.
- </para>
- <![ %Annote [
- <note><title>Annotation (Effective Maximal Distance)</title><para>
- By setting MIN_GAIN, the application implicitely defines a
- maximum distance for a given distance attenuation model and
- Source GAIN. The distance at which the effective gain is MIN_GAIN
- can be used as a replacement to the DirectSound3D MAX_DISTANCE parameter.
- Once the effective gain has reached the MIN_GAIN value, it will
- no longer decrease with increasing distance.
- </para></note>
- ]]>
-
- <para>
- <table>
- <title>Source Maximal Gain (logarithmic)</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MAX_GAIN</>
- <entry>f</>
- <entry>0.0f, (0.0f, 1.0f]</>
- <entry>1.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- MAX_GAIN defines a scalar amplitude threshold. It indicates the maximal
- GAIN permitted for this Source. At the end of the processing
- of various attenuation factors such as distance based attenuation and
- Source GAIN, the effective gain calculated is compared to this value.
- If the effective gain is higher than MAX_GAIN, MAX_GAIN is applied.
- This happens before the Listener GAIN is applied. If the Listener gain
- times MAX_GAIN still exceeds the maximum gain the implementation can
- handle, the implementation is free to clamp. If a zero MAX_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 GAIN to zero is the proper way to mute a Source.
- </para>
- <![ %Annote [
- <note><title>Annotation (Un-attenuated Source)</title><para>
- Setting MIN_GAIN and MAX_GAIN to the GAIN value will effectively
- make the Source amplitude independent of distance. The
- implementation is free to optimize for this situation. However, the
- recommended way to accomplish this effect is using a ROLLOFF_FACTOR
- of zero.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Internal GAIN threshold)</title><para>
- The &AL; implementation is free to use an internally chosen
- threshold level below which a Source is ignored for mixing.
- Reasonable choices would set this threshold low enough so
- that the user will not perceive a difference. Setting MIN_GAIN
- for a source will override any implementation defined test.
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Distance Model Attributes</title>
- <para>
- <table>
- <title> REFERENCE_DISTANCE Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> REFERENCE_DISTANCE </>
- <entry> &float; </>
- <entry> [0, any]</>
- <entry> 1.0f </>
- </row>
- </tbody>
- </tgroup>
- </table>
- This 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 the
- section on distance models for details.
- </para>
- <para>
- <table>
- <title> ROLLOFF_FACTOR Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> ROLLOFF_FACTOR </>
- <entry> &float; </>
- <entry> [0, any]</>
- <entry> 1.0f </>
- </row>
- </tbody>
- </tgroup>
- </table>
- This is used for distance attenuation calculations
- based on inverse distance with rolloff. For
- distances smaller than MAX_DISTANCE (and, depending
- on the distance model, larger than REFERENCE_DISTANCE),
- this will scale the distance attenuation over the
- applicable range. See section on distance models for
- details how the attenuation is computed as a function
- of the distance.
- </para>
- <para>
- In particular, ROLLOFF_FACTOR 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 per-Source basis.
- </para>
- <para>
- <table>
- <title> MAX_DISTANCE Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry> MAX_DISTANCE </>
- <entry> &float; </>
- <entry> [0, any]</>
- <entry> MAX_FLOAT </>
- </row>
- </tbody>
- </tgroup>
- </table>
- This 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 MAX_DISTANCE will
- be clamped to MAX_DISTANCE.
- MAX_DISTANCE based clamping is applied before MIN_GAIN clamping,
- so if the effective gain at MAX_DISTANCE is larger than MIN_GAIN,
- MIN_GAIN will have no effect. No culling is supported.
- </para>
- <![ %Annote [
- <note><title>Annotation (No Culling)</title><para>
- This is a per-Source attribute supported for DS3D compatibility
- only. Other API features might suffer from side effects due to
- the clamping of distance (instead of e.g. clamping to an effective
- gain at MAX_DISTANCE).
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Frequency Shift by Pitch</title>
- <para>
- <table>
- <title>Source PITCH Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>PITCH</>
- <entry>f</>
- <entry> (0.0f, 2.0f]</>
- <entry> 1.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- Desired pitch shift, where 1.0 equals identity. Each reduction by 50 percent
- equals a pitch shift of -12 semitones (one octave reduction). Zero is not
- a legal value.
- </para>
- </sect3>
- <sect3>
- <title>Direction and Cone</title>
- <para>
- Each Source can be directional, depending on the settings for
- CONE_INNER_ANGLE and CONE_OUTER_ANGLE. 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.
- Source GAIN is applied for the inner cone,
- with an application selectable CONE_OUTER_GAIN factor to
- define the gain in the outer zone. In the transitional
- zone implementation-dependent interpolation between
- GAIN and GAIN times CONE_OUTER_GAIN is applied.
- </para>
- <![ %Annote [
- <note><title>Annotation (Interpolation Restrictions)</title><para>
- The specification does not specify the exact interpolation
- applied in the transitional zone, to calculate gain as a
- function of angle. The implementation is free to use
- linear or other interpolation, as long as the values
- are monotonically decreasing from GAIN to GAIN times CONE_OUTER_GAIN.
- </para></note>
- ]]>
- <para>
- <table>
- <title>Source DIRECTION Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>DIRECTION</>
- <entry>3fv, 3f</>
- <entry> any except NaN </>
- <entry> { 0.0f, 0.0f, 0.0f } </>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- If DIRECTION does not equal the zero vector, 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.
- </para><para>
- The zero vector is default, 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.
- </para>
- <![ %RFC [
- <note id="rfc-bk000821-01"><title>RFC: Oriented Sources </title><para>
- Do we want an alternative AZIMUTH/ALTITUDE parametrization?
- Do we need ORIENTATION later? Is this superimposable? Can we mix both?
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (All Sources Directional)</title><para>
- From the point of view of the &AL; implementation, all
- Sources are directional. Certain choices for cone angles
- as well as a direction vector with zero length are treated
- equivalent to an omnidirectional source. The &AL;
- implementation is free to flag and optimize these cases.
- </para></note>
- ]]>
- <![ %RFC [
- <note id="rfc-bk000803-05"><title>RFC: Separate GenDirectionSource?</title><para>
- Is there any risk that directional sources require different
- resources that have to be allocated from the beginning, and
- that we can not change an omnidirectional source to a
- bidirectional source at runtime?
- </para></note>
- ]]>
- <para>
- <table>
- <title>Source CONE_INNER_ANGLE Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>CONE_INNER_ANGLE</>
- <entry>i,f</>
- <entry>any except NaN</>
- <entry>360.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description:
- Inside angle of the sound cone, in degrees. The default of 360 means that the
- inner angle covers the entire world, which is equivalent to an omnidirectional
- source.
- </para>
- <![ %RFC [
- <note id="rfc-bk000926-01"><title>RFC: inconsistent cone angles? </title><para>
- Is (inner <= outer) required? Do we generate an error?
- Shouldn't this be a CONE_ANGLES 2f call specifying both angles at once?
- </para></note>
- ]]>
- <para>
- <table>
- <title>Source CONE_OUTER_ANGLE Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>CONE_OUTER_ANGLE</>
- <entry>i,f</>
- <entry>any except NaN</>
- <entry>360.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description: Outer angle of the sound cone, in degrees. The default of 360 means that the
- outer angle covers the entire world. If the inner angle is also 360, then
- the zone for angle-dependent attenuation is zero.
- </para>
-
- <![ %RFC [
- <note id="rfc-bk000926-02"><title>RFC: addition? </title><para>
- More generally, we could specify:
- "If the sum of inner and outer angles is larger than 360,
- CONE_OUTER_ANGLE is clamped to (360-CONE_INNER_ANGLE) and
- there is no transition zone."
- </para></note>
- ]]>
- <para>
- <table>
- <title>Source CONE_OUTER_GAIN Attribute</title>
- <tgroup cols="4" align="left" colsep=1 rowsep=1>
- <thead>
- <row>
- <entry>&Par;</>
- <entry>&Sig;</>
- <entry>&Val</>
- <entry>&Def;</>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>CONE_OUTER_GAIN</>
- <entry>i,f</>
- <entry>[0.0f, 1.0f]</>
- <entry>0.0f</>
- </row>
- </tbody>
- </tgroup>
- </table>
- Description: the factor with which GAIN is multiplied to
- determine the effective gain outside the cone defined by
- the outer angle. The effective gain applied outside the
- outer cone is GAIN times CONE_OUTER_GAIN. Changing
- GAIN affects all directions, i.e. the source is attenuated
- in all directions, for any position of the listener.
- The application has to change CONE_OUTER_GAIN as well if
- a different behavior is desired.
- </para>
-
-
- <![ %Annote [
- <note><title>Annotation (GAIN calculation)</title><para>
- The angle-dependend gain DGAIN is multiplied with the
- gain determined by the source's GAIN and any distance
- attenuation as applicable. Let theta be the angle
- between the source's direction vector, and the vector
- connection the source and the listener. This multiplier
- DGAIN is calculated as:
- <literallayout>
- OUTER = CONE_OUTER_ANGLE/2;
- INNER = CONE_INNER_ANGLE/2;
- if ( theta less/equal INNER )
- DGAIN = 1
- else if ( theta greater/equal OUTER )
- DGAIN = CONE_OUTER_GAIN
- else
- DGAIN = 1 - (1-CONE_OUTER_GAIN)*((theta-INNER)/(OUTER-INNER))
- GAIN *= DGAIN
- </literallayout>
- in the case of linear interpolation. The implementation
- is free to use a different interplation across the (INNER,OUTER)
- range as long as it is monotone.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (CONE_OUTER_GAIN always less than GAIN)</title><para>
- CONE_OUTER_GAIN is not an absolute value, but (like all GAIN
- parameters) a scaling factor. This avoids a possible error
- case (implementations can count on effective gain outside the
- outer cone being smaller than GAIN), and ensures the common
- case in which changing GAIN should affect inner, transitional,
- and outer zone simultaneously.
- </para><para>
- In case that the application desires to have an outer zone
- volume exceeding that of the inner cone, the mapping to
- &AL; will require to rotate the Source direction to the
- opposite direction (negate vector), and swapping
- inner and outer angle.
- </para></note>
- ]]>
- </sect3>
- </sect2>
- <sect2>
- <title>Changing Source Attributes</title>
- <para>
- The Source specifies the position and other properties as
- taken into account during sound processing.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> Source{n}{sifd} </function></funcdef>
- <paramdef> &uint; <parameter> sourceName </parameter></paramdef>
- <paramdef> &enum; <parameter> paramName </parameter></paramdef>
- <paramdef> &type; <parameter> value </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> Source{n}{sifd}v </function></funcdef>
- <paramdef> &uint; <parameter> sourceName </parameter></paramdef>
- <paramdef> &enum; <parameter> paramName </parameter></paramdef>
- <paramdef> &type;* <parameter> values </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- </sect2>
- <sect2>
- <title>Querying Source Attributes</title>
- <para>
- Source state is maintained inside the &AL; implementation, and the
- current attributes can be queried. The performance of such queries is
- implementation dependent, no performance guarantees are made. The
- valid values for the paramName parameter are identical to the ones
- for Source*.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> GetSource{n}{sifd}{v} </function></funcdef>
- <paramdef> &uint; <parameter> sourceName </parameter></paramdef>
- <paramdef> &enum; <parameter> paramName </parameter></paramdef>
- <paramdef> &type;* <parameter> values </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- <![ %Scratch [
- <warning><para>
- Old signature: T GetSource{sifd}{v}( uint id, enum param );
- </para></warning>
- ]]>
-
- </sect2>
- <sect2 id="queueing">
- <title>Queueing Buffers with a Source</title>
- <para>
- &AL; does not specify a built-in streaming mechanism. There
- is no mechanism to stream data e.g. into a Buffer object.
- Instead, the API introduces a more flexible and versatile
- mechanism to queue Buffers for Sources.
- </para>
- <para>
- There are many ways to use this feature, with
- streaming being only one of them.
- <itemizedlist>
- <listitem>
- <para>
- 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, whether these are re-used in cycle,
- pooled, or thrown away.
- </para>
- </listitem>
- <listitem>
- <para>
- Looping (over a finite number of repititions) can be
- implemented by explicitely 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 is
- recommended.
- </para>
- </listitem>
- <listitem>
- <para>
- Loop Points for restricted looping inside a buffer
- can in many cases be replaced by splitting the
- sample into several buffers, queueing the sample
- fragments (including repetitions) accordingly.
- </para>
- </listitem>
- </itemizedlist>
- 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 a distinct advantages over approaches that
- require explicit management of samples and sample indices.
- </para>
- <![ %RFC [
- <note id="bk000626-01"><title>RFC: Unified Handling</title><para>
- Jonathan Blow has proposed removing the distinction between
- streaming and non-streaming buffers. An existing example is
- the unified for directional and omnidirectional sources, where
- all sources are treated as directional.
- </para></note>
- ]]>
- <sect3>
- <title>Queueing command</title>
- <para>
- The application can queue up one or multiple buffer names
- using SourceQueueBuffers. The buffers will be queued in the sequence
- in which they appear in the array.
- <funcsynopsis><funcprototype>
- <funcdef> &void; <function> alSourceQueueBuffers </function></funcdef>
- <paramdef> &uint; <parameter> sourceName </parameter></paramdef>
- <paramdef> &sizei; <parameter> numBuffers </parameter></paramdef>
- <paramdef> &uint; * <parameter> bufferNames </parameter></paramdef>
- </funcprototype></funcsynopsis>
- This command is legal on a Source in any state (to allow for
- streaming, queueing has to be possible on a PLAYING Source).
- Queues are read-only with exception of the unqueue operation.
- The Buffer Name NONE (i.e. 0) can be queued.
- </para>
-
- <![ %Annote [
- <note><title>Annotation (BUFFER vs. SourceQueueBuffers)</title><para>
- A Sourcei( sname, BUFFER, bname ) command is an immediate
- command, and executed immediately. It effectively unqueues
- all buffers, and then adds the specified buffer to the
- then empty queue as its single entry. Consequently, this
- call is only legal if SourceUnqueueBuffers is legal.
- In particular, the Source has to be STOPPED or INITIAL.
- The application is still obliged to delete all
- buffers as were contained in the queue.
- Sourcei( sname, BUFFER, NONE ) is a legal command,
- effectively wiping the queue without specifying an
- actually playable buffer.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Buffer Repetition)</title><para>
- To accomplish a finite number of repetitions of a buffer name multiple times,
- the buffer has to be queued multiple times. If the need occurs, the
- API could be extended by SourceQueueBuffer( sname, bname, repetitions )
- call for brevity.
- </para></note>
- ]]>
- <![ %RFC [
- <note id="rfc-bk000806-04"><title>RFC: Duration of bName==0? </title><para>
- The buffer is considered empty, it should have zero length,
- thus zero duration for consistency. If an application wants to
- schedule a pause, specifying duration for a gain==0 queue entry
- might be a cleaner solution.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Backwards Compatiblity)</title><para>
- Sourcei( sname, BUFFER, bname ) has been rejected as
- a queueing command, as it would make semantics dependent on
- source state (queueing if PLAYING, immediate else).
- The command is not legal on a PLAYING or PAUSED Source.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (No BUFFER_QUEUE)</title><para>
- Duplication of one entry point is preferable to
- duplicating token enums, and tokens do not express
- commands, but specify the attribute/state affected.
- From the same reason, there is no BUFFER_UNQUEUE
- token-as-command.
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Unqueueing command</title>
- <para>
- 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).
- </para>
- <para>
- The Unqueue command removes a number of buffers entries that
- have finished processing, in the order of appearance, from
- the queue. The operation will fail if more buffers are
- requested than available, leaving the destination arguments
- unchanged. An INVALID_VALUE error will be thrown.
- If no error, the destination argument will have been updated
- accordingly.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourceUnqueueBuffers </function></funcdef>
- <paramdef> &uint; <parameter> sourceName </parameter></paramdef>
- <paramdef> &sizei; <parameter> numEntries </parameter></paramdef>
- <paramdef> &uint;* <parameter> bufferNames </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- <![ %Annote [
- <note><title>Annotation (Unqueueing shared buffers)</title><para>
- If a buffer is queued with more than one source, it might have
- been processed for some not all of them. With the current
- interface, the application is forced to maintain its own list
- of consumers (Sources) for a buffer it wishes to unqueue.
- For groups of Sources that are never individually PAUSED
- nor STOPPED, the application can save the MRU Source for
- which the buffer was scheduled last.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Looping a Queue vs. Unqueue):</title><para>
- If a Source is playing repeatedly, it will traverse
- the entire Queue repeatedly. Consequently, no buffer
- in the queue can be considered processed until
- there is no further repetition scheduled.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (No Name based access)</title><para>
- No interface is provided to access a queue entry by name,
- due to ambiguity (same buffer name scheduled several times
- in a sequence).
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (No Index based access)</title><para>
- No interface is provided for random access to a queue entry
- by index.
- </para></note>
- ]]>
- </sect3>
- <![ %Annote [
- <sect3>
- <title>More Annotation on Queueing</title>
- <![ %Annote [
- <note><title>Annotation (No Queue Copying)</title><para>
- The current queue of a source could be copied to another source,
- as repetition and traversal parameters are stored unless the
- queue entry is unqueued, or the queue is replaced using
- AL_BUFFER. Copying a queue is a special case of
- copying Source state in one sense, and a special case of
- a synching problem in another. Due to these unresolved issues
- no such command is included in the current specification.
- To share queues, the application can keep buffer names
- and the selected attributes that define the queue entries
- in an array or other lookup table.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (No Explicit QueueClear)</title><para>
- Sourcei( sname, BUFFER, NONE ) serves the
- same purpose. The operation is also redundant
- with respect to Unqueue for a STOPPED Source.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Queueing vs. AppendData):</title><para>
- Buffer queueing does not solve the synchronization and timing
- issues raised by possible underflow, as these are inherent
- to application-driven (pushed) streaming. However, it turns
- an internal AL error condition (offset exceeds valid data)
- into an audible artifact (Source stops).
- Its main advantage is that it allows the application coder
- to operate at a scale of her own choice, selecting the
- number and size of buffers used for caching the stream,
- and to schedule buffer refill and queueing according to
- preferences and constraints. Queueing effectively moves
- all problems related to replacing or appending Buffer data
- to the scale of entire arrays istead of single samples and
- indices.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Multiple Sources on a stream)</title><para>
- Queueing allows for the application to determine how much of
- a backlog of the data stream is preserved. The application can
- keep buffers, and queue them with other Sources after they have
- been used already by the original Source. Unlike the mechanism
- for appending data to a buffer, the backlog is visible to the
- application and under its control, and no synchronization of
- Sources using the stream is required.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Loop Points and Compressed Data)</title><para>
- For compressed data, uncompression by the application might be
- impossible or undesireable. In consequence, splitting the sample
- into several buffers is not possible without explicit support
- by the API. Buffer-Buffer operations will be added as needed,
- for the time being applications should not try to use compressed
- samples if more than full looping is required.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (No Explicit Queue Objects)</title><para>
- Explicit Queue objects have been considered and rejected,
- as they introduce another producer-consumer dependency with
- another level of indirection. Further, e.g. QUEUE would
- also require deprecating BUFFER (breaking backwards
- compatibility) as an alSource argument, or would introduce
- a confusing set of precedence and overide rules if both
- are used in sequence. However, in the absence of explicit
- queue objects the application will be forced to keep track
- where buffers have been queued in case it intends to
- unqueue them for refill or deletion. If several sources
- use the same buffers (e.g. for synchronous or
- asynchronous streaming) the buffer will have to be
- unqueued from each single one.
- </para></note>
- ]]>
- <![ %Scratch [
- <note><title>Annotation (Queue no Display List)</title><para>
- An interface resembling &OGL; display-lists has been
- considered and rejected. The problem with this approach
- is that not only commands would have to be prohibited
- (similarly, not all GL calls are legal within a display
- list), but also parameters (enumerations).
- In particular, only a small set of operations is meant
- to be legal for a queue at this point, and appending
- to a queue has to be possible at any time.
- Within a hypothetical AL display list, only relative
- timing/conditionals are allowed as arguments. This
- might necessitate to have multiple forms for deferred
- commands, or to not allow for absolute timing.
- Example:
- <literallayout>
- // lock this queue for overwriting/appending
- alBeginQueue( qname, APPEND | REPLACE );
- // queue a buffer in sequence, with parameters
- // boolean: never skip? never bail?
- alQueue( AL_BUFFER, bid, loopdir, repetitions );
- ...
- // end lock.
- // Existing queue content will be replaced
- // or appended at this point.
- alEndQueue();
- </literallayout>
- </para></note>
- ]]>
- <![ %Example [
- <example>
- <title>Queue Then Delete </title>
- <programlisting>
- create source
- queue buffer1
- queue buffer2
- queue buffer3
- play
- request deletion of buffer1,2,3
-
- </programlisting>
- </example>
- ]]>
- <![ %Example [
- <example>
- <title> Queue and Refill with Dual Buffering</title>
- <programlisting>
- create source
- fill buffer1
- queue buffer1
- play
- fill buffer2
- queue buffer2
- check for unused buffers
- unqueue buffer1
- fill buffer1
- queue buffer1
- ...
-
- </programlisting>
- </example>
- ]]>
- <![ %Example [
- <example>
- <title> Queue for Loop Points</title>
- <programlisting>
- create source
- read sample data
- split sample data into pre/main/post
- queue pre
- queue main with repetitions
- queue post
- play
- set repetitions to 0 on main when needed
- wait till post has been played
-
- </programlisting>
- </example>
- ]]>
-
- </sect3>
- ]]>
- <![ %Scratch [
- <sect3>
- <title>Attributes Specific to Queueing</title>
- <section>
- <title>Buffer Traversal</title>
- <para>
- The Buffer traversal attribute specifies the direction
- in which the sample in the buffer is supposed to be
- processed. To account for the 3 basic modes of traversal that
- can be implemented in software and hardware, the following
- tokens are defined:
- <literallayout>
- LOOP_DIRECTION /* traversal direction */
- FORWARD /* linear forward (increment) */
- BACKWARD /* linear backward (decrement) */
- FORWARD_AND_BACK /* RESERVED: ping-pong-looping */
-
- </literallayout>
- The first and the next two tokens are legal with a buffer queue command.
- They are not legal for a Source command, in any possible
- Source state. The last token is reserved, but not yet legal to use.
- </para>
- <![ %Annote [
- <note><title>Annotation (Ping-Pong postponed)</title><para>
- Definition and implementation of ping-pong looping
- has been postponed. Applications can fake it at doubling
- memory expense by reverse copying the buffer (2nd buffer queued
- or in a double size single buffer). If there is hardware support
- for this feature, AL will have to support it eventually. A boolean
- flag is not acceptable because of this possibility.
- </para></note>
- ]]>
- </sect3>
- ]]> <!-- SCRATCH -->
-
-
- </sect2>
-
- <sect2>
- <title>Managing Source Execution</title>
- <para>
- The execution state of a source can be queried. &AL; provides
- a set of functions that initiate state transitions causing
- Sources to start and stop execution.
- </para>
- <para>
- TBA: State Transition Diagram.
- </para>
- <![ %Annote [
- <note><title>Annotation/ Source Config/Exec State</title><para>
- Sources have configuration state and execution state.
- Configuration state is directly set by the application using
- AL commands, starting with the INITIAL configuration. Execution
- state (e.g. the offset to the current sample) is not under direct
- application control and not exposed.
- </para></note>
- ]]>
- <sect3>
- <title>Source State Query</title>
- <para>
- The application can query the current state of any Source
- using GetSource with the parameter Name SOURCE_STATE.
- 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.
- </para>
- </sect3>
- <sect3>
- <title>State Transition Commands</title>
- <para>
- The default state of any Source is INITIAL. From this state
- it can be propagated to any other state by appropriate use
- of the commands below. There are no irreversible state
- transitions.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourcePlay </function></funcdef>
- <paramdef> &uint; <parameter> sName </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourcePause </function></funcdef>
- <paramdef> &uint; <parameter> sName </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourceStop </function></funcdef>
- <paramdef> &uint; <parameter> sName </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourceRewind </function></funcdef>
- <paramdef> &uint; <parameter> sName </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- <para>
- The functions are also available as a vector variant,
- which guarantees synchronized operation on a set of
- Sources.
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourcePlayv </function></funcdef>
- <paramdef> &sizei; <parameter> n </parameter></paramdef>
- <paramdef> &uint;* <parameter> sNames </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourcePausev </function></funcdef>
- <paramdef> &sizei; <parameter> n </parameter></paramdef>
- <paramdef> &uint;* <parameter> sNames </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourceStopv </function></funcdef>
- <paramdef> &sizei; <parameter> n </parameter></paramdef>
- <paramdef> &uint;* <parameter> sNames </parameter></paramdef>
- </funcprototype></funcsynopsis>
- <funcsynopsis><funcprototype>
- <funcdef> void <function> SourceRewindv </function></funcdef>
- <paramdef> &sizei; <parameter> n </parameter></paramdef>
- <paramdef> &uint;* <parameter> sNames </parameter></paramdef>
- </funcprototype></funcsynopsis>
- </para>
- <para>
- The following state/command/state transitions are defined:
- <itemizedlist>
- <listitem>
- <para>
- 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.
- </para>
- </listitem>
- <listitem>
- <para>
- Pause() applied to an INITIAL Source is a legal NOP.
- Pause() applied to a PLAYING Source will change its state to
- PAUSED. The Source is exempt from processing, its current
- state is preserved.
- Pause() applied to a PAUSED Source is a legal NOP.
- Pause() applied to a STOPPED Source is a legal NOP.
- </para>
- </listitem>
- <listitem>
- <para>
- 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.
- </para>
- </listitem>
- <listitem>
- <para>
- 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 a STOPPED Source promotes the Source
- to INITIAL, resetting the sampling offset to the beginning.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <![ %Annote [
- <note><title>Annotation (SourceNext)</title><para>
- The specification does not provide any means to
- immediately skip from the current Buffer to the
- next in the queue. A conditional stop (following
- the next complete traversal) is available.
- If necessary an additonal entry point could be
- provided in future revisions.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Rewind() optional)</title><para>
- The INITIAL state is not identical to the STOPPED state.
- Applications that want to verify whether a Source
- has indeed been PLAYING before becoming STOPPED can
- use Rewind() to reset the Source state to INITIAL.
- This is an optional operation that can safely be
- omitted by application without this constraint.
- Applications that want to guard against Play() on
- a Source that is INITIAL can query the Source state
- first.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (Play() on a PLAYING Source)</title><para>
- Repeated Play() commands applied a PLAYING Source are
- interpreted as an (atomic) sequence to stop and restart a
- Source. This can be used by applications that want to restart
- a sound but do not care whether the Source has finished or not,
- and do not want an audible pause. One example is the DOOM
- chaingun repeatedly abbreviating the pistol sound. To guard
- against redundant Play() commands, an application can query
- the current state before executing Play(). If the application
- coder wants to be sure that the Source will play the buffer
- again, she can either increment PLAY_COUNT, or queue the buffer.
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (redundant commands)</title><para>
- The simple variant (e.g. SourcePlay) is redundant to
- the vector variant (e.g. SourcePlayv). However, these
- calls will be used frequently, and the simple variant
- is provided for convenience. However, &AL; does not
- enable applications to use literals as source names.
- </para></note>
- ]]>
- </sect3>
- <sect3>
- <title>Resetting Configuration</title>
- <para>
- The INITIAL state is not necessarily identical to the
- default state in which Source is created. INITIAL merely
- indicates that the Source can be executed using the
- SourcePlay command. A STOPPED or INITIAL Source can
- be reset into the default configuration by using a
- sequence 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.
- </para>
-
- <![ %RFC [
- <note id="rfc-bk000802-01"><title>RFC: remove INITIAL</title><para>
- INITIAL is identical to STOPPED. The only additional information
- conveyed is that INITIAL indicates a source has never been played.
- Once a Source is STOPPED, it is not possible by state query alone
- to decide whether it has played again. If Sources are used only
- once, an application can use INITIAL to verify a Source has been
- played.
- The problem that I have with this is that if we acknowledge that
- the application might need to verify a Source has played once,
- why force the application to throw away Sources to accomplish
- this? An explicit state PLAYABLE replacing INITIAL and its
- inauspicious connotations (default state) and a state transition
- function Rewind() that makes a STOPPED Source PLAYABLE again would
- be one possibility to address this need. The obvious drawback is
- that it breaks backwards compatibility.
- </para></note>
- ]]>
- <![ %RFC [
- <note id="rfc-bk000731-01"><title>RFC: state issues </title><para>
- A Source is active if it is PAUSED or PLAYING.
- A Source that is STOPPED preserves configuration state,
- including buffer/queue information.
- Only a Source that is Reset() to INITIAL looses all
- buffer and queue information. In this case, the INITIAL
- Sources will be stopped implicitely when reaching the
- end of a non-repeating (non-looping) buffer traversal.
- Sources can be stopped explicitely by the application
- with either Stop() or Reset().
- Stop() propagates
- the source to STOPPED preserving its configuration state,
- setting its execution state to the same as if it reached
- the end of execution.
-
- </para></note>
- ]]>
- <![ %Annote [
- <note><title>Annotation (illegal NOPs)</title><para>
- In the current specification there are no illegal NOPs.
- In other words, no sequence of commands affecting the
- execution state will generate an INVALID_OPERATION error.
- </para></note>
- ]]>
- <![ %RFC [
- <note><title>RFC/bk000504:</title><para>
- No UNDEFINED state. Always valid state. I.e. we have a default Buffer
- that is used for sources where the application doesn't specify,
- and what's in it? Default gain is zero? We need to specify
- INITIAL.
- </para></note>
- <note><title>RFC/bk000504:</title><para>
- Potential ambiguity: how to we distinguish STOPPED as
- requested by the application from INACTIVE for
- non-looping sounds once the buffer has been iterated?
- Related: handling of Sources using an underflowing
- streaming buffer? IMO not recommended, make this
- undefined on error.
- </para></note>
- <note><title>RFC/bk000504:</title><para>
- Possible redundancy: the only reason for STOP seems to
- be resetting the play positions. Redundant if we
- ever manipulate offsets directly (rewind/set).
- </para></note>
- <note><title>RFC/bk000504:</title><para>
- Possible redundancy:
- If we ever want to support explicit setting of the start
- position/offset into Buffer, START is equivalent to Set(0).
- Also see LOOP (implies has to be STOPPED). Fade-Out and
- Fade-In control - always manually?
- </para></note>
- ]]>
- </sect3>
- </sect2>
- </sect1>
- </chapter>
|