using System; using System.Linq; using System.Runtime.InteropServices; namespace NAudio.Dmo.Effect { internal struct DsFxFlanger { public float WetDryMix; public float Depth; public float FeedBack; public float Frequency; public FlangerWaveForm WaveForm; public float Delay; public FlangerPhase Phase; } [ComImport, System.Security.SuppressUnmanagedCodeSecurity, Guid("903e9878-2c92-4072-9b2c-ea68f5396783"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IDirectSoundFXFlanger { [PreserveSig] int SetAllParameters([In] ref DsFxFlanger param); [PreserveSig] int GetAllParameters(out DsFxFlanger param); } /// /// DMO Flanger Effect /// public class DmoFlanger : IDmoEffector { /// /// DMO Flanger Params /// public struct Params { /// /// DSFXFLANGER_WETDRYMIX_MIN /// public const float WetDryMixMin = 0.0f; /// /// DSFXFLANGER_WETDRYMIX_MAX /// public const float WetDryMixMax = 100.0f; /// /// DSFXFLANGER_WETDRYMIX_DEFAULT /// public const float WetDrtMixDefault = 50.0f; /// /// DSFXFLANGER_DEPTH_MIN /// public const float DepthMin = 0.0f; /// /// DSFXFLANGER_DEPTH_MAX /// public const float DepthMax = 100.0f; /// /// DSFXFLANGER_DEPTH_DEFAULT /// public const float DepthDefault = 100.0f; /// /// DSFXFLANGER_FEEDBACK_MIN /// public const float FeedBackMin = -99.0f; /// /// DSFXFLANGER_FEEDBACK_MAX /// public const float FeedBackMax = 99.0f; /// /// DSFXFLANGER_FEEDBACK_DEFAULT /// public const float FeedBaclDefault = -50.0f; /// /// DSFXFLANGER_FREQUENCY_MIN /// public const float FrequencyMin = 0.0f; /// /// DSFXFLANGER_FREQUENCY_MAX /// public const float FrequencyMax = 10.0f; /// /// DSFXFLANGER_FREQUENCY_DEFAULT /// public const float FrequencyDefault = 0.25f; /// /// DSFXFLANGER_WAVE_DEFAULT /// public const FlangerWaveForm WaveFormDefault = FlangerWaveForm.Sin; /// /// DSFXFLANGER_DELAY_MIN /// public const float DelayMin = 0.0f; /// /// DSFXFLANGER_DELAY_MAX /// public const float DelayMax = 4.0f; /// /// DSFXFLANGER_DELAY_DEFAULT /// public const float DelayDefault = 2.0f; /// /// DSFXFLANGER_PHASE_DEFAULT /// public const FlangerPhase PhaseDefault = FlangerPhase.Zero; /// /// 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 by which the delay time is modulated by the low-frequency oscillator, /// in hundredths of a percentage point. /// public float Depth { get { var param = GetAllParameters(); return param.Depth; } set { var param = GetAllParameters(); param.Depth = Math.Max(Math.Min(DepthMax, value), DepthMin); SetAllParameters(param); } } /// /// Percentage of output signal to feed back into the effect's 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); } } /// /// Frequency of the LFO. /// public float Frequency { get { var param = GetAllParameters(); return param.Frequency; } set { var param = GetAllParameters(); param.Frequency = Math.Max(Math.Min(FrequencyMax, value), FrequencyMin); SetAllParameters(param); } } /// /// Waveform shape of the LFO. /// public FlangerWaveForm WaveForm { get { var param = GetAllParameters(); return param.WaveForm; } set { var param = GetAllParameters(); if (Enum.IsDefined(typeof(FlangerWaveForm), value)) { param.WaveForm = value; } SetAllParameters(param); } } /// /// Number of milliseconds the input is delayed before it is played back. /// public float Delay { get { var param = GetAllParameters(); return param.Delay; } set { var param = GetAllParameters(); param.Delay = Math.Max(Math.Min(DelayMax, value), DelayMin); SetAllParameters(param); } } /// /// Phase differential between left and right LFOs. /// public FlangerPhase Phase { get { var param = GetAllParameters(); return param.Phase; } set { var param = GetAllParameters(); if (Enum.IsDefined(typeof(FlangerPhase), value)) { param.Phase = value; } SetAllParameters(param); } } private readonly IDirectSoundFXFlanger fxFlanger; internal Params(IDirectSoundFXFlanger dsFxObject) { fxFlanger = dsFxObject; } private void SetAllParameters(DsFxFlanger param) { Marshal.ThrowExceptionForHR(fxFlanger.SetAllParameters(ref param)); } private DsFxFlanger GetAllParameters() { Marshal.ThrowExceptionForHR(fxFlanger.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 Flanger /// public DmoFlanger() { var guidFlanger = new Guid("EFCA3D92-DFD8-4672-A603-7420894BAD98"); var targetDescriptor = DmoEnumerator.GetAudioEffectNames().First(descriptor => Equals(descriptor.Clsid, guidFlanger)); if (targetDescriptor != null) { var mediaComObject = Activator.CreateInstance(Type.GetTypeFromCLSID(targetDescriptor.Clsid)); mediaObject = new MediaObject((IMediaObject)mediaComObject); mediaObjectInPlace = new MediaObjectInPlace((IMediaObjectInPlace)mediaComObject); effectParams = new Params((IDirectSoundFXFlanger)mediaComObject); } } /// /// Dispose code /// public void Dispose() { mediaObjectInPlace?.Dispose(); mediaObject?.Dispose(); } } }