type SoundFile (samplingRate: float,
numChannels: int,
bitDepth: int,
rawData: byte[],
isPCM: bool) =
member f.SamplingRate = samplingRate
member f.BitDepth = bitDepth
member f.RawData = rawData
member f.IsPCM = isPCM
member f.NumChannels = numChannels
/// Reads a PCM wave file and return a SoundFile object
/// Path of the file
/// a SoundFile object representing the data in the wav file. If the
/// file has only one channel, then the first of the tuple in Data contains
/// the data and the second of the tuple is empty
let readWavFile (path: string) =
use fileStream = new System.IO.FileStream( path, System.IO.FileMode.Open )
use reader = new System.IO.BinaryReader(fileStream)
// read chunk id - 4 bytes
let id = reader.ReadBytes(4)
if id <> "RIFF"B then
failwith "Not a WAV file"
// ignore next 12 bytes - chunk size: 4, format: 4, subChunkId: 4
reader.ReadBytes(12) |> ignore
let sizeChunk1 = System.BitConverter.ToInt32(reader.ReadBytes(4), 0)
let audioFormat = int(System.BitConverter.ToInt16(reader.ReadBytes(2), 0))
let numChannels = int(System.BitConverter.ToInt16(reader.ReadBytes(2), 0))
let samplingRate = System.BitConverter.ToInt32(reader.ReadBytes(4), 0)
// ignore byte rate: 4, block align: 2
reader.ReadBytes(6) |> ignore
let bitsPerSample =
int(System.BitConverter.ToInt16(reader.ReadBytes(2), 0))
// ignore the rest of chunk 1
reader.ReadBytes(sizeChunk1-16) |> ignore
if int audioFormat <> 1 then
// Non-PCM
reader.ReadBytes(4) |> ignore
let nExtraBytes = System.BitConverter.ToInt32(reader.ReadBytes(4), 0)
reader.ReadBytes(nExtraBytes) |> ignore
let idChunk2 = reader.ReadBytes(4)
if idChunk2 <> "data"B then
failwith "Incorrect format: chunk 2 id not 'data'"
let nBytes = System.BitConverter.ToInt32(reader.ReadBytes(4), 0)
SoundFile (float samplingRate, numChannels, bitsPerSample,
reader.ReadBytes(nBytes), (audioFormat = 1))