using NAudio.MediaFoundation; using NAudio.Wave; using System.Reflection; namespace Bmp.Core.FFMpeg.CsCorePorts; internal static class Extension { /// /// Gets the length of a as a . /// /// The source to get the length for. /// The length of the specified as a value. public static TimeSpan GetLength(this IAudioSource source) { return GetTime(source, source.Length); } /// /// Gets the position of a as a value. /// /// The source to get the position of. /// The position of the specified as a value. /// The source must support seeking to get or set the position. /// Use the property to determine whether the stream supports seeking. /// Otherwise a call to this method may result in an exception. public static TimeSpan GetPosition(this IAudioSource source) { return GetTime(source, source.Position); } /// /// Sets the position of a as a value. /// /// The source to set the new position for. /// The new position as a value. /// /// The source must support seeking to get or set the position. /// Use the property to determine whether the stream supports seeking. /// Otherwise a call to this method may result in an exception. /// public static void SetPosition(this IAudioSource source, TimeSpan position) { if (source == null) throw new ArgumentNullException("source"); if (position.TotalMilliseconds < 0) throw new ArgumentOutOfRangeException("position"); var bytes = GetRawElements(source, position); source.Position = bytes; } /// /// Converts a duration in raw elements to a value. For more information about "raw elements" see remarks. /// /// The instance which provides the used /// to convert the duration in "raw elements" to a value. /// The duration in "raw elements" to convert to a value. /// The duration as a value. /// /// source /// or /// elementCount /// /// /// The term "raw elements" describes the elements, an audio source uses. /// What type of unit an implementation of the interface uses, depends on the implementation itself. /// For example, a uses bytes while a uses samples. /// That means that a provides its position, length,... in bytes /// while a provides its position, length,... in samples. /// /// To get the length or the position of a as a value, use the /// or the property. /// /// Internally this method uses the class. /// public static TimeSpan GetTime(this IAudioSource source, long elementCount) { if (source == null) throw new ArgumentNullException("source"); if (elementCount < 0) throw new ArgumentNullException("elementCount"); return TimeConverterFactory.Instance.GetTimeConverterForSource(source) .ToTimeSpan(source.WaveFormat, elementCount); } /// /// Converts a duration in raw elements to a duration in milliseconds. For more information about "raw elements" see remarks. /// /// The instance which provides the used /// to convert the duration in "raw elements" to a duration in milliseconds. /// The duration in "raw elements" to convert to duration in milliseconds. /// The duration in milliseconds. /// /// source /// or /// elementCount /// /// /// The term "raw elements" describes the elements, an audio source uses. /// What type of unit an implementation of the interface uses, depends on the implementation itself. /// For example, a uses bytes while a uses samples. /// That means that a provides its position, length,... in bytes /// while a provides its position, length,... in samples. /// /// To get the length or the position of a as a value, use the /// or the property. /// /// Internally this method uses the class. /// public static long GetMilliseconds(this IAudioSource source, long elementCount) { if (source == null) throw new ArgumentNullException("source"); if (elementCount < 0) throw new ArgumentOutOfRangeException("elementCount"); return (long)GetTime(source, elementCount).TotalMilliseconds; } /// /// Converts a duration as a to a duration in "raw elements". For more information about "raw elements" see remarks. /// /// /// instance which provides the used to convert /// the duration as a to a duration in "raw elements". /// /// Duration as a to convert to a duration in "raw elements". /// Duration in "raw elements". /// source /// /// The term "raw elements" describes the elements, an audio source uses. /// What type of unit an implementation of the interface uses, depends on the implementation itself. /// For example, a uses bytes while a uses samples. /// That means that a provides its position, length,... in bytes /// while a provides its position, length,... in samples. /// /// To get the length or the position of a as a value, use the /// or the property. /// /// Internally this method uses the class. /// public static long GetRawElements(this IAudioSource source, TimeSpan timespan) { if (source == null) throw new ArgumentNullException("source"); return TimeConverterFactory.Instance.GetTimeConverterForSource(source) .ToRawElements(source.WaveFormat, timespan); } /// /// Converts a duration in milliseconds to a duration in "raw elements". For more information about "raw elements" see remarks. /// /// instance which provides the used to convert /// the duration in milliseconds to a duration in "raw elements". /// Duration in milliseconds to convert to a duration in "raw elements". /// /// Duration in "raw elements". /// /// /// The term "raw elements" describes the elements, an audio source uses. /// What type of unit an implementation of the interface uses, depends on the implementation itself. /// For example, a uses bytes while a uses samples. /// That means that a provides its position, length,... in bytes /// while a provides its position, length,... in samples. /// /// To get the length or the position of a as a value, use the /// or the property. /// /// Internally this method uses the class. /// /// source /// milliseconds is less than zero. public static long GetRawElements(this IAudioSource source, long milliseconds) { if (source == null) throw new ArgumentNullException("source"); if (milliseconds < 0) throw new ArgumentOutOfRangeException("milliseconds"); return GetRawElements(source, TimeSpan.FromMilliseconds(milliseconds)); } /// /// Writes all audio data of the to a stream. In comparison to the method, /// the method won't encode the provided audio to any particular format. No wav, aiff,... header won't be included. /// /// The waveSource which provides the audio data to write to the . /// The to store the audio data in. /// /// waveSource /// or /// stream /// /// Stream is not writeable.;stream public static void WriteToStream(this IWaveSource waveSource, Stream stream) { if (waveSource == null) throw new ArgumentNullException("waveSource"); if (stream == null) throw new ArgumentNullException("stream"); if (!stream.CanWrite) throw new ArgumentException("Stream is not writeable.", "stream"); var buffer = new byte[waveSource.WaveFormat.BytesPerSecond]; int read; while ((read = waveSource.Read(buffer, 0, buffer.Length)) > 0) { stream.Write(buffer, 0, read); } } /// /// Checks the length of an array. /// /// Type of the array. /// The array to check. This parameter can be null. /// The target length of the array. /// A value which indicates whether the length of the array has to fit exactly the specified . /// Array which fits the specified requirements. Note that if a new array got created, the content of the old array won't get copied to the return value. public static T[] CheckBuffer(this T[] inst, long size, bool exactSize = false) { if (inst == null || (!exactSize && inst.Length < size) || (exactSize && inst.Length != size)) return new T[size]; return inst; } internal static byte[] ReadBytes(this IWaveSource waveSource, int count) { if (waveSource == null) throw new ArgumentNullException("waveSource"); count -= (count % waveSource.WaveFormat.BlockAlign); if (count <= 0) throw new ArgumentOutOfRangeException("count"); var buffer = new byte[count]; var read = waveSource.Read(buffer, 0, buffer.Length); if (read < count) Array.Resize(ref buffer, read); return buffer; } internal static bool IsClosed(this Stream stream) { return !stream.CanRead && !stream.CanWrite; } internal static bool IsEndOfStream(this Stream stream) { return stream.Position == stream.Length; } //copied from http://stackoverflow.com/questions/1436190/c-sharp-get-and-set-the-high-order-word-of-an-integer internal static int LowWord(this int number) { return number & 0x0000FFFF; } internal static int LowWord(this int number, int newValue) { return (int)((number & 0xFFFF0000) + (newValue & 0x0000FFFF)); } internal static int HighWord(this int number) { return (int)(number & 0xFFFF0000); } internal static int HighWord(this int number, int newValue) { return (number & 0x0000FFFF) + (newValue << 16); } internal static uint LowWord(this uint number) { return number & 0x0000FFFF; } internal static uint LowWord(this uint number, int newValue) { return (uint)((number & 0xFFFF0000) + (newValue & 0x0000FFFF)); } internal static uint HighWord(this uint number) { return number & 0xFFFF0000; } internal static uint HighWord(this uint number, int newValue) { return (uint)((number & 0x0000FFFF) + (newValue << 16)); } //-- internal static Guid GetGuid(this Object obj) { return obj.GetType().GUID; } internal static void WaitForExit(this Thread thread) { if (thread == null) return; if (thread == Thread.CurrentThread) throw new InvalidOperationException("Deadlock detected."); thread.Join(); } internal static bool WaitForExit(this Thread thread, int timeout) { if (thread == null) return true; if (thread == Thread.CurrentThread) throw new InvalidOperationException("Deadlock detected."); return thread.Join(timeout); } // ReSharper disable once InconsistentNaming //copied from http://stackoverflow.com/questions/9927590/can-i-set-a-value-on-a-struct-through-reflection-without-boxing internal static void SetValueForValueType(this FieldInfo field, ref T item, object value) where T : struct { field.SetValueDirect(__makeref(item), value); } }