File: AudioFormat\SpeechAudioFormatInfo.cs
Web Access
Project: src\src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Speech.Internal.Synthesis;

namespace System.Speech.AudioFormat
{
    [Serializable]
    public class SpeechAudioFormatInfo
    {
        #region Constructors

        private SpeechAudioFormatInfo(EncodingFormat encodingFormat, int samplesPerSecond, short bitsPerSample, short channelCount, byte[]? formatSpecificData)
        {
            if (encodingFormat == 0)
            {
                throw new ArgumentException(SR.Get(SRID.CannotUseCustomFormat), nameof(encodingFormat));
            }
            if (samplesPerSecond <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(samplesPerSecond), SR.Get(SRID.MustBeGreaterThanZero));
            }
            if (bitsPerSample <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bitsPerSample), SR.Get(SRID.MustBeGreaterThanZero));
            }
            if (channelCount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(channelCount), SR.Get(SRID.MustBeGreaterThanZero));
            }

            _encodingFormat = encodingFormat;
            _samplesPerSecond = samplesPerSecond;
            _bitsPerSample = bitsPerSample;
            _channelCount = channelCount;
            if (formatSpecificData == null)
            {
                _formatSpecificData = Array.Empty<byte>();
            }
            else
            {
                _formatSpecificData = (byte[])formatSpecificData.Clone();
            }

            switch (encodingFormat)
            {
                case EncodingFormat.ALaw:
                case EncodingFormat.ULaw:
                    if (bitsPerSample != 8)
                    {
                        throw new ArgumentOutOfRangeException(nameof(bitsPerSample));
                    }
                    if (formatSpecificData != null && formatSpecificData.Length != 0)
                    {
                        throw new ArgumentOutOfRangeException(nameof(formatSpecificData));
                    }
                    break;
            }
        }
        [EditorBrowsable(EditorBrowsableState.Never)]
        public SpeechAudioFormatInfo(EncodingFormat encodingFormat, int samplesPerSecond, int bitsPerSample, int channelCount, int averageBytesPerSecond, int blockAlign, byte[]? formatSpecificData)
            : this(encodingFormat, samplesPerSecond, (short)bitsPerSample, (short)channelCount, formatSpecificData)
        {
            // Don't explicitly check these are sensible values - allow flexibility here as some formats may do unexpected things here.
            if (averageBytesPerSecond <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(averageBytesPerSecond), SR.Get(SRID.MustBeGreaterThanZero));
            }
            if (blockAlign <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(blockAlign), SR.Get(SRID.MustBeGreaterThanZero));
            }
            _averageBytesPerSecond = averageBytesPerSecond;
            _blockAlign = (short)blockAlign;
        }
        public SpeechAudioFormatInfo(int samplesPerSecond, AudioBitsPerSample bitsPerSample, AudioChannel channel)
            : this(EncodingFormat.Pcm, samplesPerSecond, (short)bitsPerSample, (short)channel, null)
        {
            // Don't explicitly check these are sensible values - allow flexibility here as some formats may do unexpected things here.
            _blockAlign = (short)(_channelCount * (_bitsPerSample / 8));
            _averageBytesPerSecond = _samplesPerSecond * _blockAlign;
        }

        #endregion

        #region Public Properties
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public int AverageBytesPerSecond { get { return _averageBytesPerSecond; } }
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public int BitsPerSample { get { return _bitsPerSample; } }
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public int BlockAlign { get { return _blockAlign; } }
        public EncodingFormat EncodingFormat { get { return _encodingFormat; } }
        public int ChannelCount { get { return _channelCount; } }
        public int SamplesPerSecond { get { return _samplesPerSecond; } }

        #endregion

        #region Public Methods
        public byte[] FormatSpecificData() { return (byte[])_formatSpecificData.Clone(); }
        public override bool Equals([NotNullWhen(true)] object? obj)
        {
            if (obj is not SpeechAudioFormatInfo refObj)
            {
                return false;
            }

            if (!(_averageBytesPerSecond.Equals(refObj._averageBytesPerSecond) &&
                _bitsPerSample.Equals(refObj._bitsPerSample) &&
                _blockAlign.Equals(refObj._blockAlign) &&
                _encodingFormat.Equals(refObj._encodingFormat) &&
                _channelCount.Equals(refObj._channelCount) &&
                _samplesPerSecond.Equals(refObj._samplesPerSecond)))
            {
                return false;
            }
            if (_formatSpecificData.Length != refObj._formatSpecificData.Length)
            {
                return false;
            }
            for (int i = 0; i < _formatSpecificData.Length; i++)
            {
                if (_formatSpecificData[i] != refObj._formatSpecificData[i])
                {
                    return false;
                }
            }
            return true;
        }
        public override int GetHashCode()
        {
            return _averageBytesPerSecond.GetHashCode();
        }

        #endregion

        #region Internal Methods
        internal byte[] WaveFormat
        {
            get
            {
                WAVEFORMATEX wfx = new();
                wfx.wFormatTag = (short)EncodingFormat;
                wfx.nChannels = (short)ChannelCount;
                wfx.nSamplesPerSec = SamplesPerSecond;
                wfx.nAvgBytesPerSec = AverageBytesPerSecond;
                wfx.nBlockAlign = (short)BlockAlign;
                wfx.wBitsPerSample = (short)BitsPerSample;
                wfx.cbSize = (short)FormatSpecificData().Length;

                byte[] abWfx = wfx.ToBytes();
                if (wfx.cbSize > 0)
                {
                    byte[] wfxTemp = new byte[abWfx.Length + wfx.cbSize];
                    Array.Copy(abWfx, wfxTemp, abWfx.Length);
                    Array.Copy(FormatSpecificData(), 0, wfxTemp, abWfx.Length, wfx.cbSize);
                    abWfx = wfxTemp;
                }
                return abWfx;
            }
        }
        #endregion

        #region Private Fields

        private int _averageBytesPerSecond;
        private short _bitsPerSample;
        private short _blockAlign;
        private EncodingFormat _encodingFormat;
        private short _channelCount;
        private int _samplesPerSecond;
        private byte[] _formatSpecificData;

        #endregion
    }

    #region Public Properties
    public enum AudioChannel
    {
        Mono = 1,
        Stereo = 2
    }
    public enum AudioBitsPerSample
    {
        Eight = 8,
        Sixteen = 16
    }

    #endregion
}