using System; using System.Linq; using System.Runtime.InteropServices; namespace NAudio.Dmo.Effect { internal struct DsFxI3Dl2Reverb { public int Room; public int RoomHf; public float RoomRollOffFactor; public float DecayTime; public float DecayHfRatio; public int Reflections; public float ReflectionsDelay; public int Reverb; public float ReverbDelay; public float Diffusion; public float Density; public float HfReference; } [ComImport, System.Security.SuppressUnmanagedCodeSecurity, Guid("4b166a6a-0d66-43f3-80e3-ee6280dee1a4"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IDirectSoundFXI3DL2Reverb { [PreserveSig] int SetAllParameters([In] ref DsFxI3Dl2Reverb param); [PreserveSig] int GetAllParameters(out DsFxI3Dl2Reverb param); [PreserveSig] int SetPreset([In] uint preset); [PreserveSig] int GetPreset(out uint preset); [PreserveSig] int SetQuality([In] int quality); [PreserveSig] int GetQuality(out int quality); } /// /// DMO I3DL2Reverb Effect /// public class DmoI3DL2Reverb : IDmoEffector { /// /// DMO I3DL2Reverb Params /// public struct Params { /// /// DSFX_I3DL2REVERB_ROOM_MIN /// public const int RoomMin = -10000; /// /// DSFX_I3DL2REVERB_ROOM_MAX /// public const int RoomMax = 0; /// /// DSFX_I3DL2REVERB_ROOM_DEFAULT /// public const int RoomDefault = -1000; /// /// DSFX_I3DL2REVERB_ROOMHF_MIN /// public const int RoomHfMin = -10000; /// /// DSFX_I3DL2REVERB_ROOMHF_MAX /// public const int RoomHfMax = 0; /// /// DSFX_I3DL2REVERB_ROOMHF_DEFAULT /// public const int RoomHfDefault = -100; /// /// DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MIN /// public const float RoomRollOffFactorMin = 0.0f; /// /// DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_MAX /// public const float RoomRollOffFactorMax = 10.0f; /// /// DSFX_I3DL2REVERB_ROOMROLLOFFFACTOR_DEFAULT /// public const float RoomRollOffFactorDefault = 0.0f; /// /// DSFX_I3DL2REVERB_DECAYTIME_MIN /// public const float DecayTimeMin = 0.1f; /// /// DSFX_I3DL2REVERB_DECAYTIME_MAX /// public const float DecayTimeMax = 20.0f; /// /// DSFX_I3DL2REVERB_DECAYTIME_DEFAULT /// public const float DecayTimeDefault = 1.49f; /// /// DSFX_I3DL2REVERB_DECAYHFRATIO_MIN /// public const float DecayHfRatioMin = 0.1f; /// /// DSFX_I3DL2REVERB_DECAYHFRATIO_MAX /// public const float DecayHfRatioMax = 2.0f; /// /// DSFX_I3DL2REVERB_DECAYHFRATIO_DEFAULT /// public const float DecayHfRatioDefault = 0.83f; /// /// DSFX_I3DL2REVERB_REFLECTIONS_MIN /// public const int ReflectionsMin = -10000; /// /// DSFX_I3DL2REVERB_REFLECTIONS_MAX /// public const int ReflectionsMax = 1000; /// /// DSFX_I3DL2REVERB_REFLECTIONS_DEFAULT /// public const int ReflectionsDefault = -2602; /// /// DSFX_I3DL2REVERB_REFLECTIONSDELAY_MIN /// public const float ReflectionsDelayMin = 0.0f; /// /// DSFX_I3DL2REVERB_REFLECTIONSDELAY_MAX /// public const float ReflectionsDelayMax = 0.3f; /// /// DSFX_I3DL2REVERB_REFLECTIONSDELAY_DEFAULT /// public const float ReflectionsDelayDefault = 0.007f; /// /// DSFX_I3DL2REVERB_REVERB_MIN /// public const int ReverbMin = -10000; /// /// DSFX_I3DL2REVERB_REVERB_MAX /// public const int ReverbMax = 2000; /// /// DSFX_I3DL2REVERB_REVERB_DEFAULT /// public const int ReverbDefault = 200; /// /// DSFX_I3DL2REVERB_REVERBDELAY_MIN /// public const float ReverbDelayMin = 0.0f; /// /// DSFX_I3DL2REVERB_REVERBDELAY_MAX /// public const float ReverbDelayMax = 0.1f; /// /// DSFX_I3DL2REVERB_REVERBDELAY_DEFAULT /// public const float ReverbDelayDefault = 0.011f; /// /// DSFX_I3DL2REVERB_DIFFUSION_MIN /// public const float DiffusionMin = 0.0f; /// /// DSFX_I3DL2REVERB_DIFFUSION_MAX /// public const float DiffusionMax = 100.0f; /// /// DSFX_I3DL2REVERB_DIFFUSION_DEFAULT /// public const float DiffusionDefault = 100.0f; /// /// DSFX_I3DL2REVERB_DENSITY_MIN /// public const float DensityMin = 0.0f; /// /// DSFX_I3DL2REVERB_DENSITY_MAX /// public const float DensityMax = 100.0f; /// /// DSFX_I3DL2REVERB_DENSITY_DEFAULT /// public const float DensityDefault = 100.0f; /// /// DSFX_I3DL2REVERB_HFREFERENCE_MIN /// public const float HfReferenceMin = 20.0f; /// /// DSFX_I3DL2REVERB_HFREFERENCE_MAX /// public const float HfReferenceMax = 20000.0f; /// /// DSFX_I3DL2REVERB_HFREFERENCE_DEFAULT /// public const float HfReferenceDefault = 5000.0f; /// /// DSFX_I3DL2REVERB_QUALITY_MIN /// public const int QualityMin = 0; /// /// DSFX_I3DL2REVERB_QUALITY_MAX /// public const int QualityMax = 3; /// /// DSFX_I3DL2REVERB_QUALITY_DEFAULT /// public const int QualityDefault = 2; /// /// Attenuation of the room effect, in millibels (mB) /// public int Room { get { var param = GetAllParameters(); return param.Room; } set { var param = GetAllParameters(); param.Room = Math.Max(Math.Min(RoomMax, value), RoomMin); SetAllParameters(param); } } /// /// Attenuation of the room high-frequency effect, in mB. /// public int RoomHf { get { var param = GetAllParameters(); return param.RoomHf; } set { var param = GetAllParameters(); param.RoomHf = Math.Max(Math.Min(RoomHfMax, value), RoomHfMin); SetAllParameters(param); } } /// /// Rolloff factor for the reflected signals. /// public float RoomRollOffFactor { get { var param = GetAllParameters(); return param.RoomRollOffFactor; } set { var param = GetAllParameters(); param.RoomRollOffFactor = Math.Max(Math.Min(RoomRollOffFactorMax, value), RoomRollOffFactorMin); SetAllParameters(param); } } /// /// Decay time, in seconds. /// public float DecayTime { get { var param = GetAllParameters(); return param.DecayTime; } set { var param = GetAllParameters(); param.DecayTime = Math.Max(Math.Min(DecayTimeMax, value), DecayTimeMin); SetAllParameters(param); } } /// /// Ratio of the decay time at high frequencies to the decay time at low frequencies. /// public float DecayHfRatio { get { var param = GetAllParameters(); return param.DecayHfRatio; } set { var param = GetAllParameters(); param.DecayHfRatio = Math.Max(Math.Min(DecayHfRatioMax, value), DecayHfRatioMin); SetAllParameters(param); } } /// /// Attenuation of early reflections relative to lRoom, in mB. /// public int Reflections { get { var param = GetAllParameters(); return param.Reflections; } set { var param = GetAllParameters(); param.Reflections = Math.Max(Math.Min(ReflectionsMax, value), ReflectionsMin); SetAllParameters(param); } } /// /// Delay time of the first reflection relative to the direct path, in seconds. /// public float ReflectionsDelay { get { var param = GetAllParameters(); return param.ReflectionsDelay; } set { var param = GetAllParameters(); param.ReflectionsDelay = Math.Max(Math.Min(ReflectionsDelayMax, value), ReflectionsDelayMin); SetAllParameters(param); } } /// /// Attenuation of late reverberation relative to lRoom, in mB. /// public int Reverb { get { var param = GetAllParameters(); return param.Reverb; } set { var param = GetAllParameters(); param.Reverb = Math.Max(Math.Min(ReverbMax, value), ReverbMin); SetAllParameters(param); } } /// /// Time limit between the early reflections and the late reverberation relative to the time of the first reflection. /// public float ReverbDelay { get { var param = GetAllParameters(); return param.ReverbDelay; } set { var param = GetAllParameters(); param.ReverbDelay = Math.Max(Math.Min(ReverbDelayMax, value), ReverbDelayMin); SetAllParameters(param); } } /// /// Echo density in the late reverberation decay, in percent. /// public float Diffusion { get { var param = GetAllParameters(); return param.Diffusion; } set { var param = GetAllParameters(); param.Diffusion = Math.Max(Math.Min(DiffusionMax, value), DiffusionMin); SetAllParameters(param); } } /// /// Modal density in the late reverberation decay, in percent. /// public float Density { get { var param = GetAllParameters(); return param.Density; } set { var param = GetAllParameters(); param.Density = Math.Max(Math.Min(DensityMax, value), DensityMin); SetAllParameters(param); } } /// /// Reference high frequency, in hertz. /// public float HfReference { get { var param = GetAllParameters(); return param.HfReference; } set { var param = GetAllParameters(); param.HfReference = Math.Max(Math.Min(HfReferenceMax, value), HfReferenceMin); SetAllParameters(param); } } /// /// the quality of the environmental reverberation effect. Higher values produce better quality at the expense of processing time. /// public int Quality { get { Marshal.ThrowExceptionForHR(fxI3Dl2Reverb.GetQuality(out var quality)); return quality; } set => Marshal.ThrowExceptionForHR(fxI3Dl2Reverb.SetQuality(value)); } private readonly IDirectSoundFXI3DL2Reverb fxI3Dl2Reverb; internal Params(IDirectSoundFXI3DL2Reverb dsFxObject) { fxI3Dl2Reverb = dsFxObject; } /// /// Sets standard reverberation parameters of a buffer. /// /// I3DL2EnvironmentPreset public void SetPreset(I3DL2EnvironmentPreset preset) { var p = (uint)preset; Marshal.ThrowExceptionForHR(fxI3Dl2Reverb.SetPreset(p)); } /// /// retrieves an identifier for standard reverberation parameters of a buffer. /// /// I3DL2EnvironmentPreset public I3DL2EnvironmentPreset GetPreset() { Marshal.ThrowExceptionForHR(fxI3Dl2Reverb.GetPreset(out var preset)); return (I3DL2EnvironmentPreset)preset; } private void SetAllParameters(DsFxI3Dl2Reverb param) { Marshal.ThrowExceptionForHR(fxI3Dl2Reverb.SetAllParameters(ref param)); } private DsFxI3Dl2Reverb GetAllParameters() { Marshal.ThrowExceptionForHR(fxI3Dl2Reverb.GetAllParameters(out var param)); return param; } } private readonly MediaObject mediaObject; private readonly MediaObjectInPlace mediaObjectInPlace; private readonly Params effectParams; /// /// Media Object /// public MediaObject MediaObject => mediaObject; /// /// Media Object InPlace /// public MediaObjectInPlace MediaObjectInPlace => mediaObjectInPlace; /// /// Effect Parameter /// public Params EffectParams => effectParams; /// /// Create new DMO I3DL2Reverb /// public DmoI3DL2Reverb() { var guidi3Dl2Reverb = new Guid("EF985E71-D5C7-42D4-BA4D-2D073E2E96F4"); var targetDescriptor = DmoEnumerator.GetAudioEffectNames().First(descriptor => Equals(descriptor.Clsid, guidi3Dl2Reverb)); if (targetDescriptor != null) { var mediaComObject = Activator.CreateInstance(Type.GetTypeFromCLSID(targetDescriptor.Clsid)); mediaObject = new MediaObject((IMediaObject)mediaComObject); mediaObjectInPlace = new MediaObjectInPlace((IMediaObjectInPlace)mediaComObject); effectParams = new Params((IDirectSoundFXI3DL2Reverb)mediaComObject); } } /// /// Dispose code /// public void Dispose() { mediaObjectInPlace?.Dispose(); mediaObject?.Dispose(); } } }