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);
}
}