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)); } }