using System; using System.IO; namespace Ryuclaw.Audio.Shared { public class WaveStreamer : IDisposable { private readonly FileStream _fileStream; private readonly BinaryReader _reader; private long _dataPosition; // This will store the position where audio data begins in the file. private int _dataLength; // This will store the length of the audio data. private WaveHeader _header; public WaveStreamer(string filePath) { _header = new WaveHeader(); _fileStream = new FileStream(filePath, FileMode.Open); _reader = new BinaryReader(_fileStream); LoadHeader(); } private void LoadHeader() { // RIFF header string chunkID = new string(_reader.ReadChars(4)); if (chunkID != "RIFF") throw new Exception("Not a valid WAV file."); var ChunkSize = _reader.ReadInt32(); // Chunk size string format = new string(_reader.ReadChars(4)); if (format != "WAVE") throw new Exception("Not a valid WAV file."); // fmt sub-chunk string subchunk1ID = new string(_reader.ReadChars(4)); if (subchunk1ID != "fmt ") throw new Exception("Expected fmt chunk."); int subChunk1Size = _reader.ReadInt32(); short audioFormat = _reader.ReadInt16(); var NumChannels = _reader.ReadInt16(); var SampleRate = _reader.ReadInt32(); var ByteRate = _reader.ReadInt32(); // Byte rate var BlockAlign = _reader.ReadInt16(); // Block align var BitsPerSample = _reader.ReadInt16(); _header = new WaveHeader(SampleRate, ChunkSize, ByteRate, BitsPerSample, NumChannels, BlockAlign); if (audioFormat != 1 || subChunk1Size != 16) { throw new Exception("Only PCM format WAV files are supported."); } // data sub-chunk string subchunk2ID = new string(_reader.ReadChars(4)); if (subchunk2ID != "data") throw new Exception("Expected data chunk."); _dataLength = _reader.ReadInt32(); _dataPosition = _fileStream.Position; // Store the position where audio data begins. } public byte[] ReadData(int byteCount) { _fileStream.Seek(_dataPosition, SeekOrigin.Begin); byte[] buffer = _reader.ReadBytes(byteCount); // Read a chunk of audio data. _dataPosition = _fileStream.Position; // Update the position to start from next time. return buffer; } public bool HasDataLeft() { return _fileStream.Position < _dataPosition + _dataLength; } public void Dispose() { _reader.Dispose(); _fileStream.Dispose(); } } }