annotate Alc/ALu.c @ 6:99df34265b40

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