Mercurial > audio-send
view Alc/ALu.c @ 22:616215c81d23
added footnote
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Thu, 03 Nov 2011 15:14:44 -0700 |
parents | f9476ff7637e |
children |
line wrap: on
line source
1 /**2 * OpenAL cross platform audio library3 * Copyright (C) 1999-2007 by authors.4 * This library is free software; you can redistribute it and/or5 * modify it under the terms of the GNU Library General Public6 * License as published by the Free Software Foundation; either7 * version 2 of the License, or (at your option) any later version.8 *9 * This library is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12 * Library General Public License for more details.13 *14 * You should have received a copy of the GNU Library General Public15 * License along with this library; if not, write to the16 * 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.html19 */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 "alListener.h"35 #include "alAuxEffectSlot.h"36 #include "alu.h"37 #include "bs2b.h"40 static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)41 {42 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];43 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];44 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];45 }47 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)48 {49 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +50 inVector1[2]*inVector2[2];51 }53 static __inline ALvoid aluNormalize(ALfloat *inVector)54 {55 ALfloat length, inverse_length;57 length = aluSqrt(aluDotproduct(inVector, inVector));58 if(length != 0.0f)59 {60 inverse_length = 1.0f/length;61 inVector[0] *= inverse_length;62 inVector[1] *= inverse_length;63 inVector[2] *= inverse_length;64 }65 }67 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])68 {69 ALfloat temp[4] = {70 vector[0], vector[1], vector[2], w71 };73 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];74 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];75 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];76 }79 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)80 {81 static const ALfloat angles_Mono[1] = { 0.0f };82 static const ALfloat angles_Stereo[2] = { -30.0f, 30.0f };83 static const ALfloat angles_Rear[2] = { -150.0f, 150.0f };84 static const ALfloat angles_Quad[4] = { -45.0f, 45.0f, -135.0f, 135.0f };85 static const ALfloat angles_X51[6] = { -30.0f, 30.0f, 0.0f, 0.0f,86 -110.0f, 110.0f };87 static const ALfloat angles_X61[7] = { -30.0f, 30.0f, 0.0f, 0.0f,88 180.0f, -90.0f, 90.0f };89 static const ALfloat angles_X71[8] = { -30.0f, 30.0f, 0.0f, 0.0f,90 -110.0f, 110.0f, -90.0f, 90.0f };92 static const enum Channel chans_Mono[1] = { FRONT_CENTER };93 static const enum Channel chans_Stereo[2] = { FRONT_LEFT, FRONT_RIGHT };94 static const enum Channel chans_Rear[2] = { BACK_LEFT, BACK_RIGHT };95 static const enum Channel chans_Quad[4] = { FRONT_LEFT, FRONT_RIGHT,96 BACK_LEFT, BACK_RIGHT };97 static const enum Channel chans_X51[6] = { FRONT_LEFT, FRONT_RIGHT,98 FRONT_CENTER, LFE,99 BACK_LEFT, BACK_RIGHT };100 static const enum Channel chans_X61[7] = { FRONT_LEFT, FRONT_RIGHT,101 FRONT_CENTER, LFE, BACK_CENTER,102 SIDE_LEFT, SIDE_RIGHT };103 static const enum Channel chans_X71[8] = { FRONT_LEFT, FRONT_RIGHT,104 FRONT_CENTER, LFE,105 BACK_LEFT, BACK_RIGHT,106 SIDE_LEFT, SIDE_RIGHT };108 ALCdevice *Device = ALContext->Device;109 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;110 ALbufferlistitem *BufferListItem;111 enum DevFmtChannels DevChans;112 enum FmtChannels Channels;113 ALfloat (*SrcMatrix)[MAXCHANNELS];114 ALfloat DryGain, DryGainHF;115 ALfloat WetGain[MAX_SENDS];116 ALfloat WetGainHF[MAX_SENDS];117 ALint NumSends, Frequency;118 const ALfloat *SpeakerGain;119 const ALfloat *angles = NULL;120 const enum Channel *chans = NULL;121 enum Resampler Resampler;122 ALint num_channels = 0;123 ALboolean VirtualChannels;124 ALfloat Pitch;125 ALfloat cw;126 ALuint pos;127 ALint i, c;129 /* Get device properties */130 DevChans = ALContext->Device->FmtChans;131 NumSends = ALContext->Device->NumAuxSends;132 Frequency = ALContext->Device->Frequency;134 /* Get listener properties */135 ListenerGain = ALContext->Listener.Gain;137 /* Get source properties */138 SourceVolume = ALSource->flGain;139 MinVolume = ALSource->flMinGain;140 MaxVolume = ALSource->flMaxGain;141 Pitch = ALSource->flPitch;142 Resampler = ALSource->Resampler;143 VirtualChannels = ALSource->VirtualChannels;145 /* Calculate the stepping value */146 Channels = FmtMono;147 BufferListItem = ALSource->queue;148 while(BufferListItem != NULL)149 {150 ALbuffer *ALBuffer;151 if((ALBuffer=BufferListItem->buffer) != NULL)152 {153 ALint maxstep = STACK_DATA_SIZE / ALSource->NumChannels /154 ALSource->SampleSize;155 maxstep -= ResamplerPadding[Resampler] +156 ResamplerPrePadding[Resampler] + 1;157 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);159 Pitch = Pitch * ALBuffer->Frequency / Frequency;160 if(Pitch > (ALfloat)maxstep)161 ALSource->Params.Step = maxstep<<FRACTIONBITS;162 else163 {164 ALSource->Params.Step = Pitch*FRACTIONONE;165 if(ALSource->Params.Step == 0)166 ALSource->Params.Step = 1;167 }169 Channels = ALBuffer->FmtChannels;171 if(ALSource->VirtualChannels && (Device->Flags&DEVICE_USE_HRTF))172 ALSource->Params.DoMix = SelectHrtfMixer(ALBuffer,173 (ALSource->Params.Step==FRACTIONONE) ? POINT_RESAMPLER :174 Resampler);175 else176 ALSource->Params.DoMix = SelectMixer(ALBuffer,177 (ALSource->Params.Step==FRACTIONONE) ? POINT_RESAMPLER :178 Resampler);179 break;180 }181 BufferListItem = BufferListItem->next;182 }184 /* Calculate gains */185 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);186 DryGainHF = 1.0f;187 switch(ALSource->DirectFilter.type)188 {189 case AL_FILTER_LOWPASS:190 DryGain *= ALSource->DirectFilter.Gain;191 DryGainHF *= ALSource->DirectFilter.GainHF;192 break;193 }194 for(i = 0;i < NumSends;i++)195 {196 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);197 WetGainHF[i] = 1.0f;198 switch(ALSource->Send[i].WetFilter.type)199 {200 case AL_FILTER_LOWPASS:201 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;202 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;203 break;204 }205 }207 SrcMatrix = ALSource->Params.DryGains;208 for(i = 0;i < MAXCHANNELS;i++)209 {210 for(c = 0;c < MAXCHANNELS;c++)211 SrcMatrix[i][c] = 0.0f;212 }213 switch(Channels)214 {215 case FmtMono:216 angles = angles_Mono;217 chans = chans_Mono;218 num_channels = 1;219 break;220 case FmtStereo:221 if(VirtualChannels && (ALContext->Device->Flags&DEVICE_DUPLICATE_STEREO))222 {223 DryGain *= aluSqrt(2.0f/4.0f);224 for(c = 0;c < 2;c++)225 {226 pos = aluCart2LUTpos(cos(angles_Rear[c] * (M_PI/180.0)),227 sin(angles_Rear[c] * (M_PI/180.0)));228 SpeakerGain = Device->PanningLUT[pos];230 for(i = 0;i < (ALint)Device->NumChan;i++)231 {232 enum Channel chan = Device->Speaker2Chan[i];233 SrcMatrix[c][chan] += DryGain * ListenerGain *234 SpeakerGain[chan];235 }236 }237 }238 angles = angles_Stereo;239 chans = chans_Stereo;240 num_channels = 2;241 break;243 case FmtRear:244 angles = angles_Rear;245 chans = chans_Rear;246 num_channels = 2;247 break;249 case FmtQuad:250 angles = angles_Quad;251 chans = chans_Quad;252 num_channels = 4;253 break;255 case FmtX51:256 angles = angles_X51;257 chans = chans_X51;258 num_channels = 6;259 break;261 case FmtX61:262 angles = angles_X61;263 chans = chans_X61;264 num_channels = 7;265 break;267 case FmtX71:268 angles = angles_X71;269 chans = chans_X71;270 num_channels = 8;271 break;272 }274 if(VirtualChannels == AL_FALSE)275 {276 for(c = 0;c < num_channels;c++)277 SrcMatrix[c][chans[c]] += DryGain * ListenerGain;278 }279 else if((Device->Flags&DEVICE_USE_HRTF))280 {281 for(c = 0;c < num_channels;c++)282 {283 if(chans[c] == LFE)284 {285 /* Skip LFE */286 ALSource->Params.HrtfDelay[c][0] = 0;287 ALSource->Params.HrtfDelay[c][1] = 0;288 for(i = 0;i < HRIR_LENGTH;i++)289 {290 ALSource->Params.HrtfCoeffs[c][i][0] = 0.0f;291 ALSource->Params.HrtfCoeffs[c][i][1] = 0.0f;292 }293 }294 else295 {296 /* Get the static HRIR coefficients and delays for this297 * channel. */298 GetLerpedHrtfCoeffs(0.0, angles[c] * (M_PI/180.0),299 DryGain*ListenerGain,300 ALSource->Params.HrtfCoeffs[c],301 ALSource->Params.HrtfDelay[c]);302 }303 ALSource->HrtfCounter = 0;304 }305 }306 else307 {308 for(c = 0;c < num_channels;c++)309 {310 if(chans[c] == LFE) /* Special-case LFE */311 {312 SrcMatrix[c][LFE] += DryGain * ListenerGain;313 continue;314 }315 pos = aluCart2LUTpos(cos(angles[c] * (M_PI/180.0)),316 sin(angles[c] * (M_PI/180.0)));317 SpeakerGain = Device->PanningLUT[pos];319 for(i = 0;i < (ALint)Device->NumChan;i++)320 {321 enum Channel chan = Device->Speaker2Chan[i];322 SrcMatrix[c][chan] += DryGain * ListenerGain *323 SpeakerGain[chan];324 }325 }326 }327 for(i = 0;i < NumSends;i++)328 {329 ALSource->Params.Send[i].Slot = ALSource->Send[i].Slot;330 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;331 }333 /* Update filter coefficients. Calculations based on the I3DL2334 * spec. */335 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);337 /* We use two chained one-pole filters, so we need to take the338 * square root of the squared gain, which is the same as the base339 * gain. */340 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);341 for(i = 0;i < NumSends;i++)342 {343 /* We use a one-pole filter, so we need to take the squared gain */344 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);345 ALSource->Params.Send[i].iirFilter.coeff = a;346 }347 }349 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)350 {351 const ALCdevice *Device = ALContext->Device;352 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;353 ALfloat Direction[3],Position[3],SourceToListener[3];354 ALfloat Velocity[3],ListenerVel[3];355 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;356 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;357 ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;358 ALfloat AirAbsorptionFactor;359 ALfloat RoomAirAbsorption[MAX_SENDS];360 ALbufferlistitem *BufferListItem;361 ALfloat Attenuation, EffectiveDist;362 ALfloat RoomAttenuation[MAX_SENDS];363 ALfloat MetersPerUnit;364 ALfloat RoomRolloffBase;365 ALfloat RoomRolloff[MAX_SENDS];366 ALfloat DecayDistance[MAX_SENDS];367 ALfloat DryGain;368 ALfloat DryGainHF;369 ALboolean DryGainHFAuto;370 ALfloat WetGain[MAX_SENDS];371 ALfloat WetGainHF[MAX_SENDS];372 ALboolean WetGainAuto;373 ALboolean WetGainHFAuto;374 enum Resampler Resampler;375 ALfloat Pitch;376 ALuint Frequency;377 ALint NumSends;378 ALfloat cw;379 ALint i;381 DryGainHF = 1.0f;382 for(i = 0;i < MAX_SENDS;i++)383 WetGainHF[i] = 1.0f;385 //Get context properties386 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;387 DopplerVelocity = ALContext->DopplerVelocity;388 SpeedOfSound = ALContext->flSpeedOfSound;389 NumSends = Device->NumAuxSends;390 Frequency = Device->Frequency;392 //Get listener properties393 ListenerGain = ALContext->Listener.Gain;394 MetersPerUnit = ALContext->Listener.MetersPerUnit;395 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));397 //Get source properties398 SourceVolume = ALSource->flGain;399 MinVolume = ALSource->flMinGain;400 MaxVolume = ALSource->flMaxGain;401 Pitch = ALSource->flPitch;402 Resampler = ALSource->Resampler;403 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));404 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));405 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));406 MinDist = ALSource->flRefDistance;407 MaxDist = ALSource->flMaxDistance;408 Rolloff = ALSource->flRollOffFactor;409 InnerAngle = ALSource->flInnerAngle * ConeScale;410 OuterAngle = ALSource->flOuterAngle * ConeScale;411 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;412 DryGainHFAuto = ALSource->DryGainHFAuto;413 WetGainAuto = ALSource->WetGainAuto;414 WetGainHFAuto = ALSource->WetGainHFAuto;415 RoomRolloffBase = ALSource->RoomRolloffFactor;416 for(i = 0;i < NumSends;i++)417 {418 ALeffectslot *Slot = ALSource->Send[i].Slot;420 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)421 {422 RoomRolloff[i] = 0.0f;423 DecayDistance[i] = 0.0f;424 RoomAirAbsorption[i] = 1.0f;425 }426 else if(Slot->AuxSendAuto)427 {428 RoomRolloff[i] = RoomRolloffBase;429 if(IsReverbEffect(Slot->effect.type))430 {431 RoomRolloff[i] += Slot->effect.Params.Reverb.RoomRolloffFactor;432 DecayDistance[i] = Slot->effect.Params.Reverb.DecayTime *433 SPEEDOFSOUNDMETRESPERSEC;434 RoomAirAbsorption[i] = Slot->effect.Params.Reverb.AirAbsorptionGainHF;435 }436 else437 {438 DecayDistance[i] = 0.0f;439 RoomAirAbsorption[i] = 1.0f;440 }441 }442 else443 {444 /* If the slot's auxiliary send auto is off, the data sent to the445 * effect slot is the same as the dry path, sans filter effects */446 RoomRolloff[i] = Rolloff;447 DecayDistance[i] = 0.0f;448 RoomAirAbsorption[i] = AIRABSORBGAINHF;449 }451 ALSource->Params.Send[i].Slot = Slot;452 }454 //1. Translate Listener to origin (convert to head relative)455 if(ALSource->bHeadRelative == AL_FALSE)456 {457 ALfloat U[3],V[3],N[3];458 ALfloat Matrix[4][4];460 // Build transform matrix461 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector462 aluNormalize(N); // Normalized At-vector463 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector464 aluNormalize(V); // Normalized Up-vector465 aluCrossproduct(N, V, U); // Right-vector466 aluNormalize(U); // Normalized Right-vector467 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;468 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;469 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;470 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;472 // Translate position473 Position[0] -= ALContext->Listener.Position[0];474 Position[1] -= ALContext->Listener.Position[1];475 Position[2] -= ALContext->Listener.Position[2];477 // Transform source position and direction into listener space478 aluMatrixVector(Position, 1.0f, Matrix);479 aluMatrixVector(Direction, 0.0f, Matrix);480 // Transform source and listener velocity into listener space481 aluMatrixVector(Velocity, 0.0f, Matrix);482 aluMatrixVector(ListenerVel, 0.0f, Matrix);483 }484 else485 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;487 SourceToListener[0] = -Position[0];488 SourceToListener[1] = -Position[1];489 SourceToListener[2] = -Position[2];490 aluNormalize(SourceToListener);491 aluNormalize(Direction);493 //2. Calculate distance attenuation494 Distance = aluSqrt(aluDotproduct(Position, Position));495 ClampedDist = Distance;497 Attenuation = 1.0f;498 for(i = 0;i < NumSends;i++)499 RoomAttenuation[i] = 1.0f;500 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :501 ALContext->DistanceModel)502 {503 case InverseDistanceClamped:504 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);505 if(MaxDist < MinDist)506 break;507 //fall-through508 case InverseDistance:509 if(MinDist > 0.0f)510 {511 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)512 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));513 for(i = 0;i < NumSends;i++)514 {515 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)516 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));517 }518 }519 break;521 case LinearDistanceClamped:522 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);523 if(MaxDist < MinDist)524 break;525 //fall-through526 case LinearDistance:527 if(MaxDist != MinDist)528 {529 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));530 Attenuation = maxf(Attenuation, 0.0f);531 for(i = 0;i < NumSends;i++)532 {533 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));534 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);535 }536 }537 break;539 case ExponentDistanceClamped:540 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);541 if(MaxDist < MinDist)542 break;543 //fall-through544 case ExponentDistance:545 if(ClampedDist > 0.0f && MinDist > 0.0f)546 {547 Attenuation = aluPow(ClampedDist/MinDist, -Rolloff);548 for(i = 0;i < NumSends;i++)549 RoomAttenuation[i] = aluPow(ClampedDist/MinDist, -RoomRolloff[i]);550 }551 break;553 case DisableDistance:554 break;555 }557 // Source Gain + Attenuation558 DryGain = SourceVolume * Attenuation;559 for(i = 0;i < NumSends;i++)560 WetGain[i] = SourceVolume * RoomAttenuation[i];562 // Distance-based air absorption563 EffectiveDist = 0.0f;564 if(MinDist > 0.0f && Attenuation < 1.0f)565 EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;566 if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)567 {568 DryGainHF *= aluPow(AIRABSORBGAINHF, AirAbsorptionFactor*EffectiveDist);569 for(i = 0;i < NumSends;i++)570 WetGainHF[i] *= aluPow(RoomAirAbsorption[i],571 AirAbsorptionFactor*EffectiveDist);572 }574 //3. Apply directional soundcones575 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * (180.0/M_PI);576 if(Angle >= InnerAngle && Angle <= OuterAngle)577 {578 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);579 ConeVolume = lerp(1.0, ALSource->flOuterGain, scale);580 ConeHF = lerp(1.0, ALSource->OuterGainHF, scale);581 }582 else if(Angle > OuterAngle)583 {584 ConeVolume = ALSource->flOuterGain;585 ConeHF = ALSource->OuterGainHF;586 }587 else588 {589 ConeVolume = 1.0f;590 ConeHF = 1.0f;591 }593 DryGain *= ConeVolume;594 if(WetGainAuto)595 {596 for(i = 0;i < NumSends;i++)597 WetGain[i] *= ConeVolume;598 }599 if(DryGainHFAuto)600 DryGainHF *= ConeHF;601 if(WetGainHFAuto)602 {603 for(i = 0;i < NumSends;i++)604 WetGainHF[i] *= ConeHF;605 }607 // Clamp to Min/Max Gain608 DryGain = clampf(DryGain, MinVolume, MaxVolume);609 for(i = 0;i < NumSends;i++)610 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);612 // Apply filter gains and filters613 switch(ALSource->DirectFilter.type)614 {615 case AL_FILTER_LOWPASS:616 DryGain *= ALSource->DirectFilter.Gain;617 DryGainHF *= ALSource->DirectFilter.GainHF;618 break;619 }620 DryGain *= ListenerGain;621 for(i = 0;i < NumSends;i++)622 {623 switch(ALSource->Send[i].WetFilter.type)624 {625 case AL_FILTER_LOWPASS:626 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;627 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;628 break;629 }630 WetGain[i] *= ListenerGain;631 }633 if(WetGainAuto)634 {635 /* Apply a decay-time transformation to the wet path, based on the636 * attenuation of the dry path.637 *638 * Using the approximate (effective) source to listener distance, the639 * initial decay of the reverb effect is calculated and applied to the640 * wet path.641 */642 for(i = 0;i < NumSends;i++)643 {644 if(DecayDistance[i] > 0.0f)645 WetGain[i] *= aluPow(0.001f /* -60dB */,646 EffectiveDist / DecayDistance[i]);647 }648 }650 // Calculate Velocity651 if(DopplerFactor != 0.0f)652 {653 ALfloat VSS, VLS;654 ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /655 DopplerFactor;657 VSS = aluDotproduct(Velocity, SourceToListener);658 if(VSS >= MaxVelocity)659 VSS = (MaxVelocity - 1.0f);660 else if(VSS <= -MaxVelocity)661 VSS = -MaxVelocity + 1.0f;663 VLS = aluDotproduct(ListenerVel, SourceToListener);664 if(VLS >= MaxVelocity)665 VLS = (MaxVelocity - 1.0f);666 else if(VLS <= -MaxVelocity)667 VLS = -MaxVelocity + 1.0f;669 Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /670 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));671 }673 BufferListItem = ALSource->queue;674 while(BufferListItem != NULL)675 {676 ALbuffer *ALBuffer;677 if((ALBuffer=BufferListItem->buffer) != NULL)678 {679 ALint maxstep = STACK_DATA_SIZE / ALSource->NumChannels /680 ALSource->SampleSize;681 maxstep -= ResamplerPadding[Resampler] +682 ResamplerPrePadding[Resampler] + 1;683 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);685 Pitch = Pitch * ALBuffer->Frequency / Frequency;686 if(Pitch > (ALfloat)maxstep)687 ALSource->Params.Step = maxstep<<FRACTIONBITS;688 else689 {690 ALSource->Params.Step = Pitch*FRACTIONONE;691 if(ALSource->Params.Step == 0)692 ALSource->Params.Step = 1;693 }695 if((Device->Flags&DEVICE_USE_HRTF))696 ALSource->Params.DoMix = SelectHrtfMixer(ALBuffer,697 (ALSource->Params.Step==FRACTIONONE) ? POINT_RESAMPLER :698 Resampler);699 else700 ALSource->Params.DoMix = SelectMixer(ALBuffer,701 (ALSource->Params.Step==FRACTIONONE) ? POINT_RESAMPLER :702 Resampler);703 break;704 }705 BufferListItem = BufferListItem->next;706 }708 if((Device->Flags&DEVICE_USE_HRTF))709 {710 // Use a binaural HRTF algorithm for stereo headphone playback711 ALfloat delta, ev = 0.0f, az = 0.0f;713 if(Distance > 0.0f)714 {715 ALfloat invlen = 1.0f/Distance;716 Position[0] *= invlen;717 Position[1] *= invlen;718 Position[2] *= invlen;720 // Calculate elevation and azimuth only when the source is not at721 // the listener. This prevents +0 and -0 Z from producing722 // inconsistent panning.723 ev = asin(Position[1]);724 az = atan2(Position[0], -Position[2]*ZScale);725 }727 // Check to see if the HRIR is already moving.728 if(ALSource->HrtfMoving)729 {730 // Calculate the normalized HRTF transition factor (delta).731 delta = CalcHrtfDelta(ALSource->Params.HrtfGain, DryGain,732 ALSource->Params.HrtfDir, Position);733 // If the delta is large enough, get the moving HRIR target734 // coefficients, target delays, steppping values, and counter.735 if(delta > 0.001f)736 {737 ALSource->HrtfCounter = GetMovingHrtfCoeffs(ev, az, DryGain,738 delta, ALSource->HrtfCounter,739 ALSource->Params.HrtfCoeffs[0],740 ALSource->Params.HrtfDelay[0],741 ALSource->Params.HrtfCoeffStep,742 ALSource->Params.HrtfDelayStep);743 ALSource->Params.HrtfGain = DryGain;744 ALSource->Params.HrtfDir[0] = Position[0];745 ALSource->Params.HrtfDir[1] = Position[1];746 ALSource->Params.HrtfDir[2] = Position[2];747 }748 }749 else750 {751 // Get the initial (static) HRIR coefficients and delays.752 GetLerpedHrtfCoeffs(ev, az, DryGain,753 ALSource->Params.HrtfCoeffs[0],754 ALSource->Params.HrtfDelay[0]);755 ALSource->HrtfCounter = 0;756 ALSource->Params.HrtfGain = DryGain;757 ALSource->Params.HrtfDir[0] = Position[0];758 ALSource->Params.HrtfDir[1] = Position[1];759 ALSource->Params.HrtfDir[2] = Position[2];760 }761 }762 else763 {764 // Use energy-preserving panning algorithm for multi-speaker playback765 ALfloat DirGain, AmbientGain;766 const ALfloat *SpeakerGain;767 ALfloat length;768 ALint pos;770 length = maxf(Distance, MinDist);771 if(length > 0.0f)772 {773 ALfloat invlen = 1.0f/length;774 Position[0] *= invlen;775 Position[1] *= invlen;776 Position[2] *= invlen;777 }779 pos = aluCart2LUTpos(-Position[2]*ZScale, Position[0]);780 SpeakerGain = Device->PanningLUT[pos];782 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);783 // elevation adjustment for directional gain. this sucks, but784 // has low complexity785 AmbientGain = aluSqrt(1.0/Device->NumChan);786 for(i = 0;i < MAXCHANNELS;i++)787 {788 ALuint i2;789 for(i2 = 0;i2 < MAXCHANNELS;i2++)790 ALSource->Params.DryGains[i][i2] = 0.0f;791 }792 for(i = 0;i < (ALint)Device->NumChan;i++)793 {794 enum Channel chan = Device->Speaker2Chan[i];795 ALfloat gain = lerp(AmbientGain, SpeakerGain[chan], DirGain);796 ALSource->Params.DryGains[0][chan] = DryGain * gain;797 }798 }799 for(i = 0;i < NumSends;i++)800 ALSource->Params.Send[i].WetGain = WetGain[i];802 /* Update filter coefficients. */803 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);805 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);806 for(i = 0;i < NumSends;i++)807 {808 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);809 ALSource->Params.Send[i].iirFilter.coeff = a;810 }811 }814 static __inline ALfloat aluF2F(ALfloat val)815 { return val; }816 static __inline ALshort aluF2S(ALfloat val)817 {818 if(val > 1.0f) return 32767;819 if(val < -1.0f) return -32768;820 return (ALint)(val*32767.0f);821 }822 static __inline ALushort aluF2US(ALfloat val)823 { return aluF2S(val)+32768; }824 static __inline ALbyte aluF2B(ALfloat val)825 { return aluF2S(val)>>8; }826 static __inline ALubyte aluF2UB(ALfloat val)827 { return aluF2US(val)>>8; }829 #define DECL_TEMPLATE(T, N, func) \830 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \831 ALuint SamplesToDo) \832 { \833 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \834 const enum Channel *ChanMap = device->DevChannels; \835 ALuint i, j; \836 \837 for(i = 0;i < SamplesToDo;i++) \838 { \839 for(j = 0;j < N;j++) \840 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \841 } \842 }844 DECL_TEMPLATE(ALfloat, 1, aluF2F)845 DECL_TEMPLATE(ALfloat, 4, aluF2F)846 DECL_TEMPLATE(ALfloat, 6, aluF2F)847 DECL_TEMPLATE(ALfloat, 7, aluF2F)848 DECL_TEMPLATE(ALfloat, 8, aluF2F)850 DECL_TEMPLATE(ALushort, 1, aluF2US)851 DECL_TEMPLATE(ALushort, 4, aluF2US)852 DECL_TEMPLATE(ALushort, 6, aluF2US)853 DECL_TEMPLATE(ALushort, 7, aluF2US)854 DECL_TEMPLATE(ALushort, 8, aluF2US)856 DECL_TEMPLATE(ALshort, 1, aluF2S)857 DECL_TEMPLATE(ALshort, 4, aluF2S)858 DECL_TEMPLATE(ALshort, 6, aluF2S)859 DECL_TEMPLATE(ALshort, 7, aluF2S)860 DECL_TEMPLATE(ALshort, 8, aluF2S)862 DECL_TEMPLATE(ALubyte, 1, aluF2UB)863 DECL_TEMPLATE(ALubyte, 4, aluF2UB)864 DECL_TEMPLATE(ALubyte, 6, aluF2UB)865 DECL_TEMPLATE(ALubyte, 7, aluF2UB)866 DECL_TEMPLATE(ALubyte, 8, aluF2UB)868 DECL_TEMPLATE(ALbyte, 1, aluF2B)869 DECL_TEMPLATE(ALbyte, 4, aluF2B)870 DECL_TEMPLATE(ALbyte, 6, aluF2B)871 DECL_TEMPLATE(ALbyte, 7, aluF2B)872 DECL_TEMPLATE(ALbyte, 8, aluF2B)874 #undef DECL_TEMPLATE876 #define DECL_TEMPLATE(T, N, func) \877 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \878 ALuint SamplesToDo) \879 { \880 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \881 const enum Channel *ChanMap = device->DevChannels; \882 ALuint i, j; \883 \884 if(device->Bs2b) \885 { \886 for(i = 0;i < SamplesToDo;i++) \887 { \888 float samples[2]; \889 samples[0] = DryBuffer[i][ChanMap[0]]; \890 samples[1] = DryBuffer[i][ChanMap[1]]; \891 bs2b_cross_feed(device->Bs2b, samples); \892 *(buffer++) = func(samples[0]); \893 *(buffer++) = func(samples[1]); \894 } \895 } \896 else \897 { \898 for(i = 0;i < SamplesToDo;i++) \899 { \900 for(j = 0;j < N;j++) \901 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \902 } \903 } \904 }906 DECL_TEMPLATE(ALfloat, 2, aluF2F)907 DECL_TEMPLATE(ALushort, 2, aluF2US)908 DECL_TEMPLATE(ALshort, 2, aluF2S)909 DECL_TEMPLATE(ALubyte, 2, aluF2UB)910 DECL_TEMPLATE(ALbyte, 2, aluF2B)912 #undef DECL_TEMPLATE914 #define DECL_TEMPLATE(T) \915 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \916 { \917 switch(device->FmtChans) \918 { \919 case DevFmtMono: \920 Write_##T##_1(device, buffer, SamplesToDo); \921 break; \922 case DevFmtStereo: \923 Write_##T##_2(device, buffer, SamplesToDo); \924 break; \925 case DevFmtQuad: \926 Write_##T##_4(device, buffer, SamplesToDo); \927 break; \928 case DevFmtX51: \929 case DevFmtX51Side: \930 Write_##T##_6(device, buffer, SamplesToDo); \931 break; \932 case DevFmtX61: \933 Write_##T##_7(device, buffer, SamplesToDo); \934 break; \935 case DevFmtX71: \936 Write_##T##_8(device, buffer, SamplesToDo); \937 break; \938 } \939 }941 DECL_TEMPLATE(ALfloat)942 DECL_TEMPLATE(ALushort)943 DECL_TEMPLATE(ALshort)944 DECL_TEMPLATE(ALubyte)945 DECL_TEMPLATE(ALbyte)947 #undef DECL_TEMPLATE949 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)950 {951 ALuint SamplesToDo;952 ALeffectslot *ALEffectSlot;953 ALCcontext **ctx, **ctx_end;954 ALsource **src, **src_end;955 int fpuState;956 ALuint i, c;957 ALsizei e;959 #if defined(HAVE_FESETROUND)960 fpuState = fegetround();961 fesetround(FE_TOWARDZERO);962 #elif defined(HAVE__CONTROLFP)963 fpuState = _controlfp(0, 0);964 (void)_controlfp(_RC_CHOP, _MCW_RC);965 #else966 (void)fpuState;967 #endif969 while(size > 0)970 {971 /* Setup variables */972 SamplesToDo = minu(size, BUFFERSIZE);974 /* Clear mixing buffer */975 memset(device->DryBuffer, 0, SamplesToDo*MAXCHANNELS*sizeof(ALfloat));977 LockDevice(device);978 ctx = device->Contexts;979 ctx_end = ctx + device->NumContexts;980 //printf("Contexts: %d\n", device->NumContexts);981 int context_number = 0;982 while(ctx != ctx_end)983 {984 //printf("Context %d:\n", context_number++);985 ALboolean DeferUpdates = (*ctx)->DeferUpdates;986 ALboolean UpdateSources = AL_FALSE;988 if(!DeferUpdates)989 {990 //printf("NOT deferring updates, whatever that means\n");991 UpdateSources = (*ctx)->UpdateSources;992 //printf("update sources is set to %d\n", UpdateSources);993 (*ctx)->UpdateSources = AL_FALSE;994 }996 src = (*ctx)->ActiveSources;997 src_end = src + (*ctx)->ActiveSourceCount;998 //printf("number of active sources are %d\n", (*ctx)->ActiveSourceCount);999 while(src != src_end)1000 {1002 if((*src)->state != AL_PLAYING)1003 {1004 --((*ctx)->ActiveSourceCount);1005 *src = *(--src_end);1006 continue;1007 }1009 if(!DeferUpdates && ((*src)->NeedsUpdate || UpdateSources))1010 {1011 (*src)->NeedsUpdate = AL_FALSE;1012 ALsource_Update(*src, *ctx);1013 }1014 //printf("calling MixSource!\n");1015 MixSource(*src, device, SamplesToDo);1016 src++;1017 }1019 /* effect slot processing */1020 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)1021 {1022 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;1024 for(i = 0;i < SamplesToDo;i++)1025 {1026 // RLM: remove click-removal1027 ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];1028 ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;1029 }1030 for(i = 0;i < 1;i++)1031 {1032 // RLM: remove click-removal1033 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];1034 ALEffectSlot->PendingClicks[i] = 0.0f;1035 }1037 if(!DeferUpdates && ALEffectSlot->NeedsUpdate)1038 {1039 ALEffectSlot->NeedsUpdate = AL_FALSE;1040 ALEffect_Update(ALEffectSlot->EffectState, *ctx, ALEffectSlot);1041 }1043 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,1044 SamplesToDo, ALEffectSlot->WetBuffer,1045 device->DryBuffer);1047 for(i = 0;i < SamplesToDo;i++)1048 ALEffectSlot->WetBuffer[i] = 0.0f;1049 }1051 ctx++;1052 }1053 UnlockDevice(device);1055 //Post processing loop1056 if(device->FmtChans == DevFmtMono)1057 {1058 for(i = 0;i < SamplesToDo;i++)1059 {1060 // RLM: remove click-removal1061 device->DryBuffer[i][FRONT_CENTER] += device->ClickRemoval[FRONT_CENTER];1062 device->ClickRemoval[FRONT_CENTER] -= device->ClickRemoval[FRONT_CENTER] / 256.0f;1063 }1064 // RLM: remove click-removal1065 device->ClickRemoval[FRONT_CENTER] += device->PendingClicks[FRONT_CENTER];1066 device->PendingClicks[FRONT_CENTER] = 0.0f;1067 }1068 else if(device->FmtChans == DevFmtStereo)1069 {1070 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */1071 for(i = 0;i < SamplesToDo;i++)1072 {1073 for(c = 0;c < 2;c++)1074 {1075 // RLM: remove click-removal1076 device->DryBuffer[i][c] += device->ClickRemoval[c];1077 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;1078 }1079 }1080 for(c = 0;c < 2;c++)1081 {1082 // RLM: remove click-removal1083 device->ClickRemoval[c] += device->PendingClicks[c];1084 device->PendingClicks[c] = 0.0f;1085 }1086 }1087 else1088 {1089 for(i = 0;i < SamplesToDo;i++)1090 {1091 for(c = 0;c < MAXCHANNELS;c++)1092 {1093 // RLM: remove click-removal1094 device->DryBuffer[i][c] += device->ClickRemoval[c];1095 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;1096 }1097 }1098 for(c = 0;c < MAXCHANNELS;c++)1099 {1100 // RLM: remove click-removal1101 device->ClickRemoval[c] += device->PendingClicks[c];1102 device->PendingClicks[c] = 0.0f;1103 }1104 }1106 if(buffer)1107 {1108 switch(device->FmtType)1109 {1110 case DevFmtByte:1111 Write_ALbyte(device, buffer, SamplesToDo);1112 break;1113 case DevFmtUByte:1114 Write_ALubyte(device, buffer, SamplesToDo);1115 break;1116 case DevFmtShort:1117 Write_ALshort(device, buffer, SamplesToDo);1118 break;1119 case DevFmtUShort:1120 Write_ALushort(device, buffer, SamplesToDo);1121 break;1122 case DevFmtFloat:1123 Write_ALfloat(device, buffer, SamplesToDo);1124 break;1125 }1126 }1128 size -= SamplesToDo;1129 }1131 #if defined(HAVE_FESETROUND)1132 fesetround(fpuState);1133 #elif defined(HAVE__CONTROLFP)1134 _controlfp(fpuState, _MCW_RC);1135 #endif1136 }1142 ALvoid aluHandleDisconnect(ALCdevice *device)1143 {1144 ALuint i;1146 LockDevice(device);1147 for(i = 0;i < device->NumContexts;i++)1148 {1149 ALCcontext *Context = device->Contexts[i];1150 ALsource *source;1151 ALsizei pos;1153 for(pos = 0;pos < Context->SourceMap.size;pos++)1154 {1155 source = Context->SourceMap.array[pos].value;1156 if(source->state == AL_PLAYING)1157 {1158 source->state = AL_STOPPED;1159 source->BuffersPlayed = source->BuffersInQueue;1160 source->position = 0;1161 source->position_fraction = 0;1162 }1163 }1164 }1166 device->Connected = ALC_FALSE;1167 UnlockDevice(device);1168 }