Use a simple loop to set multi-channel dry gains
[openal-soft/android/lowlatency.git] / Alc / ALu.c
blob1f96d5f7b677191cf2ae7989063d67159c0d2934
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alThunk.h"
35 #include "alListener.h"
36 #include "alAuxEffectSlot.h"
37 #include "alu.h"
38 #include "bs2b.h"
40 #define FRACTIONBITS 14
41 #define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
42 #define MAX_PITCH 65536
44 /* Minimum ramp length in milliseconds. The value below was chosen to
45 * adequately reduce clicks and pops from harsh gain changes. */
46 #define MIN_RAMP_LENGTH 16
49 static __inline ALfloat aluF2F(ALfloat Value)
51 return Value;
54 static __inline ALshort aluF2S(ALfloat Value)
56 ALint i;
58 if(Value < 0.0f)
60 i = (ALint)(Value*32768.0f);
61 i = max(-32768, i);
63 else
65 i = (ALint)(Value*32767.0f);
66 i = min( 32767, i);
68 return ((ALshort)i);
71 static __inline ALubyte aluF2UB(ALfloat Value)
73 ALshort i = aluF2S(Value);
74 return (i>>8)+128;
78 static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
80 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
81 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
82 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
85 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
87 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
88 inVector1[2]*inVector2[2];
91 static __inline ALvoid aluNormalize(ALfloat *inVector)
93 ALfloat length, inverse_length;
95 length = aluSqrt(aluDotproduct(inVector, inVector));
96 if(length != 0.0f)
98 inverse_length = 1.0f/length;
99 inVector[0] *= inverse_length;
100 inVector[1] *= inverse_length;
101 inVector[2] *= inverse_length;
105 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
107 ALfloat temp[4] = {
108 vector[0], vector[1], vector[2], w
111 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
112 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
113 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
116 static ALvoid SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[OUTPUTCHANNELS],
117 Channel Speaker2Chan[OUTPUTCHANNELS], ALint chans)
119 char layout_str[256];
120 char *confkey, *next;
121 char *sep, *end;
122 Channel val;
123 int i;
125 strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
126 layout_str[255] = 0;
128 if(!layout_str[0])
129 return;
131 next = confkey = layout_str;
132 while(next && *next)
134 confkey = next;
135 next = strchr(confkey, ',');
136 if(next)
138 *next = 0;
139 do {
140 next++;
141 } while(isspace(*next) || *next == ',');
144 sep = strchr(confkey, '=');
145 if(!sep || confkey == sep)
146 continue;
148 end = sep - 1;
149 while(isspace(*end) && end != confkey)
150 end--;
151 *(++end) = 0;
153 if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
154 val = FRONT_LEFT;
155 else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
156 val = FRONT_RIGHT;
157 else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
158 val = FRONT_CENTER;
159 else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
160 val = BACK_LEFT;
161 else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
162 val = BACK_RIGHT;
163 else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
164 val = BACK_CENTER;
165 else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
166 val = SIDE_LEFT;
167 else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
168 val = SIDE_RIGHT;
169 else
171 AL_PRINT("Unknown speaker for %s: \"%s\"\n", name, confkey);
172 continue;
175 *(sep++) = 0;
176 while(isspace(*sep))
177 sep++;
179 for(i = 0;i < chans;i++)
181 if(Speaker2Chan[i] == val)
183 long angle = strtol(sep, NULL, 10);
184 if(angle >= -180 && angle <= 180)
185 SpeakerAngle[i] = angle * M_PI/180.0f;
186 else
187 AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
188 break;
193 for(i = 0;i < chans;i++)
195 int min = i;
196 int i2;
198 for(i2 = i+1;i2 < chans;i2++)
200 if(SpeakerAngle[i2] < SpeakerAngle[min])
201 min = i2;
204 if(min != i)
206 ALfloat tmpf;
207 Channel tmpc;
209 tmpf = SpeakerAngle[i];
210 SpeakerAngle[i] = SpeakerAngle[min];
211 SpeakerAngle[min] = tmpf;
213 tmpc = Speaker2Chan[i];
214 Speaker2Chan[i] = Speaker2Chan[min];
215 Speaker2Chan[min] = tmpc;
220 static __inline ALfloat aluLUTpos2Angle(ALint pos)
222 if(pos < QUADRANT_NUM)
223 return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
224 if(pos < 2 * QUADRANT_NUM)
225 return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
226 if(pos < 3 * QUADRANT_NUM)
227 return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
228 return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
231 ALvoid aluInitPanning(ALCdevice *Device)
233 ALfloat SpeakerAngle[OUTPUTCHANNELS];
234 Channel *Speaker2Chan;
235 ALfloat Alpha, Theta;
236 ALint pos, offset;
237 ALuint s, s2;
239 for(s = 0;s < OUTPUTCHANNELS;s++)
241 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
242 Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
245 Speaker2Chan = Device->Speaker2Chan;
246 switch(Device->Format)
248 case AL_FORMAT_MONO8:
249 case AL_FORMAT_MONO16:
250 case AL_FORMAT_MONO_FLOAT32:
251 Device->DuplicateStereo = AL_FALSE;
252 Device->ChannelMatrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5);
253 Device->ChannelMatrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
254 Device->ChannelMatrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5);
255 Device->ChannelMatrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
256 Device->ChannelMatrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5);
257 Device->ChannelMatrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
258 Device->ChannelMatrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
259 Device->NumChan = 1;
260 Speaker2Chan[0] = FRONT_CENTER;
261 SpeakerAngle[0] = 0.0f * M_PI/180.0f;
262 break;
264 case AL_FORMAT_STEREO8:
265 case AL_FORMAT_STEREO16:
266 case AL_FORMAT_STEREO_FLOAT32:
267 Device->DuplicateStereo = AL_FALSE;
268 Device->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
269 Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
270 Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = 1.0f;
271 Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = 1.0f;
272 Device->ChannelMatrix[BACK_LEFT][FRONT_LEFT] = 1.0f;
273 Device->ChannelMatrix[BACK_RIGHT][FRONT_RIGHT] = 1.0f;
274 Device->ChannelMatrix[BACK_CENTER][FRONT_LEFT] = aluSqrt(0.5);
275 Device->ChannelMatrix[BACK_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
276 Device->NumChan = 2;
277 Speaker2Chan[0] = FRONT_LEFT;
278 Speaker2Chan[1] = FRONT_RIGHT;
279 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
280 SpeakerAngle[1] = 90.0f * M_PI/180.0f;
281 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
282 break;
284 case AL_FORMAT_QUAD8:
285 case AL_FORMAT_QUAD16:
286 case AL_FORMAT_QUAD32:
287 Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
288 Device->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
289 Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
290 Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
291 Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
292 Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
293 Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
294 Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
295 Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
296 Device->NumChan = 4;
297 Speaker2Chan[0] = BACK_LEFT;
298 Speaker2Chan[1] = FRONT_LEFT;
299 Speaker2Chan[2] = FRONT_RIGHT;
300 Speaker2Chan[3] = BACK_RIGHT;
301 SpeakerAngle[0] = -135.0f * M_PI/180.0f;
302 SpeakerAngle[1] = -45.0f * M_PI/180.0f;
303 SpeakerAngle[2] = 45.0f * M_PI/180.0f;
304 SpeakerAngle[3] = 135.0f * M_PI/180.0f;
305 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
306 break;
308 case AL_FORMAT_51CHN8:
309 case AL_FORMAT_51CHN16:
310 case AL_FORMAT_51CHN32:
311 Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
312 Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
313 Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
314 Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
315 Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
316 Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
317 Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
318 Device->NumChan = 5;
319 Speaker2Chan[0] = BACK_LEFT;
320 Speaker2Chan[1] = FRONT_LEFT;
321 Speaker2Chan[2] = FRONT_CENTER;
322 Speaker2Chan[3] = FRONT_RIGHT;
323 Speaker2Chan[4] = BACK_RIGHT;
324 SpeakerAngle[0] = -110.0f * M_PI/180.0f;
325 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
326 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
327 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
328 SpeakerAngle[4] = 110.0f * M_PI/180.0f;
329 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
330 break;
332 case AL_FORMAT_61CHN8:
333 case AL_FORMAT_61CHN16:
334 case AL_FORMAT_61CHN32:
335 Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
336 Device->ChannelMatrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
337 Device->ChannelMatrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
338 Device->ChannelMatrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
339 Device->ChannelMatrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
340 Device->NumChan = 6;
341 Speaker2Chan[0] = SIDE_LEFT;
342 Speaker2Chan[1] = FRONT_LEFT;
343 Speaker2Chan[2] = FRONT_CENTER;
344 Speaker2Chan[3] = FRONT_RIGHT;
345 Speaker2Chan[4] = SIDE_RIGHT;
346 Speaker2Chan[5] = BACK_CENTER;
347 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
348 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
349 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
350 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
351 SpeakerAngle[4] = 90.0f * M_PI/180.0f;
352 SpeakerAngle[5] = 180.0f * M_PI/180.0f;
353 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
354 break;
356 case AL_FORMAT_71CHN8:
357 case AL_FORMAT_71CHN16:
358 case AL_FORMAT_71CHN32:
359 Device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 0);
360 Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
361 Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
362 Device->NumChan = 7;
363 Speaker2Chan[0] = BACK_LEFT;
364 Speaker2Chan[1] = SIDE_LEFT;
365 Speaker2Chan[2] = FRONT_LEFT;
366 Speaker2Chan[3] = FRONT_CENTER;
367 Speaker2Chan[4] = FRONT_RIGHT;
368 Speaker2Chan[5] = SIDE_RIGHT;
369 Speaker2Chan[6] = BACK_RIGHT;
370 SpeakerAngle[0] = -150.0f * M_PI/180.0f;
371 SpeakerAngle[1] = -90.0f * M_PI/180.0f;
372 SpeakerAngle[2] = -30.0f * M_PI/180.0f;
373 SpeakerAngle[3] = 0.0f * M_PI/180.0f;
374 SpeakerAngle[4] = 30.0f * M_PI/180.0f;
375 SpeakerAngle[5] = 90.0f * M_PI/180.0f;
376 SpeakerAngle[6] = 150.0f * M_PI/180.0f;
377 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
378 break;
380 default:
381 assert(0);
384 if(GetConfigValueBool(NULL, "scalemix", 0))
386 ALfloat maxout = 1.0f;
387 for(s = 0;s < OUTPUTCHANNELS;s++)
389 ALfloat out = 0.0f;
390 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
391 out += Device->ChannelMatrix[s2][s];
392 maxout = __max(maxout, out);
395 maxout = 1.0f/maxout;
396 for(s = 0;s < OUTPUTCHANNELS;s++)
398 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
399 Device->ChannelMatrix[s2][s] *= maxout;
403 for(pos = 0; pos < LUT_NUM; pos++)
405 /* clear all values */
406 offset = OUTPUTCHANNELS * pos;
407 for(s = 0; s < OUTPUTCHANNELS; s++)
408 Device->PanningLUT[offset+s] = 0.0f;
410 if(Device->NumChan == 1)
412 Device->PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
413 continue;
416 /* source angle */
417 Theta = aluLUTpos2Angle(pos);
419 /* set panning values */
420 for(s = 0; s < Device->NumChan - 1; s++)
422 if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
424 /* source between speaker s and speaker s+1 */
425 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
426 (SpeakerAngle[s+1]-SpeakerAngle[s]);
427 Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
428 Device->PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
429 break;
432 if(s == Device->NumChan - 1)
434 /* source between last and first speaker */
435 if(Theta < SpeakerAngle[0])
436 Theta += 2.0f * M_PI;
437 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
438 (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
439 Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
440 Device->PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
445 static ALvoid CalcNonAttnSourceParams(const ALCcontext *ALContext, ALsource *ALSource)
447 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
448 ALfloat DryGain, DryGainHF;
449 ALfloat WetGain[MAX_SENDS];
450 ALfloat WetGainHF[MAX_SENDS];
451 ALint NumSends, Frequency;
452 ALfloat cw;
453 ALint i;
455 //Get context properties
456 NumSends = ALContext->Device->NumAuxSends;
457 Frequency = ALContext->Device->Frequency;
459 //Get listener properties
460 ListenerGain = ALContext->Listener.Gain;
462 //Get source properties
463 SourceVolume = ALSource->flGain;
464 MinVolume = ALSource->flMinGain;
465 MaxVolume = ALSource->flMaxGain;
467 //1. Multi-channel buffers always play "normal"
468 ALSource->Params.Pitch = ALSource->flPitch;
470 DryGain = SourceVolume;
471 DryGain = __min(DryGain,MaxVolume);
472 DryGain = __max(DryGain,MinVolume);
473 DryGainHF = 1.0f;
475 switch(ALSource->DirectFilter.type)
477 case AL_FILTER_LOWPASS:
478 DryGain *= ALSource->DirectFilter.Gain;
479 DryGainHF *= ALSource->DirectFilter.GainHF;
480 break;
483 for(i = 0;i < OUTPUTCHANNELS;i++)
484 ALSource->Params.DryGains[i] = DryGain * ListenerGain;
486 for(i = 0;i < NumSends;i++)
488 WetGain[i] = SourceVolume;
489 WetGain[i] = __min(WetGain[i],MaxVolume);
490 WetGain[i] = __max(WetGain[i],MinVolume);
491 WetGainHF[i] = 1.0f;
493 switch(ALSource->Send[i].WetFilter.type)
495 case AL_FILTER_LOWPASS:
496 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
497 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
498 break;
501 ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
503 for(i = NumSends;i < MAX_SENDS;i++)
505 ALSource->Params.WetGains[i] = 0.0f;
506 WetGainHF[i] = 1.0f;
509 /* Update filter coefficients. Calculations based on the I3DL2
510 * spec. */
511 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
513 /* We use two chained one-pole filters, so we need to take the
514 * square root of the squared gain, which is the same as the base
515 * gain. */
516 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
518 for(i = 0;i < NumSends;i++)
520 /* We use a one-pole filter, so we need to take the squared gain */
521 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
522 ALSource->Params.Send[i].iirFilter.coeff = a;
526 static ALvoid CalcSourceParams(const ALCcontext *ALContext, ALsource *ALSource)
528 const ALCdevice *Device = ALContext->Device;
529 ALfloat InnerAngle,OuterAngle,Angle,Distance,DryMix,OrigDist;
530 ALfloat Direction[3],Position[3],SourceToListener[3];
531 ALfloat Velocity[3],ListenerVel[3];
532 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
533 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
534 ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound;
535 ALfloat Matrix[4][4];
536 ALfloat flAttenuation, effectiveDist;
537 ALfloat RoomAttenuation[MAX_SENDS];
538 ALfloat MetersPerUnit;
539 ALfloat RoomRolloff[MAX_SENDS];
540 ALfloat DryGainHF = 1.0f;
541 ALfloat WetGain[MAX_SENDS];
542 ALfloat WetGainHF[MAX_SENDS];
543 ALfloat DirGain, AmbientGain;
544 const ALfloat *SpeakerGain;
545 ALfloat length;
546 ALuint Frequency;
547 ALint NumSends;
548 ALint pos, s, i;
549 ALfloat cw;
551 for(i = 0;i < MAX_SENDS;i++)
552 WetGainHF[i] = 1.0f;
554 //Get context properties
555 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
556 DopplerVelocity = ALContext->DopplerVelocity;
557 flSpeedOfSound = ALContext->flSpeedOfSound;
558 NumSends = Device->NumAuxSends;
559 Frequency = Device->Frequency;
561 //Get listener properties
562 ListenerGain = ALContext->Listener.Gain;
563 MetersPerUnit = ALContext->Listener.MetersPerUnit;
564 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
566 //Get source properties
567 SourceVolume = ALSource->flGain;
568 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
569 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
570 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
571 MinVolume = ALSource->flMinGain;
572 MaxVolume = ALSource->flMaxGain;
573 MinDist = ALSource->flRefDistance;
574 MaxDist = ALSource->flMaxDistance;
575 Rolloff = ALSource->flRollOffFactor;
576 InnerAngle = ALSource->flInnerAngle;
577 OuterAngle = ALSource->flOuterAngle;
578 OuterGainHF = ALSource->OuterGainHF;
580 //1. Translate Listener to origin (convert to head relative)
581 if(ALSource->bHeadRelative==AL_FALSE)
583 ALfloat U[3],V[3],N[3];
585 // Build transform matrix
586 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
587 aluNormalize(N); // Normalized At-vector
588 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
589 aluNormalize(V); // Normalized Up-vector
590 aluCrossproduct(N, V, U); // Right-vector
591 aluNormalize(U); // Normalized Right-vector
592 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
593 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
594 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
595 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
597 // Translate position
598 Position[0] -= ALContext->Listener.Position[0];
599 Position[1] -= ALContext->Listener.Position[1];
600 Position[2] -= ALContext->Listener.Position[2];
602 // Transform source position and direction into listener space
603 aluMatrixVector(Position, 1.0f, Matrix);
604 aluMatrixVector(Direction, 0.0f, Matrix);
605 // Transform source and listener velocity into listener space
606 aluMatrixVector(Velocity, 0.0f, Matrix);
607 aluMatrixVector(ListenerVel, 0.0f, Matrix);
609 else
610 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
612 SourceToListener[0] = -Position[0];
613 SourceToListener[1] = -Position[1];
614 SourceToListener[2] = -Position[2];
615 aluNormalize(SourceToListener);
616 aluNormalize(Direction);
618 //2. Calculate distance attenuation
619 Distance = aluSqrt(aluDotproduct(Position, Position));
620 OrigDist = Distance;
622 flAttenuation = 1.0f;
623 for(i = 0;i < NumSends;i++)
625 RoomAttenuation[i] = 1.0f;
627 RoomRolloff[i] = ALSource->RoomRolloffFactor;
628 if(ALSource->Send[i].Slot &&
629 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
630 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
631 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
634 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
635 ALContext->DistanceModel)
637 case AL_INVERSE_DISTANCE_CLAMPED:
638 Distance=__max(Distance,MinDist);
639 Distance=__min(Distance,MaxDist);
640 if(MaxDist < MinDist)
641 break;
642 //fall-through
643 case AL_INVERSE_DISTANCE:
644 if(MinDist > 0.0f)
646 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
647 flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
648 for(i = 0;i < NumSends;i++)
650 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
651 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
654 break;
656 case AL_LINEAR_DISTANCE_CLAMPED:
657 Distance=__max(Distance,MinDist);
658 Distance=__min(Distance,MaxDist);
659 if(MaxDist < MinDist)
660 break;
661 //fall-through
662 case AL_LINEAR_DISTANCE:
663 Distance=__min(Distance,MaxDist);
664 if(MaxDist != MinDist)
666 flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
667 for(i = 0;i < NumSends;i++)
668 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
670 break;
672 case AL_EXPONENT_DISTANCE_CLAMPED:
673 Distance=__max(Distance,MinDist);
674 Distance=__min(Distance,MaxDist);
675 if(MaxDist < MinDist)
676 break;
677 //fall-through
678 case AL_EXPONENT_DISTANCE:
679 if(Distance > 0.0f && MinDist > 0.0f)
681 flAttenuation = aluPow(Distance/MinDist, -Rolloff);
682 for(i = 0;i < NumSends;i++)
683 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
685 break;
687 case AL_NONE:
688 break;
691 // Source Gain + Attenuation
692 DryMix = SourceVolume * flAttenuation;
693 for(i = 0;i < NumSends;i++)
694 WetGain[i] = SourceVolume * RoomAttenuation[i];
696 effectiveDist = 0.0f;
697 if(MinDist > 0.0f)
698 effectiveDist = (MinDist/flAttenuation - MinDist)*MetersPerUnit;
700 // Distance-based air absorption
701 if(ALSource->AirAbsorptionFactor > 0.0f && effectiveDist > 0.0f)
703 ALfloat absorb;
705 // Absorption calculation is done in dB
706 absorb = (ALSource->AirAbsorptionFactor*AIRABSORBGAINDBHF) *
707 effectiveDist;
708 // Convert dB to linear gain before applying
709 absorb = aluPow(10.0f, absorb/20.0f);
711 DryGainHF *= absorb;
714 //3. Apply directional soundcones
715 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
716 if(Angle >= InnerAngle && Angle <= OuterAngle)
718 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
719 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
720 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
722 else if(Angle > OuterAngle)
724 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
725 ConeHF = (1.0f+(OuterGainHF-1.0f));
727 else
729 ConeVolume = 1.0f;
730 ConeHF = 1.0f;
733 // Apply some high-frequency attenuation for sources behind the listener
734 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
735 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
736 // the same as SourceToListener[2]
737 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
738 // Sources within the minimum distance attenuate less
739 if(OrigDist < MinDist)
740 Angle *= OrigDist/MinDist;
741 if(Angle > 90.0f)
743 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
744 ConeHF *= 1.0f - (Device->HeadDampen*scale);
747 DryMix *= ConeVolume;
748 if(ALSource->DryGainHFAuto)
749 DryGainHF *= ConeHF;
751 // Clamp to Min/Max Gain
752 DryMix = __min(DryMix,MaxVolume);
753 DryMix = __max(DryMix,MinVolume);
755 for(i = 0;i < NumSends;i++)
757 ALeffectslot *Slot = ALSource->Send[i].Slot;
759 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
761 ALSource->Params.WetGains[i] = 0.0f;
762 WetGainHF[i] = 1.0f;
763 continue;
766 if(Slot->AuxSendAuto)
768 if(ALSource->WetGainAuto)
769 WetGain[i] *= ConeVolume;
770 if(ALSource->WetGainHFAuto)
771 WetGainHF[i] *= ConeHF;
773 // Clamp to Min/Max Gain
774 WetGain[i] = __min(WetGain[i],MaxVolume);
775 WetGain[i] = __max(WetGain[i],MinVolume);
777 if(Slot->effect.type == AL_EFFECT_REVERB ||
778 Slot->effect.type == AL_EFFECT_EAXREVERB)
780 /* Apply a decay-time transformation to the wet path, based on
781 * the attenuation of the dry path.
783 * Using the approximate (effective) source to listener
784 * distance, the initial decay of the reverb effect is
785 * calculated and applied to the wet path.
787 WetGain[i] *= aluPow(10.0f, effectiveDist /
788 (SPEEDOFSOUNDMETRESPERSEC *
789 Slot->effect.Reverb.DecayTime) *
790 -60.0 / 20.0);
792 WetGainHF[i] *= aluPow(10.0f,
793 log10(Slot->effect.Reverb.AirAbsorptionGainHF) *
794 ALSource->AirAbsorptionFactor * effectiveDist);
797 else
799 /* If the slot's auxiliary send auto is off, the data sent to the
800 * effect slot is the same as the dry path, sans filter effects */
801 WetGain[i] = DryMix;
802 WetGainHF[i] = DryGainHF;
805 switch(ALSource->Send[i].WetFilter.type)
807 case AL_FILTER_LOWPASS:
808 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
809 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
810 break;
812 ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
814 for(i = NumSends;i < MAX_SENDS;i++)
816 ALSource->Params.WetGains[i] = 0.0f;
817 WetGainHF[i] = 1.0f;
820 // Apply filter gains and filters
821 switch(ALSource->DirectFilter.type)
823 case AL_FILTER_LOWPASS:
824 DryMix *= ALSource->DirectFilter.Gain;
825 DryGainHF *= ALSource->DirectFilter.GainHF;
826 break;
828 DryMix *= ListenerGain;
830 // Calculate Velocity
831 if(DopplerFactor != 0.0f)
833 ALfloat flVSS, flVLS;
834 ALfloat flMaxVelocity = (DopplerVelocity * flSpeedOfSound) /
835 DopplerFactor;
837 flVSS = aluDotproduct(Velocity, SourceToListener);
838 if(flVSS >= flMaxVelocity)
839 flVSS = (flMaxVelocity - 1.0f);
840 else if(flVSS <= -flMaxVelocity)
841 flVSS = -flMaxVelocity + 1.0f;
843 flVLS = aluDotproduct(ListenerVel, SourceToListener);
844 if(flVLS >= flMaxVelocity)
845 flVLS = (flMaxVelocity - 1.0f);
846 else if(flVLS <= -flMaxVelocity)
847 flVLS = -flMaxVelocity + 1.0f;
849 ALSource->Params.Pitch = ALSource->flPitch *
850 ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) /
851 ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS));
853 else
854 ALSource->Params.Pitch = ALSource->flPitch;
856 // Use energy-preserving panning algorithm for multi-speaker playback
857 length = __max(OrigDist, MinDist);
858 if(length > 0.0f)
860 ALfloat invlen = 1.0f/length;
861 Position[0] *= invlen;
862 Position[1] *= invlen;
863 Position[2] *= invlen;
866 pos = aluCart2LUTpos(-Position[2], Position[0]);
867 SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
869 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
870 // elevation adjustment for directional gain. this sucks, but
871 // has low complexity
872 AmbientGain = 1.0/aluSqrt(Device->NumChan) * (1.0-DirGain);
873 for(s = 0;s < OUTPUTCHANNELS;s++)
874 ALSource->Params.DryGains[s] = 0.0f;
875 for(s = 0;s < (ALsizei)Device->NumChan;s++)
877 Channel chan = Device->Speaker2Chan[s];
878 ALfloat gain = SpeakerGain[chan]*DirGain + AmbientGain;
879 ALSource->Params.DryGains[chan] = DryMix * gain;
882 /* Update filter coefficients. */
883 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
885 /* Spatialized sources use four chained one-pole filters, so we need to
886 * take the fourth root of the squared gain, which is the same as the
887 * square root of the base gain. */
888 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
890 for(i = 0;i < NumSends;i++)
892 /* The wet path uses two chained one-pole filters, so take the
893 * base gain (square root of the squared gain) */
894 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
898 static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac)
900 return val1;
901 (void)val2;
902 (void)frac;
904 static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac)
906 return val1 + ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
908 static __inline ALfloat cos_lerp(ALfloat val1, ALfloat val2, ALint frac)
910 ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
911 return val1 + ((val2-val1)*mult);
914 static void MixSomeSources(ALCcontext *ALContext, float (*DryBuffer)[OUTPUTCHANNELS], ALuint SamplesToDo)
916 static float DummyBuffer[BUFFERSIZE];
917 ALfloat *WetBuffer[MAX_SENDS];
918 ALfloat DrySend[OUTPUTCHANNELS];
919 ALfloat dryGainStep[OUTPUTCHANNELS];
920 ALfloat wetGainStep[MAX_SENDS];
921 ALuint i, j, k, out;
922 ALsource *ALSource;
923 ALfloat value, outsamp;
924 ALbufferlistitem *BufferListItem;
925 ALint64 DataSize64,DataPos64;
926 FILTER *DryFilter, *WetFilter[MAX_SENDS];
927 ALfloat WetSend[MAX_SENDS];
928 ALuint rampLength;
929 ALboolean DuplicateStereo;
930 ALuint DeviceFreq;
931 ALint increment;
932 ALuint DataPosInt, DataPosFrac;
933 ALuint Channels, Bytes;
934 ALuint Frequency;
935 resampler_t Resampler;
936 ALuint BuffersPlayed;
937 ALfloat Pitch;
938 ALenum State;
939 ALsizei pos;
941 if(ALContext->SourceMap.size <= 0)
942 return;
944 DuplicateStereo = ALContext->Device->DuplicateStereo;
945 DeviceFreq = ALContext->Device->Frequency;
947 rampLength = DeviceFreq * MIN_RAMP_LENGTH / 1000;
948 rampLength = max(rampLength, SamplesToDo);
950 pos = ALContext->SourceMap.size;
951 next_source:
952 do {
953 if(pos-- <= 0)
954 return;
955 ALSource = ALContext->SourceMap.array[pos].value;
956 } while(ALSource->state != AL_PLAYING);
957 j = 0;
959 /* Find buffer format */
960 Frequency = 0;
961 Channels = 0;
962 Bytes = 0;
963 BufferListItem = ALSource->queue;
964 while(BufferListItem != NULL)
966 ALbuffer *ALBuffer;
967 if((ALBuffer=BufferListItem->buffer) != NULL)
969 Channels = aluChannelsFromFormat(ALBuffer->format);
970 Bytes = aluBytesFromFormat(ALBuffer->format);
971 Frequency = ALBuffer->frequency;
972 break;
974 BufferListItem = BufferListItem->next;
977 if(ALSource->NeedsUpdate)
979 //Only apply 3D calculations for mono buffers
980 if(Channels == 1)
981 CalcSourceParams(ALContext, ALSource);
982 else
983 CalcNonAttnSourceParams(ALContext, ALSource);
984 ALSource->NeedsUpdate = AL_FALSE;
987 /* Get source info */
988 Resampler = ALSource->Resampler;
989 State = ALSource->state;
990 BuffersPlayed = ALSource->BuffersPlayed;
991 DataPosInt = ALSource->position;
992 DataPosFrac = ALSource->position_fraction;
994 /* Compute 18.14 fixed point step */
995 Pitch = (ALSource->Params.Pitch*Frequency) / DeviceFreq;
996 if(Pitch > (float)MAX_PITCH) Pitch = (float)MAX_PITCH;
997 increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
998 if(increment <= 0) increment = (1<<FRACTIONBITS);
1000 if(ALSource->FirstStart)
1002 for(i = 0;i < OUTPUTCHANNELS;i++)
1003 DrySend[i] = ALSource->Params.DryGains[i];
1004 for(i = 0;i < MAX_SENDS;i++)
1005 WetSend[i] = ALSource->Params.WetGains[i];
1007 else
1009 for(i = 0;i < OUTPUTCHANNELS;i++)
1010 DrySend[i] = ALSource->DryGains[i];
1011 for(i = 0;i < MAX_SENDS;i++)
1012 WetSend[i] = ALSource->WetGains[i];
1015 DryFilter = &ALSource->Params.iirFilter;
1016 for(i = 0;i < MAX_SENDS;i++)
1018 WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
1019 WetBuffer[i] = (ALSource->Send[i].Slot ?
1020 ALSource->Send[i].Slot->WetBuffer :
1021 DummyBuffer);
1024 /* Get current buffer queue item */
1025 BufferListItem = ALSource->queue;
1026 for(i = 0;i < BuffersPlayed && BufferListItem;i++)
1027 BufferListItem = BufferListItem->next;
1029 while(State == AL_PLAYING && j < SamplesToDo)
1031 ALuint DataSize = 0;
1032 ALbuffer *ALBuffer;
1033 ALfloat *Data;
1034 ALuint BufferSize;
1036 /* Get buffer info */
1037 if((ALBuffer=BufferListItem->buffer) != NULL)
1039 Data = ALBuffer->data;
1040 DataSize = ALBuffer->size;
1041 DataSize /= Channels * Bytes;
1043 if(DataPosInt >= DataSize)
1044 goto skipmix;
1046 if(BufferListItem->next)
1048 ALbuffer *NextBuf = BufferListItem->next->buffer;
1049 if(NextBuf && NextBuf->size)
1051 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
1052 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
1053 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
1056 else if(ALSource->bLooping)
1058 ALbuffer *NextBuf = ALSource->queue->buffer;
1059 if(NextBuf && NextBuf->size)
1061 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
1062 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
1063 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
1066 else
1067 memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes));
1069 /* Compute the gain steps for each output channel */
1070 for(i = 0;i < OUTPUTCHANNELS;i++)
1071 dryGainStep[i] = (ALSource->Params.DryGains[i]-DrySend[i]) /
1072 rampLength;
1073 for(i = 0;i < MAX_SENDS;i++)
1074 wetGainStep[i] = (ALSource->Params.WetGains[i]-WetSend[i]) /
1075 rampLength;
1077 /* Figure out how many samples we can mix. */
1078 DataSize64 = DataSize;
1079 DataSize64 <<= FRACTIONBITS;
1080 DataPos64 = DataPosInt;
1081 DataPos64 <<= FRACTIONBITS;
1082 DataPos64 += DataPosFrac;
1083 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
1085 BufferSize = min(BufferSize, (SamplesToDo-j));
1087 /* Actual sample mixing loop */
1088 k = 0;
1089 Data += DataPosInt*Channels;
1091 if(Channels == 1) /* Mono */
1093 #define DO_MIX(resampler) do { \
1094 while(BufferSize--) \
1096 for(i = 0;i < OUTPUTCHANNELS;i++) \
1097 DrySend[i] += dryGainStep[i]; \
1098 for(i = 0;i < MAX_SENDS;i++) \
1099 WetSend[i] += wetGainStep[i]; \
1101 /* First order interpolator */ \
1102 value = (resampler)(Data[k], Data[k+1], DataPosFrac); \
1104 /* Direct path final mix buffer and panning */ \
1105 outsamp = lpFilter4P(DryFilter, 0, value); \
1106 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
1107 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
1108 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
1109 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
1110 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
1111 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
1112 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
1113 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
1115 /* Room path final mix buffer and panning */ \
1116 for(i = 0;i < MAX_SENDS;i++) \
1118 outsamp = lpFilter2P(WetFilter[i], 0, value); \
1119 WetBuffer[i][j] += outsamp*WetSend[i]; \
1122 DataPosFrac += increment; \
1123 k += DataPosFrac>>FRACTIONBITS; \
1124 DataPosFrac &= FRACTIONMASK; \
1125 j++; \
1127 } while(0)
1129 switch(Resampler)
1131 case POINT_RESAMPLER:
1132 DO_MIX(point); break;
1133 case LINEAR_RESAMPLER:
1134 DO_MIX(lerp); break;
1135 case COSINE_RESAMPLER:
1136 DO_MIX(cos_lerp); break;
1137 case RESAMPLER_MIN:
1138 case RESAMPLER_MAX:
1139 break;
1141 #undef DO_MIX
1143 else if(Channels == 2 && DuplicateStereo) /* Stereo */
1145 const int chans[] = {
1146 FRONT_LEFT, FRONT_RIGHT
1148 const int chans2[] = {
1149 BACK_LEFT, SIDE_LEFT, BACK_RIGHT, SIDE_RIGHT
1151 const ALfloat scaler = 1.0f/Channels;
1152 const ALfloat dupscaler = aluSqrt(1.0f/3.0f);
1154 #define DO_MIX(resampler) do { \
1155 while(BufferSize--) \
1157 for(i = 0;i < OUTPUTCHANNELS;i++) \
1158 DrySend[i] += dryGainStep[i]; \
1159 for(i = 0;i < MAX_SENDS;i++) \
1160 WetSend[i] += wetGainStep[i]; \
1162 for(i = 0;i < Channels;i++) \
1164 value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\
1165 DataPosFrac); \
1166 outsamp = lpFilter2P(DryFilter, chans[i]*2, value) * dupscaler; \
1167 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
1168 DryBuffer[j][chans2[i*2+0]] += outsamp*DrySend[chans2[i*2+0]]; \
1169 DryBuffer[j][chans2[i*2+1]] += outsamp*DrySend[chans2[i*2+1]]; \
1170 for(out = 0;out < MAX_SENDS;out++) \
1172 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
1173 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
1177 DataPosFrac += increment; \
1178 k += DataPosFrac>>FRACTIONBITS; \
1179 DataPosFrac &= FRACTIONMASK; \
1180 j++; \
1182 } while(0)
1184 switch(Resampler)
1186 case POINT_RESAMPLER:
1187 DO_MIX(point); break;
1188 case LINEAR_RESAMPLER:
1189 DO_MIX(lerp); break;
1190 case COSINE_RESAMPLER:
1191 DO_MIX(cos_lerp); break;
1192 case RESAMPLER_MIN:
1193 case RESAMPLER_MAX:
1194 break;
1196 #undef DO_MIX
1198 else if(Channels == 2) /* Stereo */
1200 const int chans[] = {
1201 FRONT_LEFT, FRONT_RIGHT
1203 const ALfloat scaler = 1.0f/Channels;
1205 #define DO_MIX(resampler) do { \
1206 while(BufferSize--) \
1208 for(i = 0;i < OUTPUTCHANNELS;i++) \
1209 DrySend[i] += dryGainStep[i]; \
1210 for(i = 0;i < MAX_SENDS;i++) \
1211 WetSend[i] += wetGainStep[i]; \
1213 for(i = 0;i < Channels;i++) \
1215 value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\
1216 DataPosFrac); \
1217 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
1218 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
1219 for(out = 0;out < MAX_SENDS;out++) \
1221 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
1222 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
1226 DataPosFrac += increment; \
1227 k += DataPosFrac>>FRACTIONBITS; \
1228 DataPosFrac &= FRACTIONMASK; \
1229 j++; \
1231 } while(0)
1233 switch(Resampler)
1235 case POINT_RESAMPLER:
1236 DO_MIX(point); break;
1237 case LINEAR_RESAMPLER:
1238 DO_MIX(lerp); break;
1239 case COSINE_RESAMPLER:
1240 DO_MIX(cos_lerp); break;
1241 case RESAMPLER_MIN:
1242 case RESAMPLER_MAX:
1243 break;
1246 else if(Channels == 4) /* Quad */
1248 const int chans[] = {
1249 FRONT_LEFT, FRONT_RIGHT,
1250 BACK_LEFT, BACK_RIGHT
1252 const ALfloat scaler = 1.0f/Channels;
1254 switch(Resampler)
1256 case POINT_RESAMPLER:
1257 DO_MIX(point); break;
1258 case LINEAR_RESAMPLER:
1259 DO_MIX(lerp); break;
1260 case COSINE_RESAMPLER:
1261 DO_MIX(cos_lerp); break;
1262 case RESAMPLER_MIN:
1263 case RESAMPLER_MAX:
1264 break;
1267 else if(Channels == 6) /* 5.1 */
1269 const int chans[] = {
1270 FRONT_LEFT, FRONT_RIGHT,
1271 FRONT_CENTER, LFE,
1272 BACK_LEFT, BACK_RIGHT
1274 const ALfloat scaler = 1.0f/Channels;
1276 switch(Resampler)
1278 case POINT_RESAMPLER:
1279 DO_MIX(point); break;
1280 case LINEAR_RESAMPLER:
1281 DO_MIX(lerp); break;
1282 case COSINE_RESAMPLER:
1283 DO_MIX(cos_lerp); break;
1284 case RESAMPLER_MIN:
1285 case RESAMPLER_MAX:
1286 break;
1289 else if(Channels == 7) /* 6.1 */
1291 const int chans[] = {
1292 FRONT_LEFT, FRONT_RIGHT,
1293 FRONT_CENTER, LFE,
1294 BACK_CENTER,
1295 SIDE_LEFT, SIDE_RIGHT
1297 const ALfloat scaler = 1.0f/Channels;
1299 switch(Resampler)
1301 case POINT_RESAMPLER:
1302 DO_MIX(point); break;
1303 case LINEAR_RESAMPLER:
1304 DO_MIX(lerp); break;
1305 case COSINE_RESAMPLER:
1306 DO_MIX(cos_lerp); break;
1307 case RESAMPLER_MIN:
1308 case RESAMPLER_MAX:
1309 break;
1312 else if(Channels == 8) /* 7.1 */
1314 const int chans[] = {
1315 FRONT_LEFT, FRONT_RIGHT,
1316 FRONT_CENTER, LFE,
1317 BACK_LEFT, BACK_RIGHT,
1318 SIDE_LEFT, SIDE_RIGHT
1320 const ALfloat scaler = 1.0f/Channels;
1322 switch(Resampler)
1324 case POINT_RESAMPLER:
1325 DO_MIX(point); break;
1326 case LINEAR_RESAMPLER:
1327 DO_MIX(lerp); break;
1328 case COSINE_RESAMPLER:
1329 DO_MIX(cos_lerp); break;
1330 case RESAMPLER_MIN:
1331 case RESAMPLER_MAX:
1332 break;
1334 #undef DO_MIX
1336 else /* Unknown? */
1338 for(i = 0;i < OUTPUTCHANNELS;i++)
1339 DrySend[i] += dryGainStep[i]*BufferSize;
1340 for(i = 0;i < MAX_SENDS;i++)
1341 WetSend[i] += wetGainStep[i]*BufferSize;
1342 while(BufferSize--)
1344 DataPosFrac += increment;
1345 k += DataPosFrac>>FRACTIONBITS;
1346 DataPosFrac &= FRACTIONMASK;
1347 j++;
1350 DataPosInt += k;
1352 skipmix:
1353 /* Handle looping sources */
1354 if(DataPosInt >= DataSize)
1356 if(BuffersPlayed < (ALSource->BuffersInQueue-1))
1358 BufferListItem = BufferListItem->next;
1359 BuffersPlayed++;
1360 DataPosInt -= DataSize;
1362 else if(ALSource->bLooping)
1364 BufferListItem = ALSource->queue;
1365 BuffersPlayed = 0;
1366 if(ALSource->BuffersInQueue == 1)
1367 DataPosInt %= DataSize;
1368 else
1369 DataPosInt -= DataSize;
1371 else
1373 State = AL_STOPPED;
1374 BufferListItem = ALSource->queue;
1375 BuffersPlayed = ALSource->BuffersInQueue;
1376 DataPosInt = 0;
1377 DataPosFrac = 0;
1382 /* Update source info */
1383 ALSource->state = State;
1384 ALSource->BuffersPlayed = BuffersPlayed;
1385 ALSource->position = DataPosInt;
1386 ALSource->position_fraction = DataPosFrac;
1387 ALSource->Buffer = BufferListItem->buffer;
1389 for(i = 0;i < OUTPUTCHANNELS;i++)
1390 ALSource->DryGains[i] = DrySend[i];
1391 for(i = 0;i < MAX_SENDS;i++)
1392 ALSource->WetGains[i] = WetSend[i];
1394 ALSource->FirstStart = AL_FALSE;
1396 goto next_source;
1399 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1401 float (*DryBuffer)[OUTPUTCHANNELS];
1402 ALfloat (*Matrix)[OUTPUTCHANNELS];
1403 const ALuint *ChanMap;
1404 ALuint SamplesToDo;
1405 ALeffectslot *ALEffectSlot;
1406 ALCcontext *ALContext;
1407 ALfloat samp;
1408 int fpuState;
1409 ALuint i, j, c;
1411 #if defined(HAVE_FESETROUND)
1412 fpuState = fegetround();
1413 fesetround(FE_TOWARDZERO);
1414 #elif defined(HAVE__CONTROLFP)
1415 fpuState = _controlfp(0, 0);
1416 _controlfp(_RC_CHOP, _MCW_RC);
1417 #else
1418 (void)fpuState;
1419 #endif
1421 DryBuffer = device->DryBuffer;
1422 while(size > 0)
1424 /* Setup variables */
1425 SamplesToDo = min(size, BUFFERSIZE);
1427 /* Clear mixing buffer */
1428 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
1430 SuspendContext(NULL);
1431 for(c = 0;c < device->NumContexts;c++)
1433 ALContext = device->Contexts[c];
1434 SuspendContext(ALContext);
1436 MixSomeSources(ALContext, DryBuffer, SamplesToDo);
1438 /* effect slot processing */
1439 ALEffectSlot = ALContext->EffectSlotList;
1440 while(ALEffectSlot)
1442 if(ALEffectSlot->EffectState)
1443 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
1445 for(i = 0;i < SamplesToDo;i++)
1446 ALEffectSlot->WetBuffer[i] = 0.0f;
1447 ALEffectSlot = ALEffectSlot->next;
1449 ProcessContext(ALContext);
1451 ProcessContext(NULL);
1453 //Post processing loop
1454 ChanMap = device->DevChannels;
1455 Matrix = device->ChannelMatrix;
1456 switch(device->Format)
1458 #define CHECK_WRITE_FORMAT(bits, type, func) \
1459 case AL_FORMAT_MONO##bits: \
1460 for(i = 0;i < SamplesToDo;i++) \
1462 samp = 0.0f; \
1463 for(c = 0;c < OUTPUTCHANNELS;c++) \
1464 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
1465 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
1466 buffer = ((type*)buffer) + 1; \
1468 break; \
1469 case AL_FORMAT_STEREO##bits: \
1470 if(device->Bs2b) \
1472 for(i = 0;i < SamplesToDo;i++) \
1474 float samples[2] = { 0.0f, 0.0f }; \
1475 for(c = 0;c < OUTPUTCHANNELS;c++) \
1477 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
1478 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
1480 bs2b_cross_feed(device->Bs2b, samples); \
1481 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
1482 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
1483 buffer = ((type*)buffer) + 2; \
1486 else \
1488 for(i = 0;i < SamplesToDo;i++) \
1490 static const Channel chans[] = { \
1491 FRONT_LEFT, FRONT_RIGHT \
1492 }; \
1493 for(j = 0;j < 2;j++) \
1495 samp = 0.0f; \
1496 for(c = 0;c < OUTPUTCHANNELS;c++) \
1497 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1498 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1500 buffer = ((type*)buffer) + 2; \
1503 break; \
1504 case AL_FORMAT_QUAD##bits: \
1505 for(i = 0;i < SamplesToDo;i++) \
1507 static const Channel chans[] = { \
1508 FRONT_LEFT, FRONT_RIGHT, \
1509 BACK_LEFT, BACK_RIGHT, \
1510 }; \
1511 for(j = 0;j < 4;j++) \
1513 samp = 0.0f; \
1514 for(c = 0;c < OUTPUTCHANNELS;c++) \
1515 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1516 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1518 buffer = ((type*)buffer) + 4; \
1520 break; \
1521 case AL_FORMAT_51CHN##bits: \
1522 for(i = 0;i < SamplesToDo;i++) \
1524 static const Channel chans[] = { \
1525 FRONT_LEFT, FRONT_RIGHT, \
1526 FRONT_CENTER, LFE, \
1527 BACK_LEFT, BACK_RIGHT, \
1528 }; \
1529 for(j = 0;j < 6;j++) \
1531 samp = 0.0f; \
1532 for(c = 0;c < OUTPUTCHANNELS;c++) \
1533 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1534 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1536 buffer = ((type*)buffer) + 6; \
1538 break; \
1539 case AL_FORMAT_61CHN##bits: \
1540 for(i = 0;i < SamplesToDo;i++) \
1542 static const Channel chans[] = { \
1543 FRONT_LEFT, FRONT_RIGHT, \
1544 FRONT_CENTER, LFE, BACK_CENTER, \
1545 SIDE_LEFT, SIDE_RIGHT, \
1546 }; \
1547 for(j = 0;j < 7;j++) \
1549 samp = 0.0f; \
1550 for(c = 0;c < OUTPUTCHANNELS;c++) \
1551 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1552 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1554 buffer = ((type*)buffer) + 7; \
1556 break; \
1557 case AL_FORMAT_71CHN##bits: \
1558 for(i = 0;i < SamplesToDo;i++) \
1560 static const Channel chans[] = { \
1561 FRONT_LEFT, FRONT_RIGHT, \
1562 FRONT_CENTER, LFE, \
1563 BACK_LEFT, BACK_RIGHT, \
1564 SIDE_LEFT, SIDE_RIGHT \
1565 }; \
1566 for(j = 0;j < 8;j++) \
1568 samp = 0.0f; \
1569 for(c = 0;c < OUTPUTCHANNELS;c++) \
1570 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1571 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1573 buffer = ((type*)buffer) + 8; \
1575 break;
1577 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
1578 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
1579 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
1580 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
1581 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
1582 #undef AL_FORMAT_STEREO32
1583 #undef AL_FORMAT_MONO32
1584 #undef CHECK_WRITE_FORMAT
1586 default:
1587 break;
1590 size -= SamplesToDo;
1593 #if defined(HAVE_FESETROUND)
1594 fesetround(fpuState);
1595 #elif defined(HAVE__CONTROLFP)
1596 _controlfp(fpuState, 0xfffff);
1597 #endif
1600 ALvoid aluHandleDisconnect(ALCdevice *device)
1602 ALuint i;
1604 SuspendContext(NULL);
1605 for(i = 0;i < device->NumContexts;i++)
1607 ALCcontext *Context = device->Contexts[i];
1608 ALsource *source;
1609 ALsizei pos;
1611 SuspendContext(Context);
1613 for(pos = 0;pos < Context->SourceMap.size;pos++)
1615 source = Context->SourceMap.array[pos].value;
1616 if(source->state == AL_PLAYING)
1618 source->state = AL_STOPPED;
1619 source->BuffersPlayed = source->BuffersInQueue;
1620 source->position = 0;
1621 source->position_fraction = 0;
1624 ProcessContext(Context);
1627 device->Connected = ALC_FALSE;
1628 ProcessContext(NULL);