view ext/openal-soft/Alc/ALu.c @ 295:faabfaf25f15

Removed the deletion of the search space from the the RoutePatherSearch class. This will fix the path finding so it now will calculate paths correctly. It should not be deleting the search space because it does not own it, it is only using it for calculations. Need to investigate further as to why the memory consumption continually increases when running UH. Also removed the need to store a local pointer in RoutePatherSearch to the singleton instance of a Heuristic, this will eliminate the possibly of having a dangling pointer or deleting something that it shouldn't.
author vtchill@33b003aa-7bff-0310-803a-e67f0ece8222
date Fri, 03 Jul 2009 05:11:54 +0000
parents 4a0efb7baf70
children
line wrap: on
line source

/**
 * 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
 */

#define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005

#include "config.h"

#include <math.h>
#include "alMain.h"
#include "AL/al.h"
#include "AL/alc.h"
#include "alSource.h"
#include "alBuffer.h"
#include "alThunk.h"
#include "alListener.h"
#include "alAuxEffectSlot.h"
#include "bs2b.h"

#if defined(HAVE_STDINT_H)
#include <stdint.h>
typedef int64_t ALint64;
#elif defined(HAVE___INT64)
typedef __int64 ALint64;
#elif (SIZEOF_LONG == 8)
typedef long ALint64;
#elif (SIZEOF_LONG_LONG == 8)
typedef long long ALint64;
#endif

#ifdef HAVE_SQRTF
#define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
#else
#define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
#endif

#ifdef HAVE_ACOSF
#define aluAcos(x) ((ALfloat)acosf((float)(x)))
#else
#define aluAcos(x) ((ALfloat)acos((double)(x)))
#endif

// fixes for mingw32.
#if defined(max) && !defined(__max)
#define __max max
#endif
#if defined(min) && !defined(__min)
#define __min min
#endif

#define BUFFERSIZE 48000
#define FRACTIONBITS 14
#define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
#define MAX_PITCH 4

enum {
    FRONT_LEFT = 0,
    FRONT_RIGHT,
    SIDE_LEFT,
    SIDE_RIGHT,
    BACK_LEFT,
    BACK_RIGHT,
    CENTER,
    LFE,

    OUTPUTCHANNELS
};

ALboolean DuplicateStereo = AL_FALSE;

/* NOTE: The AL_FORMAT_REAR* enums aren't handled here be cause they're
 *       converted to AL_FORMAT_QUAD* when loaded */
__inline ALuint aluBytesFromFormat(ALenum format)
{
    switch(format)
    {
        case AL_FORMAT_MONO8:
        case AL_FORMAT_STEREO8:
        case AL_FORMAT_QUAD8_LOKI:
        case AL_FORMAT_QUAD8:
        case AL_FORMAT_51CHN8:
        case AL_FORMAT_61CHN8:
        case AL_FORMAT_71CHN8:
            return 1;

        case AL_FORMAT_MONO16:
        case AL_FORMAT_STEREO16:
        case AL_FORMAT_QUAD16_LOKI:
        case AL_FORMAT_QUAD16:
        case AL_FORMAT_51CHN16:
        case AL_FORMAT_61CHN16:
        case AL_FORMAT_71CHN16:
            return 2;

        case AL_FORMAT_MONO_FLOAT32:
        case AL_FORMAT_STEREO_FLOAT32:
        case AL_FORMAT_QUAD32:
        case AL_FORMAT_51CHN32:
        case AL_FORMAT_61CHN32:
        case AL_FORMAT_71CHN32:
            return 4;

        default:
            return 0;
    }
}

__inline ALuint aluChannelsFromFormat(ALenum format)
{
    switch(format)
    {
        case AL_FORMAT_MONO8:
        case AL_FORMAT_MONO16:
        case AL_FORMAT_MONO_FLOAT32:
            return 1;

        case AL_FORMAT_STEREO8:
        case AL_FORMAT_STEREO16:
        case AL_FORMAT_STEREO_FLOAT32:
            return 2;

        case AL_FORMAT_QUAD8_LOKI:
        case AL_FORMAT_QUAD16_LOKI:
        case AL_FORMAT_QUAD8:
        case AL_FORMAT_QUAD16:
        case AL_FORMAT_QUAD32:
            return 4;

        case AL_FORMAT_51CHN8:
        case AL_FORMAT_51CHN16:
        case AL_FORMAT_51CHN32:
            return 6;

        case AL_FORMAT_61CHN8:
        case AL_FORMAT_61CHN16:
        case AL_FORMAT_61CHN32:
            return 7;

        case AL_FORMAT_71CHN8:
        case AL_FORMAT_71CHN16:
        case AL_FORMAT_71CHN32:
            return 8;

        default:
            return 0;
    }
}


static __inline ALshort aluF2S(ALfloat Value)
{
    ALint i;

    i = (ALint)Value;
    i = __min( 32767, i);
    i = __max(-32768, i);
    return ((ALshort)i);
}

static __inline ALvoid aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector)
{
    outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
    outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
    outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
}

static __inline ALfloat aluDotproduct(ALfloat *inVector1,ALfloat *inVector2)
{
    return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
           inVector1[2]*inVector2[2];
}

static __inline ALvoid aluNormalize(ALfloat *inVector)
{
    ALfloat length, inverse_length;

    length = aluSqrt(aluDotproduct(inVector, inVector));
    if(length != 0.0f)
    {
        inverse_length = 1.0f/length;
        inVector[0] *= inverse_length;
        inVector[1] *= inverse_length;
        inVector[2] *= inverse_length;
    }
}

static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat matrix[3][3])
{
    ALfloat result[3];

    result[0] = vector[0]*matrix[0][0] + vector[1]*matrix[1][0] + vector[2]*matrix[2][0];
    result[1] = vector[0]*matrix[0][1] + vector[1]*matrix[1][1] + vector[2]*matrix[2][1];
    result[2] = vector[0]*matrix[0][2] + vector[1]*matrix[1][2] + vector[2]*matrix[2][2];
    memcpy(vector, result, sizeof(result));
}

static __inline ALfloat aluComputeSample(ALfloat GainHF, ALfloat sample, ALfloat LastSample)
{
    if(GainHF < 1.0f)
    {
        if(GainHF > 0.0f)
        {
            sample *= GainHF;
            sample += LastSample * (1.0f-GainHF);
        }
        else
            sample = 0.0f;
    }

    return sample;
}

static ALvoid CalcSourceParams(ALCcontext *ALContext, ALsource *ALSource,
                               ALenum isMono, ALenum OutputFormat,
                               ALfloat *drysend, ALfloat *wetsend,
                               ALfloat *pitch, ALfloat *drygainhf,
                               ALfloat *wetgainhf)
{
    ALfloat InnerAngle,OuterAngle,Angle,Distance,DryMix,WetMix=0.0f;
    ALfloat Direction[3],Position[3],SourceToListener[3];
    ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
    ALfloat ConeVolume,SourceVolume,PanningFB,PanningLR,ListenerGain;
    ALfloat U[3],V[3],N[3];
    ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound, flMaxVelocity;
    ALfloat Matrix[3][3];
    ALfloat flAttenuation;
    ALfloat RoomAttenuation;
    ALfloat MetersPerUnit;
    ALfloat RoomRolloff;
    ALfloat DryGainHF = 1.0f;
    ALfloat WetGainHF = 1.0f;

    //Get context properties
    DopplerFactor   = ALContext->DopplerFactor;
    DopplerVelocity = ALContext->DopplerVelocity;
    flSpeedOfSound  = ALContext->flSpeedOfSound;

    //Get listener properties
    ListenerGain = ALContext->Listener.Gain;
    MetersPerUnit = ALContext->Listener.MetersPerUnit;

    //Get source properties
    SourceVolume = ALSource->flGain;
    memcpy(Position,  ALSource->vPosition,    sizeof(ALSource->vPosition));
    memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
    MinVolume    = ALSource->flMinGain;
    MaxVolume    = ALSource->flMaxGain;
    MinDist      = ALSource->flRefDistance;
    MaxDist      = ALSource->flMaxDistance;
    Rolloff      = ALSource->flRollOffFactor;
    InnerAngle   = ALSource->flInnerAngle;
    OuterAngle   = ALSource->flOuterAngle;
    OuterGainHF  = ALSource->OuterGainHF;
    RoomRolloff  = ALSource->RoomRolloffFactor;

    //Only apply 3D calculations for mono buffers
    if(isMono != AL_FALSE)
    {
        //1. Translate Listener to origin (convert to head relative)
        if(ALSource->bHeadRelative==AL_FALSE)
        {
            Position[0] -= ALContext->Listener.Position[0];
            Position[1] -= ALContext->Listener.Position[1];
            Position[2] -= ALContext->Listener.Position[2];
        }

        //2. Calculate distance attenuation
        Distance = aluSqrt(aluDotproduct(Position, Position));

        if(ALSource->Send[0].Slot && !ALSource->Send[0].Slot->AuxSendAuto)
        {
            if(ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB)
                RoomRolloff = ALSource->Send[0].Slot->effect.Reverb.RoomRolloffFactor;
        }

        flAttenuation = 1.0f;
        RoomAttenuation = 1.0f;
        switch (ALContext->DistanceModel)
        {
            case AL_INVERSE_DISTANCE_CLAMPED:
                Distance=__max(Distance,MinDist);
                Distance=__min(Distance,MaxDist);
                if (MaxDist < MinDist)
                    break;
                //fall-through
            case AL_INVERSE_DISTANCE:
                if (MinDist > 0.0f)
                {
                    if ((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
                        flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
                    if ((MinDist + (RoomRolloff * (Distance - MinDist))) > 0.0f)
                        RoomAttenuation = MinDist / (MinDist + (RoomRolloff * (Distance - MinDist)));
                }
                break;

            case AL_LINEAR_DISTANCE_CLAMPED:
                Distance=__max(Distance,MinDist);
                Distance=__min(Distance,MaxDist);
                if (MaxDist < MinDist)
                    break;
                //fall-through
            case AL_LINEAR_DISTANCE:
                Distance=__min(Distance,MaxDist);
                if (MaxDist != MinDist)
                {
                    flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
                    RoomAttenuation = 1.0f - (RoomRolloff*(Distance-MinDist)/(MaxDist - MinDist));
                }
                break;

            case AL_EXPONENT_DISTANCE_CLAMPED:
                Distance=__max(Distance,MinDist);
                Distance=__min(Distance,MaxDist);
                if (MaxDist < MinDist)
                    break;
                //fall-through
            case AL_EXPONENT_DISTANCE:
                if ((Distance > 0.0f) && (MinDist > 0.0f))
                {
                    flAttenuation = (ALfloat)pow(Distance/MinDist, -Rolloff);
                    RoomAttenuation = (ALfloat)pow(Distance/MinDist, -RoomRolloff);
                }
                break;

            case AL_NONE:
            default:
                flAttenuation = 1.0f;
                RoomAttenuation = 1.0f;
                break;
        }

        // 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 = __min(WetMix,MaxVolume);
        WetMix = __max(WetMix,MinVolume);

        //3. Apply directional soundcones
        SourceToListener[0] = -Position[0];
        SourceToListener[1] = -Position[1];
        SourceToListener[2] = -Position[2];
        aluNormalize(Direction);
        aluNormalize(SourceToListener);
        Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f /
                3.141592654f;
        if(Angle >= InnerAngle && Angle <= OuterAngle)
        {
            ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
            ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
            if(ALSource->WetGainAuto)
                WetMix *= ConeVolume;
            if(ALSource->DryGainHFAuto)
                DryGainHF *= (1.0f+(OuterGainHF-1.0f)*scale);
            if(ALSource->WetGainHFAuto)
                WetGainHF *= (1.0f+(OuterGainHF-1.0f)*scale);
        }
        else if(Angle > OuterAngle)
        {
            ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
            if(ALSource->WetGainAuto)
                WetMix *= ConeVolume;
            if(ALSource->DryGainHFAuto)
                DryGainHF *= (1.0f+(OuterGainHF-1.0f));
            if(ALSource->WetGainHFAuto)
                WetGainHF *= (1.0f+(OuterGainHF-1.0f));
        }
        else
            ConeVolume = 1.0f;

        //4. Calculate Velocity
        if(DopplerFactor != 0.0f)
        {
            ALfloat flVSS, flVLS;

            flVLS = aluDotproduct(ALContext->Listener.Velocity,
                                  SourceToListener);
            flVSS = aluDotproduct(ALSource->vVelocity, SourceToListener);

            flMaxVelocity = (DopplerVelocity * flSpeedOfSound) / DopplerFactor;

            if (flVSS >= flMaxVelocity)
                flVSS = (flMaxVelocity - 1.0f);
            else if (flVSS <= -flMaxVelocity)
                flVSS = -flMaxVelocity + 1.0f;

            if (flVLS >= flMaxVelocity)
                flVLS = (flMaxVelocity - 1.0f);
            else if (flVLS <= -flMaxVelocity)
                flVLS = -flMaxVelocity + 1.0f;

            pitch[0] = ALSource->flPitch *
                       ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) /
                       ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS));
        }
        else
            pitch[0] = ALSource->flPitch;

        //5. Align coordinate system axes
        aluCrossproduct(ALContext->Listener.Forward, ALContext->Listener.Up, U); // Right-vector
        aluNormalize(U);  // Normalized Right-vector
        memcpy(V, ALContext->Listener.Up, sizeof(V));   // Up-vector
        aluNormalize(V);  // Normalized Up-vector
        memcpy(N, ALContext->Listener.Forward, sizeof(N));  // At-vector
        aluNormalize(N);  // Normalized At-vector
        Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0];
        Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1];
        Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2];
        aluMatrixVector(Position, Matrix);

        //6. Apply filter gains and filters
        switch(ALSource->DirectFilter.filter)
        {
            case AL_FILTER_LOWPASS:
                DryMix *= ALSource->DirectFilter.Gain;
                DryGainHF *= ALSource->DirectFilter.GainHF;
                break;
        }

        switch(ALSource->Send[0].WetFilter.filter)
        {
            case AL_FILTER_LOWPASS:
                WetMix *= ALSource->Send[0].WetFilter.Gain;
                WetGainHF *= ALSource->Send[0].WetFilter.GainHF;
                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)
            {
                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;
        WetMix *= ListenerGain;

        //7. Convert normalized position into pannings, then into channel volumes
        aluNormalize(Position);
        switch(aluChannelsFromFormat(OutputFormat))
        {
            case 1:
                drysend[FRONT_LEFT]  = DryMix * aluSqrt(1.0f); //Direct
                drysend[FRONT_RIGHT] = DryMix * aluSqrt(1.0f); //Direct
                wetsend[FRONT_LEFT]  = WetMix * aluSqrt(1.0f); //Room
                wetsend[FRONT_RIGHT] = WetMix * aluSqrt(1.0f); //Room
                break;
            case 2:
                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
                wetsend[FRONT_LEFT]  = WetMix * aluSqrt(1.0f-PanningLR); //L Room
                wetsend[FRONT_RIGHT] = WetMix * aluSqrt(     PanningLR); //R Room
                break;
            case 4:
            /* TODO: Add center/lfe channel in spatial calculations? */
            case 6:
                // Apply a scalar so each individual speaker has more weight
                PanningLR = 0.5f + (0.5f*Position[0]*1.41421356f);
                PanningLR = __min(1.0f, PanningLR);
                PanningLR = __max(0.0f, PanningLR);
                PanningFB = 0.5f + (0.5f*Position[2]*1.41421356f);
                PanningFB = __min(1.0f, PanningFB);
                PanningFB = __max(0.0f, PanningFB);
                drysend[FRONT_LEFT]  = DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
                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));
                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));
                break;
            case 7:
            case 8:
                PanningFB = 1.0f - fabs(Position[2]*1.15470054f);
                PanningFB = __min(1.0f, PanningFB);
                PanningFB = __max(0.0f, PanningFB);
                PanningLR = 0.5f + (0.5*Position[0]*((1.0f-PanningFB)*2.0f));
                PanningLR = __min(1.0f, PanningLR);
                PanningLR = __max(0.0f, PanningLR);
                if(Position[2] > 0.0f)
                {
                    drysend[BACK_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
                    drysend[BACK_RIGHT]  = DryMix * aluSqrt((     PanningLR)*(1.0f-PanningFB));
                    drysend[SIDE_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(     PanningFB));
                    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
                {
                    drysend[FRONT_LEFT]  = DryMix * aluSqrt((1.0f-PanningLR)*(1.0f-PanningFB));
                    drysend[FRONT_RIGHT] = DryMix * aluSqrt((     PanningLR)*(1.0f-PanningFB));
                    drysend[SIDE_LEFT]   = DryMix * aluSqrt((1.0f-PanningLR)*(     PanningFB));
                    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;
        }

        *drygainhf = DryGainHF;
        *wetgainhf = WetGainHF;
    }
    else
    {
        //1. Multi-channel buffers always play "normal"
        pitch[0] = ALSource->flPitch;

        drysend[FRONT_LEFT]  = SourceVolume * ListenerGain;
        drysend[FRONT_RIGHT] = SourceVolume * ListenerGain;
        drysend[SIDE_LEFT]   = SourceVolume * ListenerGain;
        drysend[SIDE_RIGHT]  = SourceVolume * ListenerGain;
        drysend[BACK_LEFT]   = SourceVolume * ListenerGain;
        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;
        WetGainHF = 1.0f;

        *drygainhf = DryGainHF;
        *wetgainhf = WetGainHF;
    }
}

ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum format)
{
    static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS];
    static float WetBuffer[BUFFERSIZE][OUTPUTCHANNELS];
    static float ReverbBuffer[BUFFERSIZE];
    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 };
    ALfloat DryGainHF = 0.0f;
    ALfloat WetGainHF = 0.0f;
    ALuint BlockAlign,BufferSize;
    ALuint DataSize=0,DataPosInt=0,DataPosFrac=0;
    ALuint Channels,Frequency,ulExtraSamples;
    ALfloat DrySample, WetSample;
    ALboolean doReverb;
    ALfloat Pitch;
    ALint Looping,increment,State;
    ALuint Buffer,fraction;
    ALuint SamplesToDo;
    ALsource *ALSource;
    ALbuffer *ALBuffer;
    ALeffectslot *ALEffectSlot;
    ALfloat value;
    ALshort *Data;
    ALuint i,j,k;
    ALbufferlistitem *BufferListItem;
    ALuint loop;
    ALint64 DataSize64,DataPos64;

    SuspendContext(ALContext);

    //Figure output format variables
    BlockAlign  = aluChannelsFromFormat(format);
    BlockAlign *= aluBytesFromFormat(format);

    size /= BlockAlign;
    while(size > 0)
    {
        //Setup variables
        ALEffectSlot = (ALContext ? ALContext->AuxiliaryEffectSlot : NULL);
        ALSource = (ALContext ? ALContext->Source : NULL);
        SamplesToDo = min(size, BUFFERSIZE);

        //Clear mixing buffer
        memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
        memset(WetBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
        memset(ReverbBuffer, 0, SamplesToDo*sizeof(ALfloat));

        //Actual mixing loop
        while(ALSource)
        {
            j = 0;
            State = ALSource->state;

            doReverb = ((ALSource->Send[0].Slot &&
                            ALSource->Send[0].Slot->effect.type == AL_EFFECT_REVERB) ?
                        AL_TRUE : AL_FALSE);

            while(State == AL_PLAYING && j < SamplesToDo)
            {
                DataSize = 0;
                DataPosInt = 0;
                DataPosFrac = 0;

                //Get buffer info
                if((Buffer = ALSource->ulBufferID))
                {
                    ALBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(Buffer);

                    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
                    DataPosInt = ALSource->position;
                    DataPosFrac = ALSource->position_fraction;
                    DrySample = ALSource->LastDrySample;
                    WetSample = ALSource->LastWetSample;

                    //Compute 18.14 fixed point step
                    increment = (ALint)(Pitch*(ALfloat)(1L<<FRACTIONBITS));
                    if(increment > (MAX_PITCH<<FRACTIONBITS))
                        increment = (MAX_PITCH<<FRACTIONBITS);

                    //Figure out how many samples we can mix.
                    //Pitch must be <= 4 (the number below !)
                    DataSize64 = DataSize+MAX_PITCH;
                    DataSize64 <<= FRACTIONBITS;
                    DataPos64 = DataPosInt;
                    DataPos64 <<= FRACTIONBITS;
                    DataPos64 += DataPosFrac;
                    BufferSize = (ALuint)((DataSize64-DataPos64) / increment);
                    BufferListItem = ALSource->queue;
                    for(loop = 0; loop < ALSource->BuffersPlayed; loop++)
                    {
                        if(BufferListItem)
                            BufferListItem = BufferListItem->next;
                    }
                    if (BufferListItem)
                    {
                        if (BufferListItem->next)
                        {
                            ALbuffer *NextBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(BufferListItem->next->buffer);
                            if(NextBuf && NextBuf->data)
                            {
                                ulExtraSamples = min(NextBuf->size, (ALint)(16*Channels));
                                memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
                            }
                        }
                        else if (ALSource->bLooping)
                        {
                            ALbuffer *NextBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(ALSource->queue->buffer);
                            if (NextBuf && NextBuf->data)
                            {
                                ulExtraSamples = min(NextBuf->size, (ALint)(16*Channels));
                                memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
                            }
                        }
                    }
                    BufferSize = min(BufferSize, (SamplesToDo-j));

                    //Actual sample mixing loop
                    Data += DataPosInt*Channels;
                    while(BufferSize--)
                    {
                        k = DataPosFrac>>FRACTIONBITS;
                        fraction = DataPosFrac&FRACTIONMASK;
                        if(Channels==1)
                        {
                            //First order interpolator
                            ALfloat sample = (ALfloat)((ALshort)(((Data[k]*((1L<<FRACTIONBITS)-fraction))+(Data[k+1]*(fraction)))>>FRACTIONBITS));

                            //Direct path final mix buffer and panning
                            DrySample = aluComputeSample(DryGainHF, sample, DrySample);
                            DryBuffer[j][FRONT_LEFT]  += DrySample*DrySend[FRONT_LEFT];
                            DryBuffer[j][FRONT_RIGHT] += DrySample*DrySend[FRONT_RIGHT];
                            DryBuffer[j][SIDE_LEFT]   += DrySample*DrySend[SIDE_LEFT];
                            DryBuffer[j][SIDE_RIGHT]  += DrySample*DrySend[SIDE_RIGHT];
                            DryBuffer[j][BACK_LEFT]   += DrySample*DrySend[BACK_LEFT];
                            DryBuffer[j][BACK_RIGHT]  += DrySample*DrySend[BACK_RIGHT];
                            //Room path final mix buffer and panning
                            WetSample = aluComputeSample(WetGainHF, sample, WetSample);
                            if(doReverb)
                                ReverbBuffer[j] += WetSample;
                            else
                            {
                                WetBuffer[j][FRONT_LEFT]  += WetSample*WetSend[FRONT_LEFT];
                                WetBuffer[j][FRONT_RIGHT] += WetSample*WetSend[FRONT_RIGHT];
                                WetBuffer[j][SIDE_LEFT]   += WetSample*WetSend[SIDE_LEFT];
                                WetBuffer[j][SIDE_RIGHT]  += WetSample*WetSend[SIDE_RIGHT];
                                WetBuffer[j][BACK_LEFT]   += WetSample*WetSend[BACK_LEFT];
                                WetBuffer[j][BACK_RIGHT]  += WetSample*WetSend[BACK_RIGHT];
                            }
                        }
                        else
                        {
                            ALfloat samp1, samp2;
                            //First order interpolator (front left)
                            samp1 = (ALfloat)((ALshort)(((Data[k*Channels  ]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels  ]*(fraction)))>>FRACTIONBITS));
                            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));
                            DryBuffer[j][FRONT_RIGHT] += samp2*DrySend[FRONT_RIGHT];
                            WetBuffer[j][FRONT_RIGHT] += samp2*WetSend[FRONT_RIGHT];
                            if(Channels >= 4)
                            {
                                int i = 2;
                                if(Channels >= 6)
                                {
                                    if(Channels != 7)
                                    {
                                        //First order interpolator (center)
                                        value = (ALfloat)((ALshort)(((Data[k*Channels+i]*((1L<<FRACTIONBITS)-fraction))+(Data[(k+1)*Channels+i]*(fraction)))>>FRACTIONBITS));
                                        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));
                                    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));
                                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));
                                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));
                                    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));
                                    DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT];
                                    WetBuffer[j][SIDE_RIGHT] += value*WetSend[SIDE_RIGHT];
                                    i++;
                                }
                            }
                            else if(DuplicateStereo)
                            {
                                //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;
                        j++;
                    }
                    DataPosInt += (DataPosFrac>>FRACTIONBITS);
                    DataPosFrac = (DataPosFrac&FRACTIONMASK);

                    //Update source info
                    ALSource->position = DataPosInt;
                    ALSource->position_fraction = DataPosFrac;
                    ALSource->LastDrySample = DrySample;
                    ALSource->LastWetSample = WetSample;
                }

                //Handle looping sources
                if(!Buffer || DataPosInt >= DataSize)
                {
                    //queueing
                    if(ALSource->queue)
                    {
                        Looping = ALSource->bLooping;
                        if(ALSource->BuffersPlayed < (ALSource->BuffersInQueue-1))
                        {
                            BufferListItem = ALSource->queue;
                            for(loop = 0; loop <= ALSource->BuffersPlayed; loop++)
                            {
                                if(BufferListItem)
                                {
                                    if(!Looping)
                                        BufferListItem->bufferstate = PROCESSED;
                                    BufferListItem = BufferListItem->next;
                                }
                            }
                            if(!Looping)
                                ALSource->BuffersProcessed++;
                            if(BufferListItem)
                                ALSource->ulBufferID = BufferListItem->buffer;
                            ALSource->position = DataPosInt-DataSize;
                            ALSource->position_fraction = DataPosFrac;
                            ALSource->BuffersPlayed++;
                        }
                        else
                        {
                            if(!Looping)
                            {
                                /* alSourceStop */
                                ALSource->state = AL_STOPPED;
                                ALSource->inuse = AL_FALSE;
                                ALSource->BuffersPlayed = ALSource->BuffersProcessed = ALSource->BuffersInQueue;
                                BufferListItem = ALSource->queue;
                                while(BufferListItem != NULL)
                                {
                                    BufferListItem->bufferstate = PROCESSED;
                                    BufferListItem = BufferListItem->next;
                                }
                            }
                            else
                            {
                                /* alSourceRewind */
                                /* alSourcePlay */
                                ALSource->state = AL_PLAYING;
                                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)
                                {
                                    BufferListItem->bufferstate = PENDING;
                                    BufferListItem = BufferListItem->next;
                                }
                                ALSource->ulBufferID = ALSource->queue->buffer;

                                ALSource->position = DataPosInt-DataSize;
                                ALSource->position_fraction = DataPosFrac;
                            }
                        }
                    }
                }

                //Get source state
                State = ALSource->state;
            }

            ALSource = ALSource->next;
        }

        // effect slot processing
        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 Gain = ALEffectSlot->effect.Reverb.Gain;
                ALfloat ReflectGain = ALEffectSlot->effect.Reverb.ReflectionsGain;
                ALfloat LateReverbGain = ALEffectSlot->effect.Reverb.LateReverbGain;
                ALfloat LastDecaySample = ALEffectSlot->LastDecaySample;
                ALfloat sample;

                for(i = 0;i < SamplesToDo;i++)
                {
                    DelayBuffer[Pos] = ReverbBuffer[i] * Gain;

                    sample = DelayBuffer[ReflectPos] * ReflectGain;

                    DelayBuffer[LatePos] *= LateReverbGain;

                    Pos = (Pos+1) % Length;
                    DelayBuffer[Pos] *= DecayHFRatio;
                    DelayBuffer[Pos] += LastDecaySample * (1.0f-DecayHFRatio);
                    LastDecaySample = DelayBuffer[Pos];
                    DelayBuffer[Pos] *= DecayGain;

                    DelayBuffer[LatePos] += DelayBuffer[Pos];

                    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;
                ALEffectSlot->LastDecaySample = LastDecaySample;
            }

            ALEffectSlot = ALEffectSlot->next;
        }

        //Post processing loop
        switch(format)
        {
            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);
                    buffer = ((ALubyte*)buffer) + 1;
                }
                break;
            case AL_FORMAT_STEREO8:
                if(ALContext && ALContext->bs2b)
                {
                    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];
                        bs2b_cross_feed(ALContext->bs2b, samples);
                        ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(samples[0])>>8)+128);
                        ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(samples[1])>>8)+128);
                        buffer = ((ALubyte*)buffer) + 2;
                    }
                }
                else
                {
                    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);
                        buffer = ((ALubyte*)buffer) + 2;
                    }
                }
                break;
            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);
                    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);
#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);
#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);
#endif
                    buffer = ((ALubyte*)buffer) + 6;
                }
                break;
            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);
#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);
#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);
#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);
                    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);
#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);
#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);
#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);
                    buffer = ((ALubyte*)buffer) + 8;
                }
                break;

            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]);
                    buffer = ((ALshort*)buffer) + 1;
                }
                break;
            case AL_FORMAT_STEREO16:
                if(ALContext && ALContext->bs2b)
                {
                    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];
                        bs2b_cross_feed(ALContext->bs2b, samples);
                        ((ALshort*)buffer)[0] = aluF2S(samples[0]);
                        ((ALshort*)buffer)[1] = aluF2S(samples[1]);
                        buffer = ((ALshort*)buffer) + 2;
                    }
                }
                else
                {
                    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]);
                        buffer = ((ALshort*)buffer) + 2;
                    }
                }
                break;
            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]);
                    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]);
#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]);
#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]);
#endif
                    buffer = ((ALshort*)buffer) + 6;
                }
                break;
            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]);
#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]);
#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]);
#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]);
                    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]);
#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]);
#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]);
#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]);
                    buffer = ((ALshort*)buffer) + 8;
                }
                break;

            default:
                break;
        }

        size -= SamplesToDo;
    }

    ProcessContext(ALContext);
}