private void Apply3D(Vector3 listenerForward, Vector3 listenerUp, Vector3 listenerPosition, Vector3 listenerVelocity, Vector3 emitterForward, Vector3 emitterUp, Vector3 emitterPosition, Vector3 emitterVelocity) { if (!Effect.AudioManager.IsSpatialAudioEnabled) { throw new InvalidOperationException("Spatial audio must be enabled first."); } if (emitter == null) { emitter = new Emitter(); } emitter.OrientFront = emitterForward; emitter.OrientTop = emitterUp; emitter.Position = emitterPosition; emitter.Velocity = emitterVelocity; emitter.DopplerScaler = SoundEffect.DopplerScale; emitter.CurveDistanceScaler = SoundEffect.DistanceScale; emitter.ChannelCount = Effect.Format.Channels; //TODO: work out what ChannelAzimuths is supposed to be. if (emitter.ChannelCount > 1) { emitter.ChannelAzimuths = new float[emitter.ChannelCount]; } if (listener == null) { listener = new Listener(); } listener.OrientFront = listenerForward; listener.OrientTop = listenerUp; listener.Position = listenerPosition; listener.Velocity = listenerVelocity; if (dspSettings == null) { dspSettings = new DspSettings(Effect.Format.Channels, Effect.AudioManager.MasteringVoice.VoiceDetails.InputChannelCount); } CalculateFlags flags = CalculateFlags.Matrix | CalculateFlags.Doppler | CalculateFlags.LpfDirect; if ((Effect.AudioManager.Speakers & Speakers.LowFrequency) > 0) { // On devices with an LFE channel, allow the mono source data to be routed to the LFE destination channel. flags |= CalculateFlags.RedirectToLfe; } if (Effect.AudioManager.IsReverbEffectEnabled) { flags |= CalculateFlags.Reverb | CalculateFlags.LpfReverb; if (!isReverbSubmixEnabled) { VoiceSendFlags sendFlags = Effect.AudioManager.IsReverbFilterEnabled ? VoiceSendFlags.UseFilter : VoiceSendFlags.None; VoiceSendDescriptor[] outputVoices = new VoiceSendDescriptor[] { new VoiceSendDescriptor { OutputVoice = Effect.AudioManager.MasteringVoice, Flags = sendFlags }, new VoiceSendDescriptor { OutputVoice = Effect.AudioManager.ReverbVoice, Flags = sendFlags } }; voice.SetOutputVoices(outputVoices); isReverbSubmixEnabled = true; } } Effect.AudioManager.Calculate3D(listener, emitter, flags, dspSettings); voice.SetFrequencyRatio(dspSettings.DopplerFactor); voice.SetOutputMatrix(Effect.AudioManager.MasteringVoice, dspSettings.SourceChannelCount, dspSettings.DestinationChannelCount, dspSettings.MatrixCoefficients); if (Effect.AudioManager.IsReverbEffectEnabled) { if (reverbLevels == null || reverbLevels.Length != Effect.Format.Channels) { reverbLevels = new float[Effect.Format.Channels]; } for (int i = 0; i < reverbLevels.Length; i++) { reverbLevels[i] = dspSettings.ReverbLevel; } voice.SetOutputMatrix(Effect.AudioManager.ReverbVoice, Effect.Format.Channels, 1, reverbLevels); } if (Effect.AudioManager.IsReverbFilterEnabled) { FilterParameters filterDirect = new FilterParameters { Type = FilterType.LowPassFilter, // see XAudio2CutoffFrequencyToRadians() in XAudio2.h for more information on the formula used here Frequency = 2.0f * (float)Math.Sin(X3DAudio.PI / 6.0f * dspSettings.LpfDirectCoefficient), OneOverQ = 1.0f }; voice.SetOutputFilterParameters(Effect.AudioManager.MasteringVoice, filterDirect); if (Effect.AudioManager.IsReverbEffectEnabled) { FilterParameters filterReverb = new FilterParameters { Type = FilterType.LowPassFilter, // see XAudio2CutoffFrequencyToRadians() in XAudio2.h for more information on the formula used here Frequency = 2.0f * (float)Math.Sin(X3DAudio.PI / 6.0f * dspSettings.LpfReverbCoefficient), OneOverQ = 1.0f }; voice.SetOutputFilterParameters(Effect.AudioManager.ReverbVoice, filterReverb); } } }
/// <summary> /// Applies the 3D effect to the current sound effect instance. /// </summary> /// <param name="listenerAgent">Listener</param> /// <param name="emitterAgent">Emitter</param> private void Apply3D() { UpdateListener(Listener); UpdateEmitter(Emitter); var flags = Calculate3DFlags(); if (dspSettings == null) { dspSettings = new DspSettings( this.Effect.WaveFormat.Channels, this.Effect.GameAudio.MasteringVoice.VoiceDetails.InputChannelCount); } this.Effect.GameAudio.Calculate3D(listener, emitter, flags, dspSettings); voice.SetFrequencyRatio(dspSettings.DopplerFactor); voice.SetOutputMatrix( this.Effect.GameAudio.MasteringVoice, dspSettings.SourceChannelCount, dspSettings.DestinationChannelCount, dspSettings.MatrixCoefficients); if (!this.Effect.GameAudio.UseReverb) { return; } if (reverbLevels?.Length != this.Effect.WaveFormat.Channels) { reverbLevels = new float[this.Effect.WaveFormat.Channels]; } for (int i = 0; i < reverbLevels.Length; i++) { reverbLevels[i] = dspSettings.ReverbLevel; } voice.SetOutputMatrix(this.Effect.GameAudio.ReverbVoice, this.Effect.WaveFormat.Channels, 1, reverbLevels); if (!this.Effect.GameAudio.UseReverbFilter) { return; } var filterDirect = new FilterParameters { Type = FilterType.LowPassFilter, Frequency = 2.0f * (float)Math.Sin(MathUtil.Pi / 6.0f * dspSettings.LpfDirectCoefficient), OneOverQ = 1.0f }; voice.SetOutputFilterParameters(this.Effect.GameAudio.MasteringVoice, filterDirect); var filterReverb = new FilterParameters { Type = FilterType.LowPassFilter, Frequency = 2.0f * (float)Math.Sin(MathUtil.Pi / 6.0f * dspSettings.LpfReverbCoefficient), OneOverQ = 1.0f }; voice.SetOutputFilterParameters(this.Effect.GameAudio.ReverbVoice, filterReverb); }