static ALvoid CalcListenerParams(ALlistener *Listener) { ALfloat N[3], V[3], U[3]; aluVector P; /* AT then UP */ N[0] = Listener->Forward[0]; N[1] = Listener->Forward[1]; N[2] = Listener->Forward[2]; aluNormalize(N); V[0] = Listener->Up[0]; V[1] = Listener->Up[1]; V[2] = Listener->Up[2]; aluNormalize(V); /* Build and normalize right-vector */ aluCrossproduct(N, V, U); aluNormalize(U); P = Listener->Position; aluMatrixSet(&Listener->Params.Matrix, U[0], V[0], -N[0], 0.0f, U[1], V[1], -N[1], 0.0f, U[2], V[2], -N[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); aluMatrixVector(&P, &Listener->Params.Matrix); aluMatrixSetRow(&Listener->Params.Matrix, 3, -P.v[0], -P.v[1], -P.v[2], 1.0f); Listener->Params.Velocity = Listener->Velocity; aluMatrixVector(&Listener->Params.Velocity, &Listener->Params.Matrix); }
ALUAPI ALvoid ALUAPIENTRY aluCalculateSourceParameters(ALuint source,ALuint freqOutput,ALuint numOutputChannels,ALfloat *drysend,ALfloat *wetsend,ALfloat *pitch) { ALfloat ListenerOrientation[6],ListenerPosition[3],ListenerVelocity[3]; ALfloat InnerAngle,OuterAngle,OuterGain,Angle,Distance,DryMix,WetMix; ALfloat Direction[3],Position[3],Velocity[3],SourceToListener[3]; ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; ALfloat Pitch,ConeVolume,SourceVolume,PanningFB,PanningLR,ListenerGain; ALuint NumBufferChannels; ALfloat U[3],V[3],N[3]; ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound, flMaxVelocity; ALfloat flVSS, flVLS; ALuint DistanceModel; ALfloat Matrix[3][3]; ALint HeadRelative; ALuint Buffer; ALenum Error; ALfloat flAttenuation; if (alIsSource(source)) { //Get global properties alGetFloatv(AL_DOPPLER_FACTOR,&DopplerFactor); alGetIntegerv(AL_DISTANCE_MODEL,&DistanceModel); alGetFloatv(AL_DOPPLER_VELOCITY,&DopplerVelocity); alGetFloatv(AL_SPEED_OF_SOUND,&flSpeedOfSound); //Get listener properties alGetListenerfv(AL_GAIN,&ListenerGain); alGetListenerfv(AL_POSITION,ListenerPosition); alGetListenerfv(AL_VELOCITY,ListenerVelocity); alGetListenerfv(AL_ORIENTATION,ListenerOrientation); //Get source properties alGetSourcef(source,AL_PITCH,&Pitch); alGetSourcef(source,AL_GAIN,&SourceVolume); alGetSourcei(source,AL_BUFFER,&Buffer); alGetSourcefv(source,AL_POSITION,Position); alGetSourcefv(source,AL_VELOCITY,Velocity); alGetSourcefv(source,AL_DIRECTION,Direction); alGetSourcef(source,AL_MIN_GAIN,&MinVolume); alGetSourcef(source,AL_MAX_GAIN,&MaxVolume); alGetSourcef(source,AL_REFERENCE_DISTANCE,&MinDist); alGetSourcef(source,AL_MAX_DISTANCE,&MaxDist); alGetSourcef(source,AL_ROLLOFF_FACTOR,&Rolloff); alGetSourcef(source,AL_CONE_OUTER_GAIN,&OuterGain); alGetSourcef(source,AL_CONE_INNER_ANGLE,&InnerAngle); alGetSourcef(source,AL_CONE_OUTER_ANGLE,&OuterAngle); alGetSourcei(source,AL_SOURCE_RELATIVE,&HeadRelative); //Set working variables DryMix=(ALfloat)(1.0f); WetMix=(ALfloat)(0.0f); //Get buffer properties alGetBufferi(Buffer,AL_CHANNELS,&NumBufferChannels); //Only apply 3D calculations for mono buffers if (NumBufferChannels==1) { //1. Translate Listener to origin (convert to head relative) if (HeadRelative==AL_FALSE) { Position[0]-=ListenerPosition[0]; Position[1]-=ListenerPosition[1]; Position[2]-=ListenerPosition[2]; } //2. Calculate distance attenuation Distance=(ALfloat)sqrt(aluDotproduct(Position,Position)); // Clamp to MinDist and MaxDist if appropriate if ((DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) || (DistanceModel == AL_LINEAR_DISTANCE_CLAMPED) || (DistanceModel == AL_EXPONENT_DISTANCE_CLAMPED)) { Distance=(Distance<MinDist?MinDist:Distance); Distance=(Distance>MaxDist?MaxDist:Distance); } flAttenuation = 1.0f; switch (DistanceModel) { case AL_INVERSE_DISTANCE: if (MinDist > 0.0f) { if ((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f) flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist))); else flAttenuation = 1000000; } break; case AL_INVERSE_DISTANCE_CLAMPED: if ((MaxDist >= MinDist) && (MinDist > 0.0f)) { if ((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f) flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist))); else flAttenuation = 1000000; } break; case AL_LINEAR_DISTANCE: if (MaxDist != MinDist) flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist)); break; case AL_LINEAR_DISTANCE_CLAMPED: if (MaxDist > MinDist) flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist)); break; case AL_EXPONENT_DISTANCE: if ((Distance > 0.0f) && (MinDist > 0.0f)) flAttenuation = (ALfloat)pow(Distance/MinDist, -Rolloff); break; case AL_EXPONENT_DISTANCE_CLAMPED: if ((MaxDist >= MinDist) && (Distance > 0.0f) && (MinDist > 0.0f)) flAttenuation = (ALfloat)pow(Distance/MinDist, -Rolloff); break; case AL_NONE: default: flAttenuation = 1.0f; break; } // Source Gain + Attenuation DryMix = SourceVolume * flAttenuation; // Clamp to Min/Max Gain DryMix=__min(DryMix,MaxVolume); DryMix=__max(DryMix,MinVolume); 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=(ALfloat)(180.0*acos(aluDotproduct(Direction,SourceToListener))/3.141592654f); if ((Angle>=InnerAngle)&&(Angle<=OuterAngle)) ConeVolume=(1.0f+(OuterGain-1.0f)*(Angle-InnerAngle)/(OuterAngle-InnerAngle)); else if (Angle>OuterAngle) ConeVolume=(1.0f+(OuterGain-1.0f) ); else ConeVolume=1.0f; //4. Calculate Velocity if (DopplerFactor != 0.0f) { flVLS = aluDotproduct(ListenerVelocity, SourceToListener); flVSS = aluDotproduct(Velocity, 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] = Pitch * ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) / ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS)); } else { pitch[0] = Pitch; } //5. Align coordinate system axes aluCrossproduct(&ListenerOrientation[0],&ListenerOrientation[3],U); // Right-vector aluNormalize(U); // Normalized Right-vector memcpy(V,&ListenerOrientation[3],sizeof(V)); // Up-vector aluNormalize(V); // Normalized Up-vector memcpy(N,&ListenerOrientation[0],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. Convert normalized position into font/back panning if (Distance != 0.0f) { aluNormalize(Position); PanningLR=(0.5f+0.5f*Position[0]); PanningFB=(0.5f+0.5f*Position[2]); } else { PanningLR=0.5f; PanningFB=0.5f; } //7. Convert front/back panning into channel volumes switch (numOutputChannels) { case 1: drysend[0]=(ConeVolume*ListenerGain*DryMix*(ALfloat)1.0f ); //Direct wetsend[0]=(ListenerGain*WetMix*(ALfloat)1.0f ); //Room break; case 2: drysend[0]=(ConeVolume*ListenerGain*DryMix*(ALfloat)sqrt((1.0f-PanningLR))); //FL Direct drysend[1]=(ConeVolume*ListenerGain*DryMix*(ALfloat)sqrt(( PanningLR))); //FR Direct wetsend[0]=( ListenerGain*WetMix*(ALfloat)sqrt((1.0f-PanningLR))); //FL Room wetsend[1]=( ListenerGain*WetMix*(ALfloat)sqrt(( PanningLR))); //FR Room break; default: break; } } else { //1. Stereo buffers always play from front left/front right switch (numOutputChannels) { case 1: drysend[0]=(SourceVolume*1.0f*ListenerGain); wetsend[0]=(SourceVolume*0.0f*ListenerGain); break; case 2: drysend[0]=(SourceVolume*1.0f*ListenerGain); drysend[1]=(SourceVolume*1.0f*ListenerGain); wetsend[0]=(SourceVolume*0.0f*ListenerGain); wetsend[1]=(SourceVolume*0.0f*ListenerGain); break; default: break; } pitch[0]=(ALfloat)(Pitch); } Error=alGetError(); } }
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 ); } } }
AL_API ALvoid AL_APIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues) { ALCcontext *Context; if(pflValues) { switch(eParam) { case AL_GAIN: case AL_METERS_PER_UNIT: alListenerf(eParam, pflValues[0]); return; case AL_POSITION: case AL_VELOCITY: alListener3f(eParam, pflValues[0], pflValues[1], pflValues[2]); return; } } Context = GetContextRef(); if(!Context) return; if(pflValues) { switch(eParam) { case AL_ORIENTATION: if(isfinite(pflValues[0]) && isfinite(pflValues[1]) && isfinite(pflValues[2]) && isfinite(pflValues[3]) && isfinite(pflValues[4]) && isfinite(pflValues[5])) { ALfloat U[3], V[3], N[3]; /* AT then UP */ N[0] = pflValues[0]; N[1] = pflValues[1]; N[2] = pflValues[2]; aluNormalize(N); V[0] = pflValues[3]; V[1] = pflValues[4]; V[2] = pflValues[5]; aluNormalize(V); /* Build and normalize right-vector */ aluCrossproduct(N, V, U); aluNormalize(U); LockContext(Context); Context->Listener.Forward[0] = pflValues[0]; Context->Listener.Forward[1] = pflValues[1]; Context->Listener.Forward[2] = pflValues[2]; Context->Listener.Up[0] = pflValues[3]; Context->Listener.Up[1] = pflValues[4]; Context->Listener.Up[2] = pflValues[5]; Context->Listener.Matrix[0][0] = U[0]; Context->Listener.Matrix[0][1] = V[0]; Context->Listener.Matrix[0][2] = -N[0]; Context->Listener.Matrix[0][3] = 0.0f; Context->Listener.Matrix[1][0] = U[1]; Context->Listener.Matrix[1][1] = V[1]; Context->Listener.Matrix[1][2] = -N[1]; Context->Listener.Matrix[1][3] = 0.0f; Context->Listener.Matrix[2][0] = U[2]; Context->Listener.Matrix[2][1] = V[2]; Context->Listener.Matrix[2][2] = -N[2]; Context->Listener.Matrix[2][3] = 0.0f; Context->Listener.Matrix[3][0] = 0.0f; Context->Listener.Matrix[3][1] = 0.0f; Context->Listener.Matrix[3][2] = 0.0f; Context->Listener.Matrix[3][3] = 1.0f; Context->UpdateSources = AL_TRUE; UnlockContext(Context); } else alSetError(Context, AL_INVALID_VALUE); break; default: alSetError(Context, AL_INVALID_ENUM); break; } } else alSetError(Context, AL_INVALID_VALUE); ALCcontext_DecRef(Context); }