using System; using System.Linq; using System.Runtime.InteropServices; namespace NAudio.Dmo.Effect { internal struct DsFxEcho { public float WetDryMix; public float FeedBack; public float LeftDelay; public float RightDelay; public EchoPanDelay PanDelay; } [ComImport, System.Security.SuppressUnmanagedCodeSecurity, Guid("8bd28edf-50db-4e92-a2bd-445488d1ed42"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IDirectSoundFXEcho { [PreserveSig] int SetAllParameters([In] ref DsFxEcho param); [PreserveSig] int GetAllParameters(out DsFxEcho param); } /// /// Dmo Echo Effect /// public class DmoEcho : IDmoEffector { /// /// DMO Echo Params /// public struct Params { /// /// DSFXECHO_WETDRYMIX_MIN /// public const float WetDryMixMin = 0.0f; /// /// DSFXECHO_WETDRYMIX_MAX /// public const float WetDryMixMax = 100.0f; /// /// DSFXECHO_WETDRYMIX_DEFAULT /// public const float WetDeyMixDefault = 50.0f; /// /// DSFXECHO_FEEDBACK_MIN /// public const float FeedBackMin = 0.0f; /// /// DSFXECHO_FEEDBACK_MAX /// public const float FeedBackMax = 100.0f; /// /// DSFXECHO_FEEDBACK_DEFAULT /// public const float FeedBackDefault = 50.0f; /// /// DSFXECHO_LEFTDELAY_MIN /// public const float LeftDelayMin = 1.0f; /// /// DSFXECHO_LEFTDELAY_MAX /// public const float LeftDelayMax = 2000.0f; /// /// DSFXECHO_LEFTDELAY_DEFAULT /// public const float LeftDelayDefault = 500.0f; /// /// DSFXECHO_RIGHTDELAY_MIN /// public const float RightDelayMin = 1.0f; /// /// DSFXECHO_RIGHTDELAY_MAX /// public const float RightDelayMax = 2000.0f; /// /// DSFXECHO_RIGHTDELAY_DEFAULT /// public const float RightDelayDefault = 500.0f; /// /// DSFXECHO_PANDELAY_DEFAULT /// public const EchoPanDelay PanDelayDefault = EchoPanDelay.Off; /// /// Ratio of wet (processed) signal to dry (unprocessed) signal. /// public float WetDryMix { get { var param = GetAllParameters(); return param.WetDryMix; } set { var param = GetAllParameters(); param.WetDryMix = Math.Max(Math.Min(WetDryMixMax, value), WetDryMixMin); SetAllParameters(param); } } /// /// Percentage of output fed back into input. /// public float FeedBack { get { var param = GetAllParameters(); return param.FeedBack; } set { var param = GetAllParameters(); param.FeedBack = Math.Max(Math.Min(FeedBackMax, value), FeedBackMin); SetAllParameters(param); } } /// /// Delay for left channel, in milliseconds. /// public float LeftDelay { get { var param = GetAllParameters(); return param.LeftDelay; } set { var param = GetAllParameters(); param.LeftDelay = Math.Max(Math.Min(LeftDelayMax, value), LeftDelayMin); SetAllParameters(param); } } /// /// Delay for right channel, in milliseconds. /// public float RightDelay { get { var param = GetAllParameters(); return param.RightDelay; } set { var param = GetAllParameters(); param.RightDelay = Math.Max(Math.Min(RightDelayMax, value), RightDelayMin); SetAllParameters(param); } } /// /// Value that specifies whether to swap left and right delays with each successive echo. /// public EchoPanDelay PanDelay { get { var param = GetAllParameters(); return param.PanDelay; } set { var param = GetAllParameters(); if (Enum.IsDefined(typeof(EchoPanDelay), value)) { param.PanDelay = value; } SetAllParameters(param); } } private readonly IDirectSoundFXEcho fxEcho; internal Params(IDirectSoundFXEcho dsFxObject) { fxEcho = dsFxObject; } private void SetAllParameters(DsFxEcho param) { Marshal.ThrowExceptionForHR(fxEcho.SetAllParameters(ref param)); } private DsFxEcho GetAllParameters() { Marshal.ThrowExceptionForHR(fxEcho.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 Echo /// public DmoEcho() { var guidEcho = new Guid("EF3E932C-D40B-4F51-8CCF-3F98F1B29D5D"); var targetDescriptor = DmoEnumerator.GetAudioEffectNames().First(descriptor => Equals(descriptor.Clsid, guidEcho)); if (targetDescriptor != null) { var mediaComObject = Activator.CreateInstance(Type.GetTypeFromCLSID(targetDescriptor.Clsid)); mediaObject = new MediaObject((IMediaObject) mediaComObject); mediaObjectInPlace = new MediaObjectInPlace((IMediaObjectInPlace) mediaComObject); effectParams = new Params((IDirectSoundFXEcho) mediaComObject); } } /// /// Dispose code /// public void Dispose() { mediaObjectInPlace?.Dispose(); mediaObject?.Dispose(); } } }