Example #1
0
        public void Initialize(Stream stream)
        {
            Contract.Ensures(_reader != null);
            Contract.Ensures(_reader.BaseStream == stream);
            Contract.Ensures(_channels > 0);
            Contract.Ensures(_samplesRemaining >= 0);
            Contract.Ensures(_bytesPerSample > 0);
            Contract.Ensures(_divisor > 0);

            _reader = new RiffReader(stream);

            if (!_reader.Validate() || _reader.ReadFourCC() != "WAVE")
            {
                throw new UnsupportedAudioException(Resources.SampleDecoderNotWaveError);
            }

            uint fmtChunkSize = _reader.SeekToChunk("fmt ");

            if (fmtChunkSize == 0)
            {
                throw new IOException(Resources.SampleDecoderMissingFmtError);
            }
            if (fmtChunkSize < 16)
            {
                throw new IOException(Resources.SampleDecoderFmtLengthError);
            }

            var format = (Format)_reader.ReadUInt16();

            if (format != Format.Pcm && format != Format.Extensible)
            {
                throw new UnsupportedAudioException(Resources.SampleDecoderUnsupportedError);
            }

            // WAVEFORMATEXTENSIBLE headers are 40 bytes long:
            if (format == Format.Extensible && fmtChunkSize < 40)
            {
                throw new IOException(Resources.SampleDecoderFmtLengthError);
            }

            _channels = _reader.ReadUInt16();
            if (_channels == 0 || _channels > 2)
            {
                throw new UnsupportedAudioException(Resources.SampleDecoderChannelsError);
            }

            // Ignore sampleRate and bytesPerSecond:
            stream.Seek(8, SeekOrigin.Current);

            ushort blockAlign    = _reader.ReadUInt16();
            uint   bitsPerSample = _reader.ReadUInt16();

            // Read the WAVEFORMATEXTENSIBLE extended header, if present:
            if (format == Format.Extensible)
            {
                if (_reader.ReadUInt16() < 22)
                {
                    throw new UnsupportedAudioException(Resources.SampleDecoderFmtExtensionLengthError);
                }

                if (bitsPerSample % 8 != 0)
                {
                    throw new UnsupportedAudioException(Resources.SampleDecoderBitsPerSampleError);
                }
                bitsPerSample = _reader.ReadUInt16();

                // Ignore the channel mask for now:
                stream.Seek(4, SeekOrigin.Current);

                if ((Format)_reader.ReadUInt16() != Format.Pcm)
                {
                    throw new UnsupportedAudioException(Resources.SampleDecoderUnsupportedError);
                }
            }

            _bytesPerSample = (int)Math.Ceiling(bitsPerSample / (double)8);
            _divisor        = (float)Math.Pow(2, bitsPerSample - 1);

            uint dataChunkSize = _reader.SeekToChunk("data");

            if (dataChunkSize == 0)
            {
                _samplesRemaining = 0;
            }
            else
            {
                _samplesRemaining = dataChunkSize / blockAlign;
            }
        }
        public AudioInfo ReadAudioInfo(Stream stream)
        {
            Contract.Ensures(stream.CanRead);
            Contract.Ensures(stream.CanSeek);
            Contract.Ensures(Contract.Result <AudioInfo>() != null);

            if (stream.Length < 45) // 12 byte RIFF descriptor + 24 byte fmt chunk + 9 byte data chunk
            {
                throw new IOException(Resources.AudioInfoDecoderLengthError);
            }

            using (var reader = new RiffReader(stream))
            {
                if (!reader.Validate() || reader.ReadFourCC() != "WAVE")
                {
                    throw new UnsupportedAudioException(Resources.AudioInfoDecoderNotWaveError);
                }

                uint fmtChunkSize = reader.SeekToChunk("fmt ");
                if (fmtChunkSize == 0)
                {
                    throw new IOException(Resources.AudioInfoDecoderMissingFmtError);
                }
                if (fmtChunkSize < 16)
                {
                    throw new IOException(Resources.AudioInfoDecoderFmtLengthError);
                }

                var format = (Format)reader.ReadUInt16();
                if (format != Format.Pcm && format != Format.Extensible)
                {
                    throw new UnsupportedAudioException(Resources.AudioInfoDecoderUnsupportedError);
                }

                // WAVEFORMATEXTENSIBLE headers are 40 bytes long:
                if (format == Format.Extensible && fmtChunkSize < 40)
                {
                    throw new IOException(Resources.AudioInfoDecoderFmtLengthError);
                }

                ushort channels   = reader.ReadUInt16();
                uint   sampleRate = reader.ReadUInt32();
                stream.Seek(4, SeekOrigin.Current); // Ignore bytesPerSecond
                ushort blockAlign    = reader.ReadUInt16();
                uint   bitsPerSample = reader.ReadUInt16();

                // Read the WAVEFORMATEXTENSIBLE extended header, if present:
                if (format == Format.Extensible)
                {
                    if (reader.ReadUInt16() < 22)
                    {
                        throw new UnsupportedAudioException(Resources.AudioInfoDecoderFmtExtensionLengthError);
                    }

                    if (bitsPerSample % 8 != 0)
                    {
                        throw new UnsupportedAudioException(Resources.AudioInfoDecoderBitsPerSampleError);
                    }
                    bitsPerSample = reader.ReadUInt16();

                    // Ignore the channel mask for now:
                    stream.Seek(4, SeekOrigin.Current);

                    if ((Format)reader.ReadUInt16() != Format.Pcm)
                    {
                        throw new UnsupportedAudioException(Resources.AudioInfoDecoderUnsupportedError);
                    }
                }

                uint dataChunkSize = reader.SeekToChunk("data");
                if (dataChunkSize == 0)
                {
                    throw new IOException(Resources.AudioInfoDecoderMissingSamplesError);
                }

                return(new AudioInfo("LPCM", channels, (int)bitsPerSample, (int)sampleRate, dataChunkSize / blockAlign));
            }
        }