using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; namespace Bmp.Core.FFMpeg.CsCorePorts; // ReSharper disable ConvertToAutoProperty /// /// Defines the format of waveform-audio data. /// [StructLayout(LayoutKind.Sequential, Pack = 2)] public class WaveFormat : ICloneable, IEquatable { private AudioEncoding _encoding; private short _channels; private int _sampleRate; private int _bytesPerSecond; private short _blockAlign; private short _bitsPerSample; private short _extraSize; /// /// Gets the number of channels in the waveform-audio data. Mono data uses one channel and stereo data uses two /// channels. /// public virtual int Channels { get { return _channels; } protected internal set { _channels = (short)value; UpdateProperties(); } } /// /// Gets the sample rate, in samples per second (hertz). /// public virtual int SampleRate { get { return _sampleRate; } protected internal set { _sampleRate = value; UpdateProperties(); } } /// /// Gets the required average data transfer rate, in bytes per second. For example, 16-bit stereo at 44.1 kHz has an /// average data rate of 176,400 bytes per second (2 channels — 2 bytes per sample per channel — 44,100 samples per /// second). /// public virtual int BytesPerSecond { get { return _bytesPerSecond; } protected internal set { _bytesPerSecond = value; } } /// /// Gets the block alignment, in bytes. The block alignment is the minimum atomic unit of data. For PCM data, the block /// alignment is the number of bytes used by a single sample, including data for both channels if the data is stereo. /// For example, the block alignment for 16-bit stereo PCM is 4 bytes (2 channels x 2 bytes per sample). /// public virtual int BlockAlign { get { return _blockAlign; } protected internal set { _blockAlign = (short)value; } } /// /// Gets the number of bits, used to store one sample. /// public virtual int BitsPerSample { get { return _bitsPerSample; } protected internal set { _bitsPerSample = (short)value; UpdateProperties(); } } /// /// Gets the size (in bytes) of extra information. This value is mainly used for marshalling. /// public virtual int ExtraSize { get { return _extraSize; } protected internal set { _extraSize = (short)value; } } /// /// Gets the number of bytes, used to store one sample. /// public virtual int BytesPerSample { get { return BitsPerSample / 8; } } /// /// Gets the number of bytes, used to store one block. This value equals multiplied with /// . /// public virtual int BytesPerBlock { get { return BytesPerSample * Channels; } } /// /// Gets the waveform-audio format type. /// public virtual AudioEncoding WaveFormatTag { get { return _encoding; } protected internal set { _encoding = value; } } /// /// Initializes a new instance of the class with a sample rate of 44100 Hz, bits per sample /// of 16 bit, 2 channels and PCM as the format type. /// public WaveFormat() : this(44100, 16, 2) { } /// /// Initializes a new instance of the class with PCM as the format type. /// /// Samples per second. /// Number of bits, used to store one sample. /// Number of channels in the waveform-audio data. public WaveFormat(int sampleRate, int bits, int channels) : this(sampleRate, bits, channels, AudioEncoding.Pcm) { } /// /// Initializes a new instance of the class. /// /// Samples per second. /// Number of bits, used to store one sample. /// Number of channels in the waveform-audio data. /// Format type or encoding of the wave format. public WaveFormat(int sampleRate, int bits, int channels, AudioEncoding encoding) : this(sampleRate, bits, channels, encoding, 0) { } /// /// Initializes a new instance of the class. /// /// Samples per second. /// Number of bits, used to store one sample. /// Number of channels in the waveform-audio data. /// Format type or encoding of the wave format. /// Size (in bytes) of extra information. This value is mainly used for marshalling. public WaveFormat(int sampleRate, int bits, int channels, AudioEncoding encoding, int extraSize) { if (sampleRate < 1) throw new ArgumentOutOfRangeException("sampleRate"); if (bits < 0) throw new ArgumentOutOfRangeException("bits"); if (channels < 1) throw new ArgumentOutOfRangeException("channels", "Number of channels has to be bigger than 0."); _sampleRate = sampleRate; _bitsPerSample = (short)bits; _channels = (short)channels; _encoding = encoding; _extraSize = (short)extraSize; // ReSharper disable once DoNotCallOverridableMethodsInConstructor UpdateProperties(); } /// /// Converts a duration in milliseconds to a duration in bytes. /// /// Duration in millisecond to convert to a duration in bytes. /// Duration in bytes. public long MillisecondsToBytes(double milliseconds) { var result = (long)(BytesPerSecond / 1000.0 * milliseconds); result -= result % BlockAlign; return result; } /// /// Converts a duration in bytes to a duration in milliseconds. /// /// Duration in bytes to convert to a duration in milliseconds. /// Duration in milliseconds. public double BytesToMilliseconds(long bytes) { bytes -= bytes % BlockAlign; var result = bytes / (double)BytesPerSecond * 1000.0; return result; } /// /// Indicates whether the current object is equal to another object of the same type. /// /// The to compare with this . /// true if the current object is equal to the other parameter; otherwise, false. public virtual bool Equals(WaveFormat other) { return Channels == other.Channels && SampleRate == other.SampleRate && BytesPerSecond == other.BytesPerSecond && BlockAlign == other.BlockAlign && BitsPerSample == other.BitsPerSample && ExtraSize == other.ExtraSize && WaveFormatTag == other.WaveFormatTag; } /// /// Returns a string which describes the . /// /// A string which describes the . public override string ToString() { return GetInformation().ToString(); } /// /// Creates a new object that is a copy of the current instance. /// /// A copy of the current instance. public virtual object Clone() { return MemberwiseClone(); //since there are value types MemberWiseClone is enough. } internal virtual void SetWaveFormatTagInternal(AudioEncoding waveFormatTag) { WaveFormatTag = waveFormatTag; } internal virtual void SetBitsPerSampleAndFormatProperties(int bitsPerSample) { BitsPerSample = bitsPerSample; UpdateProperties(); } /// /// Updates the - and the -property. /// internal protected virtual void UpdateProperties() { BlockAlign = BitsPerSample / 8 * Channels; BytesPerSecond = BlockAlign * SampleRate; } [DebuggerStepThrough] private StringBuilder GetInformation() { var builder = new StringBuilder(); builder.Append("ChannelsAvailable: " + Channels); builder.Append("|SampleRate: " + SampleRate); builder.Append("|Bps: " + BytesPerSecond); builder.Append("|BlockAlign: " + BlockAlign); builder.Append("|BitsPerSample: " + BitsPerSample); builder.Append("|Encoding: " + _encoding); return builder; } } // ReSharper restore ConvertToAutoProperty