void aluInitMixer(void) { ALuint i; for(i = 0;i < FRACTIONONE;i++) { ALfloat mu = (ALfloat)i / FRACTIONONE; ResampleCoeffs[i][0] = lanc2(mu - -1.0f); ResampleCoeffs[i][1] = lanc2(mu - 0.0f); ResampleCoeffs[i][2] = lanc2(mu - 1.0f); ResampleCoeffs[i][3] = lanc2(mu - 2.0f); } MixHrtfSamples = SelectHrtfMixer(); MixSamples = SelectMixer(); ResampleSamples = SelectResampler(DefaultResampler); }
ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext) { static const ALfloat angles_Mono[1] = { 0.0f }; static const ALfloat angles_Stereo[2] = { -30.0f, 30.0f }; static const ALfloat angles_Rear[2] = { -150.0f, 150.0f }; static const ALfloat angles_Quad[4] = { -45.0f, 45.0f, -135.0f, 135.0f }; static const ALfloat angles_X51[6] = { -30.0f, 30.0f, 0.0f, 0.0f, -110.0f, 110.0f }; static const ALfloat angles_X61[7] = { -30.0f, 30.0f, 0.0f, 0.0f, 180.0f, -90.0f, 90.0f }; static const ALfloat angles_X71[8] = { -30.0f, 30.0f, 0.0f, 0.0f, -110.0f, 110.0f, -90.0f, 90.0f }; static const enum Channel chans_Mono[1] = { FRONT_CENTER }; static const enum Channel chans_Stereo[2] = { FRONT_LEFT, FRONT_RIGHT }; static const enum Channel chans_Rear[2] = { BACK_LEFT, BACK_RIGHT }; static const enum Channel chans_Quad[4] = { FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT }; static const enum Channel chans_X51[6] = { FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER, LFE, BACK_LEFT, BACK_RIGHT }; static const enum Channel chans_X61[7] = { FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER, LFE, BACK_CENTER, SIDE_LEFT, SIDE_RIGHT }; static const enum Channel chans_X71[8] = { FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER, LFE, BACK_LEFT, BACK_RIGHT, SIDE_LEFT, SIDE_RIGHT }; ALCdevice *Device = ALContext->Device; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; ALbufferlistitem *BufferListItem; enum DevFmtChannels DevChans; enum FmtChannels Channels; ALfloat (*SrcMatrix)[MAXCHANNELS]; ALfloat DryGain, DryGainHF; ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALint NumSends, Frequency; const ALfloat *SpeakerGain; const ALfloat *angles = NULL; const enum Channel *chans = NULL; enum Resampler Resampler; ALint num_channels = 0; ALboolean VirtualChannels; ALfloat Pitch; ALfloat cw; ALuint pos; ALint i, c; /* Get device properties */ DevChans = ALContext->Device->FmtChans; NumSends = ALContext->Device->NumAuxSends; Frequency = ALContext->Device->Frequency; /* Get listener properties */ ListenerGain = ALContext->Listener.Gain; /* Get source properties */ SourceVolume = ALSource->flGain; MinVolume = ALSource->flMinGain; MaxVolume = ALSource->flMaxGain; Pitch = ALSource->flPitch; Resampler = ALSource->Resampler; VirtualChannels = ALSource->VirtualChannels; /* Calculate the stepping value */ Channels = FmtMono; BufferListItem = ALSource->queue; while(BufferListItem != NULL) { ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { ALint maxstep = STACK_DATA_SIZE / ALSource->NumChannels / ALSource->SampleSize; maxstep -= ResamplerPadding[Resampler] + ResamplerPrePadding[Resampler] + 1; maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS); Pitch = Pitch * ALBuffer->Frequency / Frequency; if(Pitch > (ALfloat)maxstep) ALSource->Params.Step = maxstep<<FRACTIONBITS; else { ALSource->Params.Step = Pitch*FRACTIONONE; if(ALSource->Params.Step == 0) ALSource->Params.Step = 1; } Channels = ALBuffer->FmtChannels; if(ALSource->VirtualChannels && (Device->Flags&DEVICE_USE_HRTF)) ALSource->Params.DoMix = SelectHrtfMixer(ALBuffer, (ALSource->Params.Step==FRACTIONONE) ? POINT_RESAMPLER : Resampler); else ALSource->Params.DoMix = SelectMixer(ALBuffer, (ALSource->Params.Step==FRACTIONONE) ? POINT_RESAMPLER : Resampler); break; } BufferListItem = BufferListItem->next; }
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); }