/// <summary> /// Updates internal state /// </summary> internal void Update() { if (this.Effect.GameAudio.UseReverb && !isReverbSubmixEnabled) { var sendFlags = this.Effect.GameAudio.UseReverbFilter ? VoiceSendFlags.UseFilter : VoiceSendFlags.None; var outputVoices = new VoiceSendDescriptor[] { new VoiceSendDescriptor { OutputVoice = this.Effect.GameAudio.MasteringVoice, Flags = sendFlags }, new VoiceSendDescriptor { OutputVoice = this.Effect.GameAudio.ReverbVoice, Flags = sendFlags } }; voice.SetOutputVoices(outputVoices); isReverbSubmixEnabled = true; } if (this.Effect.GameAudio.UseAudio3D) { this.Apply3D(); } this.SetPanOutputMatrix(); }
private void PlaySound(int soundID, Vector3 emitterPos, float volume, float maxDistance, LinkedSoundList list, ref VoiceSendDescriptor voiceSendDescriptor, Action <IntPtr>?onFxEnd = null) { PlaySound( soundID, new Emitter { ChannelCount = 1, VolumeCurve = new[] { new CurvePoint { Distance = 0.0f, DspSetting = 1.0f }, new CurvePoint { Distance = 1.0f, DspSetting = 0.0f } }, CurveDistanceScaler = maxDistance, OrientFront = Vector3.UnitZ, OrientTop = Vector3.UnitY, Position = emitterPos, Velocity = new Vector3(0, 0, 0) }, volume, list, ref voiceSendDescriptor, onFxEnd); }
private void SetupVoice(AudioFormat format) { WaveFormat wFmt = new WaveFormat(format.SampleRate, format.BitsPerSample, format.Channels); SourceVoice = new SourceVoice(_engine.Device, wFmt); if (_submixer != null) { var vsDesc = new VoiceSendDescriptor(_submixer.SubMixerVoice); SourceVoice.SetOutputVoices(new VoiceSendDescriptor[] { vsDesc }); } SourceVoice.SetVolume(_volume); }
/// <summary> /// Initializes a new instance of the <see cref="AudioManager" /> class. /// </summary> /// <param name="listener"> The listener. </param> /// <param name="fxSoundPoolLimit"> The effects sound pool limit. </param> /// <param name="speakers"> The speakers. </param> /// <param name="deviceID"> (Optional) Identifier for the device. </param> /// <exception cref="ArgumentException"> /// Thrown when one or more arguments have unsupported or /// illegal values. /// </exception> public AudioManager(Listener listener, int fxSoundPoolLimit, Speakers speakers, string?deviceID = null) { _listener = listener; if (fxSoundPoolLimit <= 0) { throw new ArgumentException("fxSoundPoolLimit must be bigger than 0"); } _soundBuffer = new Dictionary <int, SoundBuffer>(128); _fxLinkedSoundList = new LinkedSoundList(fxSoundPoolLimit); _envLinkedSoundList = new LinkedSoundList(); #if DEBUG _xAudio2 = new XAudio2(XAudio2Flags.DebugEngine, ProcessorSpecifier.AnyProcessor); #else _xAudio2 = new XAudio2(XAudio2Flags.None, ProcessorSpecifier.AnyProcessor, XAudio2Version.Default); #endif if (_xAudio2.Version == XAudio2Version.Version27) { if (int.TryParse(deviceID, out int deviceID27)) { _masteringVoice = new MasteringVoice( _xAudio2, XAudio2.DefaultChannels, XAudio2.DefaultSampleRate, deviceID27); } else { _masteringVoice = new MasteringVoice( _xAudio2, XAudio2.DefaultChannels, XAudio2.DefaultSampleRate, deviceID); } } else { _masteringVoice = new MasteringVoice( _xAudio2, XAudio2.DefaultChannels, XAudio2.DefaultSampleRate, deviceID); } _masteringVoice.SetVolume(_masterVolume); _x3DAudio = new X3DAudio(speakers, X3DAudio.SpeedOfSound); _masteringVoice.GetVoiceDetails(out VoiceDetails details); _inputChannelCount = details.InputChannelCount; _fxSubmixVoice = new SubmixVoice(_xAudio2, _inputChannelCount, details.InputSampleRate); _fxSubmixVoice.SetVolume(_fxVolume); _envSubmixVoice = new SubmixVoice(_xAudio2, _inputChannelCount, details.InputSampleRate); _envSubmixVoice.SetVolume(_envVolume); _fxVoiceSendDescriptor = new VoiceSendDescriptor(VoiceSendFlags.None, _fxSubmixVoice); _envVoiceSendDescriptor = new VoiceSendDescriptor(VoiceSendFlags.None, _envSubmixVoice); }
private void PlaySound(int soundID, Emitter emitter, float volume, LinkedSoundList list, ref VoiceSendDescriptor voiceSendDescriptor, Action <IntPtr>?onFxEnd = null) { if (!_soundBuffer.TryGetValue(soundID, out SoundBuffer buffer)) { return; } SourceVoice sourceVoice = new SourceVoice(_xAudio2, buffer.Format, VoiceFlags.None, true); sourceVoice.SetVolume(volume); sourceVoice.SubmitSourceBuffer(buffer.AudioBuffer, buffer.DecodedPacketsInfo); sourceVoice.SetOutputVoices(voiceSendDescriptor); LinkedSoundList.Sound sound = new LinkedSoundList.Sound(emitter, sourceVoice); list.Add(sound); sourceVoice.BufferEnd += _ => { list.Remove(sound); sourceVoice.DestroyVoice(); }; if (onFxEnd != null) { sourceVoice.BufferEnd += onFxEnd; } sourceVoice.Start(); DspSettings settings = _x3DAudio.Calculate( _listener, sound.Emitter, CalculateFlags.Matrix | CalculateFlags.Doppler, buffer.Format.Channels, _inputChannelCount); sound.SourceVoice.SetOutputMatrix(buffer.Format.Channels, _inputChannelCount, settings.MatrixCoefficients); sound.SourceVoice.SetFrequencyRatio(settings.DopplerFactor); }
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); } } }
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); } } }