Compare commits

..

68 Commits

Author SHA1 Message Date
Chris Robinson 67d67a3bf6 Release 1.6.372 2008-11-21 09:16:29 -08:00
Chris Robinson 591de1ecb4 Wait until one full fragment is empty before mixing 2008-11-21 07:52:13 -08:00
Chris Robinson 3dad17c263 Make the DSound emulated fragment count configurable 2008-11-21 07:48:03 -08:00
Chris Robinson eefc18170d Fix a comment 2008-11-20 10:09:37 -08:00
Chris Robinson 5f84c5339d Fix early reflection input 2008-11-19 09:14:40 -08:00
Chris Robinson 2d461379ef Handle ALSA capture errors a bit better 2008-11-19 09:01:03 -08:00
Chris Robinson c8123756ff Simplify in-sample low-pass filter coefficient calculation 2008-11-18 06:35:00 -08:00
Chris Robinson 76c7789ee7 Fix low-pass coefficient calculation 2008-11-18 04:31:24 -08:00
Chris Robinson 13a2e6ef1f Don't calculate reverb HF limit if air absorption is 1 2008-11-18 03:26:02 -08:00
Chris Robinson 0ecb34b850 Non-cross-compiled DLLs shouldn't have lib prefixed 2008-11-18 03:24:49 -08:00
Chris Robinson 1f86c48d95 Remove outdated comments and add copyright header 2008-11-17 09:32:25 -08:00
Chris Robinson 7e1295df9a DirectSound is not explicitly dependant on windows.h 2008-11-16 04:39:12 -08:00
Chris Robinson 482b160c8a Remove unneeded macro 2008-11-16 01:07:39 -08:00
Chris Robinson 181eb95b13 Use a better dB-to-linear gain convertion 2008-11-16 00:57:35 -08:00
Chris Robinson c0ccd31a3e Implement a new reverb effect
Code created and graciously provided by Christopher Fitzgerald
2008-11-16 00:29:49 -08:00
Chris Robinson d72b132c57 Add an option to disable specific EFX effect types 2008-11-14 07:13:59 -08:00
Chris Robinson 506912aed7 Add cross-compiling option 2008-11-13 23:13:15 -08:00
Chris Robinson 670d70d3c9 Allow specifying another config file with the ALSOFT_CONF env var 2008-11-13 07:58:39 -08:00
Chris Robinson 010f7d12f4 Don't ramp gains when starting a sound from the beginning 2008-11-13 05:48:38 -08:00
Chris Robinson da684564ea Avoid unnecessary floating-point math 2008-11-11 17:59:55 -08:00
Chris Robinson fc4c867f27 Add initial AL_EXTX_buffer_sub_data support
Note that this is an in-development extension, as noted by the EXTX moniker
instead of EXT. It's behavior is subject to change, and the extension string
will be removed (replaced with the official string once it's finalized).
Developers are discouraged from using this in production code, though feel
free to play around with it.
2008-11-11 05:57:32 -08:00
Chris Robinson 9ba30c4e20 Fix Win32 thread handle leak 2008-11-05 19:42:56 -08:00
Chris Robinson 15334e56cd Be more flexible with channel count when loading IMA4 data 2008-11-02 15:30:56 -08:00
Chris Robinson ffa42ff22c Seperate data converters into reusable functions 2008-11-02 01:24:57 -07:00
Chris Robinson a7c62dbabc More padding fixes 2008-11-01 16:37:32 -07:00
Chris Robinson eda1e41152 More buffer conversion refactoring 2008-11-01 16:35:16 -07:00
Chris Robinson af5a5b76ec Padding is not dependant on the frequency cutoff anymore 2008-10-31 23:32:28 -07:00
Chris Robinson 87f3a0dc16 Restructure buffer data conversion code a bit 2008-10-31 22:13:35 -07:00
Chris Robinson 2c80a80704 Fix typo preventing capture from opening 2008-10-27 23:37:56 -07:00
Chris Robinson 301a4c4a95 Append the driver and its version to the AL version string 2008-10-25 15:48:17 -07:00
Chris Robinson 8fc4a3b724 Make sure an appropriate error is set when opening a device fails 2008-10-24 19:58:49 -07:00
Chris Robinson cb6f040005 Use plughw for capture so ALSA can convert capture data 2008-10-14 09:50:37 -07:00
Chris Robinson b91c2e4a99 Include float.h if it exists, for _RC_CHOP and _MCW_RC 2008-10-14 09:47:32 -07:00
Chris Robinson 59a71b1454 Remove another unused source member 2008-10-10 01:31:31 -07:00
Chris Robinson 36f133a5ae Use a modulo to keep the buffer position in range for looping sources
A high pitch and low buffer size can cause a lot of unnecessary iterations
otherwise, that just decrement the position
2008-10-10 01:13:32 -07:00
Chris Robinson 74a58c0d09 Clamp source position to the buffer size when it stops 2008-10-09 23:54:31 -07:00
Chris Robinson bfa1107781 Remove unneeded source member variable 2008-10-09 23:44:48 -07:00
Chris Robinson 11397f7667 Commit missing changes 2008-10-09 20:58:12 -07:00
Chris Robinson 6e9e8239ef Only send one channel through the wet path 2008-10-09 04:02:34 -07:00
Chris Robinson af9932d28b Increase max pitch to 65536
This should be safe now
2008-10-09 02:50:00 -07:00
Chris Robinson 87ff8a65e9 Simplify the lerp function 2008-10-09 02:32:47 -07:00
Chris Robinson 7b6f207790 Don't apply the wet path for multi-channel buffers 2008-10-09 02:28:52 -07:00
Chris Robinson 8672008e43 Skip mixing if the read position is beyond the end of the buffer 2008-10-09 01:17:39 -07:00
Chris Robinson c8cd193346 The wet path should be silent if no effect is set on the slot 2008-10-09 01:07:02 -07:00
Chris Robinson be292e5f0b Don't hold the whole-number position in the fractional value
This will help prevent overflows when the max pitch is increased
2008-10-02 23:53:46 -07:00
Chris Robinson 3863dcc9cb Use a new low-pass filter, based on the I3DL2 spec
Many thanks to Christopher Fitzgerald, for helping with it
2008-10-02 22:20:42 -07:00
Chris Robinson a2568409fc Implement non-mmap ALSA capture 2008-09-29 17:24:50 -07:00
Chris Robinson 6567cdd7b5 Air absorption factor is applied to the dB value, not linear gain 2008-09-22 17:01:47 -07:00
Chris Robinson 5bbf55a401 Add a variable to override the default library type with 2008-09-16 07:43:38 -07:00
Chris Robinson 4a530e2146 Fixup some source parameter calculations 2008-09-16 07:36:48 -07:00
Chris Robinson 27ba8f7b60 Fix function pointer declarations 2008-09-16 06:19:27 -07:00
Chris Robinson 6bfdb57a5b Use a 12dB/oct rolloff instead of 24 for the lowpass filter 2008-09-13 02:46:14 -07:00
Chris Robinson 26e8ea60a5 Store pi as a static const 2008-09-13 00:44:48 -07:00
Chris Robinson f4ea188ffa Fix typo to get the proper minor ALC version 2008-09-12 18:07:12 -07:00
Chris Robinson 1266580420 Print EFX info when the extension is available 2008-09-12 18:05:23 -07:00
Chris Robinson 16d96eed7b Add a Solaris playback backend 2008-09-07 14:34:14 -07:00
Chris Robinson fa76168683 Clear the end of the buffer when at the end of the queue and not looping 2008-09-06 14:08:53 -07:00
Chris Robinson 5f3329b2c9 Don't export extension function symbols from the lib 2008-09-06 13:45:27 -07:00
Chris Robinson db541f3cfa Remove unneeded source struct member 2008-08-15 17:43:07 -07:00
Chris Robinson 3e19ba6ca8 Clear channel volumes when starting a source 2008-08-15 16:33:47 -07:00
Chris Robinson ac8c082b89 Overwrite the input wet sample with the output 2008-08-14 20:44:55 -07:00
Chris Robinson 084df2a229 Allow setting the EFX doppler factor source property 2008-08-14 16:14:16 -07:00
Chris Robinson 22557070ec Ramp channel gains to remove pops and clicks from abrupt changes
Thanks to Christopher Fitzgerald for helping me work on it
2008-08-14 05:43:52 -07:00
Chris Robinson f8ef66954c Include fenv.h if it exists for fesetround 2008-08-08 08:12:41 -07:00
Chris Robinson ef59901e7c Set FPU mode to round toward zero for mixing 2008-08-08 07:32:21 -07:00
Chris Robinson cfe620ccb5 Remove unnecessary casting 2008-08-08 00:21:25 -07:00
Chris Robinson 453b015225 Prevent a 0 or negative increment for the buffer position
Thanks to Christopher Fitzgerald for pointing these last two problems out
2008-08-05 20:51:30 -07:00
Chris Robinson c1cf9ae8f6 Pass a dummy variable to CreateThread to satisfy Win9x 2008-08-05 20:19:13 -07:00
29 changed files with 2164 additions and 1361 deletions
+64 -25
View File
@@ -58,6 +58,9 @@ static struct {
#ifdef HAVE_OSS
{ "oss", alc_oss_init, EmptyFuncs },
#endif
#ifdef HAVE_SOLARIS
{ "solaris", alc_solaris_init, EmptyFuncs },
#endif
#ifdef HAVE_DSOUND
{ "dsound", alcDSoundInit, EmptyFuncs },
#endif
@@ -306,6 +309,37 @@ static void InitAL(void)
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
str = GetConfigValue(NULL, "excludefx", "");
if(str[0])
{
const struct {
const char *name;
int type;
} EffectList[] = {
{ "reverb", REVERB },
{ NULL, 0 }
};
int n;
size_t len;
const char *next = str;
do {
str = next;
next = strchr(str, ',');
if(!str[0] || next == str)
continue;
len = (next ? ((size_t)(next-str)) : strlen(str));
for(n = 0;EffectList[n].name;n++)
{
if(len == strlen(EffectList[n].name) &&
strncmp(EffectList[n].name, str, len) == 0)
DisabledEffects[EffectList[n].type] = AL_TRUE;
}
} while(next++);
}
}
}
@@ -441,7 +475,7 @@ static ALvoid InitContext(ALCcontext *pContext)
pContext->lNumStereoSources = 1;
pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources;
pContext->ExtensionList = "AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic";
pContext->ExtensionList = "AL_EXTX_buffer_sub_data AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic";
level = GetConfigValueInt(NULL, "cf_level", 0);
if(level > 0 && level <= 6)
@@ -484,44 +518,46 @@ ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, AL
InitAL();
if(SampleSize <= 0)
{
SetALCError(ALC_INVALID_VALUE);
return NULL;
}
if(deviceName && !deviceName[0])
deviceName = NULL;
pDevice = malloc(sizeof(ALCdevice));
if (pDevice)
{
if (SampleSize > 0)
//Initialise device structure
memset(pDevice, 0, sizeof(ALCdevice));
//Validate device
pDevice->IsCaptureDevice = AL_TRUE;
pDevice->Frequency = frequency;
pDevice->Format = format;
for(i = 0;BackendList[i].Init;i++)
{
//Initialise device structure
memset(pDevice, 0, sizeof(ALCdevice));
//Validate device
pDevice->IsCaptureDevice = AL_TRUE;
pDevice->Frequency = frequency;
pDevice->Format = format;
for(i = 0;BackendList[i].Init;i++)
pDevice->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize))
{
pDevice->Funcs = &BackendList[i].Funcs;
if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize))
{
SuspendContext(NULL);
pDevice->next = g_pDeviceList;
g_pDeviceList = pDevice;
g_ulDeviceCount++;
ProcessContext(NULL);
SuspendContext(NULL);
pDevice->next = g_pDeviceList;
g_pDeviceList = pDevice;
g_ulDeviceCount++;
ProcessContext(NULL);
DeviceFound = ALC_TRUE;
break;
}
DeviceFound = ALC_TRUE;
break;
}
}
else
SetALCError(ALC_INVALID_VALUE);
if(!DeviceFound)
{
SetALCError(ALC_INVALID_VALUE);
free(pDevice);
pDevice = NULL;
}
@@ -1246,10 +1282,13 @@ ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName)
if (!bDeviceFound)
{
// No suitable output device found
SetALCError(ALC_INVALID_VALUE);
free(device);
device = NULL;
}
}
else
SetALCError(ALC_OUT_OF_MEMORY);
return device;
}
+298 -305
View File
@@ -31,7 +31,13 @@
#include "alThunk.h"
#include "alListener.h"
#include "alAuxEffectSlot.h"
#include "alu.h"
#include "bs2b.h"
#include "alReverb.h"
#if defined (HAVE_FLOAT_H)
#include <float.h>
#endif
#if defined(HAVE_STDINT_H)
#include <stdint.h>
@@ -67,20 +73,11 @@ typedef long long ALint64;
#define BUFFERSIZE 24000
#define FRACTIONBITS 14
#define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
#define MAX_PITCH 4
#define MAX_PITCH 65536
enum {
FRONT_LEFT = 0,
FRONT_RIGHT,
SIDE_LEFT,
SIDE_RIGHT,
BACK_LEFT,
BACK_RIGHT,
CENTER,
LFE,
OUTPUTCHANNELS
};
/* Minimum ramp length in milliseconds. The value below was chosen to
* adequately reduce clicks and pops from harsh gain changes. */
#define MIN_RAMP_LENGTH 16
ALboolean DuplicateStereo = AL_FALSE;
@@ -165,35 +162,18 @@ __inline ALuint aluChannelsFromFormat(ALenum format)
static __inline ALfloat lpFilter(FILTER *iir, ALfloat input)
{
unsigned int i;
float *hist1_ptr,*hist2_ptr,*coef_ptr;
ALfloat output,new_hist,history1,history2;
ALfloat *history = iir->history;
ALfloat a = iir->coeff;
ALfloat output = input;
coef_ptr = iir->coef; /* coefficient pointer */
hist1_ptr = iir->history; /* first history */
hist2_ptr = hist1_ptr + 1; /* next history */
/* 1st number of coefficients array is overall input scale factor,
* or filter gain */
output = input * (*coef_ptr++);
for(i = 0;i < FILTER_SECTIONS;i++)
{
history1 = *hist1_ptr; /* history values */
history2 = *hist2_ptr;
output = output - history1 * (*coef_ptr++);
new_hist = output - history2 * (*coef_ptr++); /* poles */
output = new_hist + history1 * (*coef_ptr++);
output = output + history2 * (*coef_ptr++); /* zeros */
*hist2_ptr++ = *hist1_ptr;
*hist1_ptr++ = new_hist;
hist1_ptr++;
hist2_ptr++;
}
output = output + (history[0]-output)*a;
history[0] = output;
output = output + (history[1]-output)*a;
history[1] = output;
output = output + (history[2]-output)*a;
history[2] = output;
output = output + (history[3]-output)*a;
history[3] = output;
return output;
}
@@ -246,10 +226,6 @@ static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3])
memcpy(vector, result, sizeof(result));
}
static __inline ALfloat aluComputeSample(ALfloat GainHF, ALfloat sample, ALfloat LowSample)
{
return LowSample + ((sample - LowSample) * GainHF);
}
static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
ALenum isMono, ALenum OutputFormat,
@@ -270,6 +246,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
ALfloat RoomRolloff;
ALfloat DryGainHF = 1.0f;
ALfloat WetGainHF = 1.0f;
ALfloat cw, a, g;
//Get context properties
DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
@@ -339,7 +316,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
//2. Calculate distance attenuation
Distance = aluSqrt(aluDotproduct(Position, Position));
if(ALSource->Send[0].Slot && !ALSource->Send[0].Slot->AuxSendAuto)
if(ALSource->Send[0].Slot)
{
if(ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB)
RoomRolloff += ALSource->Send[0].Slot->effect.Reverb.RoomRolloffFactor;
@@ -395,19 +372,33 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
break;
case AL_NONE:
default:
flAttenuation = 1.0f;
RoomAttenuation = 1.0f;
break;
}
// Distance-based air absorption
if(ALSource->AirAbsorptionFactor > 0.0f && ALContext->DistanceModel != AL_NONE)
{
ALfloat dist = Distance-MinDist;
ALfloat absorb;
if(dist < 0.0f) dist = 0.0f;
// Absorption calculation is done in dB
absorb = (ALSource->AirAbsorptionFactor*AIRABSORBGAINDBHF) *
(Distance*MetersPerUnit);
// Convert dB to linear gain before applying
absorb = pow(10.0, absorb/20.0);
DryGainHF *= absorb;
WetGainHF *= absorb;
}
// Source Gain + Attenuation and clamp to Min/Max Gain
DryMix = SourceVolume * flAttenuation;
DryMix = __min(DryMix,MaxVolume);
DryMix = __max(DryMix,MinVolume);
WetMix = SourceVolume * (ALSource->WetGainAuto ?
RoomAttenuation : 1.0f);
WetMix = SourceVolume * RoomAttenuation;
WetMix = __min(WetMix,MaxVolume);
WetMix = __max(WetMix,MinVolume);
@@ -418,6 +409,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
{
ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
DryMix *= ConeVolume;
if(ALSource->WetGainAuto)
WetMix *= ConeVolume;
if(ALSource->DryGainHFAuto)
@@ -428,6 +420,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
else if(Angle > OuterAngle)
{
ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
DryMix *= ConeVolume;
if(ALSource->WetGainAuto)
WetMix *= ConeVolume;
if(ALSource->DryGainHFAuto)
@@ -435,8 +428,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
if(ALSource->WetGainHFAuto)
WetGainHF *= (1.0f+(OuterGainHF-1.0f));
}
else
ConeVolume = 1.0f;
//4. Calculate Velocity
if(DopplerFactor != 0.0f)
@@ -466,6 +457,34 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
else
pitch[0] = ALSource->flPitch;
if(ALSource->Send[0].Slot &&
ALSource->Send[0].Slot->effect.type != AL_EFFECT_NULL)
{
if(ALSource->Send[0].Slot->AuxSendAuto)
{
// Apply minimal attenuation in place of missing statistical
// reverb model.
WetMix *= pow(DryMix, 1.0f / 2.0f);
}
else
{
// If the slot's auxilliary send auto is off, the data sent to the
// effect slot is the same as the dry path, sans filter effects
WetMix = DryMix;
WetGainHF = DryGainHF;
}
// Note that this is really applied by the effect slot. However,
// it's easier (more optimal) to handle it here.
if(ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB)
WetGainHF *= ALSource->Send[0].Slot->effect.Reverb.GainHF;
}
else
{
WetMix = 0.0f;
WetGainHF = 1.0f;
}
//5. Apply filter gains and filters
switch(ALSource->DirectFilter.type)
{
@@ -483,29 +502,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
break;
}
if(ALSource->AirAbsorptionFactor > 0.0f)
DryGainHF *= pow(ALSource->AirAbsorptionFactor * AIRABSORBGAINHF,
Distance * MetersPerUnit);
if(ALSource->Send[0].Slot)
{
WetMix *= ALSource->Send[0].Slot->Gain;
if(ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB)
{
WetMix *= ALSource->Send[0].Slot->effect.Reverb.Gain;
WetGainHF *= ALSource->Send[0].Slot->effect.Reverb.GainHF;
WetGainHF *= pow(ALSource->Send[0].Slot->effect.Reverb.AirAbsorptionGainHF,
Distance * MetersPerUnit);
}
}
else
{
WetMix = 0.0f;
WetGainHF = 1.0f;
}
DryMix *= ListenerGain * ConeVolume;
DryMix *= ListenerGain;
WetMix *= ListenerGain;
//6. Convert normalized position into pannings, then into channel volumes
@@ -517,16 +514,10 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
PanningLR = 0.5f + 0.5f*Position[0];
drysend[FRONT_LEFT] = DryMix * aluSqrt(1.0f-PanningLR); //L Direct
drysend[FRONT_RIGHT] = DryMix * aluSqrt( PanningLR); //R Direct
drysend[BACK_LEFT] = drysend[FRONT_LEFT];
drysend[BACK_RIGHT] = drysend[FRONT_RIGHT];
drysend[SIDE_LEFT] = drysend[FRONT_LEFT];
drysend[SIDE_RIGHT] = drysend[FRONT_RIGHT];
wetsend[FRONT_LEFT] = WetMix * aluSqrt(1.0f-PanningLR); //L Room
wetsend[FRONT_RIGHT] = WetMix * aluSqrt( PanningLR); //R Room
wetsend[BACK_LEFT] = wetsend[FRONT_LEFT];
wetsend[BACK_RIGHT] = wetsend[FRONT_RIGHT];
wetsend[SIDE_LEFT] = wetsend[FRONT_LEFT];
wetsend[SIDE_RIGHT] = wetsend[FRONT_RIGHT];
drysend[BACK_LEFT] = 0.0f;
drysend[BACK_RIGHT] = 0.0f;
drysend[SIDE_LEFT] = 0.0f;
drysend[SIDE_RIGHT] = 0.0f;
break;
case 4:
/* TODO: Add center/lfe channel in spatial calculations? */
@@ -542,14 +533,8 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
drysend[FRONT_RIGHT] = DryMix * aluSqrt(( PanningLR)*(1.0f-PanningFB));
drysend[BACK_LEFT] = DryMix * aluSqrt((1.0f-PanningLR)*( PanningFB));
drysend[BACK_RIGHT] = DryMix * aluSqrt(( PanningLR)*( PanningFB));
drysend[SIDE_LEFT] = (drysend[FRONT_LEFT] +drysend[BACK_LEFT]) * 0.5f;
drysend[SIDE_RIGHT] = (drysend[FRONT_RIGHT]+drysend[BACK_RIGHT]) * 0.5f;
wetsend[FRONT_LEFT] = WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
wetsend[FRONT_RIGHT] = WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB));
wetsend[BACK_LEFT] = WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB));
wetsend[BACK_RIGHT] = WetMix * aluSqrt(( PanningLR)*( PanningFB));
wetsend[SIDE_LEFT] = (wetsend[FRONT_LEFT] +wetsend[BACK_LEFT]) * 0.5f;
wetsend[SIDE_RIGHT] = (wetsend[FRONT_RIGHT]+wetsend[BACK_RIGHT]) * 0.5f;
drysend[SIDE_LEFT] = 0.0f;
drysend[SIDE_RIGHT] = 0.0f;
break;
case 7:
case 8:
@@ -567,12 +552,6 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
drysend[SIDE_RIGHT] = DryMix * aluSqrt(( PanningLR)*( PanningFB));
drysend[FRONT_LEFT] = 0.0f;
drysend[FRONT_RIGHT] = 0.0f;
wetsend[BACK_LEFT] = WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
wetsend[BACK_RIGHT] = WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB));
wetsend[SIDE_LEFT] = WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB));
wetsend[SIDE_RIGHT] = WetMix * aluSqrt(( PanningLR)*( PanningFB));
wetsend[FRONT_LEFT] = 0.0f;
wetsend[FRONT_RIGHT] = 0.0f;
}
else
{
@@ -582,16 +561,30 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
drysend[SIDE_RIGHT] = DryMix * aluSqrt(( PanningLR)*( PanningFB));
drysend[BACK_LEFT] = 0.0f;
drysend[BACK_RIGHT] = 0.0f;
wetsend[FRONT_LEFT] = WetMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
wetsend[FRONT_RIGHT] = WetMix * aluSqrt(( PanningLR)*(1.0f-PanningFB));
wetsend[SIDE_LEFT] = WetMix * aluSqrt((1.0f-PanningLR)*( PanningFB));
wetsend[SIDE_RIGHT] = WetMix * aluSqrt(( PanningLR)*( PanningFB));
wetsend[BACK_LEFT] = 0.0f;
wetsend[BACK_RIGHT] = 0.0f;
}
default:
break;
}
*wetsend = WetMix;
// Update filter coefficients. Calculations based on the I3DL2 spec.
cw = cos(2.0f*3.141592654f * LOWPASSFREQCUTOFF / ALContext->Frequency);
// We use four chained one-pole filters, so we need to take the fourth
// root of the squared gain, which is the same as the square root of
// the base gain.
// Be careful with gains < 0.0001, as that causes the coefficient to
// head towards 1, which will flatten the signal
g = aluSqrt(__max(DryGainHF, 0.0001f));
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
ALSource->iirFilter.coeff = a;
g = aluSqrt(__max(WetGainHF, 0.0001f));
a = 0.0f;
if(g < 0.9999f) // 1-epsilon
a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
ALSource->Send[0].iirFilter.coeff = a;
*drygainhf = DryGainHF;
*wetgainhf = WetGainHF;
@@ -609,14 +602,7 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
drysend[BACK_RIGHT] = SourceVolume * ListenerGain;
drysend[CENTER] = SourceVolume * ListenerGain;
drysend[LFE] = SourceVolume * ListenerGain;
wetsend[FRONT_LEFT] = 0.0f;
wetsend[FRONT_RIGHT] = 0.0f;
wetsend[SIDE_LEFT] = 0.0f;
wetsend[SIDE_RIGHT] = 0.0f;
wetsend[BACK_LEFT] = 0.0f;
wetsend[BACK_RIGHT] = 0.0f;
wetsend[CENTER] = 0.0f;
wetsend[LFE] = 0.0f;
*wetsend = 0.0f;
WetGainHF = 1.0f;
*drygainhf = DryGainHF;
@@ -624,20 +610,30 @@ static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
}
}
static __inline ALshort lerp(ALshort val1, ALshort val2, ALint frac)
{
return val1 + (((val2-val1)*frac)>>FRACTIONBITS);
}
ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum format)
{
static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS];
static float WetBuffer[BUFFERSIZE][OUTPUTCHANNELS];
ALfloat DrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
ALfloat WetSend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
static float WetBuffer[BUFFERSIZE];
ALfloat newDrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
ALfloat newWetSend = 0.0f;
ALfloat DryGainHF = 0.0f;
ALfloat WetGainHF = 0.0f;
ALfloat *DrySend;
ALfloat *WetSend;
ALuint rampLength;
ALfloat dryGainStep[OUTPUTCHANNELS];
ALfloat wetGainStep;
ALuint BlockAlign,BufferSize;
ALuint DataSize=0,DataPosInt=0,DataPosFrac=0;
ALuint Channels,Frequency,ulExtraSamples;
ALfloat Pitch;
ALint Looping,State;
ALint fraction,increment;
ALint increment;
ALuint Buffer;
ALuint SamplesToDo;
ALsource *ALSource;
@@ -649,10 +645,21 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
ALbufferlistitem *BufferListItem;
ALuint loop;
ALint64 DataSize64,DataPos64;
FILTER *Filter;
FILTER *DryFilter, *WetFilter;
int fpuState;
SuspendContext(ALContext);
#if defined(HAVE_FESETROUND)
fpuState = fegetround();
fesetround(FE_TOWARDZERO);
#elif defined(HAVE__CONTROLFP)
fpuState = _controlfp(0, 0);
_controlfp(_RC_CHOP, _MCW_RC);
#else
(void)fpuState;
#endif
//Figure output format variables
BlockAlign = aluChannelsFromFormat(format);
BlockAlign *= aluBytesFromFormat(format);
@@ -661,13 +668,24 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
while(size > 0)
{
//Setup variables
ALEffectSlot = (ALContext ? ALContext->AuxiliaryEffectSlot : NULL);
ALSource = (ALContext ? ALContext->Source : NULL);
SamplesToDo = min(size, BUFFERSIZE);
if(ALContext)
{
ALEffectSlot = ALContext->AuxiliaryEffectSlot;
ALSource = ALContext->Source;
rampLength = ALContext->Frequency * MIN_RAMP_LENGTH / 1000;
}
else
{
ALEffectSlot = NULL;
ALSource = NULL;
rampLength = 0;
}
rampLength = max(rampLength, SamplesToDo);
//Clear mixing buffer
memset(WetBuffer, 0, SamplesToDo*sizeof(ALfloat));
memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
memset(WetBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
//Actual mixing loop
while(ALSource)
@@ -689,26 +707,52 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
Data = ALBuffer->data;
Channels = aluChannelsFromFormat(ALBuffer->format);
DataSize = ALBuffer->size;
Frequency = ALBuffer->frequency;
CalcSourceParams(ALContext, ALSource,
(Channels==1) ? AL_TRUE : AL_FALSE,
format, DrySend, WetSend, &Pitch,
&DryGainHF, &WetGainHF);
Pitch = (Pitch*Frequency) / ALContext->Frequency;
DataSize /= Channels * aluBytesFromFormat(ALBuffer->format);
//Get source info
Frequency = ALBuffer->frequency;
DataPosInt = ALSource->position;
DataPosFrac = ALSource->position_fraction;
Filter = &ALSource->iirFilter;
if(DataPosInt >= DataSize)
goto skipmix;
CalcSourceParams(ALContext, ALSource,
(Channels==1) ? AL_TRUE : AL_FALSE,
format, newDrySend, &newWetSend, &Pitch,
&DryGainHF, &WetGainHF);
Pitch = (Pitch*Frequency) / ALContext->Frequency;
//Get source info
DryFilter = &ALSource->iirFilter;
WetFilter = &ALSource->Send[0].iirFilter;
DrySend = ALSource->DryGains;
WetSend = &ALSource->WetGain;
//Compute the gain steps for each output channel
if(ALSource->FirstStart && DataPosInt == 0 && DataPosFrac == 0)
{
for(i = 0;i < OUTPUTCHANNELS;i++)
{
DrySend[i] = newDrySend[i];
dryGainStep[i] = 0;
}
*WetSend = newWetSend;
wetGainStep = 0;
}
else
{
for(i = 0;i < OUTPUTCHANNELS;i++)
dryGainStep[i] = (newDrySend[i]-DrySend[i]) / rampLength;
wetGainStep = (newWetSend-(*WetSend)) / rampLength;
}
ALSource->FirstStart = AL_FALSE;
//Compute 18.14 fixed point step
if(Pitch > (float)MAX_PITCH)
Pitch = (float)MAX_PITCH;
increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
if(increment > (MAX_PITCH<<FRACTIONBITS))
increment = (MAX_PITCH<<FRACTIONBITS);
if(increment <= 0)
increment = (1<<FRACTIONBITS);
//Figure out how many samples we can mix.
DataSize64 = DataSize;
@@ -744,26 +788,28 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
}
}
else
memset(&Data[DataSize*Channels], 0, (ALBuffer->padding*Channels*2));
}
BufferSize = min(BufferSize, (SamplesToDo-j));
//Actual sample mixing loop
k = 0;
Data += DataPosInt*Channels;
while(BufferSize--)
{
k = DataPosFrac>>FRACTIONBITS;
fraction = DataPosFrac&FRACTIONMASK;
for(i = 0;i < OUTPUTCHANNELS;i++)
DrySend[i] += dryGainStep[i];
*WetSend += wetGainStep;
if(Channels==1)
{
ALfloat sample, lowsamp, outsamp;
ALfloat sample, outsamp;
//First order interpolator
sample = (Data[k]*((1<<FRACTIONBITS)-fraction) +
Data[k+1]*fraction) >> FRACTIONBITS;
lowsamp = lpFilter(Filter, sample);
sample = lerp(Data[k], Data[k+1], DataPosFrac);
//Direct path final mix buffer and panning
outsamp = aluComputeSample(DryGainHF, sample, lowsamp);
outsamp = lpFilter(DryFilter, sample);
DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT];
DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT];
DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT];
@@ -771,25 +817,18 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT];
DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT];
//Room path final mix buffer and panning
outsamp = aluComputeSample(WetGainHF, sample, lowsamp);
WetBuffer[j][FRONT_LEFT] += outsamp*WetSend[FRONT_LEFT];
WetBuffer[j][FRONT_RIGHT] += outsamp*WetSend[FRONT_RIGHT];
WetBuffer[j][SIDE_LEFT] += outsamp*WetSend[SIDE_LEFT];
WetBuffer[j][SIDE_RIGHT] += outsamp*WetSend[SIDE_RIGHT];
WetBuffer[j][BACK_LEFT] += outsamp*WetSend[BACK_LEFT];
WetBuffer[j][BACK_RIGHT] += outsamp*WetSend[BACK_RIGHT];
outsamp = lpFilter(WetFilter, sample);
WetBuffer[j] += outsamp*(*WetSend);
}
else
{
ALfloat samp1, samp2;
//First order interpolator (front left)
samp1 = (ALfloat)((ALshort)(((Data[k*Channels ]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels ]*(fraction)))>>FRACTIONBITS));
samp1 = lerp(Data[k*Channels], Data[(k+1)*Channels], DataPosFrac);
DryBuffer[j][FRONT_LEFT] += samp1*DrySend[FRONT_LEFT];
WetBuffer[j][FRONT_LEFT] += samp1*WetSend[FRONT_LEFT];
//First order interpolator (front right)
samp2 = (ALfloat)((ALshort)(((Data[k*Channels+1]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+1]*(fraction)))>>FRACTIONBITS));
samp2 = lerp(Data[k*Channels+1], Data[(k+1)*Channels+1], DataPosFrac);
DryBuffer[j][FRONT_RIGHT] += samp2*DrySend[FRONT_RIGHT];
WetBuffer[j][FRONT_RIGHT] += samp2*WetSend[FRONT_RIGHT];
if(Channels >= 4)
{
int i = 2;
@@ -798,38 +837,32 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
if(Channels != 7)
{
//First order interpolator (center)
value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][CENTER] += value*DrySend[CENTER];
WetBuffer[j][CENTER] += value*WetSend[CENTER];
i++;
}
//First order interpolator (lfe)
value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][LFE] += value*DrySend[LFE];
WetBuffer[j][LFE] += value*WetSend[LFE];
i++;
}
//First order interpolator (back left)
value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT];
WetBuffer[j][BACK_LEFT] += value*WetSend[BACK_LEFT];
i++;
//First order interpolator (back right)
value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT];
WetBuffer[j][BACK_RIGHT] += value*WetSend[BACK_RIGHT];
i++;
if(Channels >= 7)
{
//First order interpolator (side left)
value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT];
WetBuffer[j][SIDE_LEFT] += value*WetSend[SIDE_LEFT];
i++;
//First order interpolator (side right)
value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
value = lerp(Data[k*Channels+i], Data[(k+1)*Channels+i], DataPosFrac);
DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT];
WetBuffer[j][SIDE_RIGHT] += value*WetSend[SIDE_RIGHT];
i++;
}
}
@@ -837,20 +870,21 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
//Duplicate stereo channels on the back speakers
DryBuffer[j][BACK_LEFT] += samp1*DrySend[BACK_LEFT];
WetBuffer[j][BACK_LEFT] += samp1*WetSend[BACK_LEFT];
DryBuffer[j][BACK_RIGHT] += samp2*DrySend[BACK_RIGHT];
WetBuffer[j][BACK_RIGHT] += samp2*WetSend[BACK_RIGHT];
}
}
DataPosFrac += increment;
k += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
j++;
}
DataPosInt += (DataPosFrac>>FRACTIONBITS);
DataPosFrac = (DataPosFrac&FRACTIONMASK);
DataPosInt += k;
//Update source info
ALSource->position = DataPosInt;
ALSource->position_fraction = DataPosFrac;
skipmix: ;
}
//Handle looping sources
@@ -872,8 +906,6 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
BufferListItem = BufferListItem->next;
}
}
if(!Looping)
ALSource->BuffersProcessed++;
if(BufferListItem)
ALSource->ulBufferID = BufferListItem->buffer;
ALSource->position = DataPosInt-DataSize;
@@ -887,13 +919,15 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
/* alSourceStop */
ALSource->state = AL_STOPPED;
ALSource->inuse = AL_FALSE;
ALSource->BuffersPlayed = ALSource->BuffersProcessed = ALSource->BuffersInQueue;
ALSource->BuffersPlayed = ALSource->BuffersInQueue;
BufferListItem = ALSource->queue;
while(BufferListItem != NULL)
{
BufferListItem->bufferstate = PROCESSED;
BufferListItem = BufferListItem->next;
}
ALSource->position = DataSize;
ALSource->position_fraction = 0;
}
else
{
@@ -903,9 +937,6 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
ALSource->inuse = AL_TRUE;
ALSource->play = AL_TRUE;
ALSource->BuffersPlayed = 0;
ALSource->BufferPosition = 0;
ALSource->lBytesPlayed = 0;
ALSource->BuffersProcessed = 0;
BufferListItem = ALSource->queue;
while(BufferListItem != NULL)
{
@@ -914,7 +945,10 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
}
ALSource->ulBufferID = ALSource->queue->buffer;
ALSource->position = DataPosInt-DataSize;
if(ALSource->BuffersInQueue == 1)
ALSource->position = DataPosInt%DataSize;
else
ALSource->position = DataPosInt-DataSize;
ALSource->position_fraction = DataPosFrac;
}
}
@@ -932,52 +966,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
while(ALEffectSlot)
{
if(ALEffectSlot->effect.type == AL_EFFECT_REVERB)
{
ALfloat *DelayBuffer = ALEffectSlot->ReverbBuffer;
ALuint Pos = ALEffectSlot->ReverbPos;
ALuint LatePos = ALEffectSlot->ReverbLatePos;
ALuint ReflectPos = ALEffectSlot->ReverbReflectPos;
ALuint Length = ALEffectSlot->ReverbLength;
ALfloat DecayGain = ALEffectSlot->ReverbDecayGain;
ALfloat DecayHFRatio = ALEffectSlot->effect.Reverb.DecayHFRatio;
ALfloat ReflectGain = ALEffectSlot->effect.Reverb.ReflectionsGain;
ALfloat LateReverbGain = ALEffectSlot->effect.Reverb.LateReverbGain;
ALfloat sample, lowsample;
Filter = &ALEffectSlot->iirFilter;
for(i = 0;i < SamplesToDo;i++)
{
sample = WetBuffer[i][FRONT_LEFT] +WetBuffer[i][SIDE_LEFT] +WetBuffer[i][BACK_LEFT];
sample += WetBuffer[i][FRONT_RIGHT]+WetBuffer[i][SIDE_RIGHT]+WetBuffer[i][BACK_RIGHT];
DelayBuffer[Pos] = sample / 6.0f;
sample = DelayBuffer[ReflectPos] * ReflectGain;
DelayBuffer[LatePos] *= LateReverbGain;
Pos = (Pos+1) % Length;
lowsample = lpFilter(Filter, DelayBuffer[Pos]);
lowsample += (DelayBuffer[Pos]-lowsample) * DecayHFRatio;
DelayBuffer[LatePos] += lowsample * DecayGain;
sample += DelayBuffer[LatePos];
WetBuffer[i][FRONT_LEFT] += sample;
WetBuffer[i][FRONT_RIGHT] += sample;
WetBuffer[i][SIDE_LEFT] += sample;
WetBuffer[i][SIDE_RIGHT] += sample;
WetBuffer[i][BACK_LEFT] += sample;
WetBuffer[i][BACK_RIGHT] += sample;
LatePos = (LatePos+1) % Length;
ReflectPos = (ReflectPos+1) % Length;
}
ALEffectSlot->ReverbPos = Pos;
ALEffectSlot->ReverbLatePos = LatePos;
ALEffectSlot->ReverbReflectPos = ReflectPos;
}
VerbProcess(ALEffectSlot->ReverbState, SamplesToDo, WetBuffer, DryBuffer);
ALEffectSlot = ALEffectSlot->next;
}
@@ -988,8 +977,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
case AL_FORMAT_MONO8:
for(i = 0;i < SamplesToDo;i++)
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT]+DryBuffer[i][FRONT_RIGHT]+
WetBuffer[i][FRONT_LEFT]+WetBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT]+DryBuffer[i][FRONT_RIGHT])>>8)+128);
buffer = ((ALubyte*)buffer) + 1;
}
break;
@@ -999,8 +987,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
for(i = 0;i < SamplesToDo;i++)
{
float samples[2];
samples[0] = DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT];
samples[1] = DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT];
samples[0] = DryBuffer[i][FRONT_LEFT];
samples[1] = DryBuffer[i][FRONT_RIGHT];
bs2b_cross_feed(ALContext->bs2b, samples);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(samples[0])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(samples[1])>>8)+128);
@@ -1011,8 +999,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
for(i = 0;i < SamplesToDo;i++)
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
buffer = ((ALubyte*)buffer) + 2;
}
}
@@ -1020,28 +1008,28 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
case AL_FORMAT_QUAD8:
for(i = 0;i < SamplesToDo;i++)
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
buffer = ((ALubyte*)buffer) + 4;
}
break;
case AL_FORMAT_51CHN8:
for(i = 0;i < SamplesToDo;i++)
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
#ifdef _WIN32 /* Of course, Windows can't use the same ordering... */
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
#else
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
#endif
buffer = ((ALubyte*)buffer) + 6;
}
@@ -1049,40 +1037,40 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
case AL_FORMAT_61CHN8:
for(i = 0;i < SamplesToDo;i++)
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
#ifdef _WIN32
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
#else
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
#endif
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT] +WetBuffer[i][SIDE_LEFT])>>8)+128);
((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT] +WetBuffer[i][SIDE_RIGHT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT])>>8)+128);
((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT])>>8)+128);
buffer = ((ALubyte*)buffer) + 7;
}
break;
case AL_FORMAT_71CHN8:
for(i = 0;i < SamplesToDo;i++)
{
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT])>>8)+128);
((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128);
((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128);
#ifdef _WIN32
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
#else
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE])>>8)+128);
((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128);
((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128);
((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][CENTER])>>8)+128);
((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128);
#endif
((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT] +WetBuffer[i][SIDE_LEFT])>>8)+128);
((ALubyte*)buffer)[7] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT] +WetBuffer[i][SIDE_RIGHT])>>8)+128);
((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT])>>8)+128);
((ALubyte*)buffer)[7] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT])>>8)+128);
buffer = ((ALubyte*)buffer) + 8;
}
break;
@@ -1090,8 +1078,7 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
case AL_FORMAT_MONO16:
for(i = 0;i < SamplesToDo;i++)
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]+DryBuffer[i][FRONT_RIGHT]+
WetBuffer[i][FRONT_LEFT]+WetBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]+DryBuffer[i][FRONT_RIGHT]);
buffer = ((ALshort*)buffer) + 1;
}
break;
@@ -1101,8 +1088,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
for(i = 0;i < SamplesToDo;i++)
{
float samples[2];
samples[0] = DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT];
samples[1] = DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT];
samples[0] = DryBuffer[i][FRONT_LEFT];
samples[1] = DryBuffer[i][FRONT_RIGHT];
bs2b_cross_feed(ALContext->bs2b, samples);
((ALshort*)buffer)[0] = aluF2S(samples[0]);
((ALshort*)buffer)[1] = aluF2S(samples[1]);
@@ -1113,8 +1100,8 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
{
for(i = 0;i < SamplesToDo;i++)
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
buffer = ((ALshort*)buffer) + 2;
}
}
@@ -1122,28 +1109,28 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
case AL_FORMAT_QUAD16:
for(i = 0;i < SamplesToDo;i++)
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
buffer = ((ALshort*)buffer) + 4;
}
break;
case AL_FORMAT_51CHN16:
for(i = 0;i < SamplesToDo;i++)
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
#ifdef _WIN32
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT]);
#else
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE]);
#endif
buffer = ((ALshort*)buffer) + 6;
}
@@ -1151,40 +1138,40 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
case AL_FORMAT_61CHN16:
for(i = 0;i < SamplesToDo;i++)
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
#ifdef _WIN32
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_RIGHT]);
#else
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][LFE]);
#endif
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][SIDE_LEFT] +WetBuffer[i][SIDE_LEFT]);
((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_RIGHT] +WetBuffer[i][SIDE_RIGHT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][SIDE_LEFT]);
((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_RIGHT]);
buffer = ((ALshort*)buffer) + 7;
}
break;
case AL_FORMAT_71CHN16:
for(i = 0;i < SamplesToDo;i++)
{
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT] +WetBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]+WetBuffer[i][FRONT_RIGHT]);
((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]);
((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]);
#ifdef _WIN32
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT]);
#else
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT] +WetBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT] +WetBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][CENTER] +WetBuffer[i][CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE] +WetBuffer[i][LFE]);
((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]);
((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]);
((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][CENTER]);
((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE]);
#endif
((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_LEFT] +WetBuffer[i][SIDE_LEFT]);
((ALshort*)buffer)[7] = aluF2S(DryBuffer[i][SIDE_RIGHT] +WetBuffer[i][SIDE_RIGHT]);
((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_LEFT]);
((ALshort*)buffer)[7] = aluF2S(DryBuffer[i][SIDE_RIGHT]);
buffer = ((ALshort*)buffer) + 8;
}
break;
@@ -1196,5 +1183,11 @@ ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum forma
size -= SamplesToDo;
}
#if defined(HAVE_FESETROUND)
fesetround(fpuState);
#elif defined(HAVE__CONTROLFP)
_controlfp(fpuState, 0xfffff);
#endif
ProcessContext(ALContext);
}
+9
View File
@@ -250,6 +250,15 @@ void ReadALConfig(void)
}
}
#endif
if(getenv("ALSOFT_CONF"))
{
f = fopen(getenv("ALSOFT_CONF"), "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
}
void FreeALConfig(void)
+559
View File
@@ -0,0 +1,559 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2008 by Christopher Fitzgerald.
* 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
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alEffect.h"
#include "alReverb.h"
#ifdef HAVE_SQRTF
#define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
#else
#define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
#endif
// fixes for mingw32.
#if defined(max) && !defined(__max)
#define __max max
#endif
#if defined(min) && !defined(__min)
#define __min min
#endif
typedef struct DelayLine
{
// The delay lines use lengths that are powers of 2 to allow bitmasking
// instead of modulus wrapping.
ALuint Mask;
ALfloat *Line;
} DelayLine;
struct ALverbState
{
// All delay lines are allocated as a single buffer to reduce memory
// fragmentation and teardown code.
ALfloat *SampleBuffer;
// Master reverb gain.
ALfloat Gain;
// Initial reverb delay.
DelayLine Delay;
// The tap points for the initial delay. First tap goes to early
// reflections, the second to late reverb.
ALuint Tap[2];
struct {
// Gain for early reflections.
ALfloat Gain;
// Early reflections are done with 4 delay lines.
ALfloat Coeff[4];
DelayLine Delay[4];
ALuint Offset[4];
} Early;
struct {
// Gain for late reverb.
ALfloat Gain;
// Diffusion of late reverb.
ALfloat Diffusion;
// Late reverb is done with 8 delay lines.
ALfloat Coeff[8];
DelayLine Delay[8];
ALuint Offset[8];
// The input and last 4 delay lines are low-pass filtered.
ALfloat LpCoeff[5];
ALfloat LpSample[5];
} Late;
ALuint Offset;
};
// All delay line lengths are specified in seconds.
// The length of the initial delay line (a sum of the maximum delay before
// early reflections and late reverb; 0.3 + 0.1).
static const ALfloat MASTER_LINE_LENGTH = 0.4000f;
// The lengths of the early delay lines.
static const ALfloat EARLY_LINE_LENGTH[4] =
{
0.0015f, 0.0045f, 0.0135f, 0.0405f
};
// The lengths of the late delay lines.
static const ALfloat LATE_LINE_LENGTH[8] =
{
0.0015f, 0.0037f, 0.0093f, 0.0234f,
0.0100f, 0.0150f, 0.0225f, 0.0337f
};
// The last 4 late delay lines have a variable length dependent on the effect
// density parameter and this multiplier.
static const ALfloat LATE_LINE_MULTIPLIER = 9.0f;
static ALuint NextPowerOf2(ALuint value)
{
ALuint powerOf2 = 1;
if(value)
{
value--;
while(value)
{
value >>= 1;
powerOf2 <<= 1;
}
}
return powerOf2;
}
// Basic delay line input/output routines.
static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
{
return Delay->Line[offset&Delay->Mask];
}
static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
{
Delay->Line[offset&Delay->Mask] = in;
}
// Delay line output routine for early reflections.
static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
{
return State->Early.Coeff[index] *
DelayLineOut(&State->Early.Delay[index],
State->Offset - State->Early.Offset[index]);
}
// Given an input sample, this function produces a decorrelated stereo output
// for early reflections.
static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
{
ALfloat d[4], v, f[4];
// Obtain the decayed results of each early delay line.
d[0] = EarlyDelayLineOut(State, 0);
d[1] = EarlyDelayLineOut(State, 1);
d[2] = EarlyDelayLineOut(State, 2);
d[3] = EarlyDelayLineOut(State, 3);
/* The following uses a lossless scattering junction from waveguide
* theory. It actually amounts to a householder mixing matrix, which
* will produce a maximally diffuse response, and means this can probably
* be considered a simple FDN.
* N
* ---
* \
* v = 2/N / di
* ---
* i=1
*/
v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
// The junction is loaded with the input here.
v += in;
// Calculate the feed values for the delay lines.
f[0] = v - d[0];
f[1] = v - d[1];
f[2] = v - d[2];
f[3] = v - d[3];
// Refeed the delay lines.
DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
// To decorrelate the output for stereo separation, the two outputs are
// obtained from the inner delay lines.
// Output is instant by using the inputs to them instead of taking the
// result of the two delay lines directly (f[0] and f[3] instead of d[1]
// and d[2]).
out[0] = State->Early.Gain * f[0];
out[1] = State->Early.Gain * f[3];
}
// Delay line output routine for late reverb.
static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
{
return State->Late.Coeff[index] *
DelayLineOut(&State->Late.Delay[index],
State->Offset - State->Late.Offset[index]);
}
// Low-pass filter input/output routine for late reverb.
static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
{
State->Late.LpSample[index] = in + ((State->Late.LpSample[index] - in) *
State->Late.LpCoeff[index]);
return State->Late.LpSample[index];
}
// Given an input sample, this function produces a decorrelated stereo output
// for late reverb.
static __inline ALvoid LateReverb(ALverbState *State, ALfloat in, ALfloat *out)
{
ALfloat din, d[8], v, dv, f[8];
// Since the input will be sent directly to the output as in the early
// reflections function, it needs to take into account some immediate
// absorption.
in = LateLowPassInOut(State, 0, in);
// When diffusion is full, no input is directly passed to the variable-
// length delay lines (the last 4).
din = (1.0f - State->Late.Diffusion) * in;
// Obtain the decayed results of the fixed-length delay lines.
d[0] = LateDelayLineOut(State, 0);
d[1] = LateDelayLineOut(State, 1);
d[2] = LateDelayLineOut(State, 2);
d[3] = LateDelayLineOut(State, 3);
// Obtain the decayed and low-pass filtered results of the variable-
// length delay lines.
d[4] = LateLowPassInOut(State, 1, LateDelayLineOut(State, 4));
d[5] = LateLowPassInOut(State, 2, LateDelayLineOut(State, 5));
d[6] = LateLowPassInOut(State, 3, LateDelayLineOut(State, 6));
d[7] = LateLowPassInOut(State, 4, LateDelayLineOut(State, 7));
// The waveguide formula used in the early reflections function works
// great for high diffusion, but it is not obviously paramerized to allow
// a variable diffusion. With only limited time and resources, what
// follows is the best variation of that formula I could come up with.
// First, there are 8 delay lines used. The first 4 are fixed-length and
// generate the highest density of the diffuse response. The last 4 are
// variable-length, and are used to smooth out the diffuse response. The
// density effect parameter alters their length. The inner two delay
// lines of each group have their signs reversed (more about this later).
v = (d[0] - d[1] - d[2] + d[3] +
d[4] - d[5] - d[6] + d[7]) * 0.25f;
// Diffusion is applied as a reduction of the junction pressure for all
// branches. This presents two problems. When the diffusion factor (0
// to 1) reaches 0.5, the average feed value is reduced (the junction
// becomes lossy). Thus, at 0.5 the signal decays almost twice as fast
// as it should. The second problem is the introduction of some
// resonant frequencies (coloration). The reversed signs above are used
// to help combat some of the coloration by adding variations along the
// feed cycle.
v *= State->Late.Diffusion;
// Load the junction with the input. To reduce the noticeable echo of
// the longer delay lines (the variable-length ones) the input is loaded
// with the inverse of the effect diffusion. So at full diffusion, the
// input is not applied to the last 4 delay lines. Input signs reversed
// to balance the equation.
dv = v + din;
v += in;
// As with the reversed signs above, to balance the equation the signs
// need to be reversed here, too.
f[0] = d[0] - v;
f[1] = d[1] + v;
f[2] = d[2] + v;
f[3] = d[3] - v;
f[4] = d[4] - dv;
f[5] = d[5] + dv;
f[6] = d[6] + dv;
f[7] = d[7] - dv;
// Feed the fixed-length delay lines with their own cycle (0 -> 1 -> 3 ->
// 2 -> 0...).
DelayLineIn(&State->Late.Delay[0], State->Offset, f[2]);
DelayLineIn(&State->Late.Delay[1], State->Offset, f[0]);
DelayLineIn(&State->Late.Delay[2], State->Offset, f[3]);
DelayLineIn(&State->Late.Delay[3], State->Offset, f[1]);
// Feed the variable-length delay lines with their cycle (4 -> 6 -> 7 ->
// 5 -> 4...).
DelayLineIn(&State->Late.Delay[4], State->Offset, f[5]);
DelayLineIn(&State->Late.Delay[5], State->Offset, f[7]);
DelayLineIn(&State->Late.Delay[6], State->Offset, f[4]);
DelayLineIn(&State->Late.Delay[7], State->Offset, f[6]);
// Output is derived from the values fed to the inner two variable-length
// delay lines (5 and 6).
out[0] = State->Late.Gain * f[7];
out[1] = State->Late.Gain * f[4];
}
// This creates the reverb state. It should be called only when the reverb
// effect is loaded into a slot that doesn't already have a reverb effect.
ALverbState *VerbCreate(ALCcontext *Context)
{
ALverbState *State = NULL;
ALuint length[13], totalLength, index;
State = malloc(sizeof(ALverbState));
if(!State)
return NULL;
// All line lengths are powers of 2, calculated from the line timings and
// the addition of an extra sample (for safety).
length[0] = NextPowerOf2((ALuint)(MASTER_LINE_LENGTH*Context->Frequency) + 1);
totalLength = length[0];
for(index = 0;index < 4;index++)
{
length[1+index] = NextPowerOf2((ALuint)(EARLY_LINE_LENGTH[index]*Context->Frequency) + 1);
totalLength += length[1+index];
}
for(index = 0;index < 4;index++)
{
length[5+index] = NextPowerOf2((ALuint)(LATE_LINE_LENGTH[index]*Context->Frequency) + 1);
totalLength += length[5+index];
}
for(index = 4;index < 8;index++)
{
length[5+index] = NextPowerOf2((ALuint)(LATE_LINE_LENGTH[index]*(1.0f + LATE_LINE_MULTIPLIER)*Context->Frequency) + 1);
totalLength += length[5+index];
}
// They all share a single sample buffer.
State->SampleBuffer = malloc(totalLength * sizeof(ALfloat));
if(!State->SampleBuffer)
{
free(State);
return NULL;
}
for(index = 0; index < totalLength;index++)
State->SampleBuffer[index] = 0.0f;
// Each one has its mask and start address calculated one time.
State->Gain = 0.0f;
State->Delay.Mask = length[0] - 1;
State->Delay.Line = &State->SampleBuffer[0];
totalLength = length[0];
State->Tap[0] = 0;
State->Tap[1] = 0;
State->Early.Gain = 0.0f;
// All fixed-length delay lines have their read-write offsets calculated
// one time.
for(index = 0;index < 4;index++)
{
State->Early.Coeff[index] = 0.0f;
State->Early.Delay[index].Mask = length[1 + index] - 1;
State->Early.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[1 + index];
State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] * Context->Frequency);
}
State->Late.Gain = 0.0f;
State->Late.Diffusion = 0.0f;
for(index = 0;index < 8;index++)
{
State->Late.Coeff[index] = 0.0f;
State->Late.Delay[index].Mask = length[5 + index] - 1;
State->Late.Delay[index].Line = &State->SampleBuffer[totalLength];
totalLength += length[5 + index];
State->Late.Offset[index] = 0;
if(index < 4)
{
State->Late.Offset[index] = (ALuint)(LATE_LINE_LENGTH[index] * Context->Frequency);
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
else if(index == 4)
{
State->Late.LpCoeff[index] = 0.0f;
State->Late.LpSample[index] = 0.0f;
}
}
State->Offset = 0;
return State;
}
// This destroys the reverb state. It should be called only when the effect
// slot has a different (or no) effect loaded over the reverb effect.
ALvoid VerbDestroy(ALverbState *State)
{
if(State)
{
free(State->SampleBuffer);
State->SampleBuffer = NULL;
free(State);
}
}
// This updates the reverb state. This is called any time the reverb effect
// is loaded into a slot.
ALvoid VerbUpdate(ALCcontext *Context, ALeffectslot *Slot, ALeffect *Effect)
{
ALverbState *State = Slot->ReverbState;
ALuint index, index2;
ALfloat length, lpcoeff, cw, g;
ALfloat hfRatio = Effect->Reverb.DecayHFRatio;
// Calculate the master gain (from the slot and master reverb gain).
State->Gain = Slot->Gain * Effect->Reverb.Gain;
// Calculate the initial delay taps.
length = Effect->Reverb.ReflectionsDelay;
State->Tap[0] = (ALuint)(length * Context->Frequency);
length += Effect->Reverb.LateReverbDelay;
State->Tap[1] = (ALuint)(length * Context->Frequency);
// Calculate the early reflections gain. Right now this uses a gain of
// 0.75 to compensate for the increase in density. It should probably
// use a power (RMS) based measurement from the resulting distribution of
// early delay lines.
State->Early.Gain = Effect->Reverb.ReflectionsGain * 0.75f;
// Calculate the gain (coefficient) for each early delay line.
for(index = 0;index < 4;index++)
State->Early.Coeff[index] = pow(10.0f, EARLY_LINE_LENGTH[index] /
Effect->Reverb.LateReverbDelay *
-60.0f / 20.0f);
// Calculate the late reverb gain, adjusted by density, diffusion, and
// decay time. To be accurate, the adjustments should probably use power
// measurements for each contribution, but they are not too bad as they
// are.
State->Late.Gain = Effect->Reverb.LateReverbGain *
(0.45f + (0.55f * Effect->Reverb.Density)) *
(1.0f - (0.25f * Effect->Reverb.Diffusion)) *
(1.0f - (0.025f * Effect->Reverb.DecayTime));
State->Late.Diffusion = Effect->Reverb.Diffusion;
// The EFX specification does not make it clear whether the air
// absorption parameter should always take effect. Both Generic Software
// and Generic Hardware only apply it when HF limit is flagged, so that's
// what is done here.
// If the HF limit parameter is flagged, calculate an appropriate limit
// based on the air absorption parameter.
if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
{
ALfloat limitRatio;
// The following is my best guess at how to limit the HF ratio by the
// air absorption parameter.
// For each of the last 4 delays, find the attenuation due to air
// absorption in dB (converting delay time to meters using the speed
// of sound). Then reversing the decay equation, solve for HF ratio.
// The delay length is cancelled out of the equation, so it can be
// calculated once for all lines.
limitRatio = 1.0f / (log10(Effect->Reverb.AirAbsorptionGainHF) *
SPEEDOFSOUNDMETRESPERSEC *
Effect->Reverb.DecayTime / -60.0f * 20.0f);
// Need to limit the result to a minimum of 0.1, just like the HF
// ratio parameter.
limitRatio = __max(limitRatio, 0.1f);
// Using the limit calculated above, apply the upper bound to the
// HF ratio.
hfRatio = __min(hfRatio, limitRatio);
}
cw = cos(2.0f*3.141592654f * LOWPASSFREQCUTOFF / Context->Frequency);
for(index = 0;index < 8;index++)
{
// Calculate the length (in seconds) of each delay line.
length = LATE_LINE_LENGTH[index];
if(index >= 4)
{
// Calculate the delay offset for the variable-length delay
// lines.
length *= 1.0f + (Effect->Reverb.Density * LATE_LINE_MULTIPLIER);
State->Late.Offset[index] = (ALuint)(length * Context->Frequency);
}
// Calculate the gain (coefficient) for each line.
State->Late.Coeff[index] = pow(10.0f, length / Effect->Reverb.DecayTime *
-60.0f / 20.0f);
if(index >= 4)
{
index2 = index - 3;
// Calculate the decay equation for each low-pass filter.
g = pow(10.0f, length / (Effect->Reverb.DecayTime * hfRatio) *
-60.0f / 20.0f) /
State->Late.Coeff[index];
g = __max(g, 0.1f);
g *= g;
// Calculate the gain (coefficient) for each low-pass filter.
lpcoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpcoeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
// Very low decay times will produce minimal output, so apply an
// upper bound to the coefficient.
State->Late.LpCoeff[index2] = __min(lpcoeff, 0.98f);
}
}
// This just calculates the coefficient for the late reverb input low-
// pass filter. It is calculated based the average (hence -30 instead
// of -60) length of the inner two variable-length delay lines.
length = LATE_LINE_LENGTH[5] * (1.0f + Effect->Reverb.Density * LATE_LINE_MULTIPLIER) +
LATE_LINE_LENGTH[6] * (1.0f + Effect->Reverb.Density * LATE_LINE_MULTIPLIER);
g = pow(10.0f, ((length / (Effect->Reverb.DecayTime * hfRatio))-
(length / Effect->Reverb.DecayTime)) * -30.0f / 20.0f);
g = __max(g, 0.1f);
g *= g;
lpcoeff = 0.0f;
if(g < 0.9999f) // 1-epsilon
lpcoeff = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
State->Late.LpCoeff[0] = __min(lpcoeff, 0.98f);
}
// This processes the reverb state, given the input samples and an output
// buffer.
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS])
{
ALuint index;
ALfloat in, early[2], late[2], out[2];
for(index = 0;index < SamplesToDo;index++)
{
// Feed the initial delay line.
DelayLineIn(&State->Delay, State->Offset, SamplesIn[index]);
// Calculate the early reflection from the first delay tap.
in = DelayLineOut(&State->Delay, State->Offset - State->Tap[0]);
EarlyReflection(State, in, early);
// Calculate the late reverb from the second delay tap.
in = DelayLineOut(&State->Delay, State->Offset - State->Tap[1]);
LateReverb(State, in, late);
// Mix early reflections and late reverb.
out[0] = State->Gain * (early[0] + late[0]);
out[1] = State->Gain * (early[1] + late[1]);
// Step all delays forward one sample.
State->Offset++;
// Output the results.
SamplesOut[index][FRONT_LEFT] += out[0];
SamplesOut[index][FRONT_RIGHT] += out[1];
SamplesOut[index][SIDE_LEFT] += out[0];
SamplesOut[index][SIDE_RIGHT] += out[1];
SamplesOut[index][BACK_LEFT] += out[0];
SamplesOut[index][BACK_RIGHT] += out[1];
}
}
+3 -1
View File
@@ -47,13 +47,14 @@ static DWORD CALLBACK StarterFunc(void *ptr)
ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
{
DWORD dummy;
ThreadInfo *inf = malloc(sizeof(ThreadInfo));
if(!inf) return 0;
inf->func = func;
inf->ptr = ptr;
inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, NULL);
inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, &dummy);
if(!inf->thread)
{
free(inf);
@@ -70,6 +71,7 @@ ALuint StopThread(ALvoid *thread)
WaitForSingleObject(inf->thread, INFINITE);
GetExitCodeThread(inf->thread, &ret);
CloseHandle(inf->thread);
free(inf);
+197 -18
View File
@@ -40,6 +40,9 @@ typedef struct {
ALvoid *buffer;
ALsizei size;
RingBuffer *ring;
int doCapture;
volatile int killNow;
ALvoid *thread;
} alsa_data;
@@ -67,6 +70,7 @@ MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
MAKE_FUNC(snd_pcm_hw_params_set_rate);
MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
MAKE_FUNC(snd_pcm_hw_params_get_period_size);
MAKE_FUNC(snd_pcm_hw_params_get_access);
MAKE_FUNC(snd_pcm_hw_params);
@@ -79,6 +83,7 @@ MAKE_FUNC(snd_pcm_avail_update);
MAKE_FUNC(snd_pcm_areas_silence);
MAKE_FUNC(snd_pcm_mmap_begin);
MAKE_FUNC(snd_pcm_mmap_commit);
MAKE_FUNC(snd_pcm_readi);
MAKE_FUNC(snd_pcm_writei);
MAKE_FUNC(snd_pcm_drain);
MAKE_FUNC(snd_pcm_info_malloc);
@@ -274,6 +279,42 @@ static ALuint ALSANoMMapProc(ALvoid *ptr)
return 0;
}
static ALuint ALSANoMMapCaptureProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
alsa_data *data = (alsa_data*)pDevice->ExtraData;
snd_pcm_sframes_t avail;
while(!data->killNow)
{
avail = (snd_pcm_uframes_t)data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
avail = psnd_pcm_readi(data->pcmHandle, data->buffer, avail);
switch(avail)
{
case -EAGAIN:
continue;
case -ESTRPIPE:
while((avail=psnd_pcm_resume(data->pcmHandle)) == -EAGAIN)
Sleep(1);
break;
case -EPIPE:
break;
default:
if (avail >= 0 && data->doCapture)
WriteRingBuffer(data->ring, data->buffer, avail);
break;
}
if(avail < 0)
{
avail = psnd_pcm_prepare(data->pcmHandle);
if(avail < 0)
AL_PRINT("prepare error: %s\n", psnd_strerror(avail));
}
}
return 0;
}
static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
snd_pcm_uframes_t bufferSizeInFrames;
@@ -449,6 +490,7 @@ open_alsa:
data->thread = StartThread(ALSAProc, device);
if(data->thread == NULL)
{
AL_PRINT("Could not create playback thread\n");
psnd_pcm_close(data->pcmHandle);
device->ExtraData = NULL;
free(data->buffer);
@@ -477,8 +519,11 @@ static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceNam
snd_pcm_format_t alsaFormat;
snd_pcm_hw_params_t *p;
snd_pcm_uframes_t bufferSizeInFrames;
snd_pcm_access_t access;
const char *str;
alsa_data *data;
char driver[64];
int allowmmap;
char *err;
int i;
@@ -498,7 +543,7 @@ static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceNam
{
pDevice->szDeviceName = allCaptureDevNameMap[idx].name;
if(idx > 0)
sprintf(driver, "hw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
goto open_alsa;
}
}
@@ -542,12 +587,18 @@ open_alsa:
AL_PRINT("Unknown format?! %x\n", format);
}
bufferSizeInFrames = SampleSize;
str = GetConfigValue("alsa", "mmap", "true");
allowmmap = (strcasecmp(str, "true") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "on") == 0 ||
atoi(str) != 0);
bufferSizeInFrames = SampleSize;
psnd_pcm_hw_params_malloc(&p);
#define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1))
/* start with the largest configuration space possible */
if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") &&
if(!(allowmmap &&
ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") &&
/* set interleaved access */
ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access") &&
/* set format (implicitly sets sample bits) */
@@ -561,31 +612,109 @@ open_alsa:
/* install and prepare hardware configuration */
ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params")))
{
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
if(i < 0)
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
bufferSizeInFrames = SampleSize;
if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") &&
ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED), "set access") &&
ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, alsaFormat), "set format") &&
ok(psnd_pcm_hw_params_set_channels(data->pcmHandle, p, aluChannelsFromFormat(pDevice->Format)), "set channels") &&
ok(psnd_pcm_hw_params_set_rate(data->pcmHandle, p, frequency, 0), "set rate") &&
ok(psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames), "set buffer size near") &&
ok(psnd_pcm_hw_params(data->pcmHandle, p), "set params")))
{
AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
}
#undef ok
if((i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
{
AL_PRINT("get_access failed: %s\n", psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
#undef ok
psnd_pcm_hw_params_free(p);
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
AL_PRINT("get size failed: %s\n", psnd_strerror(i));
psnd_pcm_hw_params_free(p);
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
pDevice->ExtraData = data;
psnd_pcm_hw_params_free(p);
if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
{
ALuint frameSize = aluChannelsFromFormat(pDevice->Format);
frameSize *= aluBytesFromFormat(pDevice->Format);
data->ring = CreateRingBuffer(frameSize, SampleSize);
if(!data->ring)
{
AL_PRINT("ring buffer create failed\n");
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
data->buffer = malloc(data->size);
if(!data->buffer)
{
AL_PRINT("buffer malloc failed\n");
psnd_pcm_close(data->pcmHandle);
DestroyRingBuffer(data->ring);
free(data);
return ALC_FALSE;
}
pDevice->ExtraData = data;
data->thread = StartThread(ALSANoMMapCaptureProc, pDevice);
if(data->thread == NULL)
{
AL_PRINT("Could not create capture thread\n");
pDevice->ExtraData = NULL;
psnd_pcm_close(data->pcmHandle);
DestroyRingBuffer(data->ring);
free(data->buffer);
free(data);
return ALC_FALSE;
}
}
else
{
i = psnd_pcm_prepare(data->pcmHandle);
if(i < 0)
{
AL_PRINT("prepare error: %s\n", psnd_strerror(i));
psnd_pcm_close(data->pcmHandle);
free(data);
return ALC_FALSE;
}
pDevice->ExtraData = data;
}
return ALC_TRUE;
}
static void alsa_close_capture(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
if(data->thread)
{
data->killNow = 1;
StopThread(data->thread);
DestroyRingBuffer(data->ring);
}
psnd_pcm_close(data->pcmHandle);
free(data);
@@ -595,14 +724,20 @@ static void alsa_close_capture(ALCdevice *pDevice)
static void alsa_start_capture(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
psnd_pcm_prepare(data->pcmHandle);
psnd_pcm_start(data->pcmHandle);
data->doCapture = 1;
if(!data->thread)
{
psnd_pcm_prepare(data->pcmHandle);
psnd_pcm_start(data->pcmHandle);
}
}
static void alsa_stop_capture(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
psnd_pcm_drain(data->pcmHandle);
data->doCapture = 0;
if(!data->thread)
psnd_pcm_drain(data->pcmHandle);
}
static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
@@ -611,8 +746,29 @@ static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint l
const snd_pcm_channel_area_t *areas = NULL;
snd_pcm_sframes_t frames, commitres;
snd_pcm_uframes_t size, offset;
snd_pcm_state_t state;
int err;
if(data->thread)
{
if(lSamples <= (ALCuint)RingBufferSize(data->ring))
ReadRingBuffer(data->ring, pBuffer, lSamples);
else
SetALCError(ALC_INVALID_VALUE);
return;
}
state = psnd_pcm_state(data->pcmHandle);
if(state == SND_PCM_STATE_XRUN)
{
err = xrun_recovery(data->pcmHandle, -EPIPE);
if(err < 0)
{
AL_PRINT("XRUN recovery failed: %s\n", psnd_strerror(err));
return;
}
}
frames = psnd_pcm_avail_update(data->pcmHandle);
if(frames < 0)
{
@@ -668,16 +824,37 @@ static void alsa_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint l
static ALCuint alsa_available_samples(ALCdevice *pDevice)
{
alsa_data *data = (alsa_data*)pDevice->ExtraData;
snd_pcm_sframes_t frames = psnd_pcm_avail_update(data->pcmHandle);
snd_pcm_sframes_t frames;
snd_pcm_state_t state;
int err;
if(data->thread)
return RingBufferSize(data->ring);
state = psnd_pcm_state(data->pcmHandle);
if(state == SND_PCM_STATE_XRUN)
{
err = xrun_recovery(data->pcmHandle, -EPIPE);
if(err >= 0)
{
if(data->doCapture)
err = psnd_pcm_start(data->pcmHandle);
}
if (err < 0)
{
AL_PRINT("XRUN recovery failed: %s\n", psnd_strerror(err));
return 0;
}
}
frames = psnd_pcm_avail_update(data->pcmHandle);
if(frames < 0)
{
int err = xrun_recovery(data->pcmHandle, frames);
err = xrun_recovery(data->pcmHandle, frames);
if (err < 0)
AL_PRINT("available update failed: %s\n", psnd_strerror(err));
else
frames = psnd_pcm_avail_update(data->pcmHandle);
if(frames < 0) /* ew.. */
SetALCError(ALC_INVALID_DEVICE);
}
return max(frames, 0);
}
@@ -744,6 +921,7 @@ LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
LOAD_FUNC(snd_pcm_hw_params_set_rate);
LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
LOAD_FUNC(snd_pcm_hw_params_get_period_size);
LOAD_FUNC(snd_pcm_hw_params_get_access);
LOAD_FUNC(snd_pcm_hw_params);
@@ -756,6 +934,7 @@ LOAD_FUNC(snd_pcm_avail_update);
LOAD_FUNC(snd_pcm_areas_silence);
LOAD_FUNC(snd_pcm_mmap_begin);
LOAD_FUNC(snd_pcm_mmap_commit);
LOAD_FUNC(snd_pcm_readi);
LOAD_FUNC(snd_pcm_writei);
LOAD_FUNC(snd_pcm_drain);
+9 -6
View File
@@ -39,8 +39,8 @@
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
// Since DSound doesn't report the fragment size, just assume 4 fragments
#define DS_FRAGS 4
// Since DSound doesn't report the fragment size, emulate it
static int num_frags;
typedef struct {
// DirectSound Playback Device
@@ -72,7 +72,7 @@ static ALuint DSoundProc(ALvoid *ptr)
DWORD avail;
HRESULT err;
BufferSize = pDevice->UpdateSize * DS_FRAGS *
BufferSize = pDevice->UpdateSize * num_frags *
aluBytesFromFormat(pDevice->Format) *
aluChannelsFromFormat(pDevice->Format);
@@ -82,7 +82,7 @@ static ALuint DSoundProc(ALvoid *ptr)
IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
avail = (PlayCursor-LastCursor+BufferSize) % BufferSize;
if(avail == 0)
if(avail < BufferSize/num_frags)
{
Sleep(1);
continue;
@@ -258,7 +258,7 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
OutputType.Format.cbSize = 0;
device->UpdateSize /= DS_FRAGS;
device->UpdateSize /= num_frags;
}
if(OutputType.Format.nChannels > 2)
@@ -286,7 +286,7 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam
memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
DSBDescription.dwSize=sizeof(DSBUFFERDESC);
DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
DSBDescription.dwBufferBytes=device->UpdateSize * DS_FRAGS * frameSize;
DSBDescription.dwBufferBytes=device->UpdateSize * num_frags * frameSize;
DSBDescription.lpwfxFormat=&OutputType.Format;
hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
}
@@ -411,6 +411,9 @@ void alcDSoundInit(BackendFuncs *FuncList)
*FuncList = DSoundFuncs;
num_frags = GetConfigValueInt("dsound", "periods", 4);
if(num_frags < 2) num_frags = 2;
hr = DirectSoundEnumerate(DSoundEnumDevices, &iter);
if(FAILED(hr))
AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
-458
View File
@@ -1,458 +0,0 @@
/* ----------------- file filterIIR00.c begin ----------------- */
/*
Resonant low pass filter source code.
By baltrax@hotmail.com (Zxform)
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "alMain.h"
#include "alFilter.h"
static void szxform(
double *a0, double *a1, double *a2, /* numerator coefficients */
double *b0, double *b1, double *b2, /* denominator coefficients */
double fc, /* Filter cutoff frequency */
double fs, /* sampling rate */
double *k, /* overall gain factor */
float *coef); /* pointer to 4 iir coefficients */
/*
* --------------------------------------------------------------------
*
* lpFilter - Perform IIR filtering sample by sample on floats
*
* Implements cascaded direct form II second order sections.
* Requires FILTER structure for history and coefficients.
* The size of the history array is 2*FILTER_SECTIONS.
* The size of the coefficient array is 4*FILTER_SECTIONS + 1 because
* the first coefficient is the overall scale factor for the filter.
* Returns one output sample for each input sample.
*
* float lpFilter(FILTER *iir,float input)
*
* FILTER *iir pointer to FILTER structure
* float input new float input sample
*
* Returns float value giving the current output.
* --------------------------------------------------------------------
*/
/*** moved to ALu.c ***/
/*
* --------------------------------------------------------------------
*
* InitLowPassFilter()
*
* Initialize filter coefficients.
* We create a 4th order filter (24 db/oct rolloff), consisting
* of two second order sections.
* --------------------------------------------------------------------
*/
int InitLowPassFilter(ALCcontext *Context, FILTER *iir)
{
float *coef;
double fs, fc; /* Sampling frequency, cutoff frequency */
double Q; /* Resonance > 1.0 < 1000 */
unsigned nInd;
double a0, a1, a2, b0, b1, b2;
double k; /* overall gain factor */
struct {
double a0, a1, a2; /* numerator coefficients */
double b0, b1, b2; /* denominator coefficients */
} ProtoCoef[FILTER_SECTIONS]; /* Filter prototype coefficients,
1 for each filter section */
/*
* Setup filter s-domain coefficients
*/
/* Section 1 */
ProtoCoef[0].a0 = 1.0;
ProtoCoef[0].a1 = 0;
ProtoCoef[0].a2 = 0;
ProtoCoef[0].b0 = 1.0;
ProtoCoef[0].b1 = 0.765367;
ProtoCoef[0].b2 = 1.0;
/* Section 2 */
ProtoCoef[1].a0 = 1.0;
ProtoCoef[1].a1 = 0;
ProtoCoef[1].a2 = 0;
ProtoCoef[1].b0 = 1.0;
ProtoCoef[1].b1 = 1.847759;
ProtoCoef[1].b2 = 1.0;
/* Clear the coefficient and history arrays */
memset(iir->coef, 0, sizeof(iir->coef));
memset(iir->history, 0, sizeof(iir->history));
k = 1.0; /* Set overall filter gain */
coef = iir->coef + 1; /* Skip k, or gain */
Q = 1; /* Resonance */
fc = LOWPASSFREQCUTOFF; /* Filter cutoff (Hz) */
fs = Context->Frequency; /* Sampling frequency (Hz) */
/*
* Compute z-domain coefficients for each biquad section
* for new Cutoff Frequency and Resonance
*/
for (nInd = 0; nInd < FILTER_SECTIONS; nInd++)
{
a0 = ProtoCoef[nInd].a0;
a1 = ProtoCoef[nInd].a1;
a2 = ProtoCoef[nInd].a2;
b0 = ProtoCoef[nInd].b0;
b1 = ProtoCoef[nInd].b1 / Q; /* Divide by resonance or Q */
b2 = ProtoCoef[nInd].b2;
szxform(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &k, coef);
coef += 4; /* Point to next filter section */
}
/* Update overall filter gain in coef array */
iir->coef[0] = k;
return 0;
}
/* ----------------- file filterIIR00.c end ----------------- */
/* ----------------- file bilinear.c begin ----------------- */
/*
* ----------------------------------------------------------
* bilinear.c
*
* Perform bilinear transformation on s-domain coefficients
* of 2nd order biquad section.
* First design an analog filter and use s-domain coefficients
* as input to szxform() to convert them to z-domain.
*
* Here's the butterworth polinomials for 2nd, 4th and 6th order sections.
* When we construct a 24 db/oct filter, we take to 2nd order
* sections and compute the coefficients separately for each section.
*
* n Polinomials
* --------------------------------------------------------------------
* 2 s^2 + 1.4142s +1
* 4 (s^2 + 0.765367s + 1) (s^2 + 1.847759s + 1)
* 6 (s^2 + 0.5176387s + 1) (s^2 + 1.414214 + 1) (s^2 + 1.931852s + 1)
*
* Where n is a filter order.
* For n=4, or two second order sections, we have following equasions for each
* 2nd order stage:
*
* (1 / (s^2 + (1/Q) * 0.765367s + 1)) * (1 / (s^2 + (1/Q) * 1.847759s + 1))
*
* Where Q is filter quality factor in the range of
* 1 to 1000. The overall filter Q is a product of all
* 2nd order stages. For example, the 6th order filter
* (3 stages, or biquads) with individual Q of 2 will
* have filter Q = 2 * 2 * 2 = 8.
*
* The nominator part is just 1.
* The denominator coefficients for stage 1 of filter are:
* b2 = 1; b1 = 0.765367; b0 = 1;
* numerator is
* a2 = 0; a1 = 0; a0 = 1;
*
* The denominator coefficients for stage 1 of filter are:
* b2 = 1; b1 = 1.847759; b0 = 1;
* numerator is
* a2 = 0; a1 = 0; a0 = 1;
*
* These coefficients are used directly by the szxform()
* and bilinear() functions. For all stages the numerator
* is the same and the only thing that is different between
* different stages is 1st order coefficient. The rest of
* coefficients are the same for any stage and equal to 1.
*
* Any filter could be constructed using this approach.
*
* References:
* Van Valkenburg, "Analog Filter Design"
* Oxford University Press 1982
* ISBN 0-19-510734-9
*
* C Language Algorithms for Digital Signal Processing
* Paul Embree, Bruce Kimble
* Prentice Hall, 1991
* ISBN 0-13-133406-9
*
* Digital Filter Designer's Handbook
* With C++ Algorithms
* Britton Rorabaugh
* McGraw Hill, 1997
* ISBN 0-07-053806-9
* ----------------------------------------------------------
*/
static void prewarp(double *a0, double *a1, double *a2, double fc, double fs);
static void bilinear(
double a0, double a1, double a2, /* numerator coefficients */
double b0, double b1, double b2, /* denominator coefficients */
double *k, /* overall gain factor */
double fs, /* sampling rate */
float *coef); /* pointer to 4 iir coefficients */
/*
* ----------------------------------------------------------
* Pre-warp the coefficients of a numerator or denominator.
* Note that a0 is assumed to be 1, so there is no wrapping
* of it.
* ----------------------------------------------------------
*/
static void prewarp(
double *a0, double *a1, double *a2,
double fc, double fs)
{
double wp, pi;
pi = 4.0 * atan(1.0);
wp = 2.0 * fs * tan(pi * fc / fs);
*a2 = (*a2) / (wp * wp);
*a1 = (*a1) / wp;
(void)a0;
}
/*
* ----------------------------------------------------------
* bilinear()
*
* Transform the numerator and denominator coefficients
* of s-domain biquad section into corresponding
* z-domain coefficients.
*
* Store the 4 IIR coefficients in array pointed by coef
* in following order:
* beta1, beta2 (denominator)
* alpha1, alpha2 (numerator)
*
* Arguments:
* a0-a2 - s-domain numerator coefficients
* b0-b2 - s-domain denominator coefficients
* k - filter gain factor. initially set to 1
* and modified by each biquad section in such
* a way, as to make it the coefficient by
* which to multiply the overall filter gain
* in order to achieve a desired overall filter gain,
* specified in initial value of k.
* fs - sampling rate (Hz)
* coef - array of z-domain coefficients to be filled in.
*
* Return:
* On return, set coef z-domain coefficients
* ----------------------------------------------------------
*/
static void bilinear(
double a0, double a1, double a2, /* numerator coefficients */
double b0, double b1, double b2, /* denominator coefficients */
double *k, /* overall gain factor */
double fs, /* sampling rate */
float *coef /* pointer to 4 iir coefficients */
)
{
double ad, bd;
/* alpha (Numerator in s-domain) */
ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0;
/* beta (Denominator in s-domain) */
bd = 4. * b2 * fs * fs + 2. * b1* fs + b0;
/* update gain constant for this section */
*k *= ad/bd;
/* Denominator */
*coef++ = (2.*b0 - 8.*b2*fs*fs) / bd; /* beta1 */
*coef++ = (4.*b2*fs*fs - 2.*b1*fs + b0) / bd; /* beta2 */
/* Nominator */
*coef++ = (2.*a0 - 8.*a2*fs*fs) / ad; /* alpha1 */
*coef = (4.*a2*fs*fs - 2.*a1*fs + a0) / ad; /* alpha2 */
}
/*
* ----------------------------------------------------------
* Transform from s to z domain using bilinear transform
* with prewarp.
*
* Arguments:
* For argument description look at bilinear()
*
* coef - pointer to array of floating point coefficients,
* corresponding to output of bilinear transofrm
* (z domain).
*
* Note: frequencies are in Hz.
* ----------------------------------------------------------
*/
static void szxform(
double *a0, double *a1, double *a2, /* numerator coefficients */
double *b0, double *b1, double *b2, /* denominator coefficients */
double fc, /* Filter cutoff frequency */
double fs, /* sampling rate */
double *k, /* overall gain factor */
float *coef) /* pointer to 4 iir coefficients */
{
/* Calculate a1 and a2 and overwrite the original values */
prewarp(a0, a1, a2, fc, fs);
prewarp(b0, b1, b2, fc, fs);
bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef);
}
/* ----------------- file bilinear.c end ----------------- */
/* ----------------- file filter.txt begin -----------------
How to construct a kewl low pass resonant filter?
Lets assume we want to create a filter for analog synth.
The filter rolloff is 24 db/oct, which corresponds to 4th
order filter. Filter of first order is equivalent to RC circuit
and has max rolloff of 6 db/oct.
We will use classical Butterworth IIR filter design, as it
exactly corresponds to our requirements.
A common practice is to chain several 2nd order sections,
or biquads, as they commonly called, in order to achive a higher
order filter. Each 2nd order section is a 2nd order filter, which
has 12 db/oct roloff. So, we need 2 of those sections in series.
To compute those sections, we use standard Butterworth polinomials,
or so called s-domain representation and convert it into z-domain,
or digital domain. The reason we need to do this is because
the filter theory exists for analog filters for a long time
and there exist no theory of working in digital domain directly.
So the common practice is to take standard analog filter design
and use so called bilinear transform to convert the butterworth
equasion coefficients into z-domain.
Once we compute the z-domain coefficients, we can use them in
a very simple transfer function, such as iir_filter() in our
C source code, in order to perform the filtering function.
The filter itself is the simpliest thing in the world.
The most complicated thing is computing the coefficients
for z-domain.
Ok, lets look at butterworth polynomials, arranged as a series
of 2nd order sections:
* Note: n is filter order.
*
* n Polynomials
* --------------------------------------------------------------------
* 2 s^2 + 1.4142s +1
* 4 (s^2 + 0.765367s + 1) * (s^2 + 1.847759s + 1)
* 6 (s^2 + 0.5176387s + 1) * (s^2 + 1.414214 + 1) * (s^2 + 1.931852s + 1)
*
* For n=4 we have following equasion for the filter transfer function:
*
* 1 1
* T(s) = --------------------------- * ----------------------------
* s^2 + (1/Q) * 0.765367s + 1 s^2 + (1/Q) * 1.847759s + 1
*
The filter consists of two 2nd order secions since highest s power is 2.
Now we can take the coefficients, or the numbers by which s is multiplied
and plug them into a standard formula to be used by bilinear transform.
Our standard form for each 2nd order secion is:
a2 * s^2 + a1 * s + a0
H(s) = ----------------------
b2 * s^2 + b1 * s + b0
Note that butterworth nominator is 1 for all filter sections,
which means s^2 = 0 and s^1 = 0
Lets convert standard butterworth polinomials into this form:
0 + 0 + 1 0 + 0 + 1
-------------------------- * --------------------------
1 + ((1/Q) * 0.765367) + 1 1 + ((1/Q) * 1.847759) + 1
Section 1:
a2 = 0; a1 = 0; a0 = 1;
b2 = 1; b1 = 0.5176387; b0 = 1;
Section 2:
a2 = 0; a1 = 0; a0 = 1;
b2 = 1; b1 = 1.847759; b0 = 1;
That Q is filter quality factor or resonance, in the range of
1 to 1000. The overall filter Q is a product of all 2nd order stages.
For example, the 6th order filter (3 stages, or biquads)
with individual Q of 2 will have filter Q = 2 * 2 * 2 = 8.
These a and b coefficients are used directly by the szxform()
and bilinear() functions.
The transfer function for z-domain is:
1 + alpha1 * z^(-1) + alpha2 * z^(-2)
H(z) = -------------------------------------
1 + beta1 * z^(-1) + beta2 * z^(-2)
When you need to change the filter frequency cutoff or resonance,
or Q, you call the szxform() function with proper a and b
coefficients and the new filter cutoff frequency or resonance.
You also need to supply the sampling rate and filter gain you want
to achive. For our purposes the gain = 1.
We call szxform() function 2 times becase we have 2 filter sections.
Each call provides different coefficients.
The gain argument to szxform() is a pointer to desired filter
gain variable.
double k = 1.0; // overall gain factor
Upon return from each call, the k argument will be set to a value,
by which to multiply our actual signal in order for the gain
to be one. On second call to szxform() we provide k that was
changed by the previous section. During actual audio filtering
function iir_filter() will use this k
Summary:
Our filter is pretty close to ideal in terms of all relevant
parameters and filter stability even with extremely large values
of resonance. This filter design has been verified under all
variations of parameters and it all appears to work as advertized.
Good luck with it.
If you ever make a directX wrapper for it, post it to comp.dsp.
*
* ----------------------------------------------------------
*References:
*Van Valkenburg, "Analog Filter Design"
*Oxford University Press 1982
*ISBN 0-19-510734-9
*
*C Language Algorithms for Digital Signal Processing
*Paul Embree, Bruce Kimble
*Prentice Hall, 1991
*ISBN 0-13-133406-9
*
*Digital Filter Designer's Handbook
*With C++ Algorithms
*Britton Rorabaugh
*McGraw Hill, 1997
*ISBN 0-07-053806-9
* ----------------------------------------------------------
// ----------------- file filter.txt end ----------------- */
+258
View File
@@ -0,0 +1,258 @@
/**
* 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
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#include <sys/audioio.h>
static char *solaris_device;
typedef struct {
int fd;
volatile int killNow;
ALvoid *thread;
ALubyte *mix_data;
int data_size;
} solaris_data;
static ALuint SolarisProc(ALvoid *ptr)
{
ALCdevice *pDevice = (ALCdevice*)ptr;
solaris_data *data = (solaris_data*)pDevice->ExtraData;
int remaining = 0;
int wrote;
while(!data->killNow)
{
int len = data->data_size - remaining;
if(len > 0)
{
SuspendContext(NULL);
aluMixData(pDevice->Context, data->mix_data+remaining, len, pDevice->Format);
ProcessContext(NULL);
}
remaining += len;
wrote = write(data->fd, data->mix_data, remaining);
if(wrote < 0)
{
AL_PRINT("write failed: %s\n", strerror(errno));
remaining = 0;
}
else if(wrote > 0)
{
remaining -= wrote;
if(remaining > 0)
memmove(data->mix_data, data->mix_data+wrote, remaining);
}
else
Sleep(1);
}
return 0;
}
static ALCboolean solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
{
audio_info_t info;
ALuint frameSize;
char driver[64];
int numChannels;
solaris_data *data;
strncpy(driver, GetConfigValue("solaris", "device", "/dev/audio"), sizeof(driver)-1);
driver[sizeof(driver)-1] = 0;
if(deviceName)
{
if(strcmp(deviceName, solaris_device))
return ALC_FALSE;
device->szDeviceName = solaris_device;
}
else
device->szDeviceName = solaris_device;
data = (solaris_data*)calloc(1, sizeof(solaris_data));
data->killNow = 0;
data->fd = open(driver, O_WRONLY);
if(data->fd == -1)
{
free(data);
AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
return ALC_FALSE;
}
numChannels = aluChannelsFromFormat(device->Format);
AUDIO_INITINFO(&info);
info.play.sample_rate = device->Frequency;
info.play.channels = numChannels;
switch(aluBytesFromFormat(device->Format))
{
case 1:
info.play.precision = 8;
info.play.encoding = AUDIO_ENCODING_LINEAR8;
break;
case 2:
info.play.precision = 16;
info.play.encoding = AUDIO_ENCODING_LINEAR;
break;
default:
AL_PRINT("Unknown format?! %x\n", device->Format);
}
frameSize = numChannels * aluBytesFromFormat(device->Format);
info.play.buffer_size = device->UpdateSize * frameSize;
if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
{
AL_PRINT("ioctl failed: %s\n", strerror(errno));
close(data->fd);
free(data);
return ALC_FALSE;
}
device->Frequency = info.play.sample_rate;
if(aluChannelsFromFormat(device->Format) != info.play.channels)
{
AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device->Format), info.play.channels);
close(data->fd);
free(data);
return ALC_FALSE;
}
if(!((info.play.precision == 8 && aluBytesFromFormat(device->Format) == 1) ||
(info.play.precision == 16 && aluBytesFromFormat(device->Format) == 2)))
{
AL_PRINT("Could not set %d-bit output, got %d\n", aluBytesFromFormat(device->Format)*8, info.play.precision);
close(data->fd);
free(data);
return ALC_FALSE;
}
device->UpdateSize = info.play.buffer_size / 4;
data->data_size = device->UpdateSize * frameSize;
data->mix_data = calloc(1, data->data_size);
device->ExtraData = data;
data->thread = StartThread(SolarisProc, device);
if(data->thread == NULL)
{
device->ExtraData = NULL;
free(data->mix_data);
free(data);
return ALC_FALSE;
}
return ALC_TRUE;
}
static void solaris_close_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
data->killNow = 1;
StopThread(data->thread);
close(data->fd);
free(data->mix_data);
free(data);
device->ExtraData = NULL;
}
static ALCboolean solaris_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
{
(void)device;
(void)deviceName;
(void)frequency;
(void)format;
(void)SampleSize;
return ALC_FALSE;
}
static void solaris_close_capture(ALCdevice *device)
{
(void)device;
}
static void solaris_start_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void solaris_stop_capture(ALCdevice *pDevice)
{
(void)pDevice;
}
static void solaris_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
{
(void)pDevice;
(void)pBuffer;
(void)lSamples;
}
static ALCuint solaris_available_samples(ALCdevice *pDevice)
{
(void)pDevice;
return 0;
}
BackendFuncs solaris_funcs = {
solaris_open_playback,
solaris_close_playback,
solaris_open_capture,
solaris_close_capture,
solaris_start_capture,
solaris_stop_capture,
solaris_capture_samples,
solaris_available_samples
};
void alc_solaris_init(BackendFuncs *func_list)
{
*func_list = solaris_funcs;
solaris_device = AppendDeviceList("Solaris Software");
AppendAllDeviceList(solaris_device);
}
+61 -27
View File
@@ -23,6 +23,7 @@ SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
OPTION(ALSA "Check for ALSA backend" ON)
OPTION(OSS "Check for OSS backend" ON)
OPTION(SOLARIS "Check for Solaris backend" ON)
OPTION(DSOUND "Check for DirectSound backend" ON)
OPTION(WINMM "Check for Windows Multimedia backend" ON)
@@ -32,16 +33,19 @@ OPTION(WERROR "Treat compile warnings as errors" OFF)
OPTION(EXAMPLES "Build example programs" ON)
OPTION(XCOMPILEWIN32 "Cross-compile to Win32" OFF)
IF(WIN32)
IF(WIN32 OR XCOMPILEWIN32)
SET(LIBNAME openal32)
ADD_DEFINITIONS("-D_WIN32")
ELSE()
SET(LIBNAME openal)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "5")
SET(LIB_BUILD_VERSION "304")
SET(LIB_MINOR_VERSION "6")
SET(LIB_BUILD_VERSION "372")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_BUILD_VERSION}")
IF(NOT DEFINED LIB_INSTALL_DIR)
SET(LIB_INSTALL_DIR "lib")
@@ -94,7 +98,7 @@ ELSE()
FORCE)
# Set visibility options if available
IF(NOT WIN32)
IF(NOT WIN32 AND NOT XCOMPILEWIN32)
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
@@ -109,13 +113,19 @@ ELSE()
ENDIF()
ENDIF()
CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H)
CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
CHECK_LIBRARY_EXISTS(m sqrtf "" HAVE_SQRTF)
CHECK_LIBRARY_EXISTS(m acosf "" HAVE_ACOSF)
IF(HAVE_SQRTF OR HAVE_ACOSF)
IF(HAVE_FENV_H)
CHECK_LIBRARY_EXISTS(m fesetround "" HAVE_FESETROUND)
ENDIF()
IF(HAVE_SQRTF OR HAVE_ACOSF OR HAVE_FESETROUND)
SET(EXTRA_LIBS m ${EXTRA_LIBS})
ENDIF()
CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
CHECK_FUNCTION_EXISTS(_controlfp HAVE__CONTROLFP)
CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
IF(NOT HAVE_STRCASECMP)
@@ -222,10 +232,10 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
SET(ALC_OBJS Alc/ALc.c
Alc/ALu.c
Alc/alcConfig.c
Alc/alcReverb.c
Alc/alcRing.c
Alc/alcThread.c
Alc/bs2b.c
Alc/lpfilter.c
Alc/wave.c
)
@@ -259,24 +269,34 @@ IF(OSS)
ENDIF()
ENDIF()
# Check DSound/MMSystem backend
IF(HAVE_WINDOWS_H)
IF(DSOUND)
CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
IF(HAVE_DSOUND_H)
SET(HAVE_DSOUND 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
SET(BACKENDS "${BACKENDS} DirectSound,")
# Check Solaris backend
IF(SOLARIS)
CHECK_INCLUDE_FILE(sys/audioio.h HAVE_SYS_AUDIOIO_H)
IF(HAVE_SYS_AUDIOIO_H)
SET(HAVE_SOLARIS 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/solaris.c)
SET(BACKENDS "${BACKENDS} Solaris,")
ENDIF()
ENDIF()
SET(CMAKE_REQUIRED_LIBRARIES dsound)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBDSOUND)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND)
SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
ENDIF()
# Check DSound/MMSystem backend
IF(DSOUND)
CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
IF(HAVE_DSOUND_H)
SET(HAVE_DSOUND 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/dsound.c)
SET(BACKENDS "${BACKENDS} DirectSound,")
SET(CMAKE_REQUIRED_LIBRARIES dsound)
CHECK_C_SOURCE_COMPILES("int main() {return 0;}" HAVE_LIBDSOUND)
SET(CMAKE_REQUIRED_LIBRARIES "")
# CHECK_LIBRARY_EXISTS(dsound DirectSoundCreate "" HAVE_LIBDSOUND)
IF(HAVE_LIBDSOUND)
SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
ENDIF()
ENDIF()
ENDIF()
IF(HAVE_WINDOWS_H)
IF(WINMM)
CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0500)
IF(HAVE_MMSYSTEM_H)
@@ -317,13 +337,25 @@ CONFIGURE_FILE(
ADD_DEFINITIONS(-DAL_BUILD_LIBRARY)
# Build a shared library
ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
# Build a library
IF(NOT LIBTYPE)
SET(LIBTYPE SHARED)
ENDIF()
ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
IF(WIN32)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
ENDIF()
IF(XCOMPILEWIN32)
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "" SUFFIX .dll)
IF(EXAMPLES)
SET(EXAMPLES OFF)
MESSAGE(STATUS "")
MESSAGE(STATUS "Building examples disabled when cross-compiling")
ENDIF()
ENDIF()
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES OUTPUT_NAME ${LIBNAME})
TARGET_LINK_LIBRARIES(${LIBNAME} ${EXTRA_LIBS})
@@ -356,8 +388,10 @@ MESSAGE(STATUS "Building OpenAL with support for the following backends:")
MESSAGE(STATUS " ${BACKENDS}")
MESSAGE(STATUS "")
IF(WIN32 AND NOT HAVE_DSOUND)
MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
MESSAGE(STATUS " This is probably NOT what you want!")
MESSAGE(STATUS "")
IF(WIN32 OR XCOMPILEWIN32)
IF(NOT HAVE_DSOUND)
MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
MESSAGE(STATUS " This is probably NOT what you want!")
MESSAGE(STATUS "")
ENDIF()
ENDIF()
+13 -20
View File
@@ -4,6 +4,7 @@
#include "AL/al.h"
#include "alEffect.h"
#include "alFilter.h"
#include "alReverb.h"
#ifdef __cplusplus
extern "C" {
@@ -22,15 +23,7 @@ typedef struct ALeffectslot
ALfloat Gain;
ALboolean AuxSendAuto;
ALfloat *ReverbBuffer;
// in frames!
ALuint ReverbLength;
ALuint ReverbPos;
ALuint ReverbReflectPos;
ALuint ReverbLatePos;
ALfloat ReverbDecayGain;
FILTER iirFilter;
ALverbState *ReverbState;
ALuint refcount;
@@ -40,19 +33,19 @@ typedef struct ALeffectslot
struct ALeffectslot *next;
} ALeffectslot;
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
+2
View File
@@ -24,6 +24,8 @@ typedef struct ALbuffer_struct
struct ALbuffer_struct *next;
} ALbuffer;
ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
ALvoid ReleaseALBuffers(ALvoid);
#ifdef __cplusplus
+18 -11
View File
@@ -38,6 +38,13 @@ extern "C" {
#define AL_REVERB_DECAY_HFLIMIT 0x000D
enum {
REVERB = 0,
MAX_EFFECTS
};
extern ALboolean DisabledEffects[MAX_EFFECTS];
typedef struct ALeffect_struct
{
// Effect type (AL_EFFECT_NULL, ...)
@@ -66,19 +73,19 @@ typedef struct ALeffect_struct
struct ALeffect_struct *next;
} ALeffect;
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
ALboolean AL_APIENTRY alIsEffect(ALuint effect);
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
ALvoid ReleaseALEffects(ALvoid);
+13 -17
View File
@@ -7,11 +7,9 @@
extern "C" {
#endif
#define FILTER_SECTIONS 2 /* 2 filter sections for 24 db/oct filter */
typedef struct {
float history[2*FILTER_SECTIONS]; /* history in filter */
float coef[4*FILTER_SECTIONS + 1]; /* coefficients of filter */
ALfloat history[4];
ALfloat coeff;
} FILTER;
#define AL_FILTER_TYPE 0x8001
@@ -39,24 +37,22 @@ typedef struct ALfilter_struct
struct ALfilter_struct *next;
} ALfilter;
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
ALboolean AL_APIENTRY alIsFilter(ALuint filter);
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
ALvoid ReleaseALFilters(ALvoid);
int InitLowPassFilter(ALCcontext *Context, FILTER *iir);
#ifdef __cplusplus
}
#endif
+6 -1
View File
@@ -6,6 +6,10 @@
#include "alu.h"
#ifdef HAVE_FENV_H
#include <fenv.h>
#endif
#ifdef _WIN32
#ifndef _WIN32_WINNT
@@ -121,7 +125,7 @@ extern char _alDebug[256];
#define SWMIXER_OUTPUT_RATE 44100
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.994f)
#define AIRABSORBGAINDBHF (-0.05f)
#define LOWPASSFREQCUTOFF (5000)
@@ -140,6 +144,7 @@ typedef struct {
void alc_alsa_init(BackendFuncs *func_list);
void alc_oss_init(BackendFuncs *func_list);
void alc_solaris_init(BackendFuncs *func_list);
void alcDSoundInit(BackendFuncs *func_list);
void alcWinMMInit(BackendFuncs *FuncList);
void alc_wave_init(BackendFuncs *func_list);
+26
View File
@@ -0,0 +1,26 @@
#ifndef _AL_REVERB_H_
#define _AL_REVERB_H_
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alAuxEffectSlot.h"
#include "alEffect.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ALverbState ALverbState;
ALverbState *VerbCreate(ALCcontext *Context);
ALvoid VerbDestroy(ALverbState *State);
ALvoid VerbUpdate(ALCcontext *Context, struct ALeffectslot *Slot, ALeffect *Effect);
ALvoid VerbProcess(ALverbState *State, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[OUTPUTCHANNELS]);
#ifdef __cplusplus
}
#endif
#endif
+8 -4
View File
@@ -7,6 +7,7 @@
#define MAX_SENDS 1
#include "alFilter.h"
#include "alu.h"
#include "AL/al.h"
#define AL_DIRECT_FILTER 0x20005
@@ -55,19 +56,19 @@ typedef struct ALsource
ALenum state;
ALuint position;
ALuint position_fraction;
struct ALbufferlistitem *queue; // Linked list of buffers in queue
ALuint BuffersInQueue; // Number of buffers in queue
ALuint BuffersProcessed; // Number of buffers already processed (played)
ALuint TotalBufferDataSize; // Total amount of data contained in the buffers queued for this source
ALuint BuffersPlayed; // Number of buffers played on this loop
ALuint BufferPosition; // Read position in audio data of current buffer
ALfilter DirectFilter;
struct {
struct ALeffectslot *Slot;
ALfilter WetFilter;
FILTER iirFilter;
} Send[MAX_SENDS];
ALboolean DryGainHFAuto;
@@ -86,14 +87,17 @@ typedef struct ALsource
// Index to itself
ALuint source;
ALint lBytesPlayed;
ALint lOffset;
ALint lOffsetType;
// Source Type (Static, Streaming, or Undetermined)
ALint lSourceType;
// Current gains, which are ramped while mixed
ALfloat DryGains[OUTPUTCHANNELS];
ALfloat WetGain;
ALboolean FirstStart;
struct ALsource *next;
} ALsource;
+13
View File
@@ -8,6 +8,19 @@
extern "C" {
#endif
enum {
FRONT_LEFT = 0,
FRONT_RIGHT,
SIDE_LEFT,
SIDE_RIGHT,
BACK_LEFT,
BACK_RIGHT,
CENTER,
LFE,
OUTPUTCHANNELS
};
extern ALboolean DuplicateStereo;
__inline ALuint aluBytesFromFormat(ALenum format);
+20 -55
View File
@@ -29,12 +29,13 @@
#include "alAuxEffectSlot.h"
#include "alThunk.h"
#include "alError.h"
#include "alReverb.h"
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect);
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALsizei i;
@@ -71,8 +72,6 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
break;
}
InitLowPassFilter(Context, &(*list)->iirFilter);
(*list)->Gain = 1.0;
(*list)->AuxSendAuto = AL_TRUE;
(*list)->refcount = 0;
@@ -94,7 +93,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *Context;
ALeffectslot *ALAuxiliaryEffectSlot;
@@ -150,7 +149,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effect
*list = (*list)->next;
ALTHUNK_REMOVEENTRY(ALAuxiliaryEffectSlot->effectslot);
free(ALAuxiliaryEffectSlot->ReverbBuffer);
VerbDestroy(ALAuxiliaryEffectSlot->ReverbState);
memset(ALAuxiliaryEffectSlot, 0, sizeof(ALeffectslot));
free(ALAuxiliaryEffectSlot);
@@ -166,7 +165,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effect
ProcessContext(Context);
}
AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
{
ALCcontext *Context;
ALeffectslot **list;
@@ -188,7 +187,7 @@ AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
return (*list ? AL_TRUE : AL_FALSE);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
{
ALCcontext *Context;
@@ -234,7 +233,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
{
ALCcontext *Context;
@@ -266,7 +265,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum para
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
@@ -302,7 +301,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
@@ -333,7 +332,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum para
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
{
ALCcontext *Context;
@@ -370,7 +369,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum pa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
{
ALCcontext *Context;
@@ -402,7 +401,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum p
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
@@ -435,7 +434,7 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum pa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
@@ -469,54 +468,20 @@ AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum p
static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *ALEffectSlot, ALeffect *effect)
{
ALfloat *ptr = NULL;
if(!effect)
{
memset(&ALEffectSlot->effect, 0, sizeof(ALEffectSlot->effect));
goto done;
VerbDestroy(ALEffectSlot->ReverbState);
ALEffectSlot->ReverbState = NULL;
return;
}
if(effect->type == AL_EFFECT_REVERB)
{
ALuint size;
ALfloat reverbwait;
reverbwait = (1.0f-effect->Reverb.Density)*(0.1f-0.075f) + 0.075f;
size = (ALuint)((ALfloat)Context->Frequency *
(effect->Reverb.ReflectionsDelay +
effect->Reverb.LateReverbDelay +
reverbwait)) + 1;
ptr = calloc(size, sizeof(ALfloat));
if(!ptr)
{
alSetError(AL_OUT_OF_MEMORY);
return;
}
if(ALEffectSlot->ReverbBuffer)
memcpy(ptr, ALEffectSlot->ReverbBuffer, min(size, ALEffectSlot->ReverbLength)*sizeof(ALfloat));
ALEffectSlot->ReverbLength = size;
ALEffectSlot->ReverbPos %= size;
ALEffectSlot->ReverbReflectPos = (ALuint)(ALEffectSlot->ReverbLength -
((ALfloat)Context->Frequency *
effect->Reverb.ReflectionsDelay) +
ALEffectSlot->ReverbPos) %
ALEffectSlot->ReverbLength;
ALEffectSlot->ReverbLatePos = (ALuint)(ALEffectSlot->ReverbLength -
((ALfloat)Context->Frequency *
(effect->Reverb.LateReverbDelay +
effect->Reverb.ReflectionsDelay)) +
ALEffectSlot->ReverbPos) %
ALEffectSlot->ReverbLength;
ALEffectSlot->ReverbDecayGain = pow(1.0/32768.0, 1.0/(effect->Reverb.DecayTime/reverbwait));
if(!ALEffectSlot->ReverbState)
ALEffectSlot->ReverbState = VerbCreate(Context);
VerbUpdate(Context, ALEffectSlot, effect);
}
memcpy(&ALEffectSlot->effect, effect, sizeof(*effect));
done:
free(ALEffectSlot->ReverbBuffer);
ALEffectSlot->ReverbBuffer = ptr;
}
@@ -533,7 +498,7 @@ ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
Context->AuxiliaryEffectSlot = Context->AuxiliaryEffectSlot->next;
// Release effectslot structure
free(temp->ReverbBuffer);
VerbDestroy(temp->ReverbState);
ALTHUNK_REMOVEENTRY(temp->effectslot);
memset(temp, 0, sizeof(ALeffectslot));
+287 -328
View File
@@ -34,6 +34,9 @@
static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint freq, ALenum OrigFormat, ALenum NewFormat);
static void ConvertData(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len);
static void ConvertDataRear(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len);
static void ConvertDataIMA4(ALshort *dst, const ALvoid *src, ALint origChans, ALsizei len);
/*
* AL Buffer Functions
@@ -255,15 +258,9 @@ ALAPI ALboolean ALAPIENTRY alIsBuffer(ALuint uiBuffer)
*/
ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *data,ALsizei size,ALsizei freq)
{
ALuint *IMAData,IMACode;
ALCcontext *Context;
ALint Sample,Index;
ALint LeftSample,LeftIndex;
ALint RightSample,RightIndex;
ALuint LeftIMACode,RightIMACode;
ALsizei padding = 2;
ALbuffer *ALBuf;
ALsizei padding;
ALsizei i,j,k;
ALvoid *temp;
Context = alcGetCurrentContext();
@@ -296,113 +293,35 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 :
((format==AL_FORMAT_REAR16) ? 2 :
4));
ALsizei i;
assert(aluBytesFromFormat(NewFormat) == 2);
if ((size%(OrigBytes*2)) != 0)
if((size%(OrigBytes*2)) != 0)
{
alSetError(AL_INVALID_VALUE);
break;
}
padding = freq / LOWPASSFREQCUTOFF;
if(padding < 1) padding = 1;
size /= OrigBytes;
size *= 2;
switch(OrigBytes)
// Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
case 1:
size /= sizeof(ALubyte);
size *= 2;
ALBuf->data = temp;
ConvertDataRear(ALBuf->data, data, OrigBytes, size);
// 8bit Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = (ALshort)((((ALubyte*)data)[i/2+0]-128) << 8);
ALBuf->data[i+3] = (ALshort)((((ALubyte*)data)[i/2+1]-128) << 8);
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 2:
size /= sizeof(ALshort);
size *= 2;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
ALBuf->data[i+2] = ((ALshort*)data)[i/2+0];
ALBuf->data[i+3] = ((ALshort*)data)[i/2+1];
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 4:
size /= sizeof(ALfloat);
size *= 2;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALint smp;
ALBuf->data = temp;
for (i = 0;i < size;i+=4)
{
ALBuf->data[i+0] = 0;
ALBuf->data[i+1] = 0;
smp = (((ALfloat*)data)[i/2+0] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
ALBuf->data[i+2] = (ALshort)smp;
smp = (((ALfloat*)data)[i/2+1] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
ALBuf->data[i+3] = (ALshort)smp;
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
default:
assert(0);
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = format;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
} break;
case AL_FORMAT_QUAD8_LOKI:
@@ -432,167 +351,39 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
break;
case AL_FORMAT_MONO_IMA4:
padding = freq / LOWPASSFREQCUTOFF;
if(padding < 1) padding = 1;
case AL_FORMAT_STEREO_IMA4: {
int OrigChans = ((format==AL_FORMAT_MONO_IMA4) ? 1 : 2);
// Here is where things vary:
// nVidia and Apple use 64+1 samples per block => block_size=36 bytes
// Most PC sound software uses 2040+1 samples per block -> block_size=1024 bytes
if ((size%36) == 0)
// nVidia and Apple use 64+1 samples per channel per block => block_size=36*chans bytes
// Most PC sound software uses 2040+1 samples per channel per block -> block_size=1024*chans bytes
if((size%(36*OrigChans)) != 0)
{
// Allocate extra padding samples
temp=realloc(ALBuf->data,padding*2+(size/36)*(65*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
ALBuf->format = AL_FORMAT_MONO16;
ALBuf->eOriginalFormat = AL_FORMAT_MONO_IMA4;
IMAData=(ALuint *)data;
for (i=0;i<size/36;i++)
{
Sample=((ALshort *)IMAData)[0];
Index=((ALshort *)IMAData)[1];
Index=Index<0?0:Index;
Index=Index>88?88:Index;
ALBuf->data[i*65]=(short)Sample;
IMAData++;
for (j=1;j<65;j+=8)
{
IMACode=*IMAData;
for (k=0;k<8;k+=2)
{
Sample+=((g_IMAStep_size[Index]*g_IMACodeword_4[IMACode&15])/8);
Index+=g_IMAIndex_adjust_4[IMACode&15];
if (Sample<-32768) Sample=-32768;
else if (Sample>32767) Sample=32767;
if (Index<0) Index=0;
else if (Index>88) Index=88;
ALBuf->data[i*65+j+k]=(short)Sample;
IMACode>>=4;
Sample+=((g_IMAStep_size[Index]*g_IMACodeword_4[IMACode&15])/8);
Index+=g_IMAIndex_adjust_4[IMACode&15];
if (Sample<-32768) Sample=-32768;
else if (Sample>32767) Sample=32767;
if (Index<0) Index=0;
else if (Index>88) Index=88;
ALBuf->data[i*65+j+k+1]=(short)Sample;
IMACode>>=4;
}
IMAData++;
}
}
memset(&(ALBuf->data[(size/36*65)]), 0, padding*2);
ALBuf->size=size/36*65*sizeof(ALshort);
ALBuf->frequency=freq;
ALBuf->padding=padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
break;
case AL_FORMAT_STEREO_IMA4:
padding = freq / LOWPASSFREQCUTOFF;
if(padding < 1) padding = 1;
// Here is where things vary:
// nVidia and Apple use 64+1 samples per channel per block => block_size=72 bytes
// Most PC sound software uses 2040+1 samples per channel per block -> block_size=2048 bytes
if ((size%72) == 0)
{
// Allocate extra padding samples
temp=realloc(ALBuf->data,padding*2*2+(size/72)*(2*65*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
ALBuf->format = AL_FORMAT_STEREO16;
ALBuf->eOriginalFormat = AL_FORMAT_STEREO_IMA4;
IMAData=(ALuint *)data;
for (i=0;i<size/72;i++)
{
LeftSample=((ALshort *)IMAData)[0];
LeftIndex=((ALshort *)IMAData)[1];
LeftIndex=LeftIndex<0?0:LeftIndex;
LeftIndex=LeftIndex>88?88:LeftIndex;
ALBuf->data[i*2*65]=(short)LeftSample;
IMAData++;
RightSample=((ALshort *)IMAData)[0];
RightIndex=((ALshort *)IMAData)[1];
RightIndex=RightIndex<0?0:RightIndex;
RightIndex=RightIndex>88?88:RightIndex;
ALBuf->data[i*2*65+1]=(short)RightSample;
IMAData++;
for (j=2;j<130;j+=16)
{
LeftIMACode=IMAData[0];
RightIMACode=IMAData[1];
for (k=0;k<16;k+=4)
{
LeftSample+=((g_IMAStep_size[LeftIndex]*g_IMACodeword_4[LeftIMACode&15])/8);
LeftIndex+=g_IMAIndex_adjust_4[LeftIMACode&15];
if (LeftSample<-32768) LeftSample=-32768;
else if (LeftSample>32767) LeftSample=32767;
if (LeftIndex<0) LeftIndex=0;
else if (LeftIndex>88) LeftIndex=88;
ALBuf->data[i*2*65+j+k]=(short)LeftSample;
LeftIMACode>>=4;
RightSample+=((g_IMAStep_size[RightIndex]*g_IMACodeword_4[RightIMACode&15])/8);
RightIndex+=g_IMAIndex_adjust_4[RightIMACode&15];
if (RightSample<-32768) RightSample=-32768;
else if (RightSample>32767) RightSample=32767;
if (RightIndex<0) RightIndex=0;
else if (RightIndex>88) RightIndex=88;
ALBuf->data[i*2*65+j+k+1]=(short)RightSample;
RightIMACode>>=4;
LeftSample+=((g_IMAStep_size[LeftIndex]*g_IMACodeword_4[LeftIMACode&15])/8);
LeftIndex+=g_IMAIndex_adjust_4[LeftIMACode&15];
if (LeftSample<-32768) LeftSample=-32768;
else if (LeftSample>32767) LeftSample=32767;
if (LeftIndex<0) LeftIndex=0;
else if (LeftIndex>88) LeftIndex=88;
ALBuf->data[i*2*65+j+k+2]=(short)LeftSample;
LeftIMACode>>=4;
RightSample+=((g_IMAStep_size[RightIndex]*g_IMACodeword_4[RightIMACode&15])/8);
RightIndex+=g_IMAIndex_adjust_4[RightIMACode&15];
if (RightSample<-32768) RightSample=-32768;
else if (RightSample>32767) RightSample=32767;
if (RightIndex<0) RightIndex=0;
else if (RightIndex>88) RightIndex=88;
ALBuf->data[i*2*65+j+k+3]=(short)RightSample;
RightIMACode>>=4;
}
IMAData+=2;
}
}
memset(&(ALBuf->data[(size/72*2*65)]), 0, padding*2*2);
ALBuf->size=size/72*2*65*sizeof(ALshort);
ALBuf->frequency=freq;
ALBuf->padding=padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
else
alSetError(AL_INVALID_VALUE);
break;
break;
}
size /= 36;
size *= 65;
// Allocate extra padding samples
temp = realloc(ALBuf->data, (padding*OrigChans + size)*sizeof(ALshort));
if(temp)
{
ALBuf->data = temp;
ConvertDataIMA4(ALBuf->data, data, OrigChans, size/65);
memset(&(ALBuf->data[size]), 0, padding*sizeof(ALshort)*OrigChans);
ALBuf->format = ((OrigChans==1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16);
ALBuf->eOriginalFormat = format;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
} break;
default:
alSetError(AL_INVALID_ENUM);
@@ -614,6 +405,110 @@ ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *d
ProcessContext(Context);
}
/*
* alBufferSubDataEXT(ALuint buffer,ALenum format,ALvoid *data,ALsizei offset,ALsizei length)
*
* Fill buffer with audio data
*/
ALvoid ALAPIENTRY alBufferSubDataEXT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length)
{
ALCcontext *Context;
ALbuffer *ALBuf;
Context = alcGetCurrentContext();
SuspendContext(Context);
if(alIsBuffer(buffer) && buffer != 0)
{
ALBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffer);
if(ALBuf->data == NULL)
{
// buffer does not have any data
alSetError(AL_INVALID_NAME);
}
else if(length < 0 || offset < 0 || (length > 0 && data == NULL))
{
// data is NULL or offset/length is negative
alSetError(AL_INVALID_VALUE);
}
else
{
switch(format)
{
case AL_FORMAT_REAR8:
case AL_FORMAT_REAR16:
case AL_FORMAT_REAR32: {
ALuint OrigBytes = ((format==AL_FORMAT_REAR8) ? 1 :
((format==AL_FORMAT_REAR16) ? 2 :
4));
if(ALBuf->eOriginalFormat != AL_FORMAT_REAR8 &&
ALBuf->eOriginalFormat != AL_FORMAT_REAR16 &&
ALBuf->eOriginalFormat != AL_FORMAT_REAR32)
{
alSetError(AL_INVALID_ENUM);
break;
}
if(ALBuf->size/4/sizeof(ALshort) < (ALuint)offset+length)
{
alSetError(AL_INVALID_VALUE);
break;
}
ConvertDataRear(&ALBuf->data[offset*4], data, OrigBytes, length*2);
} break;
case AL_FORMAT_MONO_IMA4:
case AL_FORMAT_STEREO_IMA4: {
int Channels = aluChannelsFromFormat(ALBuf->format);
if(ALBuf->eOriginalFormat != format)
{
alSetError(AL_INVALID_ENUM);
break;
}
if((offset%65) != 0 || (length%65) != 0 ||
ALBuf->size/Channels/sizeof(ALshort) < (ALuint)offset+length)
{
alSetError(AL_INVALID_VALUE);
break;
}
ConvertDataIMA4(&ALBuf->data[offset*Channels], data, Channels, length/65*Channels);
} break;
default: {
ALuint Channels = aluChannelsFromFormat(format);
ALuint Bytes = aluBytesFromFormat(format);
if(Channels != aluChannelsFromFormat(ALBuf->format))
{
alSetError(AL_INVALID_ENUM);
break;
}
if(ALBuf->size/Channels/sizeof(ALshort) < (ALuint)offset+length)
{
alSetError(AL_INVALID_VALUE);
break;
}
ConvertData(&ALBuf->data[offset*Channels], data, Bytes, length*Channels);
} break;
}
}
}
else
{
// Invalid Buffer Name
alSetError(AL_INVALID_NAME);
}
ProcessContext(Context);
}
ALAPI void ALAPIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue)
{
@@ -1011,9 +906,8 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
ALuint NewChannels = aluChannelsFromFormat(NewFormat);
ALuint OrigBytes = aluBytesFromFormat(OrigFormat);
ALuint OrigChannels = aluChannelsFromFormat(OrigFormat);
ALsizei padding = freq / LOWPASSFREQCUTOFF;
ALsizei padding = 2;
ALvoid *temp;
ALsizei i;
assert(aluBytesFromFormat(NewFormat) == 2);
assert(NewChannels == OrigChannels);
@@ -1024,88 +918,153 @@ static void LoadData(ALbuffer *ALBuf, const ALubyte *data, ALsizei size, ALuint
return;
}
/* Ensure at least one padding byte for the bilinear filter */
if(padding < 1)
padding = 1;
switch(OrigBytes)
// Samples are converted to 16 bit here
size /= OrigBytes;
temp = realloc(ALBuf->data, (padding*NewChannels + size) * sizeof(ALshort));
if(temp)
{
case 1:
size /= sizeof(ALubyte);
ALBuf->data = temp;
ConvertData(ALBuf->data, data, OrigBytes, size);
// 8bit Samples are converted to 16 bit here
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
for (i = 0;i < size;i++)
ALBuf->data[i] = (ALshort)((data[i]-128) << 8);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
memset(&(ALBuf->data[size]), 0, padding*NewChannels*sizeof(ALshort));
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
}
case 2:
size /= sizeof(ALshort);
static void ConvertData(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len)
{
ALsizei i;
switch(origBytes)
{
case 1:
for(i = 0;i < len;i++)
dst[i] = ((ALshort)((ALubyte*)src)[i] - 128) << 8;
break;
// Allocate 8 extra samples
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALBuf->data = temp;
memcpy(ALBuf->data, data, size*1*sizeof(ALshort));
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
case 2:
memcpy(dst, src, len*sizeof(ALshort));
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
case 4:
size /= sizeof(ALfloat);
// Allocate 8 extra samples
temp = realloc(ALBuf->data, (padding*NewChannels + size) * (1*sizeof(ALshort)));
if (temp)
{
ALint smp;
ALBuf->data = temp;
for (i = 0;i < size;i++)
case 4:
for(i = 0;i < len;i++)
{
smp = (((ALfloat*)data)[i] * 32767.5f - 0.5f);
ALint smp;
smp = (((ALfloat*)src)[i] * 32767.5f - 0.5f);
smp = min(smp, 32767);
smp = max(smp, -32768);
ALBuf->data[i] = (ALshort)smp;
dst[i] = (ALshort)smp;
}
memset(&(ALBuf->data[size]), 0, padding*NewChannels*2);
break;
ALBuf->format = NewFormat;
ALBuf->eOriginalFormat = OrigFormat;
ALBuf->size = size*1*sizeof(ALshort);
ALBuf->frequency = freq;
ALBuf->padding = padding;
}
else
alSetError(AL_OUT_OF_MEMORY);
break;
default:
assert(0);
default:
assert(0);
}
}
static void ConvertDataRear(ALshort *dst, const ALvoid *src, ALint origBytes, ALsizei len)
{
ALsizei i;
switch(origBytes)
{
case 1:
for(i = 0;i < len;i+=4)
{
dst[i+0] = 0;
dst[i+1] = 0;
dst[i+2] = ((ALshort)((ALubyte*)src)[i/2+0] - 128) << 8;
dst[i+3] = ((ALshort)((ALubyte*)src)[i/2+1] - 128) << 8;
}
break;
case 2:
for(i = 0;i < len;i+=4)
{
dst[i+0] = 0;
dst[i+1] = 0;
dst[i+2] = ((ALshort*)src)[i/2+0];
dst[i+3] = ((ALshort*)src)[i/2+1];
}
break;
case 4:
for(i = 0;i < len;i+=4)
{
ALint smp;
dst[i+0] = 0;
dst[i+1] = 0;
smp = (((ALfloat*)src)[i/2+0] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i+2] = (ALshort)smp;
smp = (((ALfloat*)src)[i/2+1] * 32767.5f - 0.5);
smp = min(smp, 32767);
smp = max(smp, -32768);
dst[i+3] = (ALshort)smp;
}
break;
default:
assert(0);
}
}
static void ConvertDataIMA4(ALshort *dst, const ALvoid *src, ALint origChans, ALsizei len)
{
const ALuint *IMAData;
ALint Sample[2],Index[2];
ALuint IMACode[2];
ALsizei i,j,k,c;
assert(origChans <= 2);
IMAData = src;
for(i = 0;i < len/origChans;i++)
{
for(c = 0;c < origChans;c++)
{
Sample[c] = ((ALshort*)IMAData)[0];
Index[c] = ((ALshort*)IMAData)[1];
Index[c] = ((Index[c]<0) ? 0 : Index[c]);
Index[c] = ((Index[c]>88) ? 88 : Index[c]);
dst[i*65*origChans + c] = (ALshort)Sample[c];
IMAData++;
}
for(j = 1;j < 65;j += 8)
{
for(c = 0;c < origChans;c++)
IMACode[c] = *(IMAData++);
for(k = 0;k < 8;k++)
{
for(c = 0;c < origChans;c++)
{
Sample[c] += ((g_IMAStep_size[Index[c]]*g_IMACodeword_4[IMACode[c]&15])/8);
Index[c] += g_IMAIndex_adjust_4[IMACode[c]&15];
if(Sample[c] < -32768) Sample[c] = -32768;
else if(Sample[c] > 32767) Sample[c] = 32767;
if(Index[c]<0) Index[c] = 0;
else if(Index[c]>88) Index[c] = 88;
dst[(i*65+j+k)*origChans + c] = (ALshort)Sample[c];
IMACode[c] >>= 4;
}
}
}
}
}
/*
* ReleaseALBuffers()
+19 -13
View File
@@ -29,13 +29,17 @@
#include "alThunk.h"
#include "alError.h"
ALboolean DisabledEffects[MAX_EFFECTS];
static ALeffect *g_EffectList;
static ALuint g_EffectCount;
static void InitEffectParams(ALeffect *effect, ALenum type);
AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
{
ALCcontext *Context;
ALsizei i;
@@ -79,7 +83,7 @@ AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects)
ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects)
{
ALCcontext *Context;
ALeffect *ALEffect;
@@ -135,7 +139,7 @@ AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects)
ProcessContext(Context);
}
AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
ALboolean AL_APIENTRY alIsEffect(ALuint effect)
{
ALCcontext *Context;
ALeffect **list;
@@ -152,7 +156,7 @@ AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
return ((*list || !effect) ? AL_TRUE : AL_FALSE);
}
AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
{
ALCcontext *Context;
@@ -165,8 +169,10 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
if(param == AL_EFFECT_TYPE)
{
if(iValue == AL_EFFECT_NULL ||
iValue == AL_EFFECT_REVERB)
ALboolean isOk = (iValue == AL_EFFECT_NULL ||
(iValue == AL_EFFECT_REVERB && !DisabledEffects[REVERB]));
if(isOk)
InitEffectParams(ALEffect, iValue);
else
alSetError(AL_INVALID_VALUE);
@@ -196,7 +202,7 @@ AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues)
{
ALCcontext *Context;
@@ -233,7 +239,7 @@ AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValue
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue)
ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
@@ -346,7 +352,7 @@ AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
@@ -390,7 +396,7 @@ AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflVa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue)
ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue)
{
ALCcontext *Context;
@@ -427,7 +433,7 @@ AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piVal
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues)
{
ALCcontext *Context;
@@ -464,7 +470,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piVa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue)
ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
@@ -541,7 +547,7 @@ AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pfl
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
+3
View File
@@ -30,6 +30,7 @@
#include "alEffect.h"
#include "alAuxEffectSlot.h"
#include "alSource.h"
#include "alBuffer.h"
#include "AL/al.h"
#include "AL/alc.h"
@@ -144,6 +145,8 @@ static ALfunction function[]= {
{ "alGetAuxiliaryEffectSlotf", (ALvoid *) alGetAuxiliaryEffectSlotf },
{ "alGetAuxiliaryEffectSlotfv", (ALvoid *) alGetAuxiliaryEffectSlotfv},
{ "alBufferSubDataEXT", (ALvoid *) alBufferSubDataEXT },
{ NULL, (ALvoid *) NULL } };
static ALenums enumeration[]={
+11 -11
View File
@@ -35,7 +35,7 @@ static ALuint g_FilterCount;
static void InitFilterParams(ALfilter *filter, ALenum type);
AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
{
ALCcontext *Context;
ALsizei i;
@@ -79,7 +79,7 @@ AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
{
ALCcontext *Context;
ALfilter *ALFilter;
@@ -135,7 +135,7 @@ AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
ProcessContext(Context);
}
AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
ALboolean AL_APIENTRY alIsFilter(ALuint filter)
{
ALCcontext *Context;
ALfilter **list;
@@ -152,7 +152,7 @@ AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
return ((*list || !filter) ? AL_TRUE : AL_FALSE);
}
AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
{
ALCcontext *Context;
@@ -184,7 +184,7 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
{
ALCcontext *Context;
@@ -210,7 +210,7 @@ AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValue
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
{
ALCcontext *Context;
@@ -257,7 +257,7 @@ AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
@@ -279,7 +279,7 @@ AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflVa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
{
ALCcontext *Context;
@@ -307,7 +307,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piVal
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
{
ALCcontext *Context;
@@ -333,7 +333,7 @@ AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piVa
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
{
ALCcontext *Context;
@@ -374,7 +374,7 @@ AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pfl
ProcessContext(Context);
}
AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
{
ALCcontext *Context;
+102 -57
View File
@@ -33,7 +33,7 @@
#include "alAuxEffectSlot.h"
static ALvoid InitSourceParams(ALsource *pSource);
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset);
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize);
static ALvoid ApplyOffset(ALsource *pSource, ALboolean bUpdateContext);
static ALint GetByteOffset(ALsource *pSource);
@@ -75,8 +75,6 @@ ALAPI ALvoid ALAPIENTRY alGenSources(ALsizei n,ALuint *sources)
break;
}
InitLowPassFilter(Context, &(*list)->iirFilter);
sources[i] = (ALuint)ALTHUNK_ADDENTRY(*list);
(*list)->source = sources[i];
@@ -367,6 +365,13 @@ ALAPI ALvoid ALAPIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
alSetError(AL_INVALID_VALUE);
break;
case AL_DOPPLER_FACTOR:
if (flValue >= 0.0f && flValue <= 1.0f)
pSource->DopplerFactor = flValue;
else
alSetError(AL_INVALID_VALUE);
break;
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
@@ -627,9 +632,6 @@ ALAPI ALvoid ALAPIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
pSource->lSourceType = AL_UNDETERMINED;
}
// Set Buffers Processed
pSource->BuffersProcessed = 0;
// Update AL_BUFFER parameter
pSource->ulBufferID = lValue;
}
@@ -851,7 +853,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV
{
ALCcontext *pContext;
ALsource *pSource;
ALfloat flOffset;
ALfloat flOffset[2];
pContext = alcGetCurrentContext();
if (pContext)
@@ -901,8 +903,20 @@ ALAPI ALvoid ALAPIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflV
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
if (GetSourceOffset(pSource, eParam, &flOffset))
*pflValue = flOffset;
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
*pflValue = flOffset[0];
else
alSetError(AL_INVALID_OPERATION);
break;
case AL_SEC_RW_OFFSETS_EXT:
case AL_SAMPLE_RW_OFFSETS_EXT:
case AL_BYTE_RW_OFFSETS_EXT:
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
{
pflValue[0] = flOffset[0];
pflValue[1] = flOffset[1];
}
else
alSetError(AL_INVALID_OPERATION);
break;
@@ -1087,7 +1101,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
{
ALCcontext *pContext;
ALsource *pSource;
ALfloat flOffset;
ALfloat flOffset[2];
pContext = alcGetCurrentContext();
if (pContext)
@@ -1150,7 +1164,7 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
*plValue = 0;
}
else
*plValue = pSource->BuffersProcessed;
*plValue = pSource->BuffersPlayed;
break;
case AL_SOURCE_TYPE:
@@ -1160,8 +1174,20 @@ ALAPI ALvoid ALAPIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValu
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
if (GetSourceOffset(pSource, eParam, &flOffset))
*plValue = (ALint)flOffset;
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
*plValue = (ALint)flOffset[0];
else
alSetError(AL_INVALID_OPERATION);
break;
case AL_SEC_RW_OFFSETS_EXT:
case AL_SAMPLE_RW_OFFSETS_EXT:
case AL_BYTE_RW_OFFSETS_EXT:
if(GetSourceOffset(pSource, eParam, flOffset, pContext->Device->UpdateSize))
{
plValue[0] = (ALint)flOffset[0];
plValue[1] = (ALint)flOffset[1];
}
else
alSetError(AL_INVALID_OPERATION);
break;
@@ -1354,7 +1380,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
ALbufferlistitem *ALBufferList;
ALboolean bSourcesValid = AL_TRUE;
ALboolean bPlay;
ALsizei i;
ALsizei i, j;
pContext = alcGetCurrentContext();
if (pContext)
@@ -1397,6 +1423,10 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
if (bPlay)
{
for(j = 0;j < OUTPUTCHANNELS;j++)
pSource->DryGains[j] = 0.0f;
pSource->WetGain = 0.0f;
if (pSource->state != AL_PAUSED)
{
pSource->state = AL_PLAYING;
@@ -1404,10 +1434,8 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
pSource->play = AL_TRUE;
pSource->position = 0;
pSource->position_fraction = 0;
pSource->BuffersProcessed = 0;
pSource->BuffersPlayed = 0;
pSource->BufferPosition = 0;
pSource->lBytesPlayed = 0;
pSource->FirstStart = AL_TRUE;
pSource->ulBufferID = pSource->queue->buffer;
@@ -1424,6 +1452,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
pSource->state = AL_PLAYING;
pSource->inuse = AL_TRUE;
pSource->play = AL_TRUE;
pSource->FirstStart = AL_FALSE;
}
// Check if an Offset has been set
@@ -1440,7 +1469,7 @@ ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, const ALuint *pSourceList)
ALBufferList = ALBufferList->next;
}
pSource->BuffersPlayed = pSource->BuffersProcessed = pSource->BuffersInQueue;
pSource->BuffersPlayed = pSource->BuffersInQueue;
}
}
}
@@ -1564,7 +1593,7 @@ ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
{
Source->state=AL_STOPPED;
Source->inuse=AL_FALSE;
Source->BuffersPlayed = Source->BuffersProcessed = Source->BuffersInQueue;
Source->BuffersPlayed = Source->BuffersInQueue;
ALBufferListItem= Source->queue;
while (ALBufferListItem != NULL)
{
@@ -1636,7 +1665,7 @@ ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
Source->inuse=AL_FALSE;
Source->position=0;
Source->position_fraction=0;
Source->BuffersProcessed = 0;
Source->BuffersPlayed = 0;
ALBufferListItem= Source->queue;
while (ALBufferListItem != NULL)
{
@@ -1909,7 +1938,6 @@ ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint
// Release memory for buffer list item
free(ALBufferList);
ALSource->BuffersInQueue--;
ALSource->BuffersProcessed--;
}
if (ALSource->state != AL_PLAYING)
@@ -1923,10 +1951,7 @@ ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint
}
if((ALuint)n > ALSource->BuffersPlayed)
{
ALSource->BuffersPlayed = 0;
ALSource->BufferPosition = 0;
}
else
ALSource->BuffersPlayed -= n;
}
@@ -1998,12 +2023,13 @@ static ALvoid InitSourceParams(ALsource *pSource)
Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
The offset is relative to the start of the queue (not the start of the current buffer)
*/
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset)
static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOffset, ALuint updateSize)
{
ALbufferlistitem *pBufferList;
ALbuffer *pBuffer;
ALfloat flBufferFreq;
ALint lBytesPlayed, lChannels;
ALint lChannels;
ALint readPos, writePos;
ALenum eOriginalFormat;
ALboolean bReturn = AL_TRUE;
ALint lTotalBufferDataSize;
@@ -2017,15 +2043,20 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf
lChannels = aluChannelsFromFormat(pBuffer->format);
// Get Current BytesPlayed
lBytesPlayed = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
readPos = pSource->position * lChannels * 2; // NOTE : This is the byte offset into the *current* buffer
// Add byte length of any processed buffers in the queue
pBufferList = pSource->queue;
while ((pBufferList) && (pBufferList->bufferstate == PROCESSED))
{
lBytesPlayed += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
readPos += ((ALbuffer*)ALTHUNK_LOOKUPENTRY(pBufferList->buffer))->size;
pBufferList = pBufferList->next;
}
if(pSource->state == AL_PLAYING)
writePos = readPos + (updateSize * lChannels * 2);
else
writePos = readPos;
lTotalBufferDataSize = 0;
pBufferList = pSource->queue;
while (pBufferList)
@@ -2037,64 +2068,88 @@ static ALboolean GetSourceOffset(ALsource *pSource, ALenum eName, ALfloat *pflOf
if (pSource->bLooping)
{
if (lBytesPlayed < 0)
lBytesPlayed = 0;
if(readPos < 0)
readPos = 0;
else
lBytesPlayed = lBytesPlayed % lTotalBufferDataSize;
readPos %= lTotalBufferDataSize;
if(writePos < 0)
writePos = 0;
else
writePos %= lTotalBufferDataSize;
}
else
{
// Clamp BytesPlayed to within 0 and lTotalBufferDataSize
if(lBytesPlayed < 0)
lBytesPlayed = 0;
if(lBytesPlayed > lTotalBufferDataSize)
lBytesPlayed = lTotalBufferDataSize;
if(readPos < 0)
readPos = 0;
else if(readPos > lTotalBufferDataSize)
readPos = lTotalBufferDataSize;
if(writePos < 0)
writePos = 0;
else if(writePos > lTotalBufferDataSize)
writePos = lTotalBufferDataSize;
}
switch (eName)
{
case AL_SEC_OFFSET:
*pflOffset = ((ALfloat)lBytesPlayed / (lChannels * 2.0f * flBufferFreq));
case AL_SEC_RW_OFFSETS_EXT:
pflOffset[0] = (ALfloat)readPos / (lChannels * 2.0f * flBufferFreq);
pflOffset[1] = (ALfloat)writePos / (lChannels * 2.0f * flBufferFreq);
break;
case AL_SAMPLE_OFFSET:
*pflOffset = (ALfloat)(lBytesPlayed / (lChannels * 2));
case AL_SAMPLE_RW_OFFSETS_EXT:
pflOffset[0] = (ALfloat)(readPos / (lChannels * 2));
pflOffset[1] = (ALfloat)(writePos / (lChannels * 2));
break;
case AL_BYTE_OFFSET:
case AL_BYTE_RW_OFFSETS_EXT:
// Take into account the original format of the Buffer
if ((eOriginalFormat == AL_FORMAT_MONO_IMA4) ||
(eOriginalFormat == AL_FORMAT_STEREO_IMA4))
{
// Compression rate of the ADPCM supported is 3.6111 to 1
lBytesPlayed = (ALint)((ALfloat)lBytesPlayed / 3.6111f);
// Round down to nearest ADPCM block
*pflOffset = (ALfloat)((lBytesPlayed / (36 * lChannels)) * 36 * lChannels);
pflOffset[0] = (ALfloat)((readPos / (65 * 2 * lChannels)) * 36 * lChannels);
if(pSource->state == AL_PLAYING)
{
// Round up to nearest ADPCM block
pflOffset[1] = (ALfloat)(((writePos + (65 * 2 * lChannels) - 1) / (65 * 2 * lChannels)) * 36 * lChannels);
}
else
pflOffset[1] = pflOffset[0];
}
else if (eOriginalFormat == AL_FORMAT_REAR8)
{
*pflOffset = (ALfloat)(lBytesPlayed >> 2);
pflOffset[0] = (ALfloat)(readPos >> 2);
pflOffset[1] = (ALfloat)(writePos >> 2);
}
else if (eOriginalFormat == AL_FORMAT_REAR16)
{
*pflOffset = (ALfloat)(lBytesPlayed >> 1);
pflOffset[0] = (ALfloat)(readPos >> 1);
pflOffset[1] = (ALfloat)(writePos >> 1);
}
else if (aluBytesFromFormat(eOriginalFormat) == 1)
{
*pflOffset = (ALfloat)(lBytesPlayed >> 1);
pflOffset[0] = (ALfloat)(readPos >> 1);
pflOffset[1] = (ALfloat)(writePos >> 1);
}
else if (aluBytesFromFormat(eOriginalFormat) == 4)
{
*pflOffset = (ALfloat)(lBytesPlayed << 1);
pflOffset[0] = (ALfloat)(readPos << 1);
pflOffset[1] = (ALfloat)(writePos << 1);
}
else
{
*pflOffset = (ALfloat)lBytesPlayed;
pflOffset[0] = (ALfloat)readPos;
pflOffset[1] = (ALfloat)writePos;
}
break;
}
}
else
{
*pflOffset = 0.0f;
pflOffset[0] = 0.0f;
pflOffset[1] = 0.0f;
}
return bReturn;
@@ -2124,7 +2179,6 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
pBufferList = pSource->queue;
lTotalBufferSize = 0;
pSource->BuffersPlayed = 0;
pSource->BuffersProcessed = 0;
while (pBufferList)
{
pBuffer = ALTHUNK_LOOKUPENTRY(pBufferList->buffer);
@@ -2137,10 +2191,7 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
pSource->BuffersPlayed++;
if (!pSource->bLooping)
{
pBufferList->bufferstate = PROCESSED;
pSource->BuffersProcessed++;
}
}
else if (lTotalBufferSize <= lByteOffset)
{
@@ -2150,14 +2201,8 @@ static void ApplyOffset(ALsource *pSource, ALboolean bUpdateContext)
// Set Current Buffer ID
pSource->ulBufferID = pBufferList->buffer;
// Set current position in this buffer
pSource->BufferPosition = lByteOffset - lTotalBufferSize;
// Set Total Bytes Played to Offset
pSource->lBytesPlayed = lByteOffset;
// SW Mixer Positions are in Samples
pSource->position = pSource->BufferPosition /
pSource->position = (lByteOffset - lTotalBufferSize) /
aluBytesFromFormat(pBuffer->format) /
aluChannelsFromFormat(pBuffer->format);
}
+1 -1
View File
@@ -27,7 +27,7 @@
#include "alState.h"
static const ALchar alVendor[] = "OpenAL Community";
static const ALchar alVersion[] = "1.1";
static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION;
static const ALchar alRenderer[] = "OpenAL Soft";
// Error Messages
+14 -2
View File
@@ -5,6 +5,8 @@
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in ~/.alsoftrc.
# For Windows, these settings should go into %AppData%\alsoft.ini
# The environment variable ALSOFT_CONF can be used to specify another config
# override
# Option and block names are case-insenstive. The supplied values are only
# hints and may not be honored (though generally it'll try to get as close as
@@ -57,7 +59,13 @@ drivers = # Sets the backend driver list order, comma-seperated. Unknown
# backends and duplicated names are ignored, and unlisted backends
# won't be considered for use. An empty list means the default.
# Default is:
# alsa,oss,dsound,winmm,wave
# alsa,oss,solaris,dsound,winmm,wave
excludefx = # Sets which effects to exclude, preventing apps from using them.
# This can help for apps that try to use effects which are too CPU
# intensive for the system to handle. Available effects are:
# reverb
# Default is empty (all available effects enabled)
[alsa] # ALSA backend stuff
device = default # Sets the device name for the default playback device.
@@ -82,8 +90,12 @@ periods = 4 # Sets the number of update buffers. Default is 4
capture = /dev/dsp # Sets the device name for OSS capture. Default is /dev/dsp
[solaris] # Solaris backend stuff
device = /dev/audio # Sets the device name for Solaris output. Default is
# /dev/audio
[dsound] # DirectSound backend stuff
# Nothing yet...
periods = 4 # Sets the number of updates for the output buffer. Default is 4
[winmm] # Windows Multimedia backend stuff
# Nothing yet...
+18
View File
@@ -1,12 +1,18 @@
#ifndef CONFIG_H
#define CONFIG_H
/* Define to the library version */
#define ALSOFT_VERSION "${LIB_VERSION}"
/* Define if we have the ALSA backend */
#cmakedefine HAVE_ALSA
/* Define if we have the OSS backend */
#cmakedefine HAVE_OSS
/* Define if we have the Solaris backend */
#cmakedefine HAVE_SOLARIS
/* Define if we have the DSound backend */
#cmakedefine HAVE_DSOUND
@@ -49,4 +55,16 @@
/* Define if we have pthread_np.h */
#cmakedefine HAVE_PTHREAD_NP_H
/* Define if we have float.h */
#cmakedefine HAVE_FLOAT_H
/* Define if we have fenv.h */
#cmakedefine HAVE_FENV_H
/* Define if we have fesetround() */
#cmakedefine HAVE_FESETROUND
/* Define if we have _controlfp() */
#cmakedefine HAVE__CONTROLFP
#endif
+124 -1
View File
@@ -19,6 +19,37 @@
#include "AL/al.h"
#include "AL/alext.h"
#ifndef ALC_EXT_EFX
#define AL_FILTER_TYPE 0x8001
#define AL_EFFECT_TYPE 0x8001
#define AL_FILTER_NULL 0x0000
#define AL_FILTER_LOWPASS 0x0001
#define AL_FILTER_HIGHPASS 0x0002
#define AL_FILTER_BANDPASS 0x0003
#define AL_EFFECT_NULL 0x0000
#define AL_EFFECT_EAXREVERB 0x8000
#define AL_EFFECT_REVERB 0x0001
#define AL_EFFECT_CHORUS 0x0002
#define AL_EFFECT_DISTORTION 0x0003
#define AL_EFFECT_ECHO 0x0004
#define AL_EFFECT_FLANGER 0x0005
#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006
#define AL_EFFECT_VOCAL_MORPHER 0x0007
#define AL_EFFECT_PITCH_SHIFTER 0x0008
#define AL_EFFECT_RING_MODULATOR 0x0009
#define AL_EFFECT_AUTOWAH 0x000A
#define AL_EFFECT_COMPRESSOR 0x000B
#define AL_EFFECT_EQUALIZER 0x000C
#define ALC_EFX_MAJOR_VERSION 0x20001
#define ALC_EFX_MINOR_VERSION 0x20002
#define ALC_MAX_AUXILIARY_SENDS 0x20003
#endif
ALvoid (AL_APIENTRY *p_alGenFilters)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alDeleteFilters)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alFilteri)(ALuint,ALenum,ALint);
ALvoid (AL_APIENTRY *p_alGenEffects)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alDeleteEffects)(ALsizei,ALuint*);
ALvoid (AL_APIENTRY *p_alEffecti)(ALuint,ALenum,ALint);
static const int indentation = 4;
static const int maxmimumWidth = 79;
@@ -134,7 +165,7 @@ static void printALCInfo (void)
alcGetString(device, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
checkForErrors();
printf("ALC version: %d.%d\n", (int)major, (int)minor);
@@ -152,6 +183,97 @@ static void printALInfo(void)
checkForErrors();
}
static void printEFXInfo(void)
{
ALCint major, minor, sends;
ALCdevice *device;
ALuint obj;
int i;
const struct {
ALenum type;
const char *name;
} effects[] = {
{ AL_EFFECT_EAXREVERB, "EAX Reverb" },
{ AL_EFFECT_REVERB, "Standard Reverb" },
{ AL_EFFECT_CHORUS, "Chorus" },
{ AL_EFFECT_DISTORTION, "Distortion" },
{ AL_EFFECT_ECHO, "Echo" },
{ AL_EFFECT_FLANGER, "Flanger" },
{ AL_EFFECT_FREQUENCY_SHIFTER, "Frequency Shifter" },
{ AL_EFFECT_VOCAL_MORPHER, "Vocal Morpher" },
{ AL_EFFECT_PITCH_SHIFTER, "Pitch Shifter" },
{ AL_EFFECT_RING_MODULATOR, "Ring Modulator" },
{ AL_EFFECT_AUTOWAH, "Autowah" },
{ AL_EFFECT_COMPRESSOR, "Compressor" },
{ AL_EFFECT_EQUALIZER, "Equalizer" },
{ AL_EFFECT_NULL, NULL }
};
const struct {
ALenum type;
const char *name;
} filters[] = {
{ AL_FILTER_LOWPASS, "Low-pass" },
{ AL_FILTER_HIGHPASS, "High-pass" },
{ AL_FILTER_BANDPASS, "Band-pass" },
{ AL_FILTER_NULL, NULL }
};
device = alcGetContextsDevice(alcGetCurrentContext());
if(alcIsExtensionPresent(device, (const ALCchar*)"ALC_EXT_EFX") == AL_FALSE)
{
printf("EFX not available\n");
return;
}
alcGetIntegerv(device, ALC_EFX_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_EFX_MINOR_VERSION, 1, &minor);
checkForErrors();
printf("EFX version: %d.%d\n", (int)major, (int)minor);
alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
checkForErrors();
printf("Max auxiliary sends: %d\n", (int)sends);
p_alGenFilters = alGetProcAddress("alGenFilters");
p_alDeleteFilters = alGetProcAddress("alDeleteFilters");
p_alFilteri = alGetProcAddress("alFilteri");
p_alGenEffects = alGetProcAddress("alGenEffects");
p_alDeleteEffects = alGetProcAddress("alDeleteEffects");
p_alEffecti = alGetProcAddress("alEffecti");
checkForErrors();
if(!p_alGenEffects || !p_alDeleteEffects || !p_alEffecti ||
!p_alGenFilters || !p_alDeleteFilters || !p_alFilteri)
{
printf("Missing EFX functions!\n");
return;
}
p_alGenFilters(1, &obj);
checkForErrors();
printf("Available filters:\n");
for(i = 0;filters[i].type != AL_FILTER_NULL;i++)
{
p_alFilteri(obj, AL_FILTER_TYPE, filters[i].type);
if(alGetError() == AL_NO_ERROR)
printf(" %s\n", filters[i].name);
}
p_alDeleteFilters(1, &obj);
checkForErrors();
p_alGenEffects(1, &obj);
checkForErrors();
printf("Available effects:\n");
for(i = 0;effects[i].type != AL_EFFECT_NULL;i++)
{
p_alEffecti(obj, AL_EFFECT_TYPE, effects[i].type);
if(alGetError() == AL_NO_ERROR)
printf(" %s\n", effects[i].name);
}
p_alDeleteEffects(1, &obj);
checkForErrors();
}
int main()
{
ALCdevice *device = alcOpenDevice(NULL);
@@ -161,6 +283,7 @@ int main()
printALCInfo();
printALInfo();
printEFXInfo();
checkForErrors();
alcMakeContextCurrent(NULL);
+8
View File
@@ -91,6 +91,14 @@ extern "C" {
#define AL_FORMAT_STEREO_IMA4 0x1301
#endif
#ifndef AL_EXT_buffer_sub_data
#define AL_EXT_buffer_sub_data 1
#define AL_BYTE_RW_OFFSETS_EXT 0x1031
#define AL_SAMPLE_RW_OFFSETS_EXT 0x1032
#define AL_SEC_RW_OFFSETS_EXT 0x1033
typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATAEXTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
#endif
#ifdef __cplusplus
}
#endif