Translate the source position separately
[openal-soft.git] / Alc / ALu.c
blob2bc5cde277f8734a52faca1b167bb39bf61de7f6
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
48 ALboolean DuplicateStereo = AL_FALSE;
51 static __inline ALfloat aluF2F(ALfloat Value)
53 return Value;
56 static __inline ALshort aluF2S(ALfloat Value)
58 ALint i;
60 if(Value < 0.0f)
62 i = (ALint)(Value*32768.0f);
63 i = max(-32768, i);
65 else
67 i = (ALint)(Value*32767.0f);
68 i = min( 32767, i);
70 return ((ALshort)i);
73 static __inline ALubyte aluF2UB(ALfloat Value)
75 ALshort i = aluF2S(Value);
76 return (i>>8)+128;
80 static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
82 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
83 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
84 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
87 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
89 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
90 inVector1[2]*inVector2[2];
93 static __inline ALvoid aluNormalize(ALfloat *inVector)
95 ALfloat length, inverse_length;
97 length = aluSqrt(aluDotproduct(inVector, inVector));
98 if(length != 0.0f)
100 inverse_length = 1.0f/length;
101 inVector[0] *= inverse_length;
102 inVector[1] *= inverse_length;
103 inVector[2] *= inverse_length;
107 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
109 ALfloat temp[4] = {
110 vector[0], vector[1], vector[2], w
113 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
114 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
115 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
118 static ALvoid SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[OUTPUTCHANNELS],
119 Channel Speaker2Chan[OUTPUTCHANNELS], ALint chans)
121 char layout_str[256];
122 char *confkey, *next;
123 char *sep, *end;
124 Channel val;
125 int i;
127 strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
128 layout_str[255] = 0;
130 if(!layout_str[0])
131 return;
133 next = confkey = layout_str;
134 while(next && *next)
136 confkey = next;
137 next = strchr(confkey, ',');
138 if(next)
140 *next = 0;
141 do {
142 next++;
143 } while(isspace(*next) || *next == ',');
146 sep = strchr(confkey, '=');
147 if(!sep || confkey == sep)
148 continue;
150 end = sep - 1;
151 while(isspace(*end) && end != confkey)
152 end--;
153 *(++end) = 0;
155 if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
156 val = FRONT_LEFT;
157 else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
158 val = FRONT_RIGHT;
159 else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
160 val = FRONT_CENTER;
161 else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
162 val = BACK_LEFT;
163 else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
164 val = BACK_RIGHT;
165 else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
166 val = BACK_CENTER;
167 else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
168 val = SIDE_LEFT;
169 else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
170 val = SIDE_RIGHT;
171 else
173 AL_PRINT("Unknown speaker for %s: \"%s\"\n", name, confkey);
174 continue;
177 *(sep++) = 0;
178 while(isspace(*sep))
179 sep++;
181 for(i = 0;i < chans;i++)
183 if(Speaker2Chan[i] == val)
185 long angle = strtol(sep, NULL, 10);
186 if(angle >= -180 && angle <= 180)
187 SpeakerAngle[i] = angle * M_PI/180.0f;
188 else
189 AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
190 break;
195 for(i = 0;i < chans;i++)
197 int min = i;
198 int i2;
200 for(i2 = i+1;i2 < chans;i2++)
202 if(SpeakerAngle[i2] < SpeakerAngle[min])
203 min = i2;
206 if(min != i)
208 ALfloat tmpf;
209 Channel tmpc;
211 tmpf = SpeakerAngle[i];
212 SpeakerAngle[i] = SpeakerAngle[min];
213 SpeakerAngle[min] = tmpf;
215 tmpc = Speaker2Chan[i];
216 Speaker2Chan[i] = Speaker2Chan[min];
217 Speaker2Chan[min] = tmpc;
222 static __inline ALfloat aluLUTpos2Angle(ALint pos)
224 if(pos < QUADRANT_NUM)
225 return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
226 if(pos < 2 * QUADRANT_NUM)
227 return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
228 if(pos < 3 * QUADRANT_NUM)
229 return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
230 return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
233 ALvoid aluInitPanning(ALCdevice *Device)
235 ALfloat SpeakerAngle[OUTPUTCHANNELS];
236 Channel Speaker2Chan[OUTPUTCHANNELS];
237 ALfloat Alpha, Theta;
238 ALint pos, offset;
239 ALfloat maxout;
240 ALuint s, s2;
242 for(s = 0;s < OUTPUTCHANNELS;s++)
244 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
245 Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
248 switch(Device->Format)
250 case AL_FORMAT_MONO8:
251 case AL_FORMAT_MONO16:
252 case AL_FORMAT_MONO_FLOAT32:
253 Device->ChannelMatrix[FRONT_LEFT][FRONT_CENTER] = aluSqrt(0.5);
254 Device->ChannelMatrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
255 Device->ChannelMatrix[SIDE_LEFT][FRONT_CENTER] = aluSqrt(0.5);
256 Device->ChannelMatrix[SIDE_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
257 Device->ChannelMatrix[BACK_LEFT][FRONT_CENTER] = aluSqrt(0.5);
258 Device->ChannelMatrix[BACK_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
259 Device->ChannelMatrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
260 Device->NumChan = 1;
261 Speaker2Chan[0] = FRONT_CENTER;
262 SpeakerAngle[0] = 0.0f * M_PI/180.0f;
263 break;
265 case AL_FORMAT_STEREO8:
266 case AL_FORMAT_STEREO16:
267 case AL_FORMAT_STEREO_FLOAT32:
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->ChannelMatrix[FRONT_CENTER][FRONT_LEFT] = aluSqrt(0.5);
288 Device->ChannelMatrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
289 Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
290 Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
291 Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
292 Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
293 Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
294 Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
295 Device->NumChan = 4;
296 Speaker2Chan[0] = BACK_LEFT;
297 Speaker2Chan[1] = FRONT_LEFT;
298 Speaker2Chan[2] = FRONT_RIGHT;
299 Speaker2Chan[3] = BACK_RIGHT;
300 SpeakerAngle[0] = -135.0f * M_PI/180.0f;
301 SpeakerAngle[1] = -45.0f * M_PI/180.0f;
302 SpeakerAngle[2] = 45.0f * M_PI/180.0f;
303 SpeakerAngle[3] = 135.0f * M_PI/180.0f;
304 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
305 break;
307 case AL_FORMAT_51CHN8:
308 case AL_FORMAT_51CHN16:
309 case AL_FORMAT_51CHN32:
310 Device->ChannelMatrix[SIDE_LEFT][FRONT_LEFT] = aluSqrt(0.5);
311 Device->ChannelMatrix[SIDE_LEFT][BACK_LEFT] = aluSqrt(0.5);
312 Device->ChannelMatrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
313 Device->ChannelMatrix[SIDE_RIGHT][BACK_RIGHT] = aluSqrt(0.5);
314 Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
315 Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
316 Device->NumChan = 5;
317 Speaker2Chan[0] = BACK_LEFT;
318 Speaker2Chan[1] = FRONT_LEFT;
319 Speaker2Chan[2] = FRONT_CENTER;
320 Speaker2Chan[3] = FRONT_RIGHT;
321 Speaker2Chan[4] = BACK_RIGHT;
322 SpeakerAngle[0] = -110.0f * M_PI/180.0f;
323 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
324 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
325 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
326 SpeakerAngle[4] = 110.0f * M_PI/180.0f;
327 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
328 break;
330 case AL_FORMAT_61CHN8:
331 case AL_FORMAT_61CHN16:
332 case AL_FORMAT_61CHN32:
333 Device->ChannelMatrix[BACK_LEFT][BACK_CENTER] = aluSqrt(0.5);
334 Device->ChannelMatrix[BACK_LEFT][SIDE_LEFT] = aluSqrt(0.5);
335 Device->ChannelMatrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
336 Device->ChannelMatrix[BACK_RIGHT][SIDE_RIGHT] = aluSqrt(0.5);
337 Device->NumChan = 6;
338 Speaker2Chan[0] = SIDE_LEFT;
339 Speaker2Chan[1] = FRONT_LEFT;
340 Speaker2Chan[2] = FRONT_CENTER;
341 Speaker2Chan[3] = FRONT_RIGHT;
342 Speaker2Chan[4] = SIDE_RIGHT;
343 Speaker2Chan[5] = BACK_CENTER;
344 SpeakerAngle[0] = -90.0f * M_PI/180.0f;
345 SpeakerAngle[1] = -30.0f * M_PI/180.0f;
346 SpeakerAngle[2] = 0.0f * M_PI/180.0f;
347 SpeakerAngle[3] = 30.0f * M_PI/180.0f;
348 SpeakerAngle[4] = 90.0f * M_PI/180.0f;
349 SpeakerAngle[5] = 180.0f * M_PI/180.0f;
350 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
351 break;
353 case AL_FORMAT_71CHN8:
354 case AL_FORMAT_71CHN16:
355 case AL_FORMAT_71CHN32:
356 Device->ChannelMatrix[BACK_CENTER][BACK_LEFT] = aluSqrt(0.5);
357 Device->ChannelMatrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
358 Device->NumChan = 7;
359 Speaker2Chan[0] = BACK_LEFT;
360 Speaker2Chan[1] = SIDE_LEFT;
361 Speaker2Chan[2] = FRONT_LEFT;
362 Speaker2Chan[3] = FRONT_CENTER;
363 Speaker2Chan[4] = FRONT_RIGHT;
364 Speaker2Chan[5] = SIDE_RIGHT;
365 Speaker2Chan[6] = BACK_RIGHT;
366 SpeakerAngle[0] = -150.0f * M_PI/180.0f;
367 SpeakerAngle[1] = -90.0f * M_PI/180.0f;
368 SpeakerAngle[2] = -30.0f * M_PI/180.0f;
369 SpeakerAngle[3] = 0.0f * M_PI/180.0f;
370 SpeakerAngle[4] = 30.0f * M_PI/180.0f;
371 SpeakerAngle[5] = 90.0f * M_PI/180.0f;
372 SpeakerAngle[6] = 150.0f * M_PI/180.0f;
373 SetSpeakerArrangement("layout", SpeakerAngle, Speaker2Chan, Device->NumChan);
374 break;
376 default:
377 assert(0);
380 maxout = 1.0f;
381 for(s = 0;s < OUTPUTCHANNELS;s++)
383 ALfloat out = 0.0f;
384 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
385 out += Device->ChannelMatrix[s2][s];
386 maxout = __max(maxout, out);
389 maxout = 1.0f/maxout;
390 for(s = 0;s < OUTPUTCHANNELS;s++)
392 for(s2 = 0;s2 < OUTPUTCHANNELS;s2++)
393 Device->ChannelMatrix[s2][s] *= maxout;
397 for(pos = 0; pos < LUT_NUM; pos++)
399 /* clear all values */
400 offset = OUTPUTCHANNELS * pos;
401 for(s = 0; s < OUTPUTCHANNELS; s++)
402 Device->PanningLUT[offset+s] = 0.0f;
404 if(Device->NumChan == 1)
406 Device->PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
407 continue;
410 /* source angle */
411 Theta = aluLUTpos2Angle(pos);
413 /* set panning values */
414 for(s = 0; s < Device->NumChan - 1; s++)
416 if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
418 /* source between speaker s and speaker s+1 */
419 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
420 (SpeakerAngle[s+1]-SpeakerAngle[s]);
421 Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
422 Device->PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
423 break;
426 if(s == Device->NumChan - 1)
428 /* source between last and first speaker */
429 if(Theta < SpeakerAngle[0])
430 Theta += 2.0f * M_PI;
431 Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
432 (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
433 Device->PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
434 Device->PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
439 static ALvoid CalcNonAttnSourceParams(const ALCcontext *ALContext, ALsource *ALSource)
441 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
442 ALfloat DryGain, DryGainHF;
443 ALfloat WetGain[MAX_SENDS];
444 ALfloat WetGainHF[MAX_SENDS];
445 ALint NumSends, Frequency;
446 ALfloat cw;
447 ALint i;
449 //Get context properties
450 NumSends = ALContext->Device->NumAuxSends;
451 Frequency = ALContext->Device->Frequency;
453 //Get listener properties
454 ListenerGain = ALContext->Listener.Gain;
456 //Get source properties
457 SourceVolume = ALSource->flGain;
458 MinVolume = ALSource->flMinGain;
459 MaxVolume = ALSource->flMaxGain;
461 //1. Multi-channel buffers always play "normal"
462 ALSource->Params.Pitch = ALSource->flPitch;
464 DryGain = SourceVolume;
465 DryGain = __min(DryGain,MaxVolume);
466 DryGain = __max(DryGain,MinVolume);
467 DryGainHF = 1.0f;
469 switch(ALSource->DirectFilter.type)
471 case AL_FILTER_LOWPASS:
472 DryGain *= ALSource->DirectFilter.Gain;
473 DryGainHF *= ALSource->DirectFilter.GainHF;
474 break;
477 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
478 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
479 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
480 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
481 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
482 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
483 ALSource->Params.DryGains[FRONT_CENTER] = DryGain * ListenerGain;
484 ALSource->Params.DryGains[BACK_CENTER] = DryGain * ListenerGain;
485 ALSource->Params.DryGains[LFE] = DryGain * ListenerGain;
487 for(i = 0;i < NumSends;i++)
489 WetGain[i] = SourceVolume;
490 WetGain[i] = __min(WetGain[i],MaxVolume);
491 WetGain[i] = __max(WetGain[i],MinVolume);
492 WetGainHF[i] = 1.0f;
494 switch(ALSource->Send[i].WetFilter.type)
496 case AL_FILTER_LOWPASS:
497 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
498 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
499 break;
502 ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
504 for(i = NumSends;i < MAX_SENDS;i++)
506 ALSource->Params.WetGains[i] = 0.0f;
507 WetGainHF[i] = 1.0f;
510 /* Update filter coefficients. Calculations based on the I3DL2
511 * spec. */
512 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
514 /* We use two chained one-pole filters, so we need to take the
515 * square root of the squared gain, which is the same as the base
516 * gain. */
517 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
519 for(i = 0;i < NumSends;i++)
521 /* We use a one-pole filter, so we need to take the squared gain */
522 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
523 ALSource->Params.Send[i].iirFilter.coeff = a;
527 static ALvoid CalcSourceParams(const ALCcontext *ALContext, ALsource *ALSource)
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 ALfloat length;
545 const ALfloat *SpeakerGain;
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 = ALContext->Device->NumAuxSends;
559 Frequency = ALContext->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 - (ALContext->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 = &ALContext->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(ALContext->Device->NumChan) * (1.0-DirGain);
873 for(s = 0; s < OUTPUTCHANNELS; s++)
875 ALfloat gain = SpeakerGain[s]*DirGain + AmbientGain;
876 ALSource->Params.DryGains[s] = DryMix * gain;
879 /* Update filter coefficients. */
880 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
882 /* Spatialized sources use four chained one-pole filters, so we need to
883 * take the fourth root of the squared gain, which is the same as the
884 * square root of the base gain. */
885 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
887 for(i = 0;i < NumSends;i++)
889 /* The wet path uses two chained one-pole filters, so take the
890 * base gain (square root of the squared gain) */
891 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
895 static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac)
897 return val1;
898 (void)val2;
899 (void)frac;
901 static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac)
903 return val1 + ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
905 static __inline ALfloat cos_lerp(ALfloat val1, ALfloat val2, ALint frac)
907 ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
908 return val1 + ((val2-val1)*mult);
911 static void MixSomeSources(ALCcontext *ALContext, float (*DryBuffer)[OUTPUTCHANNELS], ALuint SamplesToDo)
913 static float DummyBuffer[BUFFERSIZE];
914 ALfloat *WetBuffer[MAX_SENDS];
915 ALfloat DrySend[OUTPUTCHANNELS];
916 ALfloat dryGainStep[OUTPUTCHANNELS];
917 ALfloat wetGainStep[MAX_SENDS];
918 ALuint i, j, k, out;
919 ALsource *ALSource;
920 ALfloat value, outsamp;
921 ALbufferlistitem *BufferListItem;
922 ALint64 DataSize64,DataPos64;
923 FILTER *DryFilter, *WetFilter[MAX_SENDS];
924 ALfloat WetSend[MAX_SENDS];
925 ALuint rampLength;
926 ALuint DeviceFreq;
927 ALint increment;
928 ALuint DataPosInt, DataPosFrac;
929 ALuint Channels, Bytes;
930 ALuint Frequency;
931 resampler_t Resampler;
932 ALuint BuffersPlayed;
933 ALfloat Pitch;
934 ALenum State;
936 if(!(ALSource=ALContext->SourceList))
937 return;
939 DeviceFreq = ALContext->Device->Frequency;
941 rampLength = DeviceFreq * MIN_RAMP_LENGTH / 1000;
942 rampLength = max(rampLength, SamplesToDo);
944 another_source:
945 if(ALSource->state != AL_PLAYING)
947 if((ALSource=ALSource->next) != NULL)
948 goto another_source;
949 return;
951 j = 0;
953 /* Find buffer format */
954 Frequency = 0;
955 Channels = 0;
956 Bytes = 0;
957 BufferListItem = ALSource->queue;
958 while(BufferListItem != NULL)
960 ALbuffer *ALBuffer;
961 if((ALBuffer=BufferListItem->buffer) != NULL)
963 Channels = aluChannelsFromFormat(ALBuffer->format);
964 Bytes = aluBytesFromFormat(ALBuffer->format);
965 Frequency = ALBuffer->frequency;
966 break;
968 BufferListItem = BufferListItem->next;
971 if(ALSource->NeedsUpdate)
973 //Only apply 3D calculations for mono buffers
974 if(Channels == 1)
975 CalcSourceParams(ALContext, ALSource);
976 else
977 CalcNonAttnSourceParams(ALContext, ALSource);
978 ALSource->NeedsUpdate = AL_FALSE;
981 /* Get source info */
982 Resampler = ALSource->Resampler;
983 State = ALSource->state;
984 BuffersPlayed = ALSource->BuffersPlayed;
985 DataPosInt = ALSource->position;
986 DataPosFrac = ALSource->position_fraction;
988 /* Compute 18.14 fixed point step */
989 Pitch = (ALSource->Params.Pitch*Frequency) / DeviceFreq;
990 if(Pitch > (float)MAX_PITCH) Pitch = (float)MAX_PITCH;
991 increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
992 if(increment <= 0) increment = (1<<FRACTIONBITS);
994 if(ALSource->FirstStart)
996 for(i = 0;i < OUTPUTCHANNELS;i++)
997 DrySend[i] = ALSource->Params.DryGains[i];
998 for(i = 0;i < MAX_SENDS;i++)
999 WetSend[i] = ALSource->Params.WetGains[i];
1001 else
1003 for(i = 0;i < OUTPUTCHANNELS;i++)
1004 DrySend[i] = ALSource->DryGains[i];
1005 for(i = 0;i < MAX_SENDS;i++)
1006 WetSend[i] = ALSource->WetGains[i];
1009 DryFilter = &ALSource->Params.iirFilter;
1010 for(i = 0;i < MAX_SENDS;i++)
1012 WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
1013 WetBuffer[i] = (ALSource->Send[i].Slot ?
1014 ALSource->Send[i].Slot->WetBuffer :
1015 DummyBuffer);
1018 /* Get current buffer queue item */
1019 BufferListItem = ALSource->queue;
1020 for(i = 0;i < BuffersPlayed && BufferListItem;i++)
1021 BufferListItem = BufferListItem->next;
1023 while(State == AL_PLAYING && j < SamplesToDo)
1025 ALuint DataSize = 0;
1026 ALbuffer *ALBuffer;
1027 ALfloat *Data;
1028 ALuint BufferSize;
1030 /* Get buffer info */
1031 if((ALBuffer=BufferListItem->buffer) != NULL)
1033 Data = ALBuffer->data;
1034 DataSize = ALBuffer->size;
1035 DataSize /= Channels * Bytes;
1037 if(DataPosInt >= DataSize)
1038 goto skipmix;
1040 if(BufferListItem->next)
1042 ALbuffer *NextBuf = BufferListItem->next->buffer;
1043 if(NextBuf && NextBuf->size)
1045 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
1046 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
1047 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
1050 else if(ALSource->bLooping)
1052 ALbuffer *NextBuf = ALSource->queue->buffer;
1053 if(NextBuf && NextBuf->size)
1055 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
1056 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
1057 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
1060 else
1061 memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes));
1063 /* Compute the gain steps for each output channel */
1064 for(i = 0;i < OUTPUTCHANNELS;i++)
1065 dryGainStep[i] = (ALSource->Params.DryGains[i]-DrySend[i]) /
1066 rampLength;
1067 for(i = 0;i < MAX_SENDS;i++)
1068 wetGainStep[i] = (ALSource->Params.WetGains[i]-WetSend[i]) /
1069 rampLength;
1071 /* Figure out how many samples we can mix. */
1072 DataSize64 = DataSize;
1073 DataSize64 <<= FRACTIONBITS;
1074 DataPos64 = DataPosInt;
1075 DataPos64 <<= FRACTIONBITS;
1076 DataPos64 += DataPosFrac;
1077 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
1079 BufferSize = min(BufferSize, (SamplesToDo-j));
1081 /* Actual sample mixing loop */
1082 k = 0;
1083 Data += DataPosInt*Channels;
1085 if(Channels == 1) /* Mono */
1087 #define DO_MIX(resampler) do { \
1088 while(BufferSize--) \
1090 for(i = 0;i < OUTPUTCHANNELS;i++) \
1091 DrySend[i] += dryGainStep[i]; \
1092 for(i = 0;i < MAX_SENDS;i++) \
1093 WetSend[i] += wetGainStep[i]; \
1095 /* First order interpolator */ \
1096 value = (resampler)(Data[k], Data[k+1], DataPosFrac); \
1098 /* Direct path final mix buffer and panning */ \
1099 outsamp = lpFilter4P(DryFilter, 0, value); \
1100 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
1101 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
1102 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
1103 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
1104 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
1105 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
1106 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
1107 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
1109 /* Room path final mix buffer and panning */ \
1110 for(i = 0;i < MAX_SENDS;i++) \
1112 outsamp = lpFilter2P(WetFilter[i], 0, value); \
1113 WetBuffer[i][j] += outsamp*WetSend[i]; \
1116 DataPosFrac += increment; \
1117 k += DataPosFrac>>FRACTIONBITS; \
1118 DataPosFrac &= FRACTIONMASK; \
1119 j++; \
1121 } while(0)
1123 switch(Resampler)
1125 case POINT_RESAMPLER:
1126 DO_MIX(point); break;
1127 case LINEAR_RESAMPLER:
1128 DO_MIX(lerp); break;
1129 case COSINE_RESAMPLER:
1130 DO_MIX(cos_lerp); break;
1131 case RESAMPLER_MIN:
1132 case RESAMPLER_MAX:
1133 break;
1135 #undef DO_MIX
1137 else if(Channels == 2 && DuplicateStereo) /* Stereo */
1139 const int chans[] = {
1140 FRONT_LEFT, FRONT_RIGHT
1142 const int chans2[] = {
1143 BACK_LEFT, SIDE_LEFT, BACK_RIGHT, SIDE_RIGHT
1145 const ALfloat scaler = 1.0f/Channels;
1146 const ALfloat dupscaler = aluSqrt(1.0f/3.0f);
1148 #define DO_MIX(resampler) do { \
1149 while(BufferSize--) \
1151 for(i = 0;i < OUTPUTCHANNELS;i++) \
1152 DrySend[i] += dryGainStep[i]; \
1153 for(i = 0;i < MAX_SENDS;i++) \
1154 WetSend[i] += wetGainStep[i]; \
1156 for(i = 0;i < Channels;i++) \
1158 value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\
1159 DataPosFrac); \
1160 outsamp = lpFilter2P(DryFilter, chans[i]*2, value) * dupscaler; \
1161 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
1162 DryBuffer[j][chans2[i*2+0]] += outsamp*DrySend[chans2[i*2+0]]; \
1163 DryBuffer[j][chans2[i*2+1]] += outsamp*DrySend[chans2[i*2+1]]; \
1164 for(out = 0;out < MAX_SENDS;out++) \
1166 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
1167 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
1171 DataPosFrac += increment; \
1172 k += DataPosFrac>>FRACTIONBITS; \
1173 DataPosFrac &= FRACTIONMASK; \
1174 j++; \
1176 } while(0)
1178 switch(Resampler)
1180 case POINT_RESAMPLER:
1181 DO_MIX(point); break;
1182 case LINEAR_RESAMPLER:
1183 DO_MIX(lerp); break;
1184 case COSINE_RESAMPLER:
1185 DO_MIX(cos_lerp); break;
1186 case RESAMPLER_MIN:
1187 case RESAMPLER_MAX:
1188 break;
1190 #undef DO_MIX
1192 else if(Channels == 2) /* Stereo */
1194 const int chans[] = {
1195 FRONT_LEFT, FRONT_RIGHT
1197 const ALfloat scaler = 1.0f/Channels;
1199 #define DO_MIX(resampler) do { \
1200 while(BufferSize--) \
1202 for(i = 0;i < OUTPUTCHANNELS;i++) \
1203 DrySend[i] += dryGainStep[i]; \
1204 for(i = 0;i < MAX_SENDS;i++) \
1205 WetSend[i] += wetGainStep[i]; \
1207 for(i = 0;i < Channels;i++) \
1209 value = (resampler)(Data[k*Channels + i],Data[(k+1)*Channels + i],\
1210 DataPosFrac); \
1211 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
1212 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
1213 for(out = 0;out < MAX_SENDS;out++) \
1215 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
1216 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
1220 DataPosFrac += increment; \
1221 k += DataPosFrac>>FRACTIONBITS; \
1222 DataPosFrac &= FRACTIONMASK; \
1223 j++; \
1225 } while(0)
1227 switch(Resampler)
1229 case POINT_RESAMPLER:
1230 DO_MIX(point); break;
1231 case LINEAR_RESAMPLER:
1232 DO_MIX(lerp); break;
1233 case COSINE_RESAMPLER:
1234 DO_MIX(cos_lerp); break;
1235 case RESAMPLER_MIN:
1236 case RESAMPLER_MAX:
1237 break;
1240 else if(Channels == 4) /* Quad */
1242 const int chans[] = {
1243 FRONT_LEFT, FRONT_RIGHT,
1244 BACK_LEFT, BACK_RIGHT
1246 const ALfloat scaler = 1.0f/Channels;
1248 switch(Resampler)
1250 case POINT_RESAMPLER:
1251 DO_MIX(point); break;
1252 case LINEAR_RESAMPLER:
1253 DO_MIX(lerp); break;
1254 case COSINE_RESAMPLER:
1255 DO_MIX(cos_lerp); break;
1256 case RESAMPLER_MIN:
1257 case RESAMPLER_MAX:
1258 break;
1261 else if(Channels == 6) /* 5.1 */
1263 const int chans[] = {
1264 FRONT_LEFT, FRONT_RIGHT,
1265 FRONT_CENTER, LFE,
1266 BACK_LEFT, BACK_RIGHT
1268 const ALfloat scaler = 1.0f/Channels;
1270 switch(Resampler)
1272 case POINT_RESAMPLER:
1273 DO_MIX(point); break;
1274 case LINEAR_RESAMPLER:
1275 DO_MIX(lerp); break;
1276 case COSINE_RESAMPLER:
1277 DO_MIX(cos_lerp); break;
1278 case RESAMPLER_MIN:
1279 case RESAMPLER_MAX:
1280 break;
1283 else if(Channels == 7) /* 6.1 */
1285 const int chans[] = {
1286 FRONT_LEFT, FRONT_RIGHT,
1287 FRONT_CENTER, LFE,
1288 BACK_CENTER,
1289 SIDE_LEFT, SIDE_RIGHT
1291 const ALfloat scaler = 1.0f/Channels;
1293 switch(Resampler)
1295 case POINT_RESAMPLER:
1296 DO_MIX(point); break;
1297 case LINEAR_RESAMPLER:
1298 DO_MIX(lerp); break;
1299 case COSINE_RESAMPLER:
1300 DO_MIX(cos_lerp); break;
1301 case RESAMPLER_MIN:
1302 case RESAMPLER_MAX:
1303 break;
1306 else if(Channels == 8) /* 7.1 */
1308 const int chans[] = {
1309 FRONT_LEFT, FRONT_RIGHT,
1310 FRONT_CENTER, LFE,
1311 BACK_LEFT, BACK_RIGHT,
1312 SIDE_LEFT, SIDE_RIGHT
1314 const ALfloat scaler = 1.0f/Channels;
1316 switch(Resampler)
1318 case POINT_RESAMPLER:
1319 DO_MIX(point); break;
1320 case LINEAR_RESAMPLER:
1321 DO_MIX(lerp); break;
1322 case COSINE_RESAMPLER:
1323 DO_MIX(cos_lerp); break;
1324 case RESAMPLER_MIN:
1325 case RESAMPLER_MAX:
1326 break;
1328 #undef DO_MIX
1330 else /* Unknown? */
1332 for(i = 0;i < OUTPUTCHANNELS;i++)
1333 DrySend[i] += dryGainStep[i]*BufferSize;
1334 for(i = 0;i < MAX_SENDS;i++)
1335 WetSend[i] += wetGainStep[i]*BufferSize;
1336 while(BufferSize--)
1338 DataPosFrac += increment;
1339 k += DataPosFrac>>FRACTIONBITS;
1340 DataPosFrac &= FRACTIONMASK;
1341 j++;
1344 DataPosInt += k;
1346 skipmix:
1347 /* Handle looping sources */
1348 if(DataPosInt >= DataSize)
1350 if(BuffersPlayed < (ALSource->BuffersInQueue-1))
1352 BufferListItem = BufferListItem->next;
1353 BuffersPlayed++;
1354 DataPosInt -= DataSize;
1356 else if(ALSource->bLooping)
1358 BufferListItem = ALSource->queue;
1359 BuffersPlayed = 0;
1360 if(ALSource->BuffersInQueue == 1)
1361 DataPosInt %= DataSize;
1362 else
1363 DataPosInt -= DataSize;
1365 else
1367 State = AL_STOPPED;
1368 BufferListItem = ALSource->queue;
1369 BuffersPlayed = ALSource->BuffersInQueue;
1370 DataPosInt = 0;
1371 DataPosFrac = 0;
1376 /* Update source info */
1377 ALSource->state = State;
1378 ALSource->BuffersPlayed = BuffersPlayed;
1379 ALSource->position = DataPosInt;
1380 ALSource->position_fraction = DataPosFrac;
1381 ALSource->Buffer = BufferListItem->buffer;
1383 for(i = 0;i < OUTPUTCHANNELS;i++)
1384 ALSource->DryGains[i] = DrySend[i];
1385 for(i = 0;i < MAX_SENDS;i++)
1386 ALSource->WetGains[i] = WetSend[i];
1388 ALSource->FirstStart = AL_FALSE;
1390 if((ALSource=ALSource->next) != NULL)
1391 goto another_source;
1394 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1396 float (*DryBuffer)[OUTPUTCHANNELS];
1397 ALfloat (*Matrix)[OUTPUTCHANNELS];
1398 const ALuint *ChanMap;
1399 ALuint SamplesToDo;
1400 ALeffectslot *ALEffectSlot;
1401 ALCcontext *ALContext;
1402 ALfloat samp;
1403 int fpuState;
1404 ALuint i, j, c;
1406 #if defined(HAVE_FESETROUND)
1407 fpuState = fegetround();
1408 fesetround(FE_TOWARDZERO);
1409 #elif defined(HAVE__CONTROLFP)
1410 fpuState = _controlfp(0, 0);
1411 _controlfp(_RC_CHOP, _MCW_RC);
1412 #else
1413 (void)fpuState;
1414 #endif
1416 DryBuffer = device->DryBuffer;
1417 while(size > 0)
1419 /* Setup variables */
1420 SamplesToDo = min(size, BUFFERSIZE);
1422 /* Clear mixing buffer */
1423 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
1425 SuspendContext(NULL);
1426 for(c = 0;c < device->NumContexts;c++)
1428 ALContext = device->Contexts[c];
1429 SuspendContext(ALContext);
1431 MixSomeSources(ALContext, DryBuffer, SamplesToDo);
1433 /* effect slot processing */
1434 ALEffectSlot = ALContext->EffectSlotList;
1435 while(ALEffectSlot)
1437 if(ALEffectSlot->EffectState)
1438 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
1440 for(i = 0;i < SamplesToDo;i++)
1441 ALEffectSlot->WetBuffer[i] = 0.0f;
1442 ALEffectSlot = ALEffectSlot->next;
1444 ProcessContext(ALContext);
1446 ProcessContext(NULL);
1448 //Post processing loop
1449 ChanMap = device->DevChannels;
1450 Matrix = device->ChannelMatrix;
1451 switch(device->Format)
1453 #define CHECK_WRITE_FORMAT(bits, type, func) \
1454 case AL_FORMAT_MONO##bits: \
1455 for(i = 0;i < SamplesToDo;i++) \
1457 samp = 0.0f; \
1458 for(c = 0;c < OUTPUTCHANNELS;c++) \
1459 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
1460 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
1461 buffer = ((type*)buffer) + 1; \
1463 break; \
1464 case AL_FORMAT_STEREO##bits: \
1465 if(device->Bs2b) \
1467 for(i = 0;i < SamplesToDo;i++) \
1469 float samples[2] = { 0.0f, 0.0f }; \
1470 for(c = 0;c < OUTPUTCHANNELS;c++) \
1472 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
1473 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
1475 bs2b_cross_feed(device->Bs2b, samples); \
1476 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
1477 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
1478 buffer = ((type*)buffer) + 2; \
1481 else \
1483 for(i = 0;i < SamplesToDo;i++) \
1485 static const Channel chans[] = { \
1486 FRONT_LEFT, FRONT_RIGHT \
1487 }; \
1488 for(j = 0;j < 2;j++) \
1490 samp = 0.0f; \
1491 for(c = 0;c < OUTPUTCHANNELS;c++) \
1492 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1493 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1495 buffer = ((type*)buffer) + 2; \
1498 break; \
1499 case AL_FORMAT_QUAD##bits: \
1500 for(i = 0;i < SamplesToDo;i++) \
1502 static const Channel chans[] = { \
1503 FRONT_LEFT, FRONT_RIGHT, \
1504 BACK_LEFT, BACK_RIGHT, \
1505 }; \
1506 for(j = 0;j < 4;j++) \
1508 samp = 0.0f; \
1509 for(c = 0;c < OUTPUTCHANNELS;c++) \
1510 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1511 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1513 buffer = ((type*)buffer) + 4; \
1515 break; \
1516 case AL_FORMAT_51CHN##bits: \
1517 for(i = 0;i < SamplesToDo;i++) \
1519 static const Channel chans[] = { \
1520 FRONT_LEFT, FRONT_RIGHT, \
1521 FRONT_CENTER, LFE, \
1522 BACK_LEFT, BACK_RIGHT, \
1523 }; \
1524 for(j = 0;j < 6;j++) \
1526 samp = 0.0f; \
1527 for(c = 0;c < OUTPUTCHANNELS;c++) \
1528 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1529 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1531 buffer = ((type*)buffer) + 6; \
1533 break; \
1534 case AL_FORMAT_61CHN##bits: \
1535 for(i = 0;i < SamplesToDo;i++) \
1537 static const Channel chans[] = { \
1538 FRONT_LEFT, FRONT_RIGHT, \
1539 FRONT_CENTER, LFE, BACK_CENTER, \
1540 SIDE_LEFT, SIDE_RIGHT, \
1541 }; \
1542 for(j = 0;j < 7;j++) \
1544 samp = 0.0f; \
1545 for(c = 0;c < OUTPUTCHANNELS;c++) \
1546 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1547 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1549 buffer = ((type*)buffer) + 7; \
1551 break; \
1552 case AL_FORMAT_71CHN##bits: \
1553 for(i = 0;i < SamplesToDo;i++) \
1555 static const Channel chans[] = { \
1556 FRONT_LEFT, FRONT_RIGHT, \
1557 FRONT_CENTER, LFE, \
1558 BACK_LEFT, BACK_RIGHT, \
1559 SIDE_LEFT, SIDE_RIGHT \
1560 }; \
1561 for(j = 0;j < 8;j++) \
1563 samp = 0.0f; \
1564 for(c = 0;c < OUTPUTCHANNELS;c++) \
1565 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
1566 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
1568 buffer = ((type*)buffer) + 8; \
1570 break;
1572 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
1573 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
1574 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
1575 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
1576 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
1577 #undef AL_FORMAT_STEREO32
1578 #undef AL_FORMAT_MONO32
1579 #undef CHECK_WRITE_FORMAT
1581 default:
1582 break;
1585 size -= SamplesToDo;
1588 #if defined(HAVE_FESETROUND)
1589 fesetround(fpuState);
1590 #elif defined(HAVE__CONTROLFP)
1591 _controlfp(fpuState, 0xfffff);
1592 #endif
1595 ALvoid aluHandleDisconnect(ALCdevice *device)
1597 ALuint i;
1599 SuspendContext(NULL);
1600 for(i = 0;i < device->NumContexts;i++)
1602 ALsource *source;
1604 SuspendContext(device->Contexts[i]);
1606 source = device->Contexts[i]->SourceList;
1607 while(source)
1609 if(source->state == AL_PLAYING)
1611 source->state = AL_STOPPED;
1612 source->BuffersPlayed = source->BuffersInQueue;
1613 source->position = 0;
1614 source->position_fraction = 0;
1616 source = source->next;
1618 ProcessContext(device->Contexts[i]);
1621 device->Connected = ALC_FALSE;
1622 ProcessContext(NULL);