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