WaveFormat.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using System.Diagnostics;
  2. using System.Runtime.InteropServices;
  3. using System.Text;
  4. namespace Bmp.Core.FFMpeg.CsCorePorts;
  5. // ReSharper disable ConvertToAutoProperty
  6. /// <summary>
  7. /// Defines the format of waveform-audio data.
  8. /// </summary>
  9. [StructLayout(LayoutKind.Sequential, Pack = 2)]
  10. public class WaveFormat : ICloneable, IEquatable<WaveFormat>
  11. {
  12. private AudioEncoding _encoding;
  13. private short _channels;
  14. private int _sampleRate;
  15. private int _bytesPerSecond;
  16. private short _blockAlign;
  17. private short _bitsPerSample;
  18. private short _extraSize;
  19. /// <summary>
  20. /// Gets the number of channels in the waveform-audio data. Mono data uses one channel and stereo data uses two
  21. /// channels.
  22. /// </summary>
  23. public virtual int Channels
  24. {
  25. get { return _channels; }
  26. protected internal set
  27. {
  28. _channels = (short)value;
  29. UpdateProperties();
  30. }
  31. }
  32. /// <summary>
  33. /// Gets the sample rate, in samples per second (hertz).
  34. /// </summary>
  35. public virtual int SampleRate
  36. {
  37. get { return _sampleRate; }
  38. protected internal set
  39. {
  40. _sampleRate = value;
  41. UpdateProperties();
  42. }
  43. }
  44. /// <summary>
  45. /// Gets the required average data transfer rate, in bytes per second. For example, 16-bit stereo at 44.1 kHz has an
  46. /// average data rate of 176,400 bytes per second (2 channels — 2 bytes per sample per channel — 44,100 samples per
  47. /// second).
  48. /// </summary>
  49. public virtual int BytesPerSecond
  50. {
  51. get { return _bytesPerSecond; }
  52. protected internal set { _bytesPerSecond = value; }
  53. }
  54. /// <summary>
  55. /// Gets the block alignment, in bytes. The block alignment is the minimum atomic unit of data. For PCM data, the block
  56. /// alignment is the number of bytes used by a single sample, including data for both channels if the data is stereo.
  57. /// For example, the block alignment for 16-bit stereo PCM is 4 bytes (2 channels x 2 bytes per sample).
  58. /// </summary>
  59. public virtual int BlockAlign
  60. {
  61. get { return _blockAlign; }
  62. protected internal set { _blockAlign = (short)value; }
  63. }
  64. /// <summary>
  65. /// Gets the number of bits, used to store one sample.
  66. /// </summary>
  67. public virtual int BitsPerSample
  68. {
  69. get { return _bitsPerSample; }
  70. protected internal set
  71. {
  72. _bitsPerSample = (short)value;
  73. UpdateProperties();
  74. }
  75. }
  76. /// <summary>
  77. /// Gets the size (in bytes) of extra information. This value is mainly used for marshalling.
  78. /// </summary>
  79. public virtual int ExtraSize
  80. {
  81. get { return _extraSize; }
  82. protected internal set { _extraSize = (short)value; }
  83. }
  84. /// <summary>
  85. /// Gets the number of bytes, used to store one sample.
  86. /// </summary>
  87. public virtual int BytesPerSample
  88. {
  89. get { return BitsPerSample / 8; }
  90. }
  91. /// <summary>
  92. /// Gets the number of bytes, used to store one block. This value equals <see cref="BytesPerSample" /> multiplied with
  93. /// <see cref="Channels" />.
  94. /// </summary>
  95. public virtual int BytesPerBlock
  96. {
  97. get { return BytesPerSample * Channels; }
  98. }
  99. /// <summary>
  100. /// Gets the waveform-audio format type.
  101. /// </summary>
  102. public virtual AudioEncoding WaveFormatTag
  103. {
  104. get { return _encoding; }
  105. protected internal set { _encoding = value; }
  106. }
  107. /// <summary>
  108. /// Initializes a new instance of the <see cref="WaveFormat" /> class with a sample rate of 44100 Hz, bits per sample
  109. /// of 16 bit, 2 channels and PCM as the format type.
  110. /// </summary>
  111. public WaveFormat()
  112. : this(44100, 16, 2)
  113. {
  114. }
  115. /// <summary>
  116. /// Initializes a new instance of the <see cref="WaveFormat" /> class with PCM as the format type.
  117. /// </summary>
  118. /// <param name="sampleRate">Samples per second.</param>
  119. /// <param name="bits">Number of bits, used to store one sample.</param>
  120. /// <param name="channels">Number of channels in the waveform-audio data.</param>
  121. public WaveFormat(int sampleRate, int bits, int channels)
  122. : this(sampleRate, bits, channels, AudioEncoding.Pcm)
  123. {
  124. }
  125. /// <summary>
  126. /// Initializes a new instance of the <see cref="WaveFormat" /> class.
  127. /// </summary>
  128. /// <param name="sampleRate">Samples per second.</param>
  129. /// <param name="bits">Number of bits, used to store one sample.</param>
  130. /// <param name="channels">Number of channels in the waveform-audio data.</param>
  131. /// <param name="encoding">Format type or encoding of the wave format.</param>
  132. public WaveFormat(int sampleRate, int bits, int channels, AudioEncoding encoding)
  133. : this(sampleRate, bits, channels, encoding, 0)
  134. {
  135. }
  136. /// <summary>
  137. /// Initializes a new instance of the <see cref="WaveFormat" /> class.
  138. /// </summary>
  139. /// <param name="sampleRate">Samples per second.</param>
  140. /// <param name="bits">Number of bits, used to store one sample.</param>
  141. /// <param name="channels">Number of channels in the waveform-audio data.</param>
  142. /// <param name="encoding">Format type or encoding of the wave format.</param>
  143. /// <param name="extraSize">Size (in bytes) of extra information. This value is mainly used for marshalling.</param>
  144. public WaveFormat(int sampleRate, int bits, int channels, AudioEncoding encoding, int extraSize)
  145. {
  146. if (sampleRate < 1)
  147. throw new ArgumentOutOfRangeException("sampleRate");
  148. if (bits < 0)
  149. throw new ArgumentOutOfRangeException("bits");
  150. if (channels < 1)
  151. throw new ArgumentOutOfRangeException("channels", "Number of channels has to be bigger than 0.");
  152. _sampleRate = sampleRate;
  153. _bitsPerSample = (short)bits;
  154. _channels = (short)channels;
  155. _encoding = encoding;
  156. _extraSize = (short)extraSize;
  157. // ReSharper disable once DoNotCallOverridableMethodsInConstructor
  158. UpdateProperties();
  159. }
  160. /// <summary>
  161. /// Converts a duration in milliseconds to a duration in bytes.
  162. /// </summary>
  163. /// <param name="milliseconds">Duration in millisecond to convert to a duration in bytes.</param>
  164. /// <returns>Duration in bytes.</returns>
  165. public long MillisecondsToBytes(double milliseconds)
  166. {
  167. var result = (long)(BytesPerSecond / 1000.0 * milliseconds);
  168. result -= result % BlockAlign;
  169. return result;
  170. }
  171. /// <summary>
  172. /// Converts a duration in bytes to a duration in milliseconds.
  173. /// </summary>
  174. /// <param name="bytes">Duration in bytes to convert to a duration in milliseconds.</param>
  175. /// <returns>Duration in milliseconds.</returns>
  176. public double BytesToMilliseconds(long bytes)
  177. {
  178. bytes -= bytes % BlockAlign;
  179. var result = bytes / (double)BytesPerSecond * 1000.0;
  180. return result;
  181. }
  182. /// <summary>
  183. /// Indicates whether the current object is equal to another object of the same type.
  184. /// </summary>
  185. /// <param name="other">The <see cref="WaveFormat"/> to compare with this <see cref="WaveFormat"/>.</param>
  186. /// <returns>true if the current object is equal to the other parameter; otherwise, false.</returns>
  187. public virtual bool Equals(WaveFormat other)
  188. {
  189. return Channels == other.Channels &&
  190. SampleRate == other.SampleRate &&
  191. BytesPerSecond == other.BytesPerSecond &&
  192. BlockAlign == other.BlockAlign &&
  193. BitsPerSample == other.BitsPerSample &&
  194. ExtraSize == other.ExtraSize &&
  195. WaveFormatTag == other.WaveFormatTag;
  196. }
  197. /// <summary>
  198. /// Returns a string which describes the <see cref="WaveFormat" />.
  199. /// </summary>
  200. /// <returns>A string which describes the <see cref="WaveFormat" />.</returns>
  201. public override string ToString()
  202. {
  203. return GetInformation().ToString();
  204. }
  205. /// <summary>
  206. /// Creates a new <see cref="WaveFormat" /> object that is a copy of the current instance.
  207. /// </summary>
  208. /// <returns>A copy of the current instance.</returns>
  209. public virtual object Clone()
  210. {
  211. return MemberwiseClone(); //since there are value types MemberWiseClone is enough.
  212. }
  213. internal virtual void SetWaveFormatTagInternal(AudioEncoding waveFormatTag)
  214. {
  215. WaveFormatTag = waveFormatTag;
  216. }
  217. internal virtual void SetBitsPerSampleAndFormatProperties(int bitsPerSample)
  218. {
  219. BitsPerSample = bitsPerSample;
  220. UpdateProperties();
  221. }
  222. /// <summary>
  223. /// Updates the <see cref="BlockAlign"/>- and the <see cref="BytesPerSecond"/>-property.
  224. /// </summary>
  225. internal protected virtual void UpdateProperties()
  226. {
  227. BlockAlign = BitsPerSample / 8 * Channels;
  228. BytesPerSecond = BlockAlign * SampleRate;
  229. }
  230. [DebuggerStepThrough]
  231. private StringBuilder GetInformation()
  232. {
  233. var builder = new StringBuilder();
  234. builder.Append("ChannelsAvailable: " + Channels);
  235. builder.Append("|SampleRate: " + SampleRate);
  236. builder.Append("|Bps: " + BytesPerSecond);
  237. builder.Append("|BlockAlign: " + BlockAlign);
  238. builder.Append("|BitsPerSample: " + BitsPerSample);
  239. builder.Append("|Encoding: " + _encoding);
  240. return builder;
  241. }
  242. }
  243. // ReSharper restore ConvertToAutoProperty