123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656 |
- /**
- * OpenAL cross platform audio library
- * Copyright (C) 1999-2007 by authors.
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
- #include "config.h"
- #include <math.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <assert.h>
- #include "alMain.h"
- #include "AL/al.h"
- #include "AL/alc.h"
- #include "alSource.h"
- #include "alBuffer.h"
- #include "alThunk.h"
- #include "alListener.h"
- #include "alAuxEffectSlot.h"
- #include "alu.h"
- #include "bs2b.h"
- #define FRACTIONBITS 14
- #define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
- #define MAX_PITCH 65536
- /* Minimum ramp length in milliseconds. The value below was chosen to
- * adequately reduce clicks and pops from harsh gain changes. */
- #define MIN_RAMP_LENGTH 16
- static __inline ALfloat aluF2F(ALfloat Value)
- {
- return Value;
- }
- static __inline ALshort aluF2S(ALfloat Value)
- {
- ALint i;
- if(Value < 0.0f)
- {
- i = (ALint)(Value*32768.0f);
- i = max(-32768, i);
- }
- else
- {
- i = (ALint)(Value*32767.0f);
- i = min( 32767, i);
- }
- return ((ALshort)i);
- }
- static __inline ALubyte aluF2UB(ALfloat Value)
- {
- ALshort i = aluF2S(Value);
- return (i>>8)+128;
- }
- static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
- {
- outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
- outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
- outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
- }
- static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
- {
- return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
- inVector1[2]*inVector2[2];
- }
- static __inline ALvoid aluNormalize(ALfloat *inVector)
- {
- ALfloat length, inverse_length;
- length = aluSqrt(aluDotproduct(inVector, inVector));
- if(length != 0.0f)
- {
- inverse_length = 1.0f/length;
- inVector[0] *= inverse_length;
- inVector[1] *= inverse_length;
- inVector[2] *= inverse_length;
- }
- }
- static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
- {
- ALfloat temp[4] = {
- vector[0], vector[1], vector[2], w
- };
- vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
- vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
- vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
- }
- static ALvoid SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[OUTPUTCHANNELS],
- Channel Speaker2Chan[OUTPUTCHANNELS], ALint chans)
- {
- char layout_str[256];
- char *confkey, *next;
- char *sep, *end;
- Channel val;
- int i;
- strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
- layout_str[255] = 0;
- if(!layout_str[0])
- return;
- next = confkey = layout_str;
- while(next && *next)
- {
- confkey = next;
- next = strchr(confkey, ',');
- if(next)
- {
- *next = 0;
- do {
- next++;
- } while(isspace(*next) || *next == ',');
- }
- sep = strchr(confkey, '=');
- if(!sep || confkey == sep)
- continue;
- end = sep - 1;
- while(isspace(*end) && end != confkey)
- end--;
- *(++end) = 0;
- if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
- val = FRONT_LEFT;
- else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
- val = FRONT_RIGHT;
- else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
- val = FRONT_CENTER;
- else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
- val = BACK_LEFT;
- else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
- val = BACK_RIGHT;
- else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
- val = BACK_CENTER;
- else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
- val = SIDE_LEFT;
- else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
- val = SIDE_RIGHT;
- else
- {
- AL_PRINT("Unknown speaker for %s: \"%s\"\n", name, confkey);
- continue;
- }
- *(sep++) = 0;
- while(isspace(*sep))
- sep++;
- for(i = 0;i < chans;i++)
- {
- if(Speaker2Chan[i] == val)
- {
- long angle = strtol(sep, NULL, 10);
- if(angle >= -180 && angle <= 180)
- SpeakerAngle[i] = angle * M_PI/180.0f;
- else
- AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
- break;
- }
- }
- }
- for(i = 0;i < chans;i++)
- {
- int min = i;
- int i2;
- for(i2 = i+1;i2 < chans;i2++)
- {
- if(SpeakerAngle[i2] < SpeakerAngle[min])
- min = i2;
- }
- if(min != i)
- {
- ALfloat tmpf;
- Channel tmpc;
- tmpf = SpeakerAngle[i];
- SpeakerAngle[i] = SpeakerAngle[min];
- SpeakerAngle[min] = tmpf;
- tmpc = Speaker2Chan[i];
- Speaker2Chan[i] = Speaker2Chan[min];
- Speaker2Chan[min] = tmpc;
- }
- }
- }
- static __inline ALfloat aluLUTpos2Angle(ALint pos)
- {
- if(pos < QUADRANT_NUM)
- return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
- if(pos < 2 * QUADRANT_NUM)
- return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
- if(pos < 3 * QUADRANT_NUM)
- return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
- return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
- }
- ALvoid aluInitPanning(ALCdevice *Device)
- {
- ALfloat SpeakerAngle[OUTPUTCHANNELS];
- Channel *Speaker2Chan;
- ALfloat Alpha, Theta;
- ALint pos, offset;
- ALuint s, s2;
- for(s = 0;s < OUTPUTCHANNELS;s++)
- {
- for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
- Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
- }
- Speaker2Chan = Device->Speaker2Chan;
- switch(Device->Format)
- {
- case AL_FORMAT_MONO8:
- case AL_FORMAT_MONO16:
- case AL_FORMAT_MONO_FLOAT32:
- Device->DuplicateStereo = AL_FALSE;
- Device->ChannelMatrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
- Device->NumChan = 1;
- Speaker2Chan[0] = FRONT_CENTER;
- SpeakerAngle[0] = 0.0f * M_PI/180.0f;
- break;
- case AL_FORMAT_STEREO8:
- case AL_FORMAT_STEREO16:
- case AL_FORMAT_STEREO_FLOAT32:
- Device->DuplicateStereo = AL_FALSE;
- Device->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
- Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
- Device->ChannelMatrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
- Device->ChannelMatrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
- Device->ChannelMatrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
- Device->NumChan = 2;
- Speaker2Chan[0] = FRONT_LEFT;
- Speaker2Chan[1] = FRONT_RIGHT;
- SpeakerAngle[0] = -90.0f * M_PI/180.0f;
- SpeakerAngle[1] = 90.0f * M_PI/180.0f;
- SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
- break;
- case AL_FORMAT_QUAD8:
- case AL_FORMAT_QUAD16:
- case AL_FORMAT_QUAD32:
- Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
- Device->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
- Device->NumChan = 4;
- Speaker2Chan[0] = BACK_LEFT;
- Speaker2Chan[1] = FRONT_LEFT;
- Speaker2Chan[2] = FRONT_RIGHT;
- Speaker2Chan[3] = BACK_RIGHT;
- SpeakerAngle[0] = -135.0f * M_PI/180.0f;
- SpeakerAngle[1] = -45.0f * M_PI/180.0f;
- SpeakerAngle[2] = 45.0f * M_PI/180.0f;
- SpeakerAngle[3] = 135.0f * M_PI/180.0f;
- SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
- break;
- case AL_FORMAT_51CHN8:
- case AL_FORMAT_51CHN16:
- case AL_FORMAT_51CHN32:
- Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
- Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
- Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
- Device->NumChan = 5;
- Speaker2Chan[0] = BACK_LEFT;
- Speaker2Chan[1] = FRONT_LEFT;
- Speaker2Chan[2] = FRONT_CENTER;
- Speaker2Chan[3] = FRONT_RIGHT;
- Speaker2Chan[4] = BACK_RIGHT;
- SpeakerAngle[0] = -110.0f * M_PI/180.0f;
- SpeakerAngle[1] = -30.0f * M_PI/180.0f;
- SpeakerAngle[2] = 0.0f * M_PI/180.0f;
- SpeakerAngle[3] = 30.0f * M_PI/180.0f;
- SpeakerAngle[4] = 110.0f * M_PI/180.0f;
- SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
- break;
- case AL_FORMAT_61CHN8:
- case AL_FORMAT_61CHN16:
- case AL_FORMAT_61CHN32:
- Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
- Device->ChannelMatrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
- Device->NumChan = 6;
- Speaker2Chan[0] = SIDE_LEFT;
- Speaker2Chan[1] = FRONT_LEFT;
- Speaker2Chan[2] = FRONT_CENTER;
- Speaker2Chan[3] = FRONT_RIGHT;
- Speaker2Chan[4] = SIDE_RIGHT;
- Speaker2Chan[5] = BACK_CENTER;
- SpeakerAngle[0] = -90.0f * M_PI/180.0f;
- SpeakerAngle[1] = -30.0f * M_PI/180.0f;
- SpeakerAngle[2] = 0.0f * M_PI/180.0f;
- SpeakerAngle[3] = 30.0f * M_PI/180.0f;
- SpeakerAngle[4] = 90.0f * M_PI/180.0f;
- SpeakerAngle[5] = 180.0f * M_PI/180.0f;
- SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
- break;
- case AL_FORMAT_71CHN8:
- case AL_FORMAT_71CHN16:
- case AL_FORMAT_71CHN32:
- Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
- Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
- Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
- Device->NumChan = 7;
- Speaker2Chan[0] = BACK_LEFT;
- Speaker2Chan[1] = SIDE_LEFT;
- Speaker2Chan[2] = FRONT_LEFT;
- Speaker2Chan[3] = FRONT_CENTER;
- Speaker2Chan[4] = FRONT_RIGHT;
- Speaker2Chan[5] = SIDE_RIGHT;
- Speaker2Chan[6] = BACK_RIGHT;
- SpeakerAngle[0] = -150.0f * M_PI/180.0f;
- SpeakerAngle[1] = -90.0f * M_PI/180.0f;
- SpeakerAngle[2] = -30.0f * M_PI/180.0f;
- SpeakerAngle[3] = 0.0f * M_PI/180.0f;
- SpeakerAngle[4] = 30.0f * M_PI/180.0f;
- SpeakerAngle[5] = 90.0f * M_PI/180.0f;
- SpeakerAngle[6] = 150.0f * M_PI/180.0f;
- SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
- break;
- default:
- assert(0);
- }
- if(GetConfigValueBool(NULL, "scalemix", 0))
- {
- ALfloat maxout = 1.0f;
- for(s = 0;s < OUTPUTCHANNELS;s++)
- {
- ALfloat out = 0.0f;
- for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
- out += Device->ChannelMatrix[s2][s];
- maxout = __max(maxout, out);
- }
- maxout = 1.0f/maxout;
- for(s = 0;s < OUTPUTCHANNELS;s++)
- {
- for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
- Device->ChannelMatrix[s2][s] *= maxout;
- }
- }
- for(pos = 0; pos < LUT_NUM; pos++)
- {
- /* clear all values */
- offset = OUTPUTCHANNELS * pos;
- for(s = 0; s < OUTPUTCHANNELS; s++)
- Device->PanningLUT[offset+s] = 0.0f;
- if(Device->NumChan == 1)
- {
- Device->PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
- continue;
- }
- /* source angle */
- Theta = aluLUTpos2Angle(pos);
- /* set panning values */
- for(s = 0; s < Device->NumChan - 1; s++)
- {
- if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
- {
- /* source between speaker s and speaker s+1 */
- Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
- (SpeakerAngle[s+1]-SpeakerAngle[s]);
- Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
- Device->PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
- break;
- }
- }
- if(s == Device->NumChan - 1)
- {
- /* source between last and first speaker */
- if(Theta < SpeakerAngle[0])
- Theta += 2.0f * M_PI;
- Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
- (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
- Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
- Device->PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
- }
- }
- }
- static ALvoid CalcNonAttnSourceParams(const ALCcontext *ALContext, ALsource *ALSource)
- {
- ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
- ALfloat DryGain, DryGainHF;
- ALfloat WetGain[MAX_SENDS];
- ALfloat WetGainHF[MAX_SENDS];
- ALint NumSends, Frequency;
- ALfloat cw;
- ALint i;
- //Get context properties
- NumSends = ALContext->Device->NumAuxSends;
- Frequency = ALContext->Device->Frequency;
- //Get listener properties
- ListenerGain = ALContext->Listener.Gain;
- //Get source properties
- SourceVolume = ALSource->flGain;
- MinVolume = ALSource->flMinGain;
- MaxVolume = ALSource->flMaxGain;
- //1. Multi-channel buffers always play "normal"
- ALSource->Params.Pitch = ALSource->flPitch;
- DryGain = SourceVolume;
- DryGain = __min(DryGain,MaxVolume);
- DryGain = __max(DryGain,MinVolume);
- DryGainHF = 1.0f;
- switch(ALSource->DirectFilter.type)
- {
- case AL_FILTER_LOWPASS:
- DryGain *= ALSource->DirectFilter.Gain;
- DryGainHF *= ALSource->DirectFilter.GainHF;
- break;
- }
- for(i = 0;i < OUTPUTCHANNELS;i++)
- ALSource->Params.DryGains[i] = DryGain * ListenerGain;
- for(i = 0;i < NumSends;i++)
- {
- WetGain[i] = SourceVolume;
- WetGain[i] = __min(WetGain[i],MaxVolume);
- WetGain[i] = __max(WetGain[i],MinVolume);
- WetGainHF[i] = 1.0f;
- switch(ALSource->Send[i].WetFilter.type)
- {
- case AL_FILTER_LOWPASS:
- WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
- WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
- break;
- }
- ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
- }
- for(i = NumSends;i < MAX_SENDS;i++)
- {
- ALSource->Params.WetGains[i] = 0.0f;
- WetGainHF[i] = 1.0f;
- }
- /* Update filter coefficients. Calculations based on the I3DL2
- * spec. */
- cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
- /* We use two chained one-pole filters, so we need to take the
- * square root of the squared gain, which is the same as the base
- * gain. */
- ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
- for(i = 0;i < NumSends;i++)
- {
- /* We use a one-pole filter, so we need to take the squared gain */
- ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
- ALSource->Params.Send[i].iirFilter.coeff = a;
- }
- }
- static ALvoid CalcSourceParams(const ALCcontext *ALContext, ALsource *ALSource)
- {
- const ALCdevice *Device = ALContext->Device;
- ALfloat InnerAngle,OuterAngle,Angle,Distance,DryMix,OrigDist;
- ALfloat Direction[3],Position[3],SourceToListener[3];
- ALfloat Velocity[3],ListenerVel[3];
- ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
- ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
- ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound;
- ALfloat Matrix[4][4];
- ALfloat flAttenuation, effectiveDist;
- ALfloat RoomAttenuation[MAX_SENDS];
- ALfloat MetersPerUnit;
- ALfloat RoomRolloff[MAX_SENDS];
- ALfloat DryGainHF = 1.0f;
- ALfloat WetGain[MAX_SENDS];
- ALfloat WetGainHF[MAX_SENDS];
- ALfloat DirGain, AmbientGain;
- const ALfloat *SpeakerGain;
- ALfloat length;
- ALuint Frequency;
- ALint NumSends;
- ALint pos, s, i;
- ALfloat cw;
- for(i = 0;i < MAX_SENDS;i++)
- WetGainHF[i] = 1.0f;
- //Get context properties
- DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
- DopplerVelocity = ALContext->DopplerVelocity;
- flSpeedOfSound = ALContext->flSpeedOfSound;
- NumSends = Device->NumAuxSends;
- Frequency = Device->Frequency;
- //Get listener properties
- ListenerGain = ALContext->Listener.Gain;
- MetersPerUnit = ALContext->Listener.MetersPerUnit;
- memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
- //Get source properties
- SourceVolume = ALSource->flGain;
- memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
- memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
- memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
- MinVolume = ALSource->flMinGain;
- MaxVolume = ALSource->flMaxGain;
- MinDist = ALSource->flRefDistance;
- MaxDist = ALSource->flMaxDistance;
- Rolloff = ALSource->flRollOffFactor;
- InnerAngle = ALSource->flInnerAngle;
- OuterAngle = ALSource->flOuterAngle;
- OuterGainHF = ALSource->OuterGainHF;
- //1. Translate Listener to origin (convert to head relative)
- if(ALSource->bHeadRelative==AL_FALSE)
- {
- ALfloat U[3],V[3],N[3];
- // Build transform matrix
- memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
- aluNormalize(N); // Normalized At-vector
- memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
- aluNormalize(V); // Normalized Up-vector
- aluCrossproduct(N, V, U); // Right-vector
- aluNormalize(U); // Normalized Right-vector
- Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
- Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
- Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
- Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
- // Translate position
- Position[0] -= ALContext->Listener.Position[0];
- Position[1] -= ALContext->Listener.Position[1];
- Position[2] -= ALContext->Listener.Position[2];
- // Transform source position and direction into listener space
- aluMatrixVector(Position, 1.0f, Matrix);
- aluMatrixVector(Direction, 0.0f, Matrix);
- // Transform source and listener velocity into listener space
- aluMatrixVector(Velocity, 0.0f, Matrix);
- aluMatrixVector(ListenerVel, 0.0f, Matrix);
- }
- else
- ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
- SourceToListener[0] = -Position[0];
- SourceToListener[1] = -Position[1];
- SourceToListener[2] = -Position[2];
- aluNormalize(SourceToListener);
- aluNormalize(Direction);
- //2. Calculate distance attenuation
- Distance = aluSqrt(aluDotproduct(Position, Position));
- OrigDist = Distance;
- flAttenuation = 1.0f;
- for(i = 0;i < NumSends;i++)
- {
- RoomAttenuation[i] = 1.0f;
- RoomRolloff[i] = ALSource->RoomRolloffFactor;
- if(ALSource->Send[i].Slot &&
- (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
- ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
- RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
- }
- switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
- ALContext->DistanceModel)
- {
- case AL_INVERSE_DISTANCE_CLAMPED:
- Distance=__max(Distance,MinDist);
- Distance=__min(Distance,MaxDist);
- if(MaxDist < MinDist)
- break;
- //fall-through
- case AL_INVERSE_DISTANCE:
- if(MinDist > 0.0f)
- {
- if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
- flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
- for(i = 0;i < NumSends;i++)
- {
- if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
- RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
- }
- }
- break;
- case AL_LINEAR_DISTANCE_CLAMPED:
- Distance=__max(Distance,MinDist);
- Distance=__min(Distance,MaxDist);
- if(MaxDist < MinDist)
- break;
- //fall-through
- case AL_LINEAR_DISTANCE:
- Distance=__min(Distance,MaxDist);
- if(MaxDist != MinDist)
- {
- flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
- for(i = 0;i < NumSends;i++)
- RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
- }
- break;
- case AL_EXPONENT_DISTANCE_CLAMPED:
- Distance=__max(Distance,MinDist);
- Distance=__min(Distance,MaxDist);
- if(MaxDist < MinDist)
- break;
- //fall-through
- case AL_EXPONENT_DISTANCE:
- if(Distance > 0.0f && MinDist > 0.0f)
- {
- flAttenuation = aluPow(Distance/MinDist, -Rolloff);
- for(i = 0;i < NumSends;i++)
- RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
- }
- break;
- case AL_NONE:
- break;
- }
- // Source Gain + Attenuation
- DryMix = SourceVolume * flAttenuation;
- for(i = 0;i < NumSends;i++)
- WetGain[i] = SourceVolume * RoomAttenuation[i];
- effectiveDist = 0.0f;
- if(MinDist > 0.0f)
- effectiveDist = (MinDist/flAttenuation - MinDist)*MetersPerUnit;
- // Distance-based air absorption
- if(ALSource->AirAbsorptionFactor > 0.0f && effectiveDist > 0.0f)
- {
- ALfloat absorb;
- // Absorption calculation is done in dB
- absorb = (ALSource->AirAbsorptionFactor*AIRABSORBGAINDBHF) *
- effectiveDist;
- // Convert dB to linear gain before applying
- absorb = aluPow(10.0f, absorb/20.0f);
- DryGainHF *= absorb;
- }
- //3. Apply directional soundcones
- Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
- if(Angle >= InnerAngle && Angle <= OuterAngle)
- {
- ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
- ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
- ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
- }
- else if(Angle > OuterAngle)
- {
- ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
- ConeHF = (1.0f+(OuterGainHF-1.0f));
- }
- else
- {
- ConeVolume = 1.0f;
- ConeHF = 1.0f;
- }
- // Apply some high-frequency attenuation for sources behind the listener
- // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
- // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
- // the same as SourceToListener[2]
- Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
- // Sources within the minimum distance attenuate less
- if(OrigDist < MinDist)
- Angle *= OrigDist/MinDist;
- if(Angle > 90.0f)
- {
- ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
- ConeHF *= 1.0f - (Device->HeadDampen*scale);
- }
- DryMix *= ConeVolume;
- if(ALSource->DryGainHFAuto)
- DryGainHF *= ConeHF;
- // Clamp to Min/Max Gain
- DryMix = __min(DryMix,MaxVolume);
- DryMix = __max(DryMix,MinVolume);
- for(i = 0;i < NumSends;i++)
- {
- ALeffectslot *Slot = ALSource->Send[i].Slot;
- if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
- {
- ALSource->Params.WetGains[i] = 0.0f;
- WetGainHF[i] = 1.0f;
- continue;
- }
- if(Slot->AuxSendAuto)
- {
- if(ALSource->WetGainAuto)
- WetGain[i] *= ConeVolume;
- if(ALSource->WetGainHFAuto)
- WetGainHF[i] *= ConeHF;
- // Clamp to Min/Max Gain
- WetGain[i] = __min(WetGain[i],MaxVolume);
- WetGain[i] = __max(WetGain[i],MinVolume);
- if(Slot->effect.type == AL_EFFECT_REVERB ||
- Slot->effect.type == AL_EFFECT_EAXREVERB)
- {
- /* Apply a decay-time transformation to the wet path, based on
- * the attenuation of the dry path.
- *
- * Using the approximate (effective) source to listener
- * distance, the initial decay of the reverb effect is
- * calculated and applied to the wet path.
- */
- WetGain[i] *= aluPow(10.0f, effectiveDist /
- (SPEEDOFSOUNDMETRESPERSEC *
- Slot->effect.Reverb.DecayTime) *
- -60.0 / 20.0);
- WetGainHF[i] *= aluPow(10.0f,
- log10(Slot->effect.Reverb.AirAbsorptionGainHF) *
- ALSource->AirAbsorptionFactor * effectiveDist);
- }
- }
- else
- {
- /* If the slot's auxiliary send auto is off, the data sent to the
- * effect slot is the same as the dry path, sans filter effects */
- WetGain[i] = DryMix;
- WetGainHF[i] = DryGainHF;
- }
- switch(ALSource->Send[i].WetFilter.type)
- {
- case AL_FILTER_LOWPASS:
- WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
- WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
- break;
- }
- ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
- }
- for(i = NumSends;i < MAX_SENDS;i++)
- {
- ALSource->Params.WetGains[i] = 0.0f;
- WetGainHF[i] = 1.0f;
- }
- // Apply filter gains and filters
- switch(ALSource->DirectFilter.type)
- {
- case AL_FILTER_LOWPASS:
- DryMix *= ALSource->DirectFilter.Gain;
- DryGainHF *= ALSource->DirectFilter.GainHF;
- break;
- }
- DryMix *= ListenerGain;
- // Calculate Velocity
- if(DopplerFactor != 0.0f)
- {
- ALfloat flVSS, flVLS;
- ALfloat flMaxVelocity = (DopplerVelocity * flSpeedOfSound) /
- DopplerFactor;
- flVSS = aluDotproduct(Velocity, SourceToListener);
- if(flVSS >= flMaxVelocity)
- flVSS = (flMaxVelocity - 1.0f);
- else if(flVSS <= -flMaxVelocity)
- flVSS = -flMaxVelocity + 1.0f;
- flVLS = aluDotproduct(ListenerVel, SourceToListener);
- if(flVLS >= flMaxVelocity)
- flVLS = (flMaxVelocity - 1.0f);
- else if(flVLS <= -flMaxVelocity)
- flVLS = -flMaxVelocity + 1.0f;
- ALSource->Params.Pitch = ALSource->flPitch *
- ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) /
- ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS));
- }
- else
- ALSource->Params.Pitch = ALSource->flPitch;
- // Use energy-preserving panning algorithm for multi-speaker playback
- length = __max(OrigDist, MinDist);
- if(length > 0.0f)
- {
- ALfloat invlen = 1.0f/length;
- Position[0] *= invlen;
- Position[1] *= invlen;
- Position[2] *= invlen;
- }
- pos = aluCart2LUTpos(-Position[2], Position[0]);
- SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
- DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
- // elevation adjustment for directional gain. this sucks, but
- // has low complexity
- AmbientGain = 1.0/aluSqrt(Device->NumChan) * (1.0-DirGain);
- for(s = 0;s < OUTPUTCHANNELS;s++)
- ALSource->Params.DryGains[s] = 0.0f;
- for(s = 0;s < (ALsizei)Device->NumChan;s++)
- {
- Channel chan = Device->Speaker2Chan[s];
- ALfloat gain = SpeakerGain[chan]*DirGain + AmbientGain;
- ALSource->Params.DryGains[chan] = DryMix * gain;
- }
- /* Update filter coefficients. */
- cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
- /* Spatialized sources use four chained one-pole filters, so we need to
- * take the fourth root of the squared gain, which is the same as the
- * square root of the base gain. */
- ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
- for(i = 0;i < NumSends;i++)
- {
- /* The wet path uses two chained one-pole filters, so take the
- * base gain (square root of the squared gain) */
- ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
- }
- }
- static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac)
- {
- return val1;
- (void)val2;
- (void)frac;
- }
- static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac)
- {
- return val1 + ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
- }
- static __inline ALfloat cos_lerp(ALfloat val1, ALfloat val2, ALint frac)
- {
- ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
- return val1 + ((val2-val1)*mult);
- }
- static void MixSomeSources(ALCcontext *ALContext, float (*DryBuffer)[OUTPUTCHANNELS], ALuint SamplesToDo)
- {
- static float DummyBuffer[BUFFERSIZE];
- ALfloat *WetBuffer[MAX_SENDS];
- ALfloat DrySend[OUTPUTCHANNELS];
- ALfloat dryGainStep[OUTPUTCHANNELS];
- ALfloat wetGainStep[MAX_SENDS];
- ALuint i, j, k, out;
- ALsource *ALSource;
- ALfloat value, outsamp;
- ALbufferlistitem *BufferListItem;
- ALint64 DataSize64,DataPos64;
- FILTER *DryFilter, *WetFilter[MAX_SENDS];
- ALfloat WetSend[MAX_SENDS];
- ALuint rampLength;
- ALboolean DuplicateStereo;
- ALuint DeviceFreq;
- ALint increment;
- ALuint DataPosInt, DataPosFrac;
- ALuint Channels, Bytes;
- ALuint Frequency;
- resampler_t Resampler;
- ALuint BuffersPlayed;
- ALboolean Looping;
- ALfloat Pitch;
- ALenum State;
- ALsizei pos;
- DuplicateStereo = ALContext->Device->DuplicateStereo;
- DeviceFreq = ALContext->Device->Frequency;
- rampLength = DeviceFreq * MIN_RAMP_LENGTH / 1000;
- rampLength = max(rampLength, SamplesToDo);
- pos = 0;
- next_source:
- while(ALContext->ActiveSourceCount > pos)
- {
- ALsizei end;
- ALSource = ALContext->ActiveSources[pos];
- if(ALSource->state == AL_PLAYING)
- break;
- end = --(ALContext->ActiveSourceCount);
- ALContext->ActiveSources[pos] = ALContext->ActiveSources[end];
- }
- if(pos >= ALContext->ActiveSourceCount)
- return;
- /* Find buffer format */
- Frequency = 0;
- Channels = 0;
- Bytes = 0;
- BufferListItem = ALSource->queue;
- while(BufferListItem != NULL)
- {
- ALbuffer *ALBuffer;
- if((ALBuffer=BufferListItem->buffer) != NULL)
- {
- Channels = aluChannelsFromFormat(ALBuffer->format);
- Bytes = aluBytesFromFormat(ALBuffer->format);
- Frequency = ALBuffer->frequency;
- break;
- }
- BufferListItem = BufferListItem->next;
- }
- if(ALSource->NeedsUpdate)
- {
- //Only apply 3D calculations for mono buffers
- if(Channels == 1)
- CalcSourceParams(ALContext, ALSource);
- else
- CalcNonAttnSourceParams(ALContext, ALSource);
- ALSource->NeedsUpdate = AL_FALSE;
- }
- /* Get source info */
- Resampler = ALSource->Resampler;
- State = ALSource->state;
- BuffersPlayed = ALSource->BuffersPlayed;
- DataPosInt = ALSource->position;
- DataPosFrac = ALSource->position_fraction;
- Looping = ALSource->bLooping;
- /* Compute 18.14 fixed point step */
- Pitch = (ALSource->Params.Pitch*Frequency) / DeviceFreq;
- if(Pitch > (float)MAX_PITCH) Pitch = (float)MAX_PITCH;
- increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
- if(increment <= 0) increment = (1<<FRACTIONBITS);
- if(ALSource->FirstStart)
- {
- for(i = 0;i < OUTPUTCHANNELS;i++)
- DrySend[i] = ALSource->Params.DryGains[i];
- for(i = 0;i < MAX_SENDS;i++)
- WetSend[i] = ALSource->Params.WetGains[i];
- }
- else
- {
- for(i = 0;i < OUTPUTCHANNELS;i++)
- DrySend[i] = ALSource->DryGains[i];
- for(i = 0;i < MAX_SENDS;i++)
- WetSend[i] = ALSource->WetGains[i];
- }
- DryFilter = &ALSource->Params.iirFilter;
- for(i = 0;i < MAX_SENDS;i++)
- {
- WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
- WetBuffer[i] = (ALSource->Send[i].Slot ?
- ALSource->Send[i].Slot->WetBuffer :
- DummyBuffer);
- }
- /* Get current buffer queue item */
- BufferListItem = ALSource->queue;
- for(i = 0;i < BuffersPlayed && BufferListItem;i++)
- BufferListItem = BufferListItem->next;
- j = 0;
- do {
- ALfloat *Data = NULL;
- ALuint LoopStart = 0;
- ALuint LoopEnd = 0;
- ALuint DataSize = 0;
- ALbuffer *ALBuffer;
- ALuint BufferSize;
- /* Get buffer info */
- if((ALBuffer=BufferListItem->buffer) != NULL)
- {
- Data = ALBuffer->data;
- DataSize = ALBuffer->size;
- DataSize /= Channels * Bytes;
- LoopStart = ALBuffer->LoopStart;
- LoopEnd = ALBuffer->LoopEnd;
- }
- if(Looping && ALSource->lSourceType == AL_STATIC)
- {
- /* If current offset is beyond the loop range, do not loop */
- if(DataPosInt >= LoopEnd)
- Looping = AL_FALSE;
- }
- if(!Looping || ALSource->lSourceType != AL_STATIC)
- {
- /* Non-looping and non-static sources ignore loop points */
- LoopStart = 0;
- LoopEnd = DataSize;
- }
- if(DataPosInt >= DataSize)
- goto skipmix;
- if(BufferListItem->next)
- {
- ALbuffer *NextBuf = BufferListItem->next->buffer;
- if(NextBuf && NextBuf->size)
- {
- ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
- ulExtraSamples = min(NextBuf->size, ulExtraSamples);
- memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
- }
- }
- else if(Looping)
- {
- ALbuffer *NextBuf = ALSource->queue->buffer;
- if(NextBuf && NextBuf->size)
- {
- ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
- ulExtraSamples = min(NextBuf->size, ulExtraSamples);
- memcpy(&Data[DataSize*Channels], &NextBuf->data[LoopStart*Channels], ulExtraSamples);
- }
- }
- else
- memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes));
- /* Compute the gain steps for each output channel */
- for(i = 0;i < OUTPUTCHANNELS;i++)
- dryGainStep[i] = (ALSource->Params.DryGains[i]-DrySend[i]) /
- rampLength;
- for(i = 0;i < MAX_SENDS;i++)
- wetGainStep[i] = (ALSource->Params.WetGains[i]-WetSend[i]) /
- rampLength;
- /* Figure out how many samples we can mix. */
- DataSize64 = LoopEnd;
- DataSize64 <<= FRACTIONBITS;
- DataPos64 = DataPosInt;
- DataPos64 <<= FRACTIONBITS;
- DataPos64 += DataPosFrac;
- BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
- BufferSize = min(BufferSize, (SamplesToDo-j));
- /* Actual sample mixing loop */
- k = 0;
- Data += DataPosInt*Channels;
- if(Channels == 1) /* Mono */
- {
- #define DO_MIX(resampler) do { \
- while(BufferSize--) \
- { \
- for(i = 0;i < OUTPUTCHANNELS;i++) \
- DrySend[i] += dryGainStep[i]; \
- for(i = 0;i < MAX_SENDS;i++) \
- WetSend[i] += wetGainStep[i]; \
- \
- /* First order interpolator */ \
- value = (resampler)(Data[k], Data[k+1], DataPosFrac); \
- \
- /* Direct path final mix buffer and panning */ \
- outsamp = lpFilter4P(DryFilter, 0, value); \
- DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
- DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
- DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
- DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
- DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
- DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
- DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
- DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
- \
- /* Room path final mix buffer and panning */ \
- for(i = 0;i < MAX_SENDS;i++) \
- { \
- outsamp = lpFilter2P(WetFilter[i], 0, value); \
- WetBuffer[i][j] += outsamp*WetSend[i]; \
- } \
- \
- DataPosFrac += increment; \
- k += DataPosFrac>>FRACTIONBITS; \
- DataPosFrac &= FRACTIONMASK; \
- j++; \
- } \
- } while(0)
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- #undef DO_MIX
- }
- else if(Channels == 2 && DuplicateStereo) /* Stereo */
- {
- const int chans[] = {
- FRONT_LEFT, FRONT_RIGHT
- };
- const int chans2[] = {
- BACK_LEFT, SIDE_LEFT, BACK_RIGHT, SIDE_RIGHT
- };
- const ALfloat scaler = 1.0f/Channels;
- const ALfloat dupscaler = aluSqrt(1.0f/3.0f);
- #define DO_MIX(resampler) do { \
- while(BufferSize--) \
- { \
- for(i = 0;i < OUTPUTCHANNELS;i++) \
- DrySend[i] += dryGainStep[i]; \
- for(i = 0;i < MAX_SENDS;i++) \
- WetSend[i] += wetGainStep[i]; \
- \
- for(i = 0;i < Channels;i++) \
- { \
- value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\
- DataPosFrac); \
- outsamp = lpFilter2P(DryFilter, chans[i]*2, value) * dupscaler; \
- DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
- DryBuffer[j][chans2[i*2+0]] += outsamp*DrySend[chans2[i*2+0]]; \
- DryBuffer[j][chans2[i*2+1]] += outsamp*DrySend[chans2[i*2+1]]; \
- for(out = 0;out < MAX_SENDS;out++) \
- { \
- outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
- WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
- } \
- } \
- \
- DataPosFrac += increment; \
- k += DataPosFrac>>FRACTIONBITS; \
- DataPosFrac &= FRACTIONMASK; \
- j++; \
- } \
- } while(0)
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- #undef DO_MIX
- }
- else if(Channels == 2) /* Stereo */
- {
- const int chans[] = {
- FRONT_LEFT, FRONT_RIGHT
- };
- const ALfloat scaler = 1.0f/Channels;
- #define DO_MIX(resampler) do { \
- while(BufferSize--) \
- { \
- for(i = 0;i < OUTPUTCHANNELS;i++) \
- DrySend[i] += dryGainStep[i]; \
- for(i = 0;i < MAX_SENDS;i++) \
- WetSend[i] += wetGainStep[i]; \
- \
- for(i = 0;i < Channels;i++) \
- { \
- value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\
- DataPosFrac); \
- outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
- DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
- for(out = 0;out < MAX_SENDS;out++) \
- { \
- outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
- WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
- } \
- } \
- \
- DataPosFrac += increment; \
- k += DataPosFrac>>FRACTIONBITS; \
- DataPosFrac &= FRACTIONMASK; \
- j++; \
- } \
- } while(0)
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- }
- else if(Channels == 4) /* Quad */
- {
- const int chans[] = {
- FRONT_LEFT, FRONT_RIGHT,
- BACK_LEFT, BACK_RIGHT
- };
- const ALfloat scaler = 1.0f/Channels;
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- }
- else if(Channels == 6) /* 5.1 */
- {
- const int chans[] = {
- FRONT_LEFT, FRONT_RIGHT,
- FRONT_CENTER, LFE,
- BACK_LEFT, BACK_RIGHT
- };
- const ALfloat scaler = 1.0f/Channels;
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- }
- else if(Channels == 7) /* 6.1 */
- {
- const int chans[] = {
- FRONT_LEFT, FRONT_RIGHT,
- FRONT_CENTER, LFE,
- BACK_CENTER,
- SIDE_LEFT, SIDE_RIGHT
- };
- const ALfloat scaler = 1.0f/Channels;
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- }
- else if(Channels == 8) /* 7.1 */
- {
- const int chans[] = {
- FRONT_LEFT, FRONT_RIGHT,
- FRONT_CENTER, LFE,
- BACK_LEFT, BACK_RIGHT,
- SIDE_LEFT, SIDE_RIGHT
- };
- const ALfloat scaler = 1.0f/Channels;
- switch(Resampler)
- {
- case POINT_RESAMPLER:
- DO_MIX(point); break;
- case LINEAR_RESAMPLER:
- DO_MIX(lerp); break;
- case COSINE_RESAMPLER:
- DO_MIX(cos_lerp); break;
- case RESAMPLER_MIN:
- case RESAMPLER_MAX:
- break;
- }
- #undef DO_MIX
- }
- else /* Unknown? */
- {
- for(i = 0;i < OUTPUTCHANNELS;i++)
- DrySend[i] += dryGainStep[i]*BufferSize;
- for(i = 0;i < MAX_SENDS;i++)
- WetSend[i] += wetGainStep[i]*BufferSize;
- while(BufferSize--)
- {
- DataPosFrac += increment;
- k += DataPosFrac>>FRACTIONBITS;
- DataPosFrac &= FRACTIONMASK;
- j++;
- }
- }
- DataPosInt += k;
- skipmix:
- /* Handle looping sources */
- if(DataPosInt >= LoopEnd)
- {
- if(BuffersPlayed < (ALSource->BuffersInQueue-1))
- {
- BufferListItem = BufferListItem->next;
- BuffersPlayed++;
- DataPosInt -= DataSize;
- }
- else if(Looping)
- {
- BufferListItem = ALSource->queue;
- BuffersPlayed = 0;
- if(ALSource->lSourceType == AL_STATIC)
- DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
- else
- DataPosInt -= DataSize;
- }
- else
- {
- State = AL_STOPPED;
- BufferListItem = ALSource->queue;
- BuffersPlayed = ALSource->BuffersInQueue;
- DataPosInt = 0;
- DataPosFrac = 0;
- }
- }
- } while(State == AL_PLAYING && j < SamplesToDo);
- /* Update source info */
- ALSource->state = State;
- ALSource->BuffersPlayed = BuffersPlayed;
- ALSource->position = DataPosInt;
- ALSource->position_fraction = DataPosFrac;
- ALSource->Buffer = BufferListItem->buffer;
- for(i = 0;i < OUTPUTCHANNELS;i++)
- ALSource->DryGains[i] = DrySend[i];
- for(i = 0;i < MAX_SENDS;i++)
- ALSource->WetGains[i] = WetSend[i];
- ALSource->FirstStart = AL_FALSE;
- if(ALSource->state == AL_PLAYING)
- pos++;
- goto next_source;
- }
- ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
- {
- float (*DryBuffer)[OUTPUTCHANNELS];
- ALfloat (*Matrix)[OUTPUTCHANNELS];
- const ALuint *ChanMap;
- ALuint SamplesToDo;
- ALeffectslot *ALEffectSlot;
- ALCcontext *ALContext;
- ALfloat samp;
- int fpuState;
- ALuint i, j, c;
- ALsizei e;
- #if defined(HAVE_FESETROUND)
- fpuState = fegetround();
- fesetround(FE_TOWARDZERO);
- #elif defined(HAVE__CONTROLFP)
- fpuState = _controlfp(0, 0);
- _controlfp(_RC_CHOP, _MCW_RC);
- #else
- (void)fpuState;
- #endif
- DryBuffer = device->DryBuffer;
- while(size > 0)
- {
- /* Setup variables */
- SamplesToDo = min(size, BUFFERSIZE);
- /* Clear mixing buffer */
- memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
- SuspendContext(NULL);
- for(c = 0;c < device->NumContexts;c++)
- {
- ALContext = device->Contexts[c];
- SuspendContext(ALContext);
- MixSomeSources(ALContext, DryBuffer, SamplesToDo);
- /* effect slot processing */
- for(e = 0;e < ALContext->EffectSlotMap.size;e++)
- {
- ALEffectSlot = ALContext->EffectSlotMap.array[e].value;
- if(ALEffectSlot->EffectState)
- ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
- for(i = 0;i < SamplesToDo;i++)
- ALEffectSlot->WetBuffer[i] = 0.0f;
- }
- ProcessContext(ALContext);
- }
- ProcessContext(NULL);
- //Post processing loop
- ChanMap = device->DevChannels;
- Matrix = device->ChannelMatrix;
- switch(device->Format)
- {
- #define CHECK_WRITE_FORMAT(bits, type, func) \
- case AL_FORMAT_MONO##bits: \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- samp = 0.0f; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
- ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
- buffer = ((type*)buffer) + 1; \
- } \
- break; \
- case AL_FORMAT_STEREO##bits: \
- if(device->Bs2b) \
- { \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- float samples[2] = { 0.0f, 0.0f }; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- { \
- samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
- samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
- } \
- bs2b_cross_feed(device->Bs2b, samples); \
- ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
- ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
- buffer = ((type*)buffer) + 2; \
- } \
- } \
- else \
- { \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- static const Channel chans[] = { \
- FRONT_LEFT, FRONT_RIGHT \
- }; \
- for(j = 0;j < 2;j++) \
- { \
- samp = 0.0f; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
- ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
- } \
- buffer = ((type*)buffer) + 2; \
- } \
- } \
- break; \
- case AL_FORMAT_QUAD##bits: \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- static const Channel chans[] = { \
- FRONT_LEFT, FRONT_RIGHT, \
- BACK_LEFT, BACK_RIGHT, \
- }; \
- for(j = 0;j < 4;j++) \
- { \
- samp = 0.0f; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
- ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
- } \
- buffer = ((type*)buffer) + 4; \
- } \
- break; \
- case AL_FORMAT_51CHN##bits: \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- static const Channel chans[] = { \
- FRONT_LEFT, FRONT_RIGHT, \
- FRONT_CENTER, LFE, \
- BACK_LEFT, BACK_RIGHT, \
- }; \
- for(j = 0;j < 6;j++) \
- { \
- samp = 0.0f; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
- ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
- } \
- buffer = ((type*)buffer) + 6; \
- } \
- break; \
- case AL_FORMAT_61CHN##bits: \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- static const Channel chans[] = { \
- FRONT_LEFT, FRONT_RIGHT, \
- FRONT_CENTER, LFE, BACK_CENTER, \
- SIDE_LEFT, SIDE_RIGHT, \
- }; \
- for(j = 0;j < 7;j++) \
- { \
- samp = 0.0f; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
- ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
- } \
- buffer = ((type*)buffer) + 7; \
- } \
- break; \
- case AL_FORMAT_71CHN##bits: \
- for(i = 0;i < SamplesToDo;i++) \
- { \
- static const Channel chans[] = { \
- FRONT_LEFT, FRONT_RIGHT, \
- FRONT_CENTER, LFE, \
- BACK_LEFT, BACK_RIGHT, \
- SIDE_LEFT, SIDE_RIGHT \
- }; \
- for(j = 0;j < 8;j++) \
- { \
- samp = 0.0f; \
- for(c = 0;c < OUTPUTCHANNELS;c++) \
- samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
- ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
- } \
- buffer = ((type*)buffer) + 8; \
- } \
- break;
- #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
- #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
- CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
- CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
- CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
- #undef AL_FORMAT_STEREO32
- #undef AL_FORMAT_MONO32
- #undef CHECK_WRITE_FORMAT
- default:
- break;
- }
- size -= SamplesToDo;
- }
- #if defined(HAVE_FESETROUND)
- fesetround(fpuState);
- #elif defined(HAVE__CONTROLFP)
- _controlfp(fpuState, 0xfffff);
- #endif
- }
- ALvoid aluHandleDisconnect(ALCdevice *device)
- {
- ALuint i;
- SuspendContext(NULL);
- for(i = 0;i < device->NumContexts;i++)
- {
- ALCcontext *Context = device->Contexts[i];
- ALsource *source;
- ALsizei pos;
- SuspendContext(Context);
- for(pos = 0;pos < Context->SourceMap.size;pos++)
- {
- source = Context->SourceMap.array[pos].value;
- if(source->state == AL_PLAYING)
- {
- source->state = AL_STOPPED;
- source->BuffersPlayed = source->BuffersInQueue;
- source->position = 0;
- source->position_fraction = 0;
- }
- }
- ProcessContext(Context);
- }
- device->Connected = ALC_FALSE;
- ProcessContext(NULL);
- }
|