Combine duplicate lines into the mixing macro
[openal-soft.git] / Alc / ALu.c
blob4f345e51495f5c82d9ce1606d49b3754f6dfc9a2
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, 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 ALboolean Looping;
938 ALfloat Pitch;
939 ALenum State;
940 ALsizei pos;
942 DuplicateStereo = ALContext->Device->DuplicateStereo;
943 DeviceFreq = ALContext->Device->Frequency;
945 rampLength = DeviceFreq * MIN_RAMP_LENGTH / 1000;
946 rampLength = max(rampLength, SamplesToDo);
948 pos = 0;
949 next_source:
950 while(ALContext->ActiveSourceCount > pos)
952 ALsizei end;
954 ALSource = ALContext->ActiveSources[pos];
955 if(ALSource->state == AL_PLAYING)
956 break;
958 end = --(ALContext->ActiveSourceCount);
959 ALContext->ActiveSources[pos] = ALContext->ActiveSources[end];
961 if(pos >= ALContext->ActiveSourceCount)
962 return;
964 /* Find buffer format */
965 Frequency = 0;
966 Channels = 0;
967 Bytes = 0;
968 BufferListItem = ALSource->queue;
969 while(BufferListItem != NULL)
971 ALbuffer *ALBuffer;
972 if((ALBuffer=BufferListItem->buffer) != NULL)
974 Channels = aluChannelsFromFormat(ALBuffer->format);
975 Bytes = aluBytesFromFormat(ALBuffer->format);
976 Frequency = ALBuffer->frequency;
977 break;
979 BufferListItem = BufferListItem->next;
982 if(ALSource->NeedsUpdate)
984 //Only apply 3D calculations for mono buffers
985 if(Channels == 1)
986 CalcSourceParams(ALContext, ALSource);
987 else
988 CalcNonAttnSourceParams(ALContext, ALSource);
989 ALSource->NeedsUpdate = AL_FALSE;
992 /* Get source info */
993 Resampler = ALSource->Resampler;
994 State = ALSource->state;
995 BuffersPlayed = ALSource->BuffersPlayed;
996 DataPosInt = ALSource->position;
997 DataPosFrac = ALSource->position_fraction;
998 Looping = ALSource->bLooping;
1000 /* Compute 18.14 fixed point step */
1001 Pitch = (ALSource->Params.Pitch*Frequency) / DeviceFreq;
1002 if(Pitch > (float)MAX_PITCH) Pitch = (float)MAX_PITCH;
1003 increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
1004 if(increment <= 0) increment = (1<<FRACTIONBITS);
1006 if(ALSource->FirstStart)
1008 for(i = 0;i < OUTPUTCHANNELS;i++)
1009 DrySend[i] = ALSource->Params.DryGains[i];
1010 for(i = 0;i < MAX_SENDS;i++)
1011 WetSend[i] = ALSource->Params.WetGains[i];
1013 else
1015 for(i = 0;i < OUTPUTCHANNELS;i++)
1016 DrySend[i] = ALSource->DryGains[i];
1017 for(i = 0;i < MAX_SENDS;i++)
1018 WetSend[i] = ALSource->WetGains[i];
1021 DryFilter = &ALSource->Params.iirFilter;
1022 for(i = 0;i < MAX_SENDS;i++)
1024 WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
1025 WetBuffer[i] = (ALSource->Send[i].Slot ?
1026 ALSource->Send[i].Slot->WetBuffer :
1027 DummyBuffer);
1030 /* Get current buffer queue item */
1031 BufferListItem = ALSource->queue;
1032 for(i = 0;i < BuffersPlayed && BufferListItem;i++)
1033 BufferListItem = BufferListItem->next;
1035 j = 0;
1036 do {
1037 ALfloat *Data = NULL;
1038 ALuint LoopStart = 0;
1039 ALuint LoopEnd = 0;
1040 ALuint DataSize = 0;
1041 ALbuffer *ALBuffer;
1042 ALuint BufferSize;
1044 /* Get buffer info */
1045 if((ALBuffer=BufferListItem->buffer) != NULL)
1047 Data = ALBuffer->data;
1048 DataSize = ALBuffer->size;
1049 DataSize /= Channels * Bytes;
1050 LoopStart = ALBuffer->LoopStart;
1051 LoopEnd = ALBuffer->LoopEnd;
1054 if(Looping && ALSource->lSourceType == AL_STATIC)
1056 /* If current offset is beyond the loop range, do not loop */
1057 if(DataPosInt >= LoopEnd)
1058 Looping = AL_FALSE;
1060 if(!Looping || ALSource->lSourceType != AL_STATIC)
1062 /* Non-looping and non-static sources ignore loop points */
1063 LoopStart = 0;
1064 LoopEnd = DataSize;
1067 if(DataPosInt >= DataSize)
1068 goto skipmix;
1070 if(BufferListItem->next)
1072 ALbuffer *NextBuf = BufferListItem->next->buffer;
1073 if(NextBuf && NextBuf->size)
1075 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
1076 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
1077 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
1080 else if(Looping)
1082 ALbuffer *NextBuf = ALSource->queue->buffer;
1083 if(NextBuf && NextBuf->size)
1085 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
1086 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
1087 memcpy(&Data[DataSize*Channels], &NextBuf->data[LoopStart*Channels], ulExtraSamples);
1090 else
1091 memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes));
1093 /* Compute the gain steps for each output channel */
1094 for(i = 0;i < OUTPUTCHANNELS;i++)
1095 dryGainStep[i] = (ALSource->Params.DryGains[i]-DrySend[i]) /
1096 rampLength;
1097 for(i = 0;i < MAX_SENDS;i++)
1098 wetGainStep[i] = (ALSource->Params.WetGains[i]-WetSend[i]) /
1099 rampLength;
1101 /* Figure out how many samples we can mix. */
1102 DataSize64 = LoopEnd;
1103 DataSize64 <<= FRACTIONBITS;
1104 DataPos64 = DataPosInt;
1105 DataPos64 <<= FRACTIONBITS;
1106 DataPos64 += DataPosFrac;
1107 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
1109 BufferSize = min(BufferSize, (SamplesToDo-j));
1111 /* Actual sample mixing loops */
1112 if(Channels == 1) /* Mono */
1114 #define DO_MIX(resampler) do { \
1115 while(BufferSize--) \
1117 for(i = 0;i < OUTPUTCHANNELS;i++) \
1118 DrySend[i] += dryGainStep[i]; \
1119 for(i = 0;i < MAX_SENDS;i++) \
1120 WetSend[i] += wetGainStep[i]; \
1122 /* First order interpolator */ \
1123 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
1124 DataPosFrac); \
1126 /* Direct path final mix buffer and panning */ \
1127 outsamp = lpFilter4P(DryFilter, 0, value); \
1128 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
1129 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
1130 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
1131 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
1132 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
1133 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
1134 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
1135 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
1137 /* Room path final mix buffer and panning */ \
1138 for(i = 0;i < MAX_SENDS;i++) \
1140 outsamp = lpFilter2P(WetFilter[i], 0, value); \
1141 WetBuffer[i][j] += outsamp*WetSend[i]; \
1144 DataPosFrac += increment; \
1145 DataPosInt += DataPosFrac>>FRACTIONBITS; \
1146 DataPosFrac &= FRACTIONMASK; \
1147 j++; \
1149 } while(0)
1151 switch(Resampler)
1153 case POINT_RESAMPLER:
1154 DO_MIX(point); break;
1155 case LINEAR_RESAMPLER:
1156 DO_MIX(lerp); break;
1157 case COSINE_RESAMPLER:
1158 DO_MIX(cos_lerp); break;
1159 case RESAMPLER_MIN:
1160 case RESAMPLER_MAX:
1161 break;
1163 #undef DO_MIX
1165 else if(Channels == 2 && DuplicateStereo) /* Stereo */
1167 const int chans[] = {
1168 FRONT_LEFT, FRONT_RIGHT
1170 const int chans2[] = {
1171 BACK_LEFT, SIDE_LEFT, BACK_RIGHT, SIDE_RIGHT
1173 const ALfloat dupscaler = aluSqrt(1.0f/3.0f);
1175 #define DO_MIX(resampler) do { \
1176 const ALfloat scaler = 1.0f/Channels; \
1177 while(BufferSize--) \
1179 for(i = 0;i < OUTPUTCHANNELS;i++) \
1180 DrySend[i] += dryGainStep[i]; \
1181 for(i = 0;i < MAX_SENDS;i++) \
1182 WetSend[i] += wetGainStep[i]; \
1184 for(i = 0;i < Channels;i++) \
1186 value = (resampler)(Data[DataPosInt*Channels + i], \
1187 Data[(DataPosInt+1)*Channels + i], \
1188 DataPosFrac); \
1189 outsamp = lpFilter2P(DryFilter, chans[i]*2, value) * dupscaler; \
1190 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
1191 DryBuffer[j][chans2[i*2+0]] += outsamp*DrySend[chans2[i*2+0]]; \
1192 DryBuffer[j][chans2[i*2+1]] += outsamp*DrySend[chans2[i*2+1]]; \
1193 for(out = 0;out < MAX_SENDS;out++) \
1195 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
1196 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
1200 DataPosFrac += increment; \
1201 DataPosInt += DataPosFrac>>FRACTIONBITS; \
1202 DataPosFrac &= FRACTIONMASK; \
1203 j++; \
1205 } while(0)
1207 switch(Resampler)
1209 case POINT_RESAMPLER:
1210 DO_MIX(point); break;
1211 case LINEAR_RESAMPLER:
1212 DO_MIX(lerp); break;
1213 case COSINE_RESAMPLER:
1214 DO_MIX(cos_lerp); break;
1215 case RESAMPLER_MIN:
1216 case RESAMPLER_MAX:
1217 break;
1219 #undef DO_MIX
1221 else if(Channels == 2) /* Stereo */
1223 const int chans[] = {
1224 FRONT_LEFT, FRONT_RIGHT
1227 #define DO_MIX(resampler) do { \
1228 const ALfloat scaler = 1.0f/Channels; \
1229 while(BufferSize--) \
1231 for(i = 0;i < OUTPUTCHANNELS;i++) \
1232 DrySend[i] += dryGainStep[i]; \
1233 for(i = 0;i < MAX_SENDS;i++) \
1234 WetSend[i] += wetGainStep[i]; \
1236 for(i = 0;i < Channels;i++) \
1238 value = (resampler)(Data[DataPosInt*Channels + i], \
1239 Data[(DataPosInt+1)*Channels + i], \
1240 DataPosFrac); \
1241 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
1242 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
1243 for(out = 0;out < MAX_SENDS;out++) \
1245 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
1246 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
1250 DataPosFrac += increment; \
1251 DataPosInt += DataPosFrac>>FRACTIONBITS; \
1252 DataPosFrac &= FRACTIONMASK; \
1253 j++; \
1255 } while(0)
1257 switch(Resampler)
1259 case POINT_RESAMPLER:
1260 DO_MIX(point); break;
1261 case LINEAR_RESAMPLER:
1262 DO_MIX(lerp); break;
1263 case COSINE_RESAMPLER:
1264 DO_MIX(cos_lerp); break;
1265 case RESAMPLER_MIN:
1266 case RESAMPLER_MAX:
1267 break;
1270 else if(Channels == 4) /* Quad */
1272 const int chans[] = {
1273 FRONT_LEFT, FRONT_RIGHT,
1274 BACK_LEFT, BACK_RIGHT
1277 switch(Resampler)
1279 case POINT_RESAMPLER:
1280 DO_MIX(point); break;
1281 case LINEAR_RESAMPLER:
1282 DO_MIX(lerp); break;
1283 case COSINE_RESAMPLER:
1284 DO_MIX(cos_lerp); break;
1285 case RESAMPLER_MIN:
1286 case RESAMPLER_MAX:
1287 break;
1290 else if(Channels == 6) /* 5.1 */
1292 const int chans[] = {
1293 FRONT_LEFT, FRONT_RIGHT,
1294 FRONT_CENTER, LFE,
1295 BACK_LEFT, BACK_RIGHT
1298 switch(Resampler)
1300 case POINT_RESAMPLER:
1301 DO_MIX(point); break;
1302 case LINEAR_RESAMPLER:
1303 DO_MIX(lerp); break;
1304 case COSINE_RESAMPLER:
1305 DO_MIX(cos_lerp); break;
1306 case RESAMPLER_MIN:
1307 case RESAMPLER_MAX:
1308 break;
1311 else if(Channels == 7) /* 6.1 */
1313 const int chans[] = {
1314 FRONT_LEFT, FRONT_RIGHT,
1315 FRONT_CENTER, LFE,
1316 BACK_CENTER,
1317 SIDE_LEFT, SIDE_RIGHT
1320 switch(Resampler)
1322 case POINT_RESAMPLER:
1323 DO_MIX(point); break;
1324 case LINEAR_RESAMPLER:
1325 DO_MIX(lerp); break;
1326 case COSINE_RESAMPLER:
1327 DO_MIX(cos_lerp); break;
1328 case RESAMPLER_MIN:
1329 case RESAMPLER_MAX:
1330 break;
1333 else if(Channels == 8) /* 7.1 */
1335 const int chans[] = {
1336 FRONT_LEFT, FRONT_RIGHT,
1337 FRONT_CENTER, LFE,
1338 BACK_LEFT, BACK_RIGHT,
1339 SIDE_LEFT, SIDE_RIGHT
1342 switch(Resampler)
1344 case POINT_RESAMPLER:
1345 DO_MIX(point); break;
1346 case LINEAR_RESAMPLER:
1347 DO_MIX(lerp); break;
1348 case COSINE_RESAMPLER:
1349 DO_MIX(cos_lerp); break;
1350 case RESAMPLER_MIN:
1351 case RESAMPLER_MAX:
1352 break;
1354 #undef DO_MIX
1356 else /* Unknown? */
1358 for(i = 0;i < OUTPUTCHANNELS;i++)
1359 DrySend[i] += dryGainStep[i]*BufferSize;
1360 for(i = 0;i < MAX_SENDS;i++)
1361 WetSend[i] += wetGainStep[i]*BufferSize;
1362 while(BufferSize--)
1364 DataPosFrac += increment;
1365 DataPosInt += DataPosFrac>>FRACTIONBITS;
1366 DataPosFrac &= FRACTIONMASK;
1367 j++;
1371 skipmix:
1372 /* Handle looping sources */
1373 if(DataPosInt >= LoopEnd)
1375 if(BuffersPlayed < (ALSource->BuffersInQueue-1))
1377 BufferListItem = BufferListItem->next;
1378 BuffersPlayed++;
1379 DataPosInt -= DataSize;
1381 else if(Looping)
1383 BufferListItem = ALSource->queue;
1384 BuffersPlayed = 0;
1385 if(ALSource->lSourceType == AL_STATIC)
1386 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
1387 else
1388 DataPosInt -= DataSize;
1390 else
1392 State = AL_STOPPED;
1393 BufferListItem = ALSource->queue;
1394 BuffersPlayed = ALSource->BuffersInQueue;
1395 DataPosInt = 0;
1396 DataPosFrac = 0;
1399 } while(State == AL_PLAYING && j < SamplesToDo);
1401 /* Update source info */
1402 ALSource->state = State;
1403 ALSource->BuffersPlayed = BuffersPlayed;
1404 ALSource->position = DataPosInt;
1405 ALSource->position_fraction = DataPosFrac;
1406 ALSource->Buffer = BufferListItem->buffer;
1408 for(i = 0;i < OUTPUTCHANNELS;i++)
1409 ALSource->DryGains[i] = DrySend[i];
1410 for(i = 0;i < MAX_SENDS;i++)
1411 ALSource->WetGains[i] = WetSend[i];
1413 ALSource->FirstStart = AL_FALSE;
1415 if(ALSource->state == AL_PLAYING)
1416 pos++;
1417 goto next_source;
1420 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1422 float (*DryBuffer)[OUTPUTCHANNELS];
1423 ALfloat (*Matrix)[OUTPUTCHANNELS];
1424 const ALuint *ChanMap;
1425 ALuint SamplesToDo;
1426 ALeffectslot *ALEffectSlot;
1427 ALCcontext *ALContext;
1428 ALfloat samp;
1429 int fpuState;
1430 ALuint i, j, c;
1431 ALsizei e;
1433 #if defined(HAVE_FESETROUND)
1434 fpuState = fegetround();
1435 fesetround(FE_TOWARDZERO);
1436 #elif defined(HAVE__CONTROLFP)
1437 fpuState = _controlfp(0, 0);
1438 _controlfp(_RC_CHOP, _MCW_RC);
1439 #else
1440 (void)fpuState;
1441 #endif
1443 DryBuffer = device->DryBuffer;
1444 while(size > 0)
1446 /* Setup variables */
1447 SamplesToDo = min(size, BUFFERSIZE);
1449 /* Clear mixing buffer */
1450 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
1452 SuspendContext(NULL);
1453 for(c = 0;c < device->NumContexts;c++)
1455 ALContext = device->Contexts[c];
1456 SuspendContext(ALContext);
1458 MixSomeSources(ALContext, DryBuffer, SamplesToDo);
1460 /* effect slot processing */
1461 for(e = 0;e < ALContext->EffectSlotMap.size;e++)
1463 ALEffectSlot = ALContext->EffectSlotMap.array[e].value;
1464 if(ALEffectSlot->EffectState)
1465 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
1467 for(i = 0;i < SamplesToDo;i++)
1468 ALEffectSlot->WetBuffer[i] = 0.0f;
1470 ProcessContext(ALContext);
1472 device->SamplesPlayed += SamplesToDo;
1473 ProcessContext(NULL);
1475 //Post processing loop
1476 ChanMap = device->DevChannels;
1477 Matrix = device->ChannelMatrix;
1478 switch(device->Format)
1480 #define CHECK_WRITE_FORMAT(bits, type, func) \
1481 case AL_FORMAT_MONO##bits: \
1482 for(i = 0;i < SamplesToDo;i++) \
1484 samp = 0.0f; \
1485 for(c = 0;c < OUTPUTCHANNELS;c++) \
1486 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
1487 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
1488 buffer = ((type*)buffer) + 1; \
1490 break; \
1491 case AL_FORMAT_STEREO##bits: \
1492 if(device->Bs2b) \
1494 for(i = 0;i < SamplesToDo;i++) \
1496 float samples[2] = { 0.0f, 0.0f }; \
1497 for(c = 0;c < OUTPUTCHANNELS;c++) \
1499 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
1500 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
1502 bs2b_cross_feed(device->Bs2b, samples); \
1503 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
1504 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
1505 buffer = ((type*)buffer) + 2; \
1508 else \
1510 for(i = 0;i < SamplesToDo;i++) \
1512 static const Channel chans[] = { \
1513 FRONT_LEFT, FRONT_RIGHT \
1514 }; \
1515 for(j = 0;j < 2;j++) \
1517 samp = 0.0f; \
1518 for(c = 0;c < OUTPUTCHANNELS;c++) \
1519 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1520 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1522 buffer = ((type*)buffer) + 2; \
1525 break; \
1526 case AL_FORMAT_QUAD##bits: \
1527 for(i = 0;i < SamplesToDo;i++) \
1529 static const Channel chans[] = { \
1530 FRONT_LEFT, FRONT_RIGHT, \
1531 BACK_LEFT, BACK_RIGHT, \
1532 }; \
1533 for(j = 0;j < 4;j++) \
1535 samp = 0.0f; \
1536 for(c = 0;c < OUTPUTCHANNELS;c++) \
1537 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1538 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1540 buffer = ((type*)buffer) + 4; \
1542 break; \
1543 case AL_FORMAT_51CHN##bits: \
1544 for(i = 0;i < SamplesToDo;i++) \
1546 static const Channel chans[] = { \
1547 FRONT_LEFT, FRONT_RIGHT, \
1548 FRONT_CENTER, LFE, \
1549 BACK_LEFT, BACK_RIGHT, \
1550 }; \
1551 for(j = 0;j < 6;j++) \
1553 samp = 0.0f; \
1554 for(c = 0;c < OUTPUTCHANNELS;c++) \
1555 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1556 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1558 buffer = ((type*)buffer) + 6; \
1560 break; \
1561 case AL_FORMAT_61CHN##bits: \
1562 for(i = 0;i < SamplesToDo;i++) \
1564 static const Channel chans[] = { \
1565 FRONT_LEFT, FRONT_RIGHT, \
1566 FRONT_CENTER, LFE, BACK_CENTER, \
1567 SIDE_LEFT, SIDE_RIGHT, \
1568 }; \
1569 for(j = 0;j < 7;j++) \
1571 samp = 0.0f; \
1572 for(c = 0;c < OUTPUTCHANNELS;c++) \
1573 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1574 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1576 buffer = ((type*)buffer) + 7; \
1578 break; \
1579 case AL_FORMAT_71CHN##bits: \
1580 for(i = 0;i < SamplesToDo;i++) \
1582 static const Channel chans[] = { \
1583 FRONT_LEFT, FRONT_RIGHT, \
1584 FRONT_CENTER, LFE, \
1585 BACK_LEFT, BACK_RIGHT, \
1586 SIDE_LEFT, SIDE_RIGHT \
1587 }; \
1588 for(j = 0;j < 8;j++) \
1590 samp = 0.0f; \
1591 for(c = 0;c < OUTPUTCHANNELS;c++) \
1592 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1593 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1595 buffer = ((type*)buffer) + 8; \
1597 break;
1599 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
1600 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
1601 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
1602 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
1603 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
1604 #undef AL_FORMAT_STEREO32
1605 #undef AL_FORMAT_MONO32
1606 #undef CHECK_WRITE_FORMAT
1608 default:
1609 break;
1612 size -= SamplesToDo;
1615 #if defined(HAVE_FESETROUND)
1616 fesetround(fpuState);
1617 #elif defined(HAVE__CONTROLFP)
1618 _controlfp(fpuState, 0xfffff);
1619 #endif
1622 ALvoid aluHandleDisconnect(ALCdevice *device)
1624 ALuint i;
1626 SuspendContext(NULL);
1627 for(i = 0;i < device->NumContexts;i++)
1629 ALCcontext *Context = device->Contexts[i];
1630 ALsource *source;
1631 ALsizei pos;
1633 SuspendContext(Context);
1635 for(pos = 0;pos < Context->SourceMap.size;pos++)
1637 source = Context->SourceMap.array[pos].value;
1638 if(source->state == AL_PLAYING)
1640 source->state = AL_STOPPED;
1641 source->BuffersPlayed = source->BuffersInQueue;
1642 source->position = 0;
1643 source->position_fraction = 0;
1646 ProcessContext(Context);
1649 device->Connected = ALC_FALSE;
1650 ProcessContext(NULL);