Exemplo n.º 1
0
static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot)
{
    ALfloat Gain;
    ALuint i;

    for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
        state->gains[i] = 0.0f;

    Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain;
    if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
    {
        int idx;
        if((idx=GetChannelIdxByName(device, LFE)) != -1)
            state->gains[idx] = Gain;
    }
    else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
    {
        int idx;
        /* Dialog goes to the front-center speaker if it exists, otherwise it
         * plays from the front-center location. */
        if((idx=GetChannelIdxByName(device, FrontCenter)) != -1)
            state->gains[idx] = Gain;
        else
        {
            static const ALfloat front_dir[3] = { 0.0f, 0.0f, -1.0f };
            ComputeDirectionalGains(device, front_dir, Gain, state->gains);
        }
    }
}
Exemplo n.º 2
0
static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint speakermap[MAX_OUTPUT_CHANNELS])
{
    ALuint i;

    for(i = 0;i < conf->NumSpeakers;i++)
    {
        int c = -1;

        /* NOTE: AmbDec does not define any standard speaker names, however
         * for this to work we have to by able to find the output channel
         * the speaker definition corresponds to. Therefore, OpenAL Soft
         * requires these channel labels to be recognized:
         *
         * LF = Front left
         * RF = Front right
         * LS = Side left
         * RS = Side right
         * LB = Back left
         * RB = Back right
         * CE = Front center
         * CB = Back center
         *
         * Additionally, surround51 will acknowledge back speakers for side
         * channels, and surround51rear will acknowledge side speakers for
         * back channels, to avoid issues with an ambdec expecting 5.1 to
         * use the side channels when the device is configured for back,
         * and vice-versa.
         */
        if(al_string_cmp_cstr(conf->Speakers[i].Name, "LF") == 0)
            c = GetChannelIdxByName(device->RealOut, FrontLeft);
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RF") == 0)
            c = GetChannelIdxByName(device->RealOut, FrontRight);
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CE") == 0)
            c = GetChannelIdxByName(device->RealOut, FrontCenter);
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LS") == 0)
        {
            if(device->FmtChans == DevFmtX51Rear)
                c = GetChannelIdxByName(device->RealOut, BackLeft);
            else
                c = GetChannelIdxByName(device->RealOut, SideLeft);
        }
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RS") == 0)
        {
            if(device->FmtChans == DevFmtX51Rear)
                c = GetChannelIdxByName(device->RealOut, BackRight);
            else
                c = GetChannelIdxByName(device->RealOut, SideRight);
        }
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LB") == 0)
        {
            if(device->FmtChans == DevFmtX51)
                c = GetChannelIdxByName(device->RealOut, SideLeft);
            else
                c = GetChannelIdxByName(device->RealOut, BackLeft);
        }
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RB") == 0)
        {
            if(device->FmtChans == DevFmtX51)
                c = GetChannelIdxByName(device->RealOut, SideRight);
            else
                c = GetChannelIdxByName(device->RealOut, BackRight);
        }
        else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CB") == 0)
            c = GetChannelIdxByName(device->RealOut, BackCenter);
        else
        {
            const char *name = al_string_get_cstr(conf->Speakers[i].Name);
            unsigned int n;
            char ch;

            if(sscanf(name, "AUX%u%c", &n, &ch) == 1 && n < 16)
                c = GetChannelIdxByName(device->RealOut, Aux0+n);
            else
            {
                ERR("AmbDec speaker label \"%s\" not recognized\n", name);
                return false;
            }
        }
        if(c == -1)
        {
            ERR("Failed to lookup AmbDec speaker label %s\n",
                al_string_get_cstr(conf->Speakers[i].Name));
            return false;
        }
        speakermap[i] = c;
    }

    return true;
}
Exemplo n.º 3
0
ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
{
    static const struct ChanMap MonoMap[1] = {
        { FrontCenter, 0.0f, 0.0f }
    }, StereoMap[2] = {
        { FrontLeft,  DEG2RAD(-30.0f), DEG2RAD(0.0f) },
        { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
    }, StereoWideMap[2] = {
        { FrontLeft,  DEG2RAD(-90.0f), DEG2RAD(0.0f) },
        { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
    }, RearMap[2] = {
        { BackLeft,  DEG2RAD(-150.0f), DEG2RAD(0.0f) },
        { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
    }, QuadMap[4] = {
        { FrontLeft,  DEG2RAD( -45.0f), DEG2RAD(0.0f) },
        { FrontRight, DEG2RAD(  45.0f), DEG2RAD(0.0f) },
        { BackLeft,   DEG2RAD(-135.0f), DEG2RAD(0.0f) },
        { BackRight,  DEG2RAD( 135.0f), DEG2RAD(0.0f) }
    }, X51Map[6] = {
        { FrontLeft,   DEG2RAD( -30.0f), DEG2RAD(0.0f) },
        { FrontRight,  DEG2RAD(  30.0f), DEG2RAD(0.0f) },
        { FrontCenter, DEG2RAD(   0.0f), DEG2RAD(0.0f) },
        { LFE, 0.0f, 0.0f },
        { SideLeft,    DEG2RAD(-110.0f), DEG2RAD(0.0f) },
        { SideRight,   DEG2RAD( 110.0f), DEG2RAD(0.0f) }
    }, X61Map[7] = {
        { FrontLeft,    DEG2RAD(-30.0f), DEG2RAD(0.0f) },
        { FrontRight,   DEG2RAD( 30.0f), DEG2RAD(0.0f) },
        { FrontCenter,  DEG2RAD(  0.0f), DEG2RAD(0.0f) },
        { LFE, 0.0f, 0.0f },
        { BackCenter,   DEG2RAD(180.0f), DEG2RAD(0.0f) },
        { SideLeft,     DEG2RAD(-90.0f), DEG2RAD(0.0f) },
        { SideRight,    DEG2RAD( 90.0f), DEG2RAD(0.0f) }
    }, X71Map[8] = {
        { FrontLeft,   DEG2RAD( -30.0f), DEG2RAD(0.0f) },
        { FrontRight,  DEG2RAD(  30.0f), DEG2RAD(0.0f) },
        { FrontCenter, DEG2RAD(   0.0f), DEG2RAD(0.0f) },
        { LFE, 0.0f, 0.0f },
        { BackLeft,    DEG2RAD(-150.0f), DEG2RAD(0.0f) },
        { BackRight,   DEG2RAD( 150.0f), DEG2RAD(0.0f) },
        { SideLeft,    DEG2RAD( -90.0f), DEG2RAD(0.0f) },
        { SideRight,   DEG2RAD(  90.0f), DEG2RAD(0.0f) }
    };

    ALCdevice *Device = ALContext->Device;
    ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
    ALbufferlistitem *BufferListItem;
    enum FmtChannels Channels;
    ALfloat DryGain, DryGainHF, DryGainLF;
    ALfloat WetGain[MAX_SENDS];
    ALfloat WetGainHF[MAX_SENDS];
    ALfloat WetGainLF[MAX_SENDS];
    ALuint NumSends, Frequency;
    ALboolean Relative;
    const struct ChanMap *chans = NULL;
    ALuint num_channels = 0;
    ALboolean DirectChannels;
    ALboolean isbformat = AL_FALSE;
    ALfloat Pitch;
    ALuint i, j, c;

    /* Get device properties */
    NumSends  = Device->NumAuxSends;
    Frequency = Device->Frequency;

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

    /* Get source properties */
    SourceVolume    = ALSource->Gain;
    MinVolume       = ALSource->MinGain;
    MaxVolume       = ALSource->MaxGain;
    Pitch           = ALSource->Pitch;
    Relative        = ALSource->HeadRelative;
    DirectChannels  = ALSource->DirectChannels;

    voice->Direct.OutBuffer = Device->DryBuffer;
    voice->Direct.OutChannels = Device->NumChannels;
    for(i = 0;i < NumSends;i++)
    {
        ALeffectslot *Slot = ALSource->Send[i].Slot;
        if(!Slot && i == 0)
            Slot = Device->DefaultSlot;
        if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
            voice->Send[i].OutBuffer = NULL;
        else
            voice->Send[i].OutBuffer = Slot->WetBuffer;
    }

    /* Calculate the stepping value */
    Channels = FmtMono;
    BufferListItem = ATOMIC_LOAD(&ALSource->queue);
    while(BufferListItem != NULL)
    {
        ALbuffer *ALBuffer;
        if((ALBuffer=BufferListItem->buffer) != NULL)
        {
            Pitch = Pitch * ALBuffer->Frequency / Frequency;
            if(Pitch > (ALfloat)MAX_PITCH)
                voice->Step = MAX_PITCH<<FRACTIONBITS;
            else
            {
                voice->Step = fastf2i(Pitch*FRACTIONONE);
                if(voice->Step == 0)
                    voice->Step = 1;
            }

            Channels = ALBuffer->FmtChannels;
            break;
        }
        BufferListItem = BufferListItem->next;
    }

    /* Calculate gains */
    DryGain  = clampf(SourceVolume, MinVolume, MaxVolume);
    DryGain  *= ALSource->Direct.Gain * ListenerGain;
    DryGainHF = ALSource->Direct.GainHF;
    DryGainLF = ALSource->Direct.GainLF;
    for(i = 0;i < NumSends;i++)
    {
        WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
        WetGain[i]  *= ALSource->Send[i].Gain * ListenerGain;
        WetGainHF[i] = ALSource->Send[i].GainHF;
        WetGainLF[i] = ALSource->Send[i].GainLF;
    }

    switch(Channels)
    {
    case FmtMono:
        chans = MonoMap;
        num_channels = 1;
        break;

    case FmtStereo:
        /* HACK: Place the stereo channels at +/-90 degrees when using non-
         * HRTF stereo output. This helps reduce the "monoization" caused
         * by them panning towards the center. */
        if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
            chans = StereoWideMap;
        else
            chans = StereoMap;
        num_channels = 2;
        break;

    case FmtRear:
        chans = RearMap;
        num_channels = 2;
        break;

    case FmtQuad:
        chans = QuadMap;
        num_channels = 4;
        break;

    case FmtX51:
        chans = X51Map;
        num_channels = 6;
        break;

    case FmtX61:
        chans = X61Map;
        num_channels = 7;
        break;

    case FmtX71:
        chans = X71Map;
        num_channels = 8;
        break;

    case FmtBFormat2D:
        num_channels = 3;
        isbformat = AL_TRUE;
        DirectChannels = AL_FALSE;
        break;

    case FmtBFormat3D:
        num_channels = 4;
        isbformat = AL_TRUE;
        DirectChannels = AL_FALSE;
        break;
    }

    if(isbformat)
    {
        ALfloat N[3], V[3], U[3];
        aluMatrix matrix;

        /* AT then UP */
        N[0] = ALSource->Orientation[0][0];
        N[1] = ALSource->Orientation[0][1];
        N[2] = ALSource->Orientation[0][2];
        aluNormalize(N);
        V[0] = ALSource->Orientation[1][0];
        V[1] = ALSource->Orientation[1][1];
        V[2] = ALSource->Orientation[1][2];
        aluNormalize(V);
        if(!Relative)
        {
            const aluMatrix *lmatrix = &ALContext->Listener->Params.Matrix;
            aluVector at, up;
            aluVectorSet(&at, N[0], N[1], N[2], 0.0f);
            aluVectorSet(&up, V[0], V[1], V[2], 0.0f);
            aluMatrixVector(&at, lmatrix);
            aluMatrixVector(&up, lmatrix);
            N[0] = at.v[0]; N[1] = at.v[1]; N[2] = at.v[2];
            V[0] = up.v[0]; V[1] = up.v[1]; V[2] = up.v[2];
        }
        /* Build and normalize right-vector */
        aluCrossproduct(N, V, U);
        aluNormalize(U);

        aluMatrixSet(&matrix,
            1.0f,  0.0f,  0.0f,  0.0f,
            0.0f, -N[2], -N[0],  N[1],
            0.0f,  U[2],  U[0], -U[1],
            0.0f, -V[2], -V[0],  V[1]
        );

        for(c = 0;c < num_channels;c++)
        {
            MixGains *gains = voice->Direct.Gains[c];
            ALfloat Target[MAX_OUTPUT_CHANNELS];

            ComputeBFormatGains(Device, matrix.m[c], DryGain, Target);
            for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
                gains[i].Target = Target[i];
        }
        UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
        voice->Direct.Moving = AL_TRUE;

        voice->IsHrtf = AL_FALSE;
        for(i = 0;i < NumSends;i++)
            WetGain[i] *= 1.4142f;
    }
    else if(DirectChannels != AL_FALSE)
    {
        if(Device->Hrtf)
        {
            voice->Direct.OutBuffer += voice->Direct.OutChannels;
            voice->Direct.OutChannels = 2;
            for(c = 0;c < num_channels;c++)
            {
                MixGains *gains = voice->Direct.Gains[c];

                for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
                    gains[j].Target = 0.0f;

                if(chans[c].channel == FrontLeft)
                    gains[0].Target = DryGain;
                else if(chans[c].channel == FrontRight)
                    gains[1].Target = DryGain;
            }
        }
        else for(c = 0;c < num_channels;c++)
        {
            MixGains *gains = voice->Direct.Gains[c];
            int idx;

            for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
                gains[j].Target = 0.0f;
            if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
                gains[idx].Target = DryGain;
        }
        UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
        voice->Direct.Moving = AL_TRUE;

        voice->IsHrtf = AL_FALSE;
    }
    else if(Device->Hrtf_Mode == FullHrtf)
    {
        voice->Direct.OutBuffer += voice->Direct.OutChannels;
        voice->Direct.OutChannels = 2;
        for(c = 0;c < num_channels;c++)
        {
            if(chans[c].channel == LFE)
            {
                /* Skip LFE */
                voice->Direct.Hrtf[c].Params.Delay[0] = 0;
                voice->Direct.Hrtf[c].Params.Delay[1] = 0;
                for(i = 0;i < HRIR_LENGTH;i++)
                {
                    voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f;
                    voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f;
                }
            }
            else
            {
                /* Get the static HRIR coefficients and delays for this
                 * channel. */
                GetLerpedHrtfCoeffs(Device->Hrtf,
                                    chans[c].elevation, chans[c].angle, 1.0f, DryGain,
                                    voice->Direct.Hrtf[c].Params.Coeffs,
                                    voice->Direct.Hrtf[c].Params.Delay);
            }
        }
        voice->Direct.Counter = 0;
        voice->Direct.Moving  = AL_TRUE;

        voice->IsHrtf = AL_TRUE;
    }
    else
    {
        for(c = 0;c < num_channels;c++)
        {
            MixGains *gains = voice->Direct.Gains[c];
            ALfloat Target[MAX_OUTPUT_CHANNELS];

            /* Special-case LFE */
            if(chans[c].channel == LFE)
            {
                int idx;
                for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
                    gains[i].Target = 0.0f;
                if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
                    gains[idx].Target = DryGain;
                continue;
            }

            ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
            for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
                gains[i].Target = Target[i];
        }
        UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
        voice->Direct.Moving = AL_TRUE;

        voice->IsHrtf = AL_FALSE;
    }
    for(i = 0;i < NumSends;i++)
    {
        voice->Send[i].Gain.Target = WetGain[i];
        UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
        voice->Send[i].Moving = AL_TRUE;
    }

    {
        ALfloat gainhf = maxf(0.01f, DryGainHF);
        ALfloat gainlf = maxf(0.01f, DryGainLF);
        ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
        ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
        for(c = 0;c < num_channels;c++)
        {
            voice->Direct.Filters[c].ActiveType = AF_None;
            if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
            if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
            ALfilterState_setParams(
                &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
                hfscale, 0.0f
            );
            ALfilterState_setParams(
                &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
                lfscale, 0.0f
            );
        }
    }
    for(i = 0;i < NumSends;i++)
    {
        ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
        ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
        ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
        ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
        for(c = 0;c < num_channels;c++)
        {
            voice->Send[i].Filters[c].ActiveType = AF_None;
            if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
            if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
            ALfilterState_setParams(
                &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
                hfscale, 0.0f
            );
            ALfilterState_setParams(
                &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
                lfscale, 0.0f
            );
        }
    }
}
Exemplo n.º 4
0
ALvoid aluInitPanning(ALCdevice *device)
{
    static const ChannelMap MonoCfg[1] = {
        { FrontCenter, { 1.4142f } },
    }, StereoCfg[2] = {
        { FrontLeft,   { 0.7071f,  0.5f, 0.0f, 0.0f } },
        { FrontRight,  { 0.7071f, -0.5f, 0.0f, 0.0f } },
    }, QuadCfg[4] = {
        { FrontLeft,   { 0.353553f,  0.306184f, 0.0f,  0.306184f,  0.117186f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { FrontRight,  { 0.353553f, -0.306184f, 0.0f,  0.306184f, -0.117186f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { BackLeft,    { 0.353553f,  0.306184f, 0.0f, -0.306184f, -0.117186f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { BackRight,   { 0.353553f, -0.306184f, 0.0f, -0.306184f,  0.117186f, 0.0f, 0.0f, 0.0f,  0.000000f } },
    }, X51SideCfg[5] = {
        { FrontLeft,   { 0.208954f,  0.238350f, 0.0f,  0.212846f,  0.204014f, 0.0f, 0.0f, 0.0f, -0.017738f,  0.047490f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f } },
        { FrontRight,  { 0.208954f, -0.238350f, 0.0f,  0.212846f, -0.204014f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.047490f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f } },
        { FrontCenter, { 0.109403f,  0.000000f, 0.0f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f } },
        { SideLeft,    { 0.470936f,  0.349386f, 0.0f, -0.369626f, -0.058144f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.043968f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f } },
        { SideRight,   { 0.470936f, -0.349386f, 0.0f, -0.369626f,  0.058144f, 0.0f, 0.0f, 0.0f, -0.031375f,  0.043968f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f } },
    }, X51RearCfg[5] = {
        { FrontLeft,   { 0.208954f,  0.238350f, 0.0f,  0.212846f,  0.204014f, 0.0f, 0.0f, 0.0f, -0.017738f,  0.047490f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f } },
        { FrontRight,  { 0.208954f, -0.238350f, 0.0f,  0.212846f, -0.204014f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.047490f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f } },
        { FrontCenter, { 0.109403f,  0.000000f, 0.0f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f } },
        { BackLeft,    { 0.470936f,  0.349386f, 0.0f, -0.369626f, -0.058144f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.043968f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f } },
        { BackRight,   { 0.470936f, -0.349386f, 0.0f, -0.369626f,  0.058144f, 0.0f, 0.0f, 0.0f, -0.031375f,  0.043968f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f } },
    }, X61Cfg[6] = {
        { FrontLeft,   { 0.167065f,  0.172695f, 0.0f,  0.200583f,  0.186407f, 0.0f, 0.0f, 0.0f,  0.029855f,  0.068910f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f } },
        { FrontRight,  { 0.167065f, -0.172695f, 0.0f,  0.200583f, -0.186407f, 0.0f, 0.0f, 0.0f,  0.029855f, -0.068910f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f } },
        { FrontCenter, { 0.109403f,  0.000000f, 0.0f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f } },
        { BackCenter,  { 0.353556f,  0.000000f, 0.0f, -0.461940f,  0.000000f, 0.0f, 0.0f, 0.0f,  0.165723f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { SideLeft,    { 0.289151f,  0.401292f, 0.0f, -0.081301f, -0.071420f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.032897f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.010099f } },
        { SideRight,   { 0.289151f, -0.401292f, 0.0f, -0.081301f,  0.071420f, 0.0f, 0.0f, 0.0f, -0.188208f,  0.032897f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.010099f } },
    }, X71Cfg[7] = {
        { FrontLeft,   { 0.167065f,  0.172695f, 0.0f,  0.200583f,  0.186407f, 0.0f, 0.0f, 0.0f,  0.029855f,  0.068910f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f } },
        { FrontRight,  { 0.167065f, -0.172695f, 0.0f,  0.200583f, -0.186407f, 0.0f, 0.0f, 0.0f,  0.029855f, -0.068910f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f } },
        { FrontCenter, { 0.109403f,  0.000000f, 0.0f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f } },
        { BackLeft,    { 0.224752f,  0.170325f, 0.0f, -0.295009f, -0.182473f, 0.0f, 0.0f, 0.0f,  0.105349f,  0.065799f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { BackRight,   { 0.224752f, -0.170325f, 0.0f, -0.295009f,  0.182473f, 0.0f, 0.0f, 0.0f,  0.105349f, -0.065799f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { SideLeft,    { 0.224739f,  0.340644f, 0.0f,  0.000000f,  0.000000f, 0.0f, 0.0f, 0.0f, -0.210697f, -0.065795f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f } },
        { SideRight,   { 0.224739f, -0.340644f, 0.0f,  0.000000f,  0.000000f, 0.0f, 0.0f, 0.0f, -0.210697f,  0.065795f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f } },
    }, BFormat3D[4] = {
        { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
        { BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } },
        { BFormatY, { 0.0f, 1.0f, 0.0f, 0.0f } },
        { BFormatZ, { 0.0f, 0.0f, 1.0f, 0.0f } },
    };
    const ChannelMap *chanmap = NULL;
    ALfloat ambiscale = 1.0f;
    size_t count = 0;

    device->AmbiScale = 1.0f;
    memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs));
    device->NumChannels = 0;

    if(device->Hrtf)
    {
        ALfloat (*coeffs_list[4])[2];
        ALuint *delay_list[4];
        ALuint i;

        count = COUNTOF(BFormat3D);
        chanmap = BFormat3D;
        ambiscale = 1.0f;

        for(i = 0;i < count;i++)
            device->ChannelName[i] = chanmap[i].ChanName;
        for(;i < MAX_OUTPUT_CHANNELS;i++)
            device->ChannelName[i] = InvalidChannel;
        SetChannelMap(device, chanmap, count, ambiscale);

        for(i = 0;i < 4;++i)
        {
            static const enum Channel inputs[4] = { BFormatW, BFormatY, BFormatZ, BFormatX };
            int chan = GetChannelIdxByName(device, inputs[i]);
            coeffs_list[i] = device->Hrtf_Params[chan].Coeffs;
            delay_list[i] = device->Hrtf_Params[chan].Delay;
        }
        GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list);

        return;
    }

    if(LoadChannelSetup(device))
        return;

    switch(device->FmtChans)
    {
        case DevFmtMono:
            count = COUNTOF(MonoCfg);
            chanmap = MonoCfg;
            ambiscale = ZERO_ORDER_SCALE;
            break;

        case DevFmtStereo:
            count = COUNTOF(StereoCfg);
            chanmap = StereoCfg;
            ambiscale = FIRST_ORDER_SCALE;
            break;

        case DevFmtQuad:
            count = COUNTOF(QuadCfg);
            chanmap = QuadCfg;
            ambiscale = SECOND_ORDER_SCALE;
            break;

        case DevFmtX51:
            count = COUNTOF(X51SideCfg);
            chanmap = X51SideCfg;
            ambiscale = THIRD_ORDER_SCALE;
            break;

        case DevFmtX51Rear:
            count = COUNTOF(X51RearCfg);
            chanmap = X51RearCfg;
            ambiscale = THIRD_ORDER_SCALE;
            break;

        case DevFmtX61:
            count = COUNTOF(X61Cfg);
            chanmap = X61Cfg;
            ambiscale = THIRD_ORDER_SCALE;
            break;

        case DevFmtX71:
            count = COUNTOF(X71Cfg);
            chanmap = X71Cfg;
            ambiscale = THIRD_ORDER_SCALE;
            break;

        case DevFmtBFormat3D:
            count = COUNTOF(BFormat3D);
            chanmap = BFormat3D;
            ambiscale = 1.0f;
            break;
    }

    SetChannelMap(device, chanmap, count, ambiscale);
}