DSPUtil.WaveReader.ReadWaveHeader C# (CSharp) Method

ReadWaveHeader() private method

private ReadWaveHeader ( WaveFormat format, bool expectHeader ) : void
format WaveFormat
expectHeader bool
return void
        private void ReadWaveHeader(WaveFormat format, bool expectHeader)
        {
            _ok = false;
            _pos = 0;

            //          Trace.WriteLine("ReadWaveHeader {0}", format);
            if (!expectHeader)
            {
                // Input file is raw data
                _riff = "(no header)";
                _length = 0;
                _wave = "(no header)";
                _format = "(no header)";
                _size = 16;
                _data = "data";
                _dataSize = 0;
                _max = uint.MaxValue;
                _audioFormat = format;

                // Assume defaults, they can be overridden later
                NumChannels = 2;
                SampleRate = 44100;

                if (format == WaveFormat.PCM || format == WaveFormat.EXTENSIBLE)
                {
                    // Raw PCM, assume 16 bit 44k1 stereo PCM
                    _bitsPerSample = 16;
                    _ok = true;
                }
                else if (format == WaveFormat.IEEE_FLOAT)
                {
                    // IEEE Float; assume 32 bit 44k1 stereo IEEE_FLOAT
                    _bitsPerSample = 32;
                    _ok = true;
                }
                else if (format == WaveFormat.INTERNAL_DOUBLE)
                {
                    // our 64 bit 44k1 stereo 'double-precision'
                    _bitsPerSample = 32;
                    _ok = true;
                }

                _blockAlign = (ushort)((NumChannels * _bitsPerSample) >> 3);
                _byteRate = (uint)(_blockAlign * SampleRate);

                return;
            }

            // Read 'RIFF' (WAV) or 'FORM' (AIFF) tag ///////////////////////////////////////////////

            char[] hdr = _rdr.ReadChars(4);
            _riff = new string(hdr);
            if (_riff != "RIFF" && _riff != "FORM")
            {
                if (hdr.Length == 0)
                {
                    throw (new Exception("File could not be read: no data."));
                }
                string x = "";
                for (int j = 0; j < hdr.Length; j++)
                {
                    x += String.Format("{0:X} ", (int)hdr[j]);
                }
                throw (new Exception(String.Format("File is not WAV: no 'RIFF' tag found, instead '{0}'.", x)));
            }

            // File length
            int fileLen = _rdr.ReadInt32();
            _length = (uint)fileLen;

            // Read Wave //////////////////////////////////////////////

            _wave = new string(_rdr.ReadChars(4));
            if (_wave != "WAVE" && _wave != "AIFF")
                throw (new Exception(String.Format("File is not WAV: no 'WAVE' tag found, instead {0}", _wave)));
            if (_wave == "AIFF")
            {
                // The whole file is big-endian, including lengths in the header
                BigEndian = true;
                _length = (uint)System.Net.IPAddress.NetworkToHostOrder(fileLen);
            }
            // Read Format ////////////////////////////////////////////

            _format = new string(_rdr.ReadChars(4));

            // WMP11-ripped WAV files begin with 'LIST' metadata - even before the format tag.
            // AIFF files could have this too (haven't seen it yet).
            // Skip any chunks up to the format header.
            while (_format.Length > 0 && _format != "fmt " && _format != "COMM")
            {
                int chunkSize = _rdr.ReadInt32();
                if (BigEndian)
                    chunkSize = System.Net.IPAddress.NetworkToHostOrder(chunkSize);
                Trace.WriteLine("Skipping {0} ({1} bytes)", _format, chunkSize);
                _rdr.ReadBytes(chunkSize);
                _format = new string(_rdr.ReadChars(4));
            }

            if (_format == "fmt ")
            {
                // WAV file-format chunk
                _size = _rdr.ReadUInt32();
                if (_size < 16)
                    throw (new Exception("File could not be read: don't know how to read 'fmt' size " + _size));

                _audioFormat = (WaveFormat)_rdr.ReadUInt16();

                if (_audioFormat == WaveFormat.PCM ||
                    _audioFormat == WaveFormat.ADPCM ||
                    _audioFormat == WaveFormat.IEEE_FLOAT ||
                    _audioFormat == WaveFormat.INTERNAL_DOUBLE ||
                    _audioFormat == WaveFormat.EXTENSIBLE)
                {
                    //                                      // WAVEFORMATEX wFormatTag          2 bytes
                    NumChannels = _rdr.ReadUInt16();        // WAVEFORMATEX nChannels           2
                    SampleRate = _rdr.ReadUInt32();         // WAVEFORMATEX nSamplesPerSec      4
                    _byteRate = _rdr.ReadUInt32();          // WAVEFORMATEX nAvgBytesPerSec     4
                    _blockAlign = _rdr.ReadUInt16();        // WAVEFORMATEX nBlockAlign         2 (channels * bitspersample / 8)
                    _bitsPerSample = _rdr.ReadUInt16();     // WAVEFORMATEX wBitsPerSample      2 (the *container* size)
                    if (_size > 16)
                    {
                        uint skip = 16;
                        if (_audioFormat == WaveFormat.EXTENSIBLE)
                        {
                            UInt16 kip = _rdr.ReadUInt16();
                            UInt16 union = _rdr.ReadUInt16();       // the Samples union, wdc
                            _channelMask = _rdr.ReadUInt32();       // channel mask
                            // then the GUID, 16 bytes
                            _formatEx = new WaveFormatEx(_rdr.ReadBytes(16));
                            skip = 40;
                            if (_formatEx.Equals(WaveFormatEx.PCM) || _formatEx.Equals(WaveFormatEx.AMBISONIC_B_FORMAT_PCM))
                            {
                                _audioFormat = WaveFormat.PCM;
                            }
                            else if (_formatEx.Equals(WaveFormatEx.IEEE_FLOAT) || _formatEx.Equals(WaveFormatEx.AMBISONIC_B_FORMAT_IEEE_FLOAT))
                            {
                                _audioFormat = WaveFormat.IEEE_FLOAT;
                            }
                        }
                        // Read and discard the rest of the 'fmt' structure
                        _rdr.ReadBytes((int)(_size - skip));
                    }
                }
                else
                {
                    throw (new Exception("File could not be read: don't know how to read audio format " + _audioFormat));
                }
            }
            else if (_format == "COMM")
            {
                // AIFF file-format chunk
                _size = (uint)System.Net.IPAddress.NetworkToHostOrder(_rdr.ReadInt32());
                if (_size < 18)
                    throw (new Exception("File could not be read: don't know how to read 'COMM' size " + _size));

                _audioFormat = WaveFormat.PCM;
                NumChannels = (ushort)System.Net.IPAddress.NetworkToHostOrder(_rdr.ReadInt16());
                uint numFrames = (uint)System.Net.IPAddress.NetworkToHostOrder(_rdr.ReadInt32()); // number of sample frames
                _bitsPerSample = (ushort)System.Net.IPAddress.NetworkToHostOrder(_rdr.ReadInt16());

                // SampleRate is 10-byte IEEE_extended format.  Don't bother converting that
                // properly, just check for good known values (yuk!)
                byte[] ext = _rdr.ReadBytes(10);
                if (ext[0] == 64 && ext[1] == 14 && ext[2] == 172 && ext[3] == 68)
                {
                    SampleRate = 44100;
                }
                else if (ext[0] == 64 && ext[1] == 14 && ext[2] == 187 && ext[3] == 128)
                {
                    SampleRate = 48000;
                }
                else if (ext[0] == 64 && ext[1] == 15 && ext[2] == 187 && ext[3] == 128)
                {
                    SampleRate = 96000;
                }
                else
                {
                    throw (new Exception("File could not be read: don't know how to interpret sample rate."));
                }

                _blockAlign = (ushort)((NumChannels * _bitsPerSample) / 8);
                _byteRate = (uint)(_blockAlign * SampleRate);

                if (_size > 18)
                {
                    // Read and discard the rest of the 'fmt' structure
                    _rdr.ReadBytes((int)(_size - 18));
                }
            }
            else
            {
                throw (new Exception(String.Format("File could not be read: no 'fmt' tag found, instead {0}", _format)));
            }

            // Read Data ///////////////////////////////////////////////

            _data = new string(_rdr.ReadChars(4));
            while (_data.Length > 0 && _data != "data" && _data != "SSND")
            {
                // Not a data chunk, ignore
                int miscSize = _rdr.ReadInt32();
                if (BigEndian)
                    miscSize = System.Net.IPAddress.NetworkToHostOrder(miscSize);
                _rdr.ReadBytes(miscSize);
                _data = new string(_rdr.ReadChars(4));
            }

            // Read the data size
            if (BigEndian)
            {
                _dataSize = (uint)System.Net.IPAddress.NetworkToHostOrder(_rdr.ReadInt32());
            }
            else
            {
                _dataSize = _rdr.ReadUInt32();
            }

            // See if we can read this
            if (NumChannels > 0)
            {
                switch (_audioFormat)
                {
                    case WaveFormat.PCM:
                    case WaveFormat.EXTENSIBLE:
                        switch (_bitsPerSample)
                        {
                            case 8:
                            case 16:
                            case 24:
                            case 32:
                                _ok = true;
                                break;
                            default:
                                break;
                        }
                        break;
                    case WaveFormat.IEEE_FLOAT:
                        switch (_bitsPerSample)
                        {
                            case 32:
                            case 64:
                                _ok = true;
                                break;
                        }
                        break;
                    case WaveFormat.INTERNAL_DOUBLE:
                        switch (_bitsPerSample)
                        {
                            case 64:
                                _ok = true;
                                break;
                        }
                        break;
                    default:
                        break;
                }
            }
            if (_ok)
            {
                _max = (uint)((_dataSize / (_bitsPerSample / 8)) / NumChannels);
                if (_dataSize==4294967292)
                {
                    Trace.WriteLine("Wave file: unknown size from header");
                    _max = uint.MaxValue;
                }
                if (_max == 0)
                {
                    Trace.WriteLine("Wave file: zero size from header");
                    _max = uint.MaxValue;
                }
            }
        }