2007-11-14 02:02:18 +00:00
|
|
|
/**
|
|
|
|
* OpenAL cross platform audio library
|
|
|
|
* Copyright (C) 1999-2007 by authors.
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
2014-08-18 12:11:03 +00:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2007-11-14 02:02:18 +00:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
2009-01-24 18:38:04 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-01-26 03:20:47 +00:00
|
|
|
#include <ctype.h>
|
2009-02-02 19:18:33 +00:00
|
|
|
#include <assert.h>
|
2009-01-26 03:20:47 +00:00
|
|
|
|
2007-11-14 02:02:18 +00:00
|
|
|
#include "alMain.h"
|
2007-12-31 09:09:57 +00:00
|
|
|
#include "alSource.h"
|
|
|
|
#include "alBuffer.h"
|
|
|
|
#include "alListener.h"
|
2008-01-16 22:01:24 +00:00
|
|
|
#include "alAuxEffectSlot.h"
|
2008-08-14 12:43:52 +00:00
|
|
|
#include "alu.h"
|
2008-01-03 13:36:51 +00:00
|
|
|
#include "bs2b.h"
|
2014-02-24 05:11:01 +00:00
|
|
|
#include "hrtf.h"
|
2014-06-03 02:19:22 +00:00
|
|
|
#include "static_assert.h"
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2014-11-22 12:20:17 +00:00
|
|
|
#include "mixer_defs.h"
|
|
|
|
|
2014-11-01 22:55:18 +00:00
|
|
|
#include "backends/base.h"
|
2013-12-18 07:03:34 +00:00
|
|
|
#include "midi/base.h"
|
|
|
|
|
2009-08-15 18:33:38 +00:00
|
|
|
|
2014-06-03 02:19:22 +00:00
|
|
|
static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
|
|
|
|
"MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
|
|
|
|
|
2011-12-20 09:17:11 +00:00
|
|
|
struct ChanMap {
|
|
|
|
enum Channel channel;
|
|
|
|
ALfloat angle;
|
2014-10-03 01:05:42 +00:00
|
|
|
ALfloat elevation;
|
2011-12-20 09:17:11 +00:00
|
|
|
};
|
|
|
|
|
2011-09-24 05:33:37 +00:00
|
|
|
/* Cone scalar */
|
2012-08-11 13:20:24 +00:00
|
|
|
ALfloat ConeScale = 1.0f;
|
2011-09-24 05:33:37 +00:00
|
|
|
|
|
|
|
/* Localized Z scalar for mono sources */
|
|
|
|
ALfloat ZScale = 1.0f;
|
|
|
|
|
2013-11-04 21:44:46 +00:00
|
|
|
extern inline ALfloat minf(ALfloat a, ALfloat b);
|
|
|
|
extern inline ALfloat maxf(ALfloat a, ALfloat b);
|
|
|
|
extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
|
|
|
|
|
2013-11-27 08:30:13 +00:00
|
|
|
extern inline ALdouble mind(ALdouble a, ALdouble b);
|
|
|
|
extern inline ALdouble maxd(ALdouble a, ALdouble b);
|
|
|
|
extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
|
|
|
|
|
2013-11-04 21:44:46 +00:00
|
|
|
extern inline ALuint minu(ALuint a, ALuint b);
|
|
|
|
extern inline ALuint maxu(ALuint a, ALuint b);
|
|
|
|
extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
|
|
|
|
|
|
|
|
extern inline ALint mini(ALint a, ALint b);
|
|
|
|
extern inline ALint maxi(ALint a, ALint b);
|
|
|
|
extern inline ALint clampi(ALint val, ALint min, ALint max);
|
|
|
|
|
|
|
|
extern inline ALint64 mini64(ALint64 a, ALint64 b);
|
|
|
|
extern inline ALint64 maxi64(ALint64 a, ALint64 b);
|
|
|
|
extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
|
|
|
|
|
|
|
|
extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
|
|
|
|
extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
|
|
|
|
extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
|
|
|
|
|
|
|
|
extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
|
|
|
|
extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
|
2011-09-24 05:33:37 +00:00
|
|
|
|
2012-09-12 14:57:50 +00:00
|
|
|
|
2014-11-22 12:20:17 +00:00
|
|
|
static inline HrtfMixerFunc SelectHrtfMixer(void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_SSE
|
|
|
|
if((CPUCapFlags&CPU_CAP_SSE))
|
|
|
|
return MixHrtf_SSE;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NEON
|
|
|
|
if((CPUCapFlags&CPU_CAP_NEON))
|
|
|
|
return MixHrtf_Neon;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return MixHrtf_C;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
|
2012-10-26 00:24:22 +00:00
|
|
|
{
|
|
|
|
outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
|
|
|
|
outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
|
|
|
|
outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
|
|
|
|
}
|
|
|
|
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
|
2012-10-26 00:24:22 +00:00
|
|
|
{
|
|
|
|
return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
|
|
|
|
inVector1[2]*inVector2[2];
|
|
|
|
}
|
|
|
|
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline void aluNormalize(ALfloat *inVector)
|
2012-10-26 00:24:22 +00:00
|
|
|
{
|
|
|
|
ALfloat lengthsqr = aluDotproduct(inVector, inVector);
|
|
|
|
if(lengthsqr > 0.0f)
|
|
|
|
{
|
|
|
|
ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
|
|
|
|
inVector[0] *= inv_length;
|
|
|
|
inVector[1] *= inv_length;
|
|
|
|
inVector[2] *= inv_length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4])
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2009-11-23 12:13:51 +00:00
|
|
|
ALfloat temp[4] = {
|
|
|
|
vector[0], vector[1], vector[2], w
|
|
|
|
};
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2009-11-23 12:13:51 +00:00
|
|
|
vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
|
|
|
|
vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
|
|
|
|
vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2010-08-04 06:19:36 +00:00
|
|
|
|
2014-10-02 06:50:57 +00:00
|
|
|
static void UpdateDryStepping(DirectParams *params, ALuint num_chans)
|
|
|
|
{
|
|
|
|
ALuint i, j;
|
|
|
|
|
|
|
|
if(!params->Moving)
|
|
|
|
{
|
|
|
|
for(i = 0;i < num_chans;i++)
|
|
|
|
{
|
2014-11-22 20:58:54 +00:00
|
|
|
MixGains *gains = params->Gains[i];
|
2014-11-23 00:23:08 +00:00
|
|
|
for(j = 0;j < params->OutChannels;j++)
|
2014-10-02 06:50:57 +00:00
|
|
|
{
|
|
|
|
gains[j].Current = gains[j].Target;
|
|
|
|
gains[j].Step = 1.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
params->Moving = AL_TRUE;
|
|
|
|
params->Counter = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0;i < num_chans;i++)
|
|
|
|
{
|
2014-11-22 20:58:54 +00:00
|
|
|
MixGains *gains = params->Gains[i];
|
2014-11-23 00:23:08 +00:00
|
|
|
for(j = 0;j < params->OutChannels;j++)
|
2014-10-02 06:50:57 +00:00
|
|
|
{
|
|
|
|
ALfloat cur = maxf(gains[j].Current, FLT_EPSILON);
|
|
|
|
ALfloat trg = maxf(gains[j].Target, FLT_EPSILON);
|
|
|
|
if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
|
|
|
|
gains[j].Step = powf(trg/cur, 1.0f/64.0f);
|
|
|
|
else
|
|
|
|
gains[j].Step = 1.0f;
|
|
|
|
gains[j].Current = cur;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
params->Counter = 64;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void UpdateWetStepping(SendParams *params)
|
|
|
|
{
|
|
|
|
ALfloat cur, trg;
|
|
|
|
|
|
|
|
if(!params->Moving)
|
|
|
|
{
|
|
|
|
params->Gain.Current = params->Gain.Target;
|
|
|
|
params->Gain.Step = 1.0f;
|
|
|
|
|
|
|
|
params->Moving = AL_TRUE;
|
|
|
|
params->Counter = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = maxf(params->Gain.Current, FLT_EPSILON);
|
|
|
|
trg = maxf(params->Gain.Target, FLT_EPSILON);
|
|
|
|
if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
|
|
|
|
params->Gain.Step = powf(trg/cur, 1.0f/64.0f);
|
|
|
|
else
|
|
|
|
params->Gain.Step = 1.0f;
|
|
|
|
params->Gain.Current = cur;
|
|
|
|
|
|
|
|
params->Counter = 64;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-12 14:38:29 +00:00
|
|
|
static ALvoid CalcListenerParams(ALlistener *Listener)
|
|
|
|
{
|
|
|
|
ALfloat N[3], V[3], U[3], P[3];
|
|
|
|
|
|
|
|
/* AT then UP */
|
|
|
|
N[0] = Listener->Forward[0];
|
|
|
|
N[1] = Listener->Forward[1];
|
|
|
|
N[2] = Listener->Forward[2];
|
|
|
|
aluNormalize(N);
|
|
|
|
V[0] = Listener->Up[0];
|
|
|
|
V[1] = Listener->Up[1];
|
2012-10-13 06:35:00 +00:00
|
|
|
V[2] = Listener->Up[2];
|
2012-10-12 14:38:29 +00:00
|
|
|
aluNormalize(V);
|
|
|
|
/* Build and normalize right-vector */
|
|
|
|
aluCrossproduct(N, V, U);
|
|
|
|
aluNormalize(U);
|
|
|
|
|
|
|
|
Listener->Params.Matrix[0][0] = U[0];
|
|
|
|
Listener->Params.Matrix[0][1] = V[0];
|
|
|
|
Listener->Params.Matrix[0][2] = -N[0];
|
|
|
|
Listener->Params.Matrix[0][3] = 0.0f;
|
|
|
|
Listener->Params.Matrix[1][0] = U[1];
|
|
|
|
Listener->Params.Matrix[1][1] = V[1];
|
|
|
|
Listener->Params.Matrix[1][2] = -N[1];
|
|
|
|
Listener->Params.Matrix[1][3] = 0.0f;
|
|
|
|
Listener->Params.Matrix[2][0] = U[2];
|
|
|
|
Listener->Params.Matrix[2][1] = V[2];
|
|
|
|
Listener->Params.Matrix[2][2] = -N[2];
|
|
|
|
Listener->Params.Matrix[2][3] = 0.0f;
|
|
|
|
Listener->Params.Matrix[3][0] = 0.0f;
|
|
|
|
Listener->Params.Matrix[3][1] = 0.0f;
|
|
|
|
Listener->Params.Matrix[3][2] = 0.0f;
|
|
|
|
Listener->Params.Matrix[3][3] = 1.0f;
|
|
|
|
|
|
|
|
P[0] = Listener->Position[0];
|
|
|
|
P[1] = Listener->Position[1];
|
|
|
|
P[2] = Listener->Position[2];
|
|
|
|
aluMatrixVector(P, 1.0f, Listener->Params.Matrix);
|
|
|
|
Listener->Params.Matrix[3][0] = -P[0];
|
|
|
|
Listener->Params.Matrix[3][1] = -P[1];
|
|
|
|
Listener->Params.Matrix[3][2] = -P[2];
|
2012-10-12 14:56:37 +00:00
|
|
|
|
|
|
|
Listener->Params.Velocity[0] = Listener->Velocity[0];
|
|
|
|
Listener->Params.Velocity[1] = Listener->Velocity[1];
|
|
|
|
Listener->Params.Velocity[2] = Listener->Velocity[2];
|
|
|
|
aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
|
2012-10-12 14:38:29 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
|
2010-08-05 08:07:20 +00:00
|
|
|
{
|
2014-10-03 01:05:42 +00:00
|
|
|
static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } };
|
2012-02-10 07:52:20 +00:00
|
|
|
static const struct ChanMap StereoMap[2] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
|
2012-02-10 07:52:20 +00:00
|
|
|
};
|
2012-08-09 12:38:07 +00:00
|
|
|
static const struct ChanMap StereoWideMap[2] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
|
2012-08-09 12:38:07 +00:00
|
|
|
};
|
2012-02-10 07:52:20 +00:00
|
|
|
static const struct ChanMap RearMap[2] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
|
|
|
|
{ BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
|
2012-02-10 07:52:20 +00:00
|
|
|
};
|
|
|
|
static const struct ChanMap QuadMap[4] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
|
|
|
|
{ BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
|
|
|
|
{ BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
|
2012-02-10 07:52:20 +00:00
|
|
|
};
|
|
|
|
static const struct ChanMap X51Map[6] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
|
|
|
|
{ LFE, 0.0f, 0.0f },
|
2014-11-07 08:54:16 +00:00
|
|
|
{ SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
|
|
|
|
{ SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
|
2012-02-10 07:52:20 +00:00
|
|
|
};
|
|
|
|
static const struct ChanMap X61Map[7] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
|
|
|
|
{ LFE, 0.0f, 0.0f },
|
|
|
|
{ BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
|
|
|
|
{ SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
|
|
|
|
{ SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
|
2012-02-10 07:52:20 +00:00
|
|
|
};
|
|
|
|
static const struct ChanMap X71Map[8] = {
|
2014-10-03 01:05:42 +00:00
|
|
|
{ FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
|
|
|
|
{ FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
|
|
|
|
{ LFE, 0.0f, 0.0f },
|
|
|
|
{ BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
|
|
|
|
{ BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
|
|
|
|
{ SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
|
|
|
|
{ SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
|
2012-02-10 07:52:20 +00:00
|
|
|
};
|
2011-06-30 06:18:49 +00:00
|
|
|
|
2011-05-06 11:37:10 +00:00
|
|
|
ALCdevice *Device = ALContext->Device;
|
2010-08-05 08:07:20 +00:00
|
|
|
ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
|
2010-08-07 07:38:02 +00:00
|
|
|
ALbufferlistitem *BufferListItem;
|
2010-11-27 08:15:07 +00:00
|
|
|
enum FmtChannels Channels;
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat DryGain, DryGainHF, DryGainLF;
|
2010-08-05 08:07:20 +00:00
|
|
|
ALfloat WetGain[MAX_SENDS];
|
|
|
|
ALfloat WetGainHF[MAX_SENDS];
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat WetGainLF[MAX_SENDS];
|
2014-10-11 16:35:32 +00:00
|
|
|
ALuint NumSends, Frequency;
|
2014-11-01 05:43:13 +00:00
|
|
|
ALboolean Relative;
|
2011-12-20 09:17:11 +00:00
|
|
|
const struct ChanMap *chans = NULL;
|
2014-10-11 16:35:32 +00:00
|
|
|
ALuint num_channels = 0;
|
2012-02-10 07:35:17 +00:00
|
|
|
ALboolean DirectChannels;
|
2014-11-01 00:18:45 +00:00
|
|
|
ALboolean isbformat = AL_FALSE;
|
2010-08-07 12:43:16 +00:00
|
|
|
ALfloat Pitch;
|
2014-10-11 16:35:32 +00:00
|
|
|
ALuint i, j, c;
|
2010-08-05 08:07:20 +00:00
|
|
|
|
2010-11-27 02:01:29 +00:00
|
|
|
/* Get device properties */
|
2011-10-12 05:30:58 +00:00
|
|
|
NumSends = Device->NumAuxSends;
|
|
|
|
Frequency = Device->Frequency;
|
2010-08-05 08:07:20 +00:00
|
|
|
|
2010-11-27 02:01:29 +00:00
|
|
|
/* Get listener properties */
|
2012-10-09 11:44:27 +00:00
|
|
|
ListenerGain = ALContext->Listener->Gain;
|
2010-08-05 08:07:20 +00:00
|
|
|
|
2010-11-27 02:01:29 +00:00
|
|
|
/* Get source properties */
|
2012-04-20 04:46:29 +00:00
|
|
|
SourceVolume = ALSource->Gain;
|
|
|
|
MinVolume = ALSource->MinGain;
|
|
|
|
MaxVolume = ALSource->MaxGain;
|
|
|
|
Pitch = ALSource->Pitch;
|
2014-11-01 05:43:13 +00:00
|
|
|
Relative = ALSource->HeadRelative;
|
2012-02-10 07:35:17 +00:00
|
|
|
DirectChannels = ALSource->DirectChannels;
|
2010-08-05 08:07:20 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Direct.OutBuffer = Device->DryBuffer;
|
2014-11-23 00:23:08 +00:00
|
|
|
voice->Direct.OutChannels = Device->NumChannels;
|
2014-03-19 23:10:09 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
{
|
|
|
|
ALeffectslot *Slot = ALSource->Send[i].Slot;
|
|
|
|
if(!Slot && i == 0)
|
|
|
|
Slot = Device->DefaultSlot;
|
|
|
|
if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].OutBuffer = NULL;
|
2014-03-19 23:10:09 +00:00
|
|
|
else
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].OutBuffer = Slot->WetBuffer;
|
2014-03-19 23:10:09 +00:00
|
|
|
}
|
|
|
|
|
2010-11-27 02:01:29 +00:00
|
|
|
/* Calculate the stepping value */
|
2010-11-27 08:15:07 +00:00
|
|
|
Channels = FmtMono;
|
2014-07-31 14:20:36 +00:00
|
|
|
BufferListItem = ATOMIC_LOAD(&ALSource->queue);
|
2010-08-07 07:38:02 +00:00
|
|
|
while(BufferListItem != NULL)
|
|
|
|
{
|
|
|
|
ALbuffer *ALBuffer;
|
|
|
|
if((ALBuffer=BufferListItem->buffer) != NULL)
|
|
|
|
{
|
2010-11-28 21:08:51 +00:00
|
|
|
Pitch = Pitch * ALBuffer->Frequency / Frequency;
|
2014-06-03 02:19:22 +00:00
|
|
|
if(Pitch > (ALfloat)MAX_PITCH)
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Step = MAX_PITCH<<FRACTIONBITS;
|
2010-11-27 01:47:43 +00:00
|
|
|
else
|
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Step = fastf2i(Pitch*FRACTIONONE);
|
|
|
|
if(voice->Step == 0)
|
|
|
|
voice->Step = 1;
|
2010-11-27 01:47:43 +00:00
|
|
|
}
|
|
|
|
|
2010-11-27 08:15:07 +00:00
|
|
|
Channels = ALBuffer->FmtChannels;
|
2010-08-07 07:38:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BufferListItem = BufferListItem->next;
|
|
|
|
}
|
2010-08-05 08:07:20 +00:00
|
|
|
|
2010-11-27 02:01:29 +00:00
|
|
|
/* Calculate gains */
|
2011-08-31 09:18:16 +00:00
|
|
|
DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
|
2014-05-11 08:36:18 +00:00
|
|
|
DryGain *= ALSource->Direct.Gain * ListenerGain;
|
|
|
|
DryGainHF = ALSource->Direct.GainHF;
|
2014-05-17 14:54:25 +00:00
|
|
|
DryGainLF = ALSource->Direct.GainLF;
|
2011-07-05 18:00:52 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
{
|
2014-05-11 08:36:18 +00:00
|
|
|
WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
|
|
|
|
WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
|
2012-04-27 07:45:42 +00:00
|
|
|
WetGainHF[i] = ALSource->Send[i].GainHF;
|
2014-05-17 14:54:25 +00:00
|
|
|
WetGainLF[i] = ALSource->Send[i].GainLF;
|
2011-07-05 18:00:52 +00:00
|
|
|
}
|
2010-08-05 08:07:20 +00:00
|
|
|
|
2010-12-10 00:37:23 +00:00
|
|
|
switch(Channels)
|
|
|
|
{
|
|
|
|
case FmtMono:
|
2011-12-20 09:17:11 +00:00
|
|
|
chans = MonoMap;
|
2011-05-15 09:12:42 +00:00
|
|
|
num_channels = 1;
|
2010-12-10 00:37:23 +00:00
|
|
|
break;
|
2011-05-15 07:18:28 +00:00
|
|
|
|
2012-04-29 11:44:53 +00:00
|
|
|
case FmtStereo:
|
2014-10-03 01:05:42 +00:00
|
|
|
/* HACK: Place the stereo channels at +/-90 degrees when using non-
|
|
|
|
* HRTF stereo output. This helps reduce the "monoization" caused
|
|
|
|
* by them panning towards the center. */
|
|
|
|
if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
|
2012-08-09 12:38:07 +00:00
|
|
|
chans = StereoWideMap;
|
2014-10-03 01:05:42 +00:00
|
|
|
else
|
|
|
|
chans = StereoMap;
|
2011-06-17 23:20:18 +00:00
|
|
|
num_channels = 2;
|
2010-12-10 00:37:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FmtRear:
|
2011-12-20 09:17:11 +00:00
|
|
|
chans = RearMap;
|
2011-05-15 09:12:42 +00:00
|
|
|
num_channels = 2;
|
2010-12-10 00:37:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FmtQuad:
|
2011-12-20 09:17:11 +00:00
|
|
|
chans = QuadMap;
|
2011-05-15 09:12:42 +00:00
|
|
|
num_channels = 4;
|
2010-12-10 00:37:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FmtX51:
|
2011-12-20 09:17:11 +00:00
|
|
|
chans = X51Map;
|
2011-05-15 09:12:42 +00:00
|
|
|
num_channels = 6;
|
2010-12-10 00:37:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FmtX61:
|
2011-12-20 09:17:11 +00:00
|
|
|
chans = X61Map;
|
2011-05-15 09:12:42 +00:00
|
|
|
num_channels = 7;
|
2010-12-10 00:37:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FmtX71:
|
2011-12-20 09:17:11 +00:00
|
|
|
chans = X71Map;
|
2011-05-15 09:12:42 +00:00
|
|
|
num_channels = 8;
|
|
|
|
break;
|
2014-11-01 00:18:45 +00:00
|
|
|
|
|
|
|
case FmtBFormat2D:
|
|
|
|
num_channels = 3;
|
|
|
|
isbformat = AL_TRUE;
|
|
|
|
DirectChannels = AL_FALSE;
|
2014-11-02 10:30:45 +00:00
|
|
|
break;
|
2014-11-01 00:18:45 +00:00
|
|
|
|
|
|
|
case FmtBFormat3D:
|
|
|
|
num_channels = 4;
|
|
|
|
isbformat = AL_TRUE;
|
|
|
|
DirectChannels = AL_FALSE;
|
2014-11-02 10:30:45 +00:00
|
|
|
break;
|
2011-05-15 09:12:42 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 00:18:45 +00:00
|
|
|
if(isbformat)
|
|
|
|
{
|
2014-11-01 05:43:13 +00:00
|
|
|
ALfloat N[3], V[3], U[3];
|
|
|
|
ALfloat matrix[4][4];
|
|
|
|
|
|
|
|
/* AT then UP */
|
|
|
|
N[0] = ALSource->Orientation[0][0];
|
|
|
|
N[1] = ALSource->Orientation[0][1];
|
|
|
|
N[2] = ALSource->Orientation[0][2];
|
|
|
|
aluNormalize(N);
|
|
|
|
V[0] = ALSource->Orientation[1][0];
|
|
|
|
V[1] = ALSource->Orientation[1][1];
|
|
|
|
V[2] = ALSource->Orientation[1][2];
|
|
|
|
aluNormalize(V);
|
|
|
|
if(!Relative)
|
|
|
|
{
|
|
|
|
ALfloat (*restrict lmatrix)[4] = ALContext->Listener->Params.Matrix;
|
|
|
|
aluMatrixVector(N, 0.0f, lmatrix);
|
|
|
|
aluMatrixVector(V, 0.0f, lmatrix);
|
|
|
|
}
|
|
|
|
/* Build and normalize right-vector */
|
|
|
|
aluCrossproduct(N, V, U);
|
|
|
|
aluNormalize(U);
|
|
|
|
|
|
|
|
matrix[0][0] = 1.0f;
|
|
|
|
matrix[0][1] = 0.0f;
|
|
|
|
matrix[0][2] = 0.0f;
|
|
|
|
matrix[0][3] = 0.0f;
|
|
|
|
matrix[1][0] = 0.0f;
|
|
|
|
matrix[1][1] = -N[2];
|
|
|
|
matrix[1][2] = -N[0];
|
|
|
|
matrix[1][3] = N[1];
|
|
|
|
matrix[2][0] = 0.0f;
|
|
|
|
matrix[2][1] = U[2];
|
|
|
|
matrix[2][2] = U[0];
|
|
|
|
matrix[2][3] = -U[1];
|
|
|
|
matrix[3][0] = 0.0f;
|
|
|
|
matrix[3][1] = -V[2];
|
|
|
|
matrix[3][2] = -V[0];
|
|
|
|
matrix[3][3] = V[1];
|
|
|
|
|
2014-11-01 00:18:45 +00:00
|
|
|
for(c = 0;c < num_channels;c++)
|
|
|
|
{
|
2014-11-22 20:58:54 +00:00
|
|
|
MixGains *gains = voice->Direct.Gains[c];
|
2014-11-07 10:18:24 +00:00
|
|
|
ALfloat Target[MAX_OUTPUT_CHANNELS];
|
2014-11-01 00:18:45 +00:00
|
|
|
|
2014-11-01 05:43:13 +00:00
|
|
|
ComputeBFormatGains(Device, matrix[c], DryGain, Target);
|
2014-11-07 10:18:24 +00:00
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
2014-11-01 00:18:45 +00:00
|
|
|
gains[i].Target = Target[i];
|
|
|
|
}
|
|
|
|
/* B-Format cannot handle logarithmic gain stepping, since the gain can
|
|
|
|
* switch between positive and negative values. */
|
|
|
|
voice->Direct.Moving = AL_FALSE;
|
|
|
|
UpdateDryStepping(&voice->Direct, num_channels);
|
|
|
|
|
|
|
|
voice->IsHrtf = AL_FALSE;
|
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
WetGain[i] *= 1.4142f;
|
|
|
|
}
|
|
|
|
else if(DirectChannels != AL_FALSE)
|
2011-06-30 06:18:49 +00:00
|
|
|
{
|
2014-11-22 21:10:32 +00:00
|
|
|
if(Device->Hrtf)
|
|
|
|
{
|
2014-11-23 00:23:08 +00:00
|
|
|
voice->Direct.OutBuffer = &voice->Direct.OutBuffer[voice->Direct.OutChannels];
|
|
|
|
voice->Direct.OutChannels = 2;
|
2014-11-22 21:10:32 +00:00
|
|
|
for(c = 0;c < num_channels;c++)
|
|
|
|
{
|
|
|
|
MixGains *gains = voice->Direct.Gains[c];
|
|
|
|
|
|
|
|
for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
|
|
|
|
gains[j].Target = 0.0f;
|
|
|
|
|
|
|
|
if(chans[c].channel == FrontLeft)
|
|
|
|
gains[0].Target = DryGain;
|
|
|
|
else if(chans[c].channel == FrontRight)
|
|
|
|
gains[1].Target = DryGain;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else for(c = 0;c < num_channels;c++)
|
2014-03-19 23:10:09 +00:00
|
|
|
{
|
2014-11-22 20:58:54 +00:00
|
|
|
MixGains *gains = voice->Direct.Gains[c];
|
2014-11-05 10:54:11 +00:00
|
|
|
int idx;
|
2014-10-02 06:50:57 +00:00
|
|
|
|
2014-11-07 10:18:24 +00:00
|
|
|
for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
|
2014-06-13 18:42:04 +00:00
|
|
|
gains[j].Target = 0.0f;
|
2014-11-05 10:54:11 +00:00
|
|
|
if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
|
|
|
|
gains[idx].Target = DryGain;
|
2012-03-13 01:27:25 +00:00
|
|
|
}
|
2014-10-02 06:50:57 +00:00
|
|
|
UpdateDryStepping(&voice->Direct, num_channels);
|
2014-03-23 13:57:00 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->IsHrtf = AL_FALSE;
|
2011-06-30 06:18:49 +00:00
|
|
|
}
|
2011-06-17 23:20:18 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
for(c = 0;c < num_channels;c++)
|
2011-05-02 09:22:30 +00:00
|
|
|
{
|
2014-11-22 20:58:54 +00:00
|
|
|
MixGains *gains = voice->Direct.Gains[c];
|
2014-11-07 10:18:24 +00:00
|
|
|
ALfloat Target[MAX_OUTPUT_CHANNELS];
|
2014-06-13 18:42:04 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Special-case LFE */
|
|
|
|
if(chans[c].channel == LFE)
|
2011-04-15 04:03:37 +00:00
|
|
|
{
|
2014-11-05 10:54:11 +00:00
|
|
|
int idx;
|
2014-11-07 10:18:24 +00:00
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
2014-10-12 19:39:27 +00:00
|
|
|
gains[i].Target = 0.0f;
|
2014-11-05 10:54:11 +00:00
|
|
|
if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
|
|
|
|
gains[idx].Target = DryGain;
|
2014-10-12 19:39:27 +00:00
|
|
|
continue;
|
2014-10-03 01:05:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-12 19:39:27 +00:00
|
|
|
ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
|
2014-11-07 10:18:24 +00:00
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
2014-06-13 18:42:04 +00:00
|
|
|
gains[i].Target = Target[i];
|
2011-04-15 04:03:37 +00:00
|
|
|
}
|
2014-10-02 06:50:57 +00:00
|
|
|
UpdateDryStepping(&voice->Direct, num_channels);
|
2014-03-23 13:57:00 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->IsHrtf = AL_FALSE;
|
2011-04-15 04:03:37 +00:00
|
|
|
}
|
2009-12-09 15:02:26 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2014-03-23 23:11:21 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].Gain.Target = WetGain[i];
|
2014-10-02 06:50:57 +00:00
|
|
|
UpdateWetStepping(&voice->Send[i]);
|
2014-03-23 23:11:21 +00:00
|
|
|
}
|
2009-12-09 15:02:26 +00:00
|
|
|
|
2013-05-28 02:14:02 +00:00
|
|
|
{
|
2014-05-17 14:17:48 +00:00
|
|
|
ALfloat gainhf = maxf(0.01f, DryGainHF);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat gainlf = maxf(0.01f, DryGainLF);
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
|
2013-05-28 02:14:02 +00:00
|
|
|
for(c = 0;c < num_channels;c++)
|
2014-05-17 14:17:48 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Direct.Filters[c].ActiveType = AF_None;
|
|
|
|
if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
|
|
|
|
if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
|
2014-05-11 17:07:17 +00:00
|
|
|
hfscale, 0.0f
|
|
|
|
);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
|
2014-05-17 14:54:25 +00:00
|
|
|
lfscale, 0.0f
|
|
|
|
);
|
2014-05-17 14:17:48 +00:00
|
|
|
}
|
2013-05-28 02:14:02 +00:00
|
|
|
}
|
2009-12-09 15:02:26 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
{
|
2014-05-17 14:17:48 +00:00
|
|
|
ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
|
2013-05-21 14:10:24 +00:00
|
|
|
for(c = 0;c < num_channels;c++)
|
2014-05-17 14:17:48 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].Filters[c].ActiveType = AF_None;
|
|
|
|
if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
|
|
|
|
if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
|
2014-05-11 17:07:17 +00:00
|
|
|
hfscale, 0.0f
|
|
|
|
);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
|
2014-05-17 14:54:25 +00:00
|
|
|
lfscale, 0.0f
|
|
|
|
);
|
2014-05-17 14:17:48 +00:00
|
|
|
}
|
2009-12-09 15:02:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
|
2007-11-14 02:02:18 +00:00
|
|
|
{
|
2012-10-14 18:21:52 +00:00
|
|
|
ALCdevice *Device = ALContext->Device;
|
2012-10-12 14:56:37 +00:00
|
|
|
ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
|
2011-06-21 19:55:21 +00:00
|
|
|
ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
|
2011-05-06 09:53:22 +00:00
|
|
|
ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
|
2009-04-13 09:50:40 +00:00
|
|
|
ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
|
2012-03-09 02:19:15 +00:00
|
|
|
ALfloat DopplerFactor, SpeedOfSound;
|
2010-09-12 07:10:33 +00:00
|
|
|
ALfloat AirAbsorptionFactor;
|
2011-07-05 18:00:52 +00:00
|
|
|
ALfloat RoomAirAbsorption[MAX_SENDS];
|
2010-08-07 07:38:02 +00:00
|
|
|
ALbufferlistitem *BufferListItem;
|
2012-03-15 05:45:52 +00:00
|
|
|
ALfloat Attenuation;
|
2009-04-12 03:04:46 +00:00
|
|
|
ALfloat RoomAttenuation[MAX_SENDS];
|
2007-12-18 03:40:43 +00:00
|
|
|
ALfloat MetersPerUnit;
|
2011-07-05 18:00:52 +00:00
|
|
|
ALfloat RoomRolloffBase;
|
2009-04-12 03:04:46 +00:00
|
|
|
ALfloat RoomRolloff[MAX_SENDS];
|
2011-07-05 18:00:52 +00:00
|
|
|
ALfloat DecayDistance[MAX_SENDS];
|
2010-10-10 10:47:57 +00:00
|
|
|
ALfloat DryGain;
|
|
|
|
ALfloat DryGainHF;
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat DryGainLF;
|
2011-07-05 18:00:52 +00:00
|
|
|
ALboolean DryGainHFAuto;
|
2009-10-21 22:31:21 +00:00
|
|
|
ALfloat WetGain[MAX_SENDS];
|
2009-10-21 20:08:50 +00:00
|
|
|
ALfloat WetGainHF[MAX_SENDS];
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat WetGainLF[MAX_SENDS];
|
2011-07-01 08:46:56 +00:00
|
|
|
ALboolean WetGainAuto;
|
|
|
|
ALboolean WetGainHFAuto;
|
2010-08-07 07:38:02 +00:00
|
|
|
ALfloat Pitch;
|
2009-10-21 20:08:50 +00:00
|
|
|
ALuint Frequency;
|
2009-04-14 03:33:41 +00:00
|
|
|
ALint NumSends;
|
2012-03-10 07:53:45 +00:00
|
|
|
ALint i, j;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2010-10-10 10:47:57 +00:00
|
|
|
DryGainHF = 1.0f;
|
2014-05-17 14:54:25 +00:00
|
|
|
DryGainLF = 1.0f;
|
2009-12-01 11:32:04 +00:00
|
|
|
for(i = 0;i < MAX_SENDS;i++)
|
2014-05-17 14:54:25 +00:00
|
|
|
{
|
2009-12-01 11:32:04 +00:00
|
|
|
WetGainHF[i] = 1.0f;
|
2014-05-17 14:54:25 +00:00
|
|
|
WetGainLF[i] = 1.0f;
|
|
|
|
}
|
2009-12-01 11:32:04 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Get context/device properties */
|
2012-03-09 02:19:15 +00:00
|
|
|
DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
|
2012-04-20 05:50:11 +00:00
|
|
|
SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
|
2012-03-09 02:19:15 +00:00
|
|
|
NumSends = Device->NumAuxSends;
|
|
|
|
Frequency = Device->Frequency;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Get listener properties */
|
2012-10-12 14:56:37 +00:00
|
|
|
ListenerGain = ALContext->Listener->Gain;
|
|
|
|
MetersPerUnit = ALContext->Listener->MetersPerUnit;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Get source properties */
|
2012-04-20 04:46:29 +00:00
|
|
|
SourceVolume = ALSource->Gain;
|
|
|
|
MinVolume = ALSource->MinGain;
|
|
|
|
MaxVolume = ALSource->MaxGain;
|
|
|
|
Pitch = ALSource->Pitch;
|
|
|
|
Position[0] = ALSource->Position[0];
|
|
|
|
Position[1] = ALSource->Position[1];
|
|
|
|
Position[2] = ALSource->Position[2];
|
2014-11-01 00:24:46 +00:00
|
|
|
Direction[0] = ALSource->Direction[0];
|
|
|
|
Direction[1] = ALSource->Direction[1];
|
|
|
|
Direction[2] = ALSource->Direction[2];
|
2012-04-20 04:46:29 +00:00
|
|
|
Velocity[0] = ALSource->Velocity[0];
|
|
|
|
Velocity[1] = ALSource->Velocity[1];
|
|
|
|
Velocity[2] = ALSource->Velocity[2];
|
|
|
|
MinDist = ALSource->RefDistance;
|
|
|
|
MaxDist = ALSource->MaxDistance;
|
|
|
|
Rolloff = ALSource->RollOffFactor;
|
2012-08-11 13:20:24 +00:00
|
|
|
InnerAngle = ALSource->InnerAngle;
|
|
|
|
OuterAngle = ALSource->OuterAngle;
|
2011-07-05 18:00:52 +00:00
|
|
|
AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
|
2011-09-11 08:18:57 +00:00
|
|
|
DryGainHFAuto = ALSource->DryGainHFAuto;
|
|
|
|
WetGainAuto = ALSource->WetGainAuto;
|
|
|
|
WetGainHFAuto = ALSource->WetGainHFAuto;
|
2011-07-05 18:00:52 +00:00
|
|
|
RoomRolloffBase = ALSource->RoomRolloffFactor;
|
2012-10-14 18:21:52 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Direct.OutBuffer = Device->DryBuffer;
|
2014-11-23 00:23:08 +00:00
|
|
|
voice->Direct.OutChannels = Device->NumChannels;
|
2011-07-03 10:34:40 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
{
|
2011-07-05 18:00:52 +00:00
|
|
|
ALeffectslot *Slot = ALSource->Send[i].Slot;
|
|
|
|
|
2012-01-20 03:30:03 +00:00
|
|
|
if(!Slot && i == 0)
|
|
|
|
Slot = Device->DefaultSlot;
|
2013-05-26 05:07:31 +00:00
|
|
|
if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
|
2011-07-05 18:00:52 +00:00
|
|
|
{
|
2012-01-23 14:29:03 +00:00
|
|
|
Slot = NULL;
|
2011-07-05 18:00:52 +00:00
|
|
|
RoomRolloff[i] = 0.0f;
|
|
|
|
DecayDistance[i] = 0.0f;
|
2011-07-12 05:07:37 +00:00
|
|
|
RoomAirAbsorption[i] = 1.0f;
|
2011-07-05 18:00:52 +00:00
|
|
|
}
|
|
|
|
else if(Slot->AuxSendAuto)
|
|
|
|
{
|
|
|
|
RoomRolloff[i] = RoomRolloffBase;
|
2013-05-26 05:07:31 +00:00
|
|
|
if(IsReverbEffect(Slot->EffectType))
|
2011-07-05 18:00:52 +00:00
|
|
|
{
|
2013-05-26 05:07:31 +00:00
|
|
|
RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
|
|
|
|
DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
|
2011-07-05 18:00:52 +00:00
|
|
|
SPEEDOFSOUNDMETRESPERSEC;
|
2013-05-26 05:07:31 +00:00
|
|
|
RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
|
2011-07-05 18:00:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DecayDistance[i] = 0.0f;
|
2011-07-12 05:07:37 +00:00
|
|
|
RoomAirAbsorption[i] = 1.0f;
|
2011-07-05 18:00:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If the slot's auxiliary send auto is off, the data sent to the
|
|
|
|
* effect slot is the same as the dry path, sans filter effects */
|
|
|
|
RoomRolloff[i] = Rolloff;
|
|
|
|
DecayDistance[i] = 0.0f;
|
|
|
|
RoomAirAbsorption[i] = AIRABSORBGAINHF;
|
|
|
|
}
|
2011-07-05 21:14:20 +00:00
|
|
|
|
2013-10-06 17:11:01 +00:00
|
|
|
if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].OutBuffer = NULL;
|
2013-10-06 17:11:01 +00:00
|
|
|
else
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].OutBuffer = Slot->WetBuffer;
|
2011-07-03 10:34:40 +00:00
|
|
|
}
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Transform source to listener space (convert to head relative) */
|
2012-04-20 04:46:29 +00:00
|
|
|
if(ALSource->HeadRelative == AL_FALSE)
|
2009-10-19 20:25:40 +00:00
|
|
|
{
|
2013-05-22 22:11:39 +00:00
|
|
|
ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix;
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Transform source vectors */
|
2011-10-30 15:27:24 +00:00
|
|
|
aluMatrixVector(Position, 1.0f, Matrix);
|
|
|
|
aluMatrixVector(Direction, 0.0f, Matrix);
|
|
|
|
aluMatrixVector(Velocity, 0.0f, Matrix);
|
2009-10-19 20:25:40 +00:00
|
|
|
}
|
|
|
|
else
|
2011-10-30 12:49:17 +00:00
|
|
|
{
|
2012-10-12 14:56:37 +00:00
|
|
|
const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
|
2012-03-10 07:53:45 +00:00
|
|
|
/* Offset the source velocity to be relative of the listener velocity */
|
|
|
|
Velocity[0] += ListenerVel[0];
|
|
|
|
Velocity[1] += ListenerVel[1];
|
|
|
|
Velocity[2] += ListenerVel[2];
|
2011-10-30 12:49:17 +00:00
|
|
|
}
|
2009-11-23 06:36:20 +00:00
|
|
|
|
|
|
|
SourceToListener[0] = -Position[0];
|
|
|
|
SourceToListener[1] = -Position[1];
|
|
|
|
SourceToListener[2] = -Position[2];
|
2009-10-19 20:25:40 +00:00
|
|
|
aluNormalize(SourceToListener);
|
|
|
|
aluNormalize(Direction);
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Calculate distance attenuation */
|
2012-06-29 09:12:36 +00:00
|
|
|
Distance = sqrtf(aluDotproduct(Position, Position));
|
2011-06-21 19:55:21 +00:00
|
|
|
ClampedDist = Distance;
|
2009-10-19 20:25:40 +00:00
|
|
|
|
2010-10-10 11:00:50 +00:00
|
|
|
Attenuation = 1.0f;
|
2009-12-06 11:59:12 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2009-10-19 20:25:40 +00:00
|
|
|
RoomAttenuation[i] = 1.0f;
|
2009-11-28 04:05:21 +00:00
|
|
|
switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
|
|
|
|
ALContext->DistanceModel)
|
2009-10-19 20:25:40 +00:00
|
|
|
{
|
2011-07-04 02:39:19 +00:00
|
|
|
case InverseDistanceClamped:
|
2011-08-17 01:40:21 +00:00
|
|
|
ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
|
2009-10-19 20:25:40 +00:00
|
|
|
if(MaxDist < MinDist)
|
|
|
|
break;
|
2012-04-26 07:59:17 +00:00
|
|
|
/*fall-through*/
|
2011-07-04 02:39:19 +00:00
|
|
|
case InverseDistance:
|
2009-10-19 20:25:40 +00:00
|
|
|
if(MinDist > 0.0f)
|
|
|
|
{
|
2011-06-21 19:55:21 +00:00
|
|
|
if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
|
|
|
|
Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
|
2009-10-19 20:25:40 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2007-12-19 03:03:40 +00:00
|
|
|
{
|
2011-06-21 19:55:21 +00:00
|
|
|
if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
|
|
|
|
RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
|
2007-12-19 03:03:40 +00:00
|
|
|
}
|
2009-10-19 20:25:40 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-07-04 02:39:19 +00:00
|
|
|
case LinearDistanceClamped:
|
2011-08-17 01:40:21 +00:00
|
|
|
ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
|
2009-10-19 20:25:40 +00:00
|
|
|
if(MaxDist < MinDist)
|
2007-11-14 02:02:18 +00:00
|
|
|
break;
|
2012-04-26 07:59:17 +00:00
|
|
|
/*fall-through*/
|
2011-07-04 02:39:19 +00:00
|
|
|
case LinearDistance:
|
2009-10-19 20:25:40 +00:00
|
|
|
if(MaxDist != MinDist)
|
|
|
|
{
|
2011-06-21 19:55:21 +00:00
|
|
|
Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
|
2011-08-17 01:40:21 +00:00
|
|
|
Attenuation = maxf(Attenuation, 0.0f);
|
2009-10-19 20:25:40 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2010-09-24 20:16:09 +00:00
|
|
|
{
|
2011-06-21 19:55:21 +00:00
|
|
|
RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
|
2011-08-17 01:40:21 +00:00
|
|
|
RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
|
2010-09-24 20:16:09 +00:00
|
|
|
}
|
2009-10-19 20:25:40 +00:00
|
|
|
}
|
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2011-07-04 02:39:19 +00:00
|
|
|
case ExponentDistanceClamped:
|
2011-08-17 01:40:21 +00:00
|
|
|
ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
|
2009-10-19 20:25:40 +00:00
|
|
|
if(MaxDist < MinDist)
|
2007-11-14 02:02:18 +00:00
|
|
|
break;
|
2012-04-26 07:59:17 +00:00
|
|
|
/*fall-through*/
|
2011-07-04 02:39:19 +00:00
|
|
|
case ExponentDistance:
|
2011-06-21 19:55:21 +00:00
|
|
|
if(ClampedDist > 0.0f && MinDist > 0.0f)
|
2009-10-19 20:25:40 +00:00
|
|
|
{
|
2012-06-29 09:12:36 +00:00
|
|
|
Attenuation = powf(ClampedDist/MinDist, -Rolloff);
|
2009-10-19 20:25:40 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2012-06-29 09:12:36 +00:00
|
|
|
RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
|
2009-10-19 20:25:40 +00:00
|
|
|
}
|
|
|
|
break;
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2011-07-04 02:39:19 +00:00
|
|
|
case DisableDistance:
|
2012-03-15 05:45:52 +00:00
|
|
|
ClampedDist = MinDist;
|
2009-10-19 20:25:40 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-04-12 03:27:55 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Source Gain + Attenuation */
|
2011-06-18 23:45:26 +00:00
|
|
|
DryGain = SourceVolume * Attenuation;
|
2011-07-05 18:00:52 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
WetGain[i] = SourceVolume * RoomAttenuation[i];
|
2011-06-18 23:45:26 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Distance-based air absorption */
|
2012-03-18 15:09:59 +00:00
|
|
|
if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
|
2011-07-05 18:00:52 +00:00
|
|
|
{
|
2012-03-18 15:09:59 +00:00
|
|
|
ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
|
2012-06-29 09:12:36 +00:00
|
|
|
DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
|
2011-07-05 18:00:52 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2012-06-29 09:12:36 +00:00
|
|
|
WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
|
2011-07-05 18:00:52 +00:00
|
|
|
}
|
2007-11-14 02:02:18 +00:00
|
|
|
|
2012-03-18 15:06:21 +00:00
|
|
|
if(WetGainAuto)
|
2011-10-01 00:51:21 +00:00
|
|
|
{
|
2012-03-18 15:06:21 +00:00
|
|
|
ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
|
|
|
|
|
2011-10-01 00:51:21 +00:00
|
|
|
/* Apply a decay-time transformation to the wet path, based on the
|
|
|
|
* attenuation of the dry path.
|
|
|
|
*
|
2012-03-18 15:06:21 +00:00
|
|
|
* Using the apparent distance, based on the distance attenuation, the
|
|
|
|
* initial decay of the reverb effect is calculated and applied to the
|
|
|
|
* wet path.
|
2011-10-01 00:51:21 +00:00
|
|
|
*/
|
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
{
|
|
|
|
if(DecayDistance[i] > 0.0f)
|
2012-06-29 09:12:36 +00:00
|
|
|
WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
|
2011-10-01 00:51:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate directional soundcones */
|
2013-10-08 15:29:14 +00:00
|
|
|
Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f;
|
2012-04-26 07:59:17 +00:00
|
|
|
if(Angle > InnerAngle && Angle <= OuterAngle)
|
2009-10-19 20:25:40 +00:00
|
|
|
{
|
|
|
|
ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
|
2012-04-20 04:46:29 +00:00
|
|
|
ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
|
2011-09-24 06:03:59 +00:00
|
|
|
ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
|
2009-10-19 20:25:40 +00:00
|
|
|
}
|
|
|
|
else if(Angle > OuterAngle)
|
|
|
|
{
|
2012-04-20 04:46:29 +00:00
|
|
|
ConeVolume = ALSource->OuterGain;
|
2011-05-06 09:53:22 +00:00
|
|
|
ConeHF = ALSource->OuterGainHF;
|
2009-10-19 20:25:40 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ConeVolume = 1.0f;
|
|
|
|
ConeHF = 1.0f;
|
|
|
|
}
|
2008-01-16 05:57:50 +00:00
|
|
|
|
2010-10-10 10:47:57 +00:00
|
|
|
DryGain *= ConeVolume;
|
2011-07-05 18:00:52 +00:00
|
|
|
if(WetGainAuto)
|
|
|
|
{
|
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
WetGain[i] *= ConeVolume;
|
|
|
|
}
|
|
|
|
if(DryGainHFAuto)
|
2009-12-08 22:18:07 +00:00
|
|
|
DryGainHF *= ConeHF;
|
2011-07-05 18:00:52 +00:00
|
|
|
if(WetGainHFAuto)
|
|
|
|
{
|
|
|
|
for(i = 0;i < NumSends;i++)
|
2011-08-13 13:58:05 +00:00
|
|
|
WetGainHF[i] *= ConeHF;
|
2011-07-05 18:00:52 +00:00
|
|
|
}
|
2009-12-08 22:18:07 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Clamp to Min/Max Gain */
|
2011-08-17 01:40:21 +00:00
|
|
|
DryGain = clampf(DryGain, MinVolume, MaxVolume);
|
2009-10-19 20:25:40 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2011-08-17 01:40:21 +00:00
|
|
|
WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
|
2010-03-08 06:12:33 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Apply gain and frequency filters */
|
2014-05-11 08:36:18 +00:00
|
|
|
DryGain *= ALSource->Direct.Gain * ListenerGain;
|
|
|
|
DryGainHF *= ALSource->Direct.GainHF;
|
2014-05-17 14:54:25 +00:00
|
|
|
DryGainLF *= ALSource->Direct.GainLF;
|
2011-07-05 18:00:52 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
|
|
|
{
|
2012-04-27 07:45:42 +00:00
|
|
|
WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
|
|
|
|
WetGainHF[i] *= ALSource->Send[i].GainHF;
|
2014-05-17 14:54:25 +00:00
|
|
|
WetGainLF[i] *= ALSource->Send[i].GainLF;
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2008-01-19 08:49:05 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Calculate velocity-based doppler effect */
|
2012-03-18 15:20:08 +00:00
|
|
|
if(DopplerFactor > 0.0f)
|
2009-12-01 11:32:04 +00:00
|
|
|
{
|
2012-10-12 14:56:37 +00:00
|
|
|
const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
|
2010-10-10 11:00:50 +00:00
|
|
|
ALfloat VSS, VLS;
|
2012-03-09 02:19:15 +00:00
|
|
|
|
2012-03-18 15:20:08 +00:00
|
|
|
if(SpeedOfSound < 1.0f)
|
|
|
|
{
|
|
|
|
DopplerFactor *= 1.0f/SpeedOfSound;
|
|
|
|
SpeedOfSound = 1.0f;
|
|
|
|
}
|
|
|
|
|
2012-03-09 02:19:15 +00:00
|
|
|
VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
|
|
|
|
VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
|
|
|
|
|
2012-03-10 06:38:26 +00:00
|
|
|
Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
|
|
|
|
clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
|
2009-12-01 11:32:04 +00:00
|
|
|
}
|
2010-08-07 07:38:02 +00:00
|
|
|
|
2014-07-31 14:20:36 +00:00
|
|
|
BufferListItem = ATOMIC_LOAD(&ALSource->queue);
|
2010-08-07 07:38:02 +00:00
|
|
|
while(BufferListItem != NULL)
|
|
|
|
{
|
|
|
|
ALbuffer *ALBuffer;
|
|
|
|
if((ALBuffer=BufferListItem->buffer) != NULL)
|
|
|
|
{
|
2012-04-26 07:59:17 +00:00
|
|
|
/* Calculate fixed-point stepping value, based on the pitch, buffer
|
|
|
|
* frequency, and output frequency. */
|
2010-11-28 21:08:51 +00:00
|
|
|
Pitch = Pitch * ALBuffer->Frequency / Frequency;
|
2014-06-03 02:19:22 +00:00
|
|
|
if(Pitch > (ALfloat)MAX_PITCH)
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Step = MAX_PITCH<<FRACTIONBITS;
|
2010-11-27 01:47:43 +00:00
|
|
|
else
|
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Step = fastf2i(Pitch*FRACTIONONE);
|
|
|
|
if(voice->Step == 0)
|
|
|
|
voice->Step = 1;
|
2010-11-27 01:47:43 +00:00
|
|
|
}
|
2011-06-25 07:08:05 +00:00
|
|
|
|
2010-08-07 07:38:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
BufferListItem = BufferListItem->next;
|
|
|
|
}
|
2009-12-01 11:32:04 +00:00
|
|
|
|
2009-10-19 20:25:40 +00:00
|
|
|
{
|
2014-11-22 20:58:54 +00:00
|
|
|
MixGains *gains = voice->Direct.Gains[0];
|
2014-11-05 12:48:48 +00:00
|
|
|
ALfloat radius = ALSource->Radius;
|
2014-11-07 10:18:24 +00:00
|
|
|
ALfloat Target[MAX_OUTPUT_CHANNELS];
|
2012-04-28 20:06:16 +00:00
|
|
|
|
|
|
|
/* Normalize the length, and compute panned gains. */
|
2014-11-05 12:48:48 +00:00
|
|
|
if(!(Distance > FLT_EPSILON) && !(radius > FLT_EPSILON))
|
2014-11-04 11:33:35 +00:00
|
|
|
{
|
2014-11-05 12:48:48 +00:00
|
|
|
const ALfloat front[3] = { 0.0f, 0.0f, -1.0f };
|
|
|
|
ComputeDirectionalGains(Device, front, DryGain, Target);
|
2014-11-04 11:33:35 +00:00
|
|
|
}
|
2014-10-12 19:39:27 +00:00
|
|
|
else
|
2011-05-20 14:58:05 +00:00
|
|
|
{
|
2014-07-08 16:13:35 +00:00
|
|
|
ALfloat invlen = 1.0f/maxf(Distance, radius);
|
2011-05-20 14:58:05 +00:00
|
|
|
Position[0] *= invlen;
|
|
|
|
Position[1] *= invlen;
|
|
|
|
Position[2] *= invlen;
|
2014-11-04 11:33:35 +00:00
|
|
|
ComputeDirectionalGains(Device, Position, DryGain, Target);
|
2012-04-28 20:06:16 +00:00
|
|
|
}
|
2014-10-11 16:35:32 +00:00
|
|
|
|
2014-11-07 10:18:24 +00:00
|
|
|
for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
|
2014-10-11 16:35:32 +00:00
|
|
|
gains[j].Target = Target[j];
|
2014-10-02 06:50:57 +00:00
|
|
|
UpdateDryStepping(&voice->Direct, 1);
|
2014-03-23 10:03:03 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->IsHrtf = AL_FALSE;
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
2011-07-05 18:00:52 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2014-03-23 23:11:21 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].Gain.Target = WetGain[i];
|
2014-10-02 06:50:57 +00:00
|
|
|
UpdateWetStepping(&voice->Send[i]);
|
2014-03-23 23:11:21 +00:00
|
|
|
}
|
2009-12-09 15:21:59 +00:00
|
|
|
|
2013-05-28 04:57:22 +00:00
|
|
|
{
|
2014-05-17 14:17:48 +00:00
|
|
|
ALfloat gainhf = maxf(0.01f, DryGainHF);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat gainlf = maxf(0.01f, DryGainLF);
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Direct.Filters[0].ActiveType = AF_None;
|
|
|
|
if(gainhf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
|
|
|
|
if(gainlf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
|
2014-05-11 17:07:17 +00:00
|
|
|
hfscale, 0.0f
|
|
|
|
);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
|
2014-05-17 14:54:25 +00:00
|
|
|
lfscale, 0.0f
|
|
|
|
);
|
2013-05-28 04:57:22 +00:00
|
|
|
}
|
2009-10-21 20:08:50 +00:00
|
|
|
for(i = 0;i < NumSends;i++)
|
2013-05-28 04:57:22 +00:00
|
|
|
{
|
2014-05-17 14:17:48 +00:00
|
|
|
ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Send[i].Filters[0].ActiveType = AF_None;
|
|
|
|
if(gainhf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
|
|
|
|
if(gainlf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
|
2014-05-11 17:07:17 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
|
2014-05-11 17:07:17 +00:00
|
|
|
hfscale, 0.0f
|
|
|
|
);
|
2014-05-17 14:54:25 +00:00
|
|
|
ALfilterState_setParams(
|
2014-08-21 10:24:48 +00:00
|
|
|
&voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
|
2014-05-17 14:54:25 +00:00
|
|
|
lfscale, 0.0f
|
|
|
|
);
|
2013-05-28 04:57:22 +00:00
|
|
|
}
|
2007-11-14 02:02:18 +00:00
|
|
|
}
|
|
|
|
|
2009-08-27 02:15:17 +00:00
|
|
|
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALint aluF2I25(ALfloat val)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2013-03-17 16:07:55 +00:00
|
|
|
/* Clamp the value between -1 and +1. This handles that with only a single branch. */
|
|
|
|
if(fabsf(val) > 1.0f)
|
2013-03-22 18:21:21 +00:00
|
|
|
val = (ALfloat)((0.0f < val) - (val < 0.0f));
|
2013-04-22 07:52:50 +00:00
|
|
|
/* Convert to a signed integer, between -16777215 and +16777215. */
|
|
|
|
return fastf2i(val*16777215.0f);
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
2013-04-22 07:52:50 +00:00
|
|
|
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALfloat aluF2F(ALfloat val)
|
2013-04-22 07:52:50 +00:00
|
|
|
{ return val; }
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALint aluF2I(ALfloat val)
|
2013-04-22 07:52:50 +00:00
|
|
|
{ return aluF2I25(val)<<7; }
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALuint aluF2UI(ALfloat val)
|
2012-02-14 19:44:57 +00:00
|
|
|
{ return aluF2I(val)+2147483648u; }
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALshort aluF2S(ALfloat val)
|
2013-04-22 07:52:50 +00:00
|
|
|
{ return aluF2I25(val)>>9; }
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALushort aluF2US(ALfloat val)
|
2011-08-17 09:33:25 +00:00
|
|
|
{ return aluF2S(val)+32768; }
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALbyte aluF2B(ALfloat val)
|
2013-04-22 07:52:50 +00:00
|
|
|
{ return aluF2I25(val)>>17; }
|
2013-05-29 05:27:07 +00:00
|
|
|
static inline ALubyte aluF2UB(ALfloat val)
|
2012-02-14 19:44:57 +00:00
|
|
|
{ return aluF2B(val)+128; }
|
2010-11-21 10:51:18 +00:00
|
|
|
|
2012-09-11 13:41:24 +00:00
|
|
|
#define DECL_TEMPLATE(T, func) \
|
2014-11-08 00:00:07 +00:00
|
|
|
static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
|
2014-11-05 12:07:06 +00:00
|
|
|
ALuint SamplesToDo, ALuint numchans) \
|
2010-12-02 05:50:49 +00:00
|
|
|
{ \
|
2011-04-15 04:03:37 +00:00
|
|
|
ALuint i, j; \
|
2014-11-05 10:54:11 +00:00
|
|
|
for(j = 0;j < numchans;j++) \
|
2010-12-02 05:50:49 +00:00
|
|
|
{ \
|
2014-11-08 00:00:07 +00:00
|
|
|
const ALfloat *in = InBuffer[j]; \
|
|
|
|
T *restrict out = (T*)OutBuffer + j; \
|
2012-03-03 18:31:27 +00:00
|
|
|
for(i = 0;i < SamplesToDo;i++) \
|
2014-09-10 23:52:54 +00:00
|
|
|
out[i*numchans] = func(in[i]); \
|
2010-12-02 05:50:49 +00:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2012-09-11 13:41:24 +00:00
|
|
|
DECL_TEMPLATE(ALfloat, aluF2F)
|
|
|
|
DECL_TEMPLATE(ALuint, aluF2UI)
|
|
|
|
DECL_TEMPLATE(ALint, aluF2I)
|
|
|
|
DECL_TEMPLATE(ALushort, aluF2US)
|
|
|
|
DECL_TEMPLATE(ALshort, aluF2S)
|
|
|
|
DECL_TEMPLATE(ALubyte, aluF2UB)
|
|
|
|
DECL_TEMPLATE(ALbyte, aluF2B)
|
2010-12-03 00:36:37 +00:00
|
|
|
|
2010-12-02 05:50:49 +00:00
|
|
|
#undef DECL_TEMPLATE
|
|
|
|
|
|
|
|
|
2010-11-21 10:51:18 +00:00
|
|
|
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
|
|
|
|
{
|
|
|
|
ALuint SamplesToDo;
|
2011-08-31 03:13:42 +00:00
|
|
|
ALeffectslot **slot, **slot_end;
|
2014-08-21 10:24:48 +00:00
|
|
|
ALvoice *voice, *voice_end;
|
2011-08-29 02:28:41 +00:00
|
|
|
ALCcontext *ctx;
|
2012-09-16 08:35:16 +00:00
|
|
|
FPUCtl oldMode;
|
2010-12-02 05:50:49 +00:00
|
|
|
ALuint i, c;
|
2010-11-21 10:51:18 +00:00
|
|
|
|
2012-09-16 08:35:16 +00:00
|
|
|
SetMixerFPUMode(&oldMode);
|
2010-11-21 10:51:18 +00:00
|
|
|
|
|
|
|
while(size > 0)
|
|
|
|
{
|
2014-11-22 12:20:17 +00:00
|
|
|
ALuint outchanoffset = 0;
|
|
|
|
ALuint outchancount = device->NumChannels;
|
|
|
|
|
Keep track of the mix count
The purpose of this is to provide a safe way to be able to "swap" resources
used by the mixer from other threads without the need to block the mixer, as
well as a way to track when mixes have occurred. The idea is two-fold:
It provides a way to safely swap resources. If the mixer were to (atomically)
get a reference to an object to access it from, another thread would be able
allocate and prepare a new object then swap the reference to it with the stored
one. The other thread would then be able to wait until (count&1) is clear,
indicating the mixer is not running, before safely freeing the old object for
the mixer to use the new one.
It also provides a way to tell if the mixer has run. With this, a thread would
be able to read multiple values, which could be altered by the mixer, without
requiring a mixer lock. Comparing the before and after counts for inequality
would signify if the mixer has (started to) run, indicating the values may be
out of sync and should try getting them again. Of course, it will still need
something like a RWLock to ensure another (non-mixer) thread doesn't try to
write to the values at the same time.
Note that because of the possibility of overflow, the counter is not reliable
as an absolute count.
2014-03-20 02:00:54 +00:00
|
|
|
IncrementRef(&device->MixCount);
|
|
|
|
|
2011-08-17 01:33:10 +00:00
|
|
|
SamplesToDo = minu(size, BUFFERSIZE);
|
2014-11-21 21:45:57 +00:00
|
|
|
for(c = 0;c < device->NumChannels;c++)
|
2012-09-11 13:32:42 +00:00
|
|
|
memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
|
2014-11-22 12:20:17 +00:00
|
|
|
if(device->Hrtf)
|
|
|
|
{
|
|
|
|
outchanoffset = device->NumChannels;
|
|
|
|
outchancount = 2;
|
|
|
|
for(c = 0;c < outchancount;c++)
|
|
|
|
memset(device->DryBuffer[outchanoffset+c], 0, SamplesToDo*sizeof(ALfloat));
|
|
|
|
}
|
2010-11-21 10:51:18 +00:00
|
|
|
|
2014-11-01 22:55:18 +00:00
|
|
|
V0(device->Backend,lock)();
|
2014-11-22 12:20:17 +00:00
|
|
|
V(device->Synth,process)(SamplesToDo, &device->DryBuffer[outchanoffset]);
|
2013-11-28 02:52:56 +00:00
|
|
|
|
2014-08-01 09:04:40 +00:00
|
|
|
ctx = ATOMIC_LOAD(&device->ContextList);
|
2011-08-29 02:28:41 +00:00
|
|
|
while(ctx)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2011-08-29 07:50:55 +00:00
|
|
|
ALenum DeferUpdates = ctx->DeferUpdates;
|
|
|
|
ALenum UpdateSources = AL_FALSE;
|
2011-07-11 08:05:42 +00:00
|
|
|
|
2011-08-23 00:13:03 +00:00
|
|
|
if(!DeferUpdates)
|
2014-07-26 10:00:49 +00:00
|
|
|
UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);
|
2011-07-11 08:05:42 +00:00
|
|
|
|
2012-10-09 13:19:36 +00:00
|
|
|
if(UpdateSources)
|
2012-10-12 14:38:29 +00:00
|
|
|
CalcListenerParams(ctx->Listener);
|
2012-10-09 13:19:36 +00:00
|
|
|
|
2012-04-26 07:59:17 +00:00
|
|
|
/* source processing */
|
2014-08-21 10:24:48 +00:00
|
|
|
voice = ctx->Voices;
|
|
|
|
voice_end = voice + ctx->VoiceCount;
|
|
|
|
while(voice != voice_end)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
ALsource *source = voice->Source;
|
2014-08-21 04:35:18 +00:00
|
|
|
if(!source) goto next;
|
2014-03-19 02:56:25 +00:00
|
|
|
|
2014-03-19 20:14:11 +00:00
|
|
|
if(source->state != AL_PLAYING && source->state != AL_PAUSED)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Source = NULL;
|
2014-08-21 04:35:18 +00:00
|
|
|
goto next;
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
2014-07-26 10:00:49 +00:00
|
|
|
if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
|
2011-08-29 07:50:55 +00:00
|
|
|
UpdateSources))
|
2014-08-21 10:24:48 +00:00
|
|
|
voice->Update(voice, source, ctx);
|
2010-11-21 10:51:18 +00:00
|
|
|
|
2014-03-19 20:14:11 +00:00
|
|
|
if(source->state != AL_PAUSED)
|
2014-08-21 10:24:48 +00:00
|
|
|
MixSource(voice, source, device, SamplesToDo);
|
2014-08-21 04:35:18 +00:00
|
|
|
next:
|
2014-08-21 10:24:48 +00:00
|
|
|
voice++;
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* effect slot processing */
|
2014-03-21 07:54:37 +00:00
|
|
|
slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
|
|
|
|
slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
|
2011-08-31 03:13:42 +00:00
|
|
|
while(slot != slot_end)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2014-07-26 10:00:49 +00:00
|
|
|
if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
|
2013-11-03 00:30:28 +00:00
|
|
|
V((*slot)->EffectState,update)(device, *slot);
|
2011-07-16 09:41:02 +00:00
|
|
|
|
2013-11-03 00:30:28 +00:00
|
|
|
V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
|
2014-11-07 11:43:33 +00:00
|
|
|
device->DryBuffer, device->NumChannels);
|
2010-11-21 10:51:18 +00:00
|
|
|
|
|
|
|
for(i = 0;i < SamplesToDo;i++)
|
2012-09-16 15:27:50 +00:00
|
|
|
(*slot)->WetBuffer[0][i] = 0.0f;
|
2011-08-31 03:13:42 +00:00
|
|
|
|
|
|
|
slot++;
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
2011-08-29 02:28:41 +00:00
|
|
|
ctx = ctx->next;
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
2012-01-20 03:30:03 +00:00
|
|
|
|
|
|
|
slot = &device->DefaultSlot;
|
2012-01-26 02:48:26 +00:00
|
|
|
if(*slot != NULL)
|
2012-01-20 03:30:03 +00:00
|
|
|
{
|
2014-07-26 10:00:49 +00:00
|
|
|
if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
|
2013-11-03 00:30:28 +00:00
|
|
|
V((*slot)->EffectState,update)(device, *slot);
|
2012-01-20 03:30:03 +00:00
|
|
|
|
2013-11-03 00:30:28 +00:00
|
|
|
V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
|
2014-11-07 11:43:33 +00:00
|
|
|
device->DryBuffer, device->NumChannels);
|
2012-01-20 03:30:03 +00:00
|
|
|
|
2012-01-26 02:48:26 +00:00
|
|
|
for(i = 0;i < SamplesToDo;i++)
|
2012-09-16 15:27:50 +00:00
|
|
|
(*slot)->WetBuffer[0][i] = 0.0f;
|
2012-01-26 02:48:26 +00:00
|
|
|
}
|
2014-02-02 00:37:11 +00:00
|
|
|
|
|
|
|
/* Increment the clock time. Every second's worth of samples is
|
|
|
|
* converted and added to clock base so that large sample counts don't
|
|
|
|
* overflow during conversion. This also guarantees an exact, stable
|
|
|
|
* conversion. */
|
|
|
|
device->SamplesDone += SamplesToDo;
|
|
|
|
device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
|
|
|
|
device->SamplesDone %= device->Frequency;
|
2014-11-01 22:55:18 +00:00
|
|
|
V0(device->Backend,unlock)();
|
2010-11-21 10:51:18 +00:00
|
|
|
|
2014-11-22 12:20:17 +00:00
|
|
|
if(device->Hrtf)
|
|
|
|
{
|
|
|
|
HrtfMixerFunc HrtfMix = SelectHrtfMixer();
|
|
|
|
ALuint irsize = GetHrtfIrSize(device->Hrtf);
|
|
|
|
for(c = 0;c < device->NumChannels;c++)
|
|
|
|
HrtfMix(&device->DryBuffer[outchanoffset], device->DryBuffer[c], device->Hrtf_Offset, irsize,
|
|
|
|
&device->Hrtf_Params[c], &device->Hrtf_State[c], SamplesToDo);
|
|
|
|
device->Hrtf_Offset += SamplesToDo;
|
|
|
|
}
|
|
|
|
else if(device->Bs2b)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2014-03-23 14:31:33 +00:00
|
|
|
/* Apply binaural/crossfeed filter */
|
|
|
|
for(i = 0;i < SamplesToDo;i++)
|
2012-03-03 17:41:16 +00:00
|
|
|
{
|
2012-09-11 13:32:42 +00:00
|
|
|
float samples[2];
|
2014-11-05 12:11:18 +00:00
|
|
|
samples[0] = device->DryBuffer[0][i];
|
|
|
|
samples[1] = device->DryBuffer[1][i];
|
2014-03-23 14:31:33 +00:00
|
|
|
bs2b_cross_feed(device->Bs2b, samples);
|
2014-11-05 12:11:18 +00:00
|
|
|
device->DryBuffer[0][i] = samples[0];
|
|
|
|
device->DryBuffer[1][i] = samples[1];
|
2011-07-30 12:43:47 +00:00
|
|
|
}
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 22:42:36 +00:00
|
|
|
if(buffer)
|
2010-11-21 10:51:18 +00:00
|
|
|
{
|
2011-08-12 22:42:36 +00:00
|
|
|
switch(device->FmtType)
|
|
|
|
{
|
|
|
|
case DevFmtByte:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALbyte(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALbyte);
|
2011-08-12 22:42:36 +00:00
|
|
|
break;
|
|
|
|
case DevFmtUByte:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALubyte(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALubyte);
|
2011-08-12 22:42:36 +00:00
|
|
|
break;
|
|
|
|
case DevFmtShort:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALshort(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALshort);
|
2011-08-12 22:42:36 +00:00
|
|
|
break;
|
|
|
|
case DevFmtUShort:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALushort(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALushort);
|
2012-02-14 19:44:57 +00:00
|
|
|
break;
|
|
|
|
case DevFmtInt:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALint(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALint);
|
2012-02-14 19:44:57 +00:00
|
|
|
break;
|
|
|
|
case DevFmtUInt:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALuint(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALuint);
|
2011-08-12 22:42:36 +00:00
|
|
|
break;
|
|
|
|
case DevFmtFloat:
|
2014-11-22 12:20:17 +00:00
|
|
|
Write_ALfloat(&device->DryBuffer[outchanoffset], buffer, SamplesToDo, outchancount);
|
|
|
|
buffer = (char*)buffer + SamplesToDo*outchancount*sizeof(ALfloat);
|
2011-08-12 22:42:36 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size -= SamplesToDo;
|
Keep track of the mix count
The purpose of this is to provide a safe way to be able to "swap" resources
used by the mixer from other threads without the need to block the mixer, as
well as a way to track when mixes have occurred. The idea is two-fold:
It provides a way to safely swap resources. If the mixer were to (atomically)
get a reference to an object to access it from, another thread would be able
allocate and prepare a new object then swap the reference to it with the stored
one. The other thread would then be able to wait until (count&1) is clear,
indicating the mixer is not running, before safely freeing the old object for
the mixer to use the new one.
It also provides a way to tell if the mixer has run. With this, a thread would
be able to read multiple values, which could be altered by the mixer, without
requiring a mixer lock. Comparing the before and after counts for inequality
would signify if the mixer has (started to) run, indicating the values may be
out of sync and should try getting them again. Of course, it will still need
something like a RWLock to ensure another (non-mixer) thread doesn't try to
write to the values at the same time.
Note that because of the possibility of overflow, the counter is not reliable
as an absolute count.
2014-03-20 02:00:54 +00:00
|
|
|
IncrementRef(&device->MixCount);
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
2012-09-16 08:35:16 +00:00
|
|
|
RestoreFPUMode(&oldMode);
|
2010-11-21 10:51:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-27 02:15:17 +00:00
|
|
|
ALvoid aluHandleDisconnect(ALCdevice *device)
|
|
|
|
{
|
2011-08-29 02:28:41 +00:00
|
|
|
ALCcontext *Context;
|
2009-10-20 18:54:04 +00:00
|
|
|
|
2011-09-11 02:22:46 +00:00
|
|
|
device->Connected = ALC_FALSE;
|
|
|
|
|
2014-08-01 09:04:40 +00:00
|
|
|
Context = ATOMIC_LOAD(&device->ContextList);
|
2011-08-29 02:28:41 +00:00
|
|
|
while(Context)
|
2009-08-27 02:15:17 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
ALvoice *voice, *voice_end;
|
2009-08-27 02:15:17 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice = Context->Voices;
|
|
|
|
voice_end = voice + Context->VoiceCount;
|
|
|
|
while(voice != voice_end)
|
2009-08-27 02:15:17 +00:00
|
|
|
{
|
2014-08-21 10:24:48 +00:00
|
|
|
ALsource *source = voice->Source;
|
|
|
|
voice->Source = NULL;
|
2014-08-21 04:35:18 +00:00
|
|
|
|
|
|
|
if(source && source->state == AL_PLAYING)
|
2009-08-27 02:15:17 +00:00
|
|
|
{
|
2014-03-19 02:56:25 +00:00
|
|
|
source->state = AL_STOPPED;
|
2014-07-31 14:20:36 +00:00
|
|
|
ATOMIC_STORE(&source->current_buffer, NULL);
|
2014-03-19 02:56:25 +00:00
|
|
|
source->position = 0;
|
|
|
|
source->position_fraction = 0;
|
2009-08-27 02:15:17 +00:00
|
|
|
}
|
2014-08-21 04:35:18 +00:00
|
|
|
|
2014-08-21 10:24:48 +00:00
|
|
|
voice++;
|
2009-08-27 02:15:17 +00:00
|
|
|
}
|
2014-08-21 10:24:48 +00:00
|
|
|
Context->VoiceCount = 0;
|
2011-08-29 02:28:41 +00:00
|
|
|
|
|
|
|
Context = Context->next;
|
2009-08-27 02:15:17 +00:00
|
|
|
}
|
|
|
|
}
|