ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) { ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); ALeffectStateFactory *factory; if(newtype != EffectSlot->Effect.Type) { ALeffectState *State; FPUCtl oldMode; factory = getFactoryByType(newtype); if(!factory) { ERR("Failed to find factory for effect type 0x%04x\n", newtype); return AL_INVALID_ENUM; } State = V0(factory,create)(); if(!State) return AL_OUT_OF_MEMORY; SetMixerFPUMode(&oldMode); /* FIXME: This just needs to prevent the device from being reset during * the state's device update, so the list lock in ALc.c should do here. */ ALCdevice_Lock(Device); State->OutBuffer = Device->Dry.Buffer; State->OutChannels = Device->Dry.NumChannels; if(V(State,deviceUpdate)(Device) == AL_FALSE) { ALCdevice_Unlock(Device); RestoreFPUMode(&oldMode); DELETE_OBJ(State); return AL_OUT_OF_MEMORY; } ALCdevice_Unlock(Device); RestoreFPUMode(&oldMode); if(!effect) { EffectSlot->Effect.Type = AL_EFFECT_NULL; memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); } else { EffectSlot->Effect.Type = effect->type; memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); } EffectSlot->Effect.State = State; UpdateEffectSlotProps(EffectSlot, AL_TRUE); } else if(effect) { memcpy(&EffectSlot->Effect.Props, &effect->Props, sizeof(EffectSlot->Effect.Props)); UpdateEffectSlotProps(EffectSlot, AL_FALSE); } return AL_NO_ERROR; }
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) { ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); ALeffectStateFactory *factory; if(newtype != EffectSlot->Effect.Type) { ALeffectState *State; FPUCtl oldMode; factory = getFactoryByType(newtype); if(!factory) { ERR("Failed to find factory for effect type 0x%04x\n", newtype); return AL_INVALID_ENUM; } State = V0(factory,create)(); if(!State) return AL_OUT_OF_MEMORY; SetMixerFPUMode(&oldMode); almtx_lock(&Device->BackendLock); State->OutBuffer = Device->Dry.Buffer; State->OutChannels = Device->Dry.NumChannels; if(V(State,deviceUpdate)(Device) == AL_FALSE) { almtx_unlock(&Device->BackendLock); RestoreFPUMode(&oldMode); DELETE_OBJ(State); return AL_OUT_OF_MEMORY; } almtx_unlock(&Device->BackendLock); RestoreFPUMode(&oldMode); if(!effect) { EffectSlot->Effect.Type = AL_EFFECT_NULL; memset(&EffectSlot->Effect.Props, 0, sizeof(EffectSlot->Effect.Props)); } else { EffectSlot->Effect.Type = effect->type; EffectSlot->Effect.Props = effect->Props; } EffectSlot->Effect.State = State; UpdateEffectSlotProps(EffectSlot); } else if(effect) { EffectSlot->Effect.Props = effect->Props; UpdateEffectSlotProps(EffectSlot); } return AL_NO_ERROR; }
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); }
AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) { ALCcontext *Context; Context = GetContextRef(); if(!Context) return; if(!Context->DeferUpdates) { ALboolean UpdateSources; ALsource **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 = ExchangeInt(&Context->UpdateSources, AL_FALSE); src = Context->ActiveSources; src_end = src + Context->ActiveSourceCount; while(src != src_end) { if((*src)->state != AL_PLAYING) { Context->ActiveSourceCount--; *src = *(--src_end); continue; } if(ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) || UpdateSources) ALsource_Update(*src, Context); src++; } slot = Context->ActiveEffectSlots; slot_end = slot + Context->ActiveEffectSlotCount; while(slot != slot_end) { if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE)) VCALL((*slot)->EffectState,update,(Context->Device, *slot)); slot++; } UnlockContext(Context); RestoreFPUMode(&oldMode); } ALCcontext_DecRef(Context); }
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) { ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); ALeffectStateFactory *factory; if(newtype != EffectSlot->EffectType) { ALeffectState *State; FPUCtl oldMode; factory = getFactoryByType(newtype); if(!factory) { ERR("Failed to find factory for effect type 0x%04x\n", newtype); return AL_INVALID_ENUM; } State = V0(factory,create)(); if(!State) return AL_OUT_OF_MEMORY; SetMixerFPUMode(&oldMode); ALCdevice_Lock(Device); if(V(State,deviceUpdate)(Device) == AL_FALSE) { ALCdevice_Unlock(Device); RestoreFPUMode(&oldMode); DELETE_OBJ(State); return AL_OUT_OF_MEMORY; } State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State); if(!effect) { memset(&EffectSlot->EffectProps, 0, sizeof(EffectSlot->EffectProps)); EffectSlot->EffectType = AL_EFFECT_NULL; } else { memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props)); EffectSlot->EffectType = effect->type; } /* FIXME: This should be done asynchronously, but since the EffectState * object was changed, it needs an update before its Process method can * be called. */ ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE); V(EffectSlot->EffectState,update)(Device, EffectSlot); ALCdevice_Unlock(Device); RestoreFPUMode(&oldMode); DELETE_OBJ(State); State = NULL; } else { if(effect) { ALCdevice_Lock(Device); memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props)); ALCdevice_Unlock(Device); ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE); } } return AL_NO_ERROR; }
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); }
ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect) { ALenum newtype = (effect ? effect->type : AL_EFFECT_NULL); ALeffectState *State = NULL; ALenum err = AL_NO_ERROR; LockDevice(Device); if(newtype == AL_EFFECT_NULL && EffectSlot->effect.type != AL_EFFECT_NULL) { State = NoneCreate(); if(!State) err = AL_OUT_OF_MEMORY; } else if(newtype == AL_EFFECT_EAXREVERB || newtype == AL_EFFECT_REVERB) { if(EffectSlot->effect.type != AL_EFFECT_EAXREVERB && EffectSlot->effect.type != AL_EFFECT_REVERB) { State = ReverbCreate(); if(!State) err = AL_OUT_OF_MEMORY; } } else if(newtype == AL_EFFECT_ECHO && EffectSlot->effect.type != AL_EFFECT_ECHO) { State = EchoCreate(); if(!State) err = AL_OUT_OF_MEMORY; } else if(newtype == AL_EFFECT_RING_MODULATOR && EffectSlot->effect.type != AL_EFFECT_RING_MODULATOR) { State = ModulatorCreate(); if(!State) err = AL_OUT_OF_MEMORY; } else if(newtype == AL_EFFECT_DEDICATED_DIALOGUE || newtype == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { if(EffectSlot->effect.type != AL_EFFECT_DEDICATED_DIALOGUE && EffectSlot->effect.type != AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { State = DedicatedCreate(); if(!State) err = AL_OUT_OF_MEMORY; } } if(err != AL_NO_ERROR) { UnlockDevice(Device); return err; } if(State) { int oldMode; oldMode = SetMixerFPUMode(); if(ALeffectState_DeviceUpdate(State, Device) == AL_FALSE) { RestoreFPUMode(oldMode); UnlockDevice(Device); ALeffectState_Destroy(State); return AL_OUT_OF_MEMORY; } State = ExchangePtr((XchgPtr*)&EffectSlot->EffectState, State); if(!effect) memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); else memcpy(&EffectSlot->effect, effect, sizeof(*effect)); /* FIXME: This should be done asynchronously, but since the EffectState * object was changed, it needs an update before its Process method can * be called. */ EffectSlot->NeedsUpdate = AL_FALSE; ALeffectState_Update(EffectSlot->EffectState, Device, EffectSlot); UnlockDevice(Device); RestoreFPUMode(oldMode); ALeffectState_Destroy(State); State = NULL; } else { if(!effect) memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect)); else memcpy(&EffectSlot->effect, effect, sizeof(*effect)); UnlockDevice(Device); EffectSlot->NeedsUpdate = AL_TRUE; } return AL_NO_ERROR; }