using System; using NAudio.Dmo; using NAudio.Dmo.Effect; // ReSharper disable once CheckNamespace namespace NAudio.Wave { /// /// Provide WaveProvider that can apply effects in real time using DMO. /// /// If the audio thread is running on the STA thread, please generate and operate from the same thread. /// If the audio thread is running on the MTA thread, please operate on any MTA thread. /// /// Types of DMO effectors to use /// Parameters of the effect to be used public class DmoEffectWaveProvider : IWaveProvider, IDisposable where TDmoEffector : IDmoEffector, new() { private readonly IWaveProvider inputProvider; private readonly IDmoEffector effector; /// /// Create a new DmoEffectWaveProvider /// /// Input Stream public DmoEffectWaveProvider(IWaveProvider inputProvider) { this.inputProvider = inputProvider; effector = new TDmoEffector(); var mediaObject = effector.MediaObject; if (mediaObject == null) { throw new NotSupportedException(@"Dmo Effector Not Supported: " + nameof(TDmoEffector)); } if (!mediaObject.SupportsInputWaveFormat(0, inputProvider.WaveFormat)) { throw new ArgumentException(@"Unsupported Input Stream format", nameof(inputProvider)); } mediaObject.AllocateStreamingResources(); mediaObject.SetInputWaveFormat(0, this.inputProvider.WaveFormat); mediaObject.SetOutputWaveFormat(0, this.inputProvider.WaveFormat); } /// /// Stream Wave Format /// public WaveFormat WaveFormat => inputProvider.WaveFormat; /// /// Reads data from input stream /// /// buffer /// offset into buffer /// Bytes required /// Number of bytes read public int Read(byte[] buffer, int offset, int count) { var readNum = inputProvider.Read(buffer, offset, count); if (effector == null) { return readNum; } if (effector.MediaObjectInPlace.Process(readNum, offset, buffer, 0, DmoInPlaceProcessFlags.Normal) == DmoInPlaceProcessReturn.HasEffectTail) { var effectTail = new byte[readNum]; while (effector.MediaObjectInPlace.Process(readNum, 0, effectTail, 0, DmoInPlaceProcessFlags.Zero) == DmoInPlaceProcessReturn.HasEffectTail) { } } return readNum; } /// /// Get Effector Parameters /// public TEffectorParam EffectParams => effector.EffectParams; /// /// Dispose /// public void Dispose() { if (effector != null) { effector.MediaObject.FreeStreamingResources(); effector.Dispose(); } } } }