示例#1
0
static GenModList GenModList_clone(const GenModList *self)
{
    GenModList ret;

    GenModList_Construct(&ret);

    VECTOR_INSERT(ret.gens, VECTOR_ITER_END(ret.gens),
        VECTOR_ITER_BEGIN(self->gens), VECTOR_ITER_END(self->gens)
    );
    VECTOR_INSERT(ret.mods, VECTOR_ITER_END(ret.mods),
        VECTOR_ITER_BEGIN(self->mods), VECTOR_ITER_END(self->mods)
    );

    return ret;
}
示例#2
0
static void GenModList_accumGen(GenModList *self, const Generator *gen)
{
    Generator *i = VECTOR_ITER_BEGIN(self->gens);
    Generator *end = VECTOR_ITER_END(self->gens);
    for(;i != end;i++)
    {
        if(i->mGenerator == gen->mGenerator)
        {
            if(gen->mGenerator == 43 || gen->mGenerator == 44)
            {
                /* Range generators accumulate by taking the intersection of
                 * the two ranges.
                 */
                ALushort low = maxu(i->mAmount&0x00ff, gen->mAmount&0x00ff);
                ALushort high = minu(i->mAmount&0xff00, gen->mAmount&0xff00);
                i->mAmount = low | high;
            }
            else
                i->mAmount += gen->mAmount;
            return;
        }
    }

    if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
    {
        ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
        return;
    }
    if(gen->mGenerator < 60)
        VECTOR_BACK(self->gens).mAmount += DefaultGenValue[gen->mGenerator];
}
示例#3
0
static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboolean ispreset)
{
    Generator *i = VECTOR_ITER_BEGIN(self->gens);
    Generator *end = VECTOR_ITER_END(self->gens);
    for(;i != end;i++)
    {
        if(i->mGenerator == gen->mGenerator)
        {
            i->mAmount = gen->mAmount;
            return;
        }
    }

    if(ispreset &&
       (gen->mGenerator == 0 || gen->mGenerator == 1 || gen->mGenerator == 2 ||
        gen->mGenerator == 3 || gen->mGenerator == 4 || gen->mGenerator == 12 ||
        gen->mGenerator == 45 || gen->mGenerator == 46 || gen->mGenerator == 47 ||
        gen->mGenerator == 50 || gen->mGenerator == 54 || gen->mGenerator == 57 ||
        gen->mGenerator == 58))
        return;

    if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
    {
        ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
        return;
    }
}
示例#4
0
AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
{
    ALCcontext *context;

    context = GetContextRef();
    if(!context) return;

    if(!context->DeferUpdates)
    {
        ALboolean UpdateSources;
        ALactivesource **src, **src_end;
        ALeffectslot **slot, **slot_end;
        FPUCtl oldMode;

        SetMixerFPUMode(&oldMode);

        LockContext(context);
        context->DeferUpdates = AL_TRUE;

        /* Make sure all pending updates are performed */
        UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE);

        src = context->ActiveSources;
        src_end = src + context->ActiveSourceCount;
        while(src != src_end)
        {
            ALsource *source = (*src)->Source;

            if(source->state != AL_PLAYING && source->state != AL_PAUSED)
            {
                ALactivesource *temp = *(--src_end);
                *src_end = *src;
                *src = temp;
                --(context->ActiveSourceCount);
                continue;
            }

            if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)
                (*src)->Update(*src, context);

            src++;
        }

        slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
        slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
        while(slot != slot_end)
        {
            if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
                V((*slot)->EffectState,update)(context->Device, *slot);
            slot++;
        }

        UnlockContext(context);
        RestoreFPUMode(&oldMode);
    }

    ALCcontext_DecRef(context);
}
示例#5
0
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
    ALCcontext *context;
    VECTOR(ALeffectslot*) slotvec;
    ALsizei cur;
    ALenum err;

    context = GetContextRef();
    if(!context) return;

    VECTOR_INIT(slotvec);

    if(!(n >= 0))
        SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
    if(!VECTOR_RESERVE(slotvec, n))
        SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);

    for(cur = 0;cur < n;cur++)
    {
        ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
        err = AL_OUT_OF_MEMORY;
        if(!slot || (err=InitEffectSlot(slot)) != AL_NO_ERROR)
        {
            al_free(slot);
            alDeleteAuxiliaryEffectSlots(cur, effectslots);
            SET_ERROR_AND_GOTO(context, err, done);
        }

        err = NewThunkEntry(&slot->id);
        if(err == AL_NO_ERROR)
            err = InsertUIntMapEntry(&context->EffectSlotMap, slot->id, slot);
        if(err != AL_NO_ERROR)
        {
            FreeThunkEntry(slot->id);
            DELETE_OBJ(slot->EffectState);
            al_free(slot);

            alDeleteAuxiliaryEffectSlots(cur, effectslots);
            SET_ERROR_AND_GOTO(context, err, done);
        }

        VECTOR_PUSH_BACK(slotvec, slot);

        effectslots[cur] = slot->id;
    }
    err = AddEffectSlotArray(context, VECTOR_ITER_BEGIN(slotvec), n);
    if(err != AL_NO_ERROR)
    {
        alDeleteAuxiliaryEffectSlots(cur, effectslots);
        SET_ERROR_AND_GOTO(context, err, done);
    }

done:
    VECTOR_DEINIT(slotvec);

    ALCcontext_DecRef(context);
}
示例#6
0
static void clear_devlist(vector_DevMap *list)
{
    DevMap *iter, *end;

    iter = VECTOR_ITER_BEGIN(*list);
    end = VECTOR_ITER_END(*list);
    for(;iter != end;++iter)
        AL_STRING_DEINIT(iter->name);
    VECTOR_RESIZE(*list, 0);
}
示例#7
0
文件: alsa.c 项目: johndpope/Medusa
static void clear_devlist(vector_DevMap *devlist)
{
    DevMap *iter, *end;

    iter = VECTOR_ITER_BEGIN(*devlist);
    end = VECTOR_ITER_END(*devlist);
    for(;iter != end;iter++)
    {
        AL_STRING_DEINIT(iter->name);
        AL_STRING_DEINIT(iter->device_name);
    }
    VECTOR_RESIZE(*devlist, 0);
}
示例#8
0
static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data)
{
    vector_DevMap *devices = data;
    OLECHAR *guidstr = NULL;
    DevMap *iter, *end;
    DevMap entry;
    HRESULT hr;
    int count;

    if(!guid)
        return TRUE;

    AL_STRING_INIT(entry.name);

    count = 0;
    do {
        al_string_copy_wcstr(&entry.name, desc);
        if(count != 0)
        {
            char str[64];
            snprintf(str, sizeof(str), " #%d", count+1);
            al_string_append_cstr(&entry.name, str);
        }
        count++;

        iter = VECTOR_ITER_BEGIN(*devices);
        end = VECTOR_ITER_END(*devices);
        for(;iter != end;++iter)
        {
            if(al_string_cmp(entry.name, iter->name) == 0)
                break;
        }
    } while(iter != end);
    entry.guid = *guid;

    hr = StringFromCLSID(guid, &guidstr);
    if(SUCCEEDED(hr))
    {
        TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry.name), guidstr);
        CoTaskMemFree(guidstr);
    }

    VECTOR_PUSH_BACK(*devices, entry);

    return TRUE;
}
示例#9
0
static void ProbePlaybackDevices(void)
{
    al_string *iter, *end;
    ALuint numdevs;
    ALuint i;

    clear_devlist(&PlaybackDevices);

    numdevs = waveOutGetNumDevs();
    VECTOR_RESERVE(PlaybackDevices, numdevs);
    for(i = 0; i < numdevs; i++)
    {
        WAVEOUTCAPSW WaveCaps;
        al_string dname;

        AL_STRING_INIT(dname);
        if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
        {
            ALuint count = 0;
            do {
                al_string_copy_wcstr(&dname, WaveCaps.szPname);
                if(count != 0)
                {
                    char str[64];
                    snprintf(str, sizeof(str), " #%d", count+1);
                    al_string_append_cstr(&dname, str);
                }
                count++;

                iter = VECTOR_ITER_BEGIN(PlaybackDevices);
                end = VECTOR_ITER_END(PlaybackDevices);
                for(; iter != end; iter++)
                {
                    if(al_string_cmp(*iter, dname) == 0)
                        break;
                }
            } while(iter != end);

            TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
        }
        VECTOR_PUSH_BACK(PlaybackDevices, dname);
    }
}
示例#10
0
static void GenModList_insertMod(GenModList *self, const Modulator *mod)
{
    Modulator *i = VECTOR_ITER_BEGIN(self->mods);
    Modulator *end = VECTOR_ITER_END(self->mods);
    for(;i != end;i++)
    {
        if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
           i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp)
        {
            i->mAmount = mod->mAmount;
            return;
        }
    }

    if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
    {
        ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
        return;
    }
}
示例#11
0
static void GenModList_accumMod(GenModList *self, const Modulator *mod)
{
    Modulator *i = VECTOR_ITER_BEGIN(self->mods);
    Modulator *end = VECTOR_ITER_END(self->mods);
    for(;i != end;i++)
    {
        if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
           i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp)
        {
            i->mAmount += mod->mAmount;
            return;
        }
    }

    if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
    {
        ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
        return;
    }

    if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 960;
    else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += -2400;
    else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 50;
    else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 50;
    else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 960;
    else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 1000;
    else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 960;
    else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 200;
    else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 200;
    /*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0)
        VECTOR_BACK(self->mods).mAmount += 12700;*/
}
示例#12
0
static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp)
{
    Generator *gen = VECTOR_ITER_BEGIN(zone->gens);
    Generator *gen_end = VECTOR_ITER_END(zone->gens);
    for(;gen != gen_end;gen++)
    {
        if(gen->mGenerator == 43 || gen->mGenerator == 44)
        {
            int high = gen->mAmount>>8;
            int low = gen->mAmount&0xff;

            if(!(low >= 0 && high <= 127 && high >= low))
            {
                TRACE("Preset \"%s\", inst \"%s\", sample \"%s\": invalid %s range %d...%d\n",
                      preset->mName, inst->mName, samp->mName,
                      (gen->mGenerator == 43) ? "key" :
                      (gen->mGenerator == 44) ? "velocity" : "(unknown)",
                      low, high);
                return AL_FALSE;
            }
        }
    }
示例#13
0
static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
{
    const al_string *iter, *end;
    ALbyte *BufferData = NULL;
    DWORD CapturedDataSize;
    WinMMData *data = NULL;
    ALint BufferSize;
    UINT DeviceID;
    MMRESULT res;
    ALuint i;

    if(VECTOR_SIZE(CaptureDevices) == 0)
        ProbeCaptureDevices();

    // Find the Device ID matching the deviceName if valid
    iter = VECTOR_ITER_BEGIN(CaptureDevices);
    end = VECTOR_ITER_END(CaptureDevices);
    for(; iter != end; iter++)
    {
        if(!al_string_empty(*iter) &&
                (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
        {
            DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
            break;
        }
    }
    if(iter == end)
        return ALC_INVALID_VALUE;

    switch(Device->FmtChans)
    {
    case DevFmtMono:
    case DevFmtStereo:
        break;

    case DevFmtQuad:
    case DevFmtX51:
    case DevFmtX51Side:
    case DevFmtX61:
    case DevFmtX71:
        return ALC_INVALID_ENUM;
    }

    switch(Device->FmtType)
    {
    case DevFmtUByte:
    case DevFmtShort:
    case DevFmtInt:
    case DevFmtFloat:
        break;

    case DevFmtByte:
    case DevFmtUShort:
    case DevFmtUInt:
        return ALC_INVALID_ENUM;
    }

    data = calloc(1, sizeof(*data));
    if(!data)
        return ALC_OUT_OF_MEMORY;
    Device->ExtraData = data;

    memset(&data->Format, 0, sizeof(WAVEFORMATEX));
    data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ?
                               WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
    data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans);
    data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8;
    data->Format.nBlockAlign = data->Format.wBitsPerSample *
                               data->Format.nChannels / 8;
    data->Format.nSamplesPerSec = Device->Frequency;
    data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec *
                                   data->Format.nBlockAlign;
    data->Format.cbSize = 0;

    if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
    {
        ERR("waveInOpen failed: %u\n", res);
        goto failure;
    }

    // Allocate circular memory buffer for the captured audio
    CapturedDataSize = Device->UpdateSize*Device->NumUpdates;

    // Make sure circular buffer is at least 100ms in size
    if(CapturedDataSize < (data->Format.nSamplesPerSec / 10))
        CapturedDataSize = data->Format.nSamplesPerSec / 10;

    data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize);
    if(!data->Ring)
        goto failure;

    InitRef(&data->WaveBuffersCommitted, 0);

    // Create 4 Buffers of 50ms each
    BufferSize = data->Format.nAvgBytesPerSec / 20;
    BufferSize -= (BufferSize % data->Format.nBlockAlign);

    BufferData = calloc(4, BufferSize);
    if(!BufferData)
        goto failure;

    for(i = 0; i < 4; i++)
    {
        memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
        data->WaveBuffer[i].dwBufferLength = BufferSize;
        data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
                                      (data->WaveBuffer[i-1].lpData +
                                       data->WaveBuffer[i-1].dwBufferLength));
        data->WaveBuffer[i].dwFlags = 0;
        data->WaveBuffer[i].dwLoops = 0;
        waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
        waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
        IncrementRef(&data->WaveBuffersCommitted);
    }

    if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success)
        goto failure;

    al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
    return ALC_NO_ERROR;

failure:
    if(BufferData)
    {
        for(i = 0; i < 4; i++)
            waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
        free(BufferData);
    }

    if(data->Ring)
        DestroyRingBuffer(data->Ring);

    if(data->WaveHandle.In)
        waveInClose(data->WaveHandle.In);

    free(data);
    Device->ExtraData = NULL;
    return ALC_INVALID_VALUE;
}
示例#14
0
static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName)
{
    WinMMData *data = NULL;
    const al_string *iter, *end;
    UINT DeviceID;
    MMRESULT res;

    if(VECTOR_SIZE(PlaybackDevices) == 0)
        ProbePlaybackDevices();

    // Find the Device ID matching the deviceName if valid
    iter = VECTOR_ITER_BEGIN(PlaybackDevices);
    end = VECTOR_ITER_END(PlaybackDevices);
    for(; iter != end; iter++)
    {
        if(!al_string_empty(*iter) &&
                (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
        {
            DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
            break;
        }
    }
    if(iter == end)
        return ALC_INVALID_VALUE;

    data = calloc(1, sizeof(*data));
    if(!data)
        return ALC_OUT_OF_MEMORY;
    Device->ExtraData = data;

retry_open:
    memset(&data->Format, 0, sizeof(WAVEFORMATEX));
    if(Device->FmtType == DevFmtFloat)
    {
        data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
        data->Format.wBitsPerSample = 32;
    }
    else
    {
        data->Format.wFormatTag = WAVE_FORMAT_PCM;
        if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte)
            data->Format.wBitsPerSample = 8;
        else
            data->Format.wBitsPerSample = 16;
    }
    data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2);
    data->Format.nBlockAlign = data->Format.wBitsPerSample *
                               data->Format.nChannels / 8;
    data->Format.nSamplesPerSec = Device->Frequency;
    data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec *
                                   data->Format.nBlockAlign;
    data->Format.cbSize = 0;

    if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
    {
        if(Device->FmtType == DevFmtFloat)
        {
            Device->FmtType = DevFmtShort;
            goto retry_open;
        }
        ERR("waveOutOpen failed: %u\n", res);
        goto failure;
    }

    al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
    return ALC_NO_ERROR;

failure:
    if(data->WaveHandle.Out)
        waveOutClose(data->WaveHandle.Out);

    free(data);
    Device->ExtraData = NULL;
    return ALC_INVALID_VALUE;
}
示例#15
0
文件: ALu.c 项目: johndpope/Medusa
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
{
    ALuint SamplesToDo;
    ALeffectslot **slot, **slot_end;
    ALvoice *voice, *voice_end;
    ALCcontext *ctx;
    FPUCtl oldMode;
    ALuint i, c;

    SetMixerFPUMode(&oldMode);

    while(size > 0)
    {
        ALfloat (*OutBuffer)[BUFFERSIZE];
        ALuint OutChannels;

        IncrementRef(&device->MixCount);

        OutBuffer = device->DryBuffer;
        OutChannels = device->NumChannels;

        SamplesToDo = minu(size, BUFFERSIZE);
        for(c = 0;c < OutChannels;c++)
            memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
        if(device->Hrtf)
        {
            /* Set OutBuffer/OutChannels to correspond to the actual output
             * with HRTF. Make sure to clear them too. */
            OutBuffer += OutChannels;
            OutChannels = 2;
            for(c = 0;c < OutChannels;c++)
                memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
        }

        V0(device->Backend,lock)();
        V(device->Synth,process)(SamplesToDo, OutBuffer, OutChannels);

        ctx = ATOMIC_LOAD(&device->ContextList);
        while(ctx)
        {
            ALenum DeferUpdates = ctx->DeferUpdates;
            ALenum UpdateSources = AL_FALSE;

            if(!DeferUpdates)
                UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);

            if(UpdateSources)
                CalcListenerParams(ctx->Listener);

            /* source processing */
            voice = ctx->Voices;
            voice_end = voice + ctx->VoiceCount;
            while(voice != voice_end)
            {
                ALsource *source = voice->Source;
                if(!source) goto next;

                if(source->state != AL_PLAYING && source->state != AL_PAUSED)
                {
                    voice->Source = NULL;
                    goto next;
                }

                if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
                                     UpdateSources))
                    voice->Update(voice, source, ctx);

                if(source->state != AL_PAUSED)
                    MixSource(voice, source, device, SamplesToDo);
            next:
                voice++;
            }

            /* effect slot processing */
            slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
            slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
            while(slot != slot_end)
            {
                if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
                    V((*slot)->EffectState,update)(device, *slot);

                V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
                                                device->DryBuffer, device->NumChannels);

                for(i = 0;i < SamplesToDo;i++)
                    (*slot)->WetBuffer[0][i] = 0.0f;

                slot++;
            }

            ctx = ctx->next;
        }

        slot = &device->DefaultSlot;
        if(*slot != NULL)
        {
            if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
                V((*slot)->EffectState,update)(device, *slot);

            V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
                                            device->DryBuffer, device->NumChannels);

            for(i = 0;i < SamplesToDo;i++)
                (*slot)->WetBuffer[0][i] = 0.0f;
        }

        /* Increment the clock time. Every second's worth of samples is
         * converted and added to clock base so that large sample counts don't
         * overflow during conversion. This also guarantees an exact, stable
         * conversion. */
        device->SamplesDone += SamplesToDo;
        device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
        device->SamplesDone %= device->Frequency;
        V0(device->Backend,unlock)();

        if(device->Hrtf)
        {
            HrtfMixerFunc HrtfMix = SelectHrtfMixer();
            ALuint irsize = GetHrtfIrSize(device->Hrtf);
            for(c = 0;c < device->NumChannels;c++)
                HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
                    0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c],
                    SamplesToDo
                );
            device->Hrtf_Offset += SamplesToDo;
        }
        else if(device->Bs2b)
        {
            /* Apply binaural/crossfeed filter */
            for(i = 0;i < SamplesToDo;i++)
            {
                float samples[2];
                samples[0] = device->DryBuffer[0][i];
                samples[1] = device->DryBuffer[1][i];
                bs2b_cross_feed(device->Bs2b, samples);
                device->DryBuffer[0][i] = samples[0];
                device->DryBuffer[1][i] = samples[1];
            }
        }

        if(buffer)
        {
#define WRITE(T, a, b, c, d) do {               \
    Write_##T((a), (b), (c), (d));              \
    buffer = (T*)buffer + (c)*(d);              \
} while(0)
            switch(device->FmtType)
            {
                case DevFmtByte:
                    WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
                case DevFmtUByte:
                    WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
                case DevFmtShort:
                    WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
                case DevFmtUShort:
                    WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
                case DevFmtInt:
                    WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
                case DevFmtUInt:
                    WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
                case DevFmtFloat:
                    WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
                    break;
            }
#undef WRITE
        }

        size -= SamplesToDo;
        IncrementRef(&device->MixCount);
    }

    RestoreFPUMode(&oldMode);
}