Very WIP & Experimental
WAV file reader and writer in pure OCaml.
Reading a WAV file requires constructing a WAV reader. This requires a function for filling a buffer with more bytes, i.e. a source.
# Wav.reader;;
- : ?initial_size:int -> ?max_size:int -> Wav.src -> Wav.reader = <fun>
The best way to do this is with Eio, the API was designed with that in mind. Eio's Flow.source
is perfect for a Wav.src
. Here we construct a function for building a with_source
function which will automatically close the opened file for us thanks to with_open_in
.
# let src ~flow buf = Eio.Flow.read flow buf;;
val src : flow:#Eio.Flow.source -> Cstruct.t -> int = <fun>
# let with_reader ~fs fn =
Eio.Path.(with_open_in (fs / "data" / "noaa-example.wav")) @@ fun flow ->
fn @@ Wav.reader (src ~flow);;
val with_reader : fs:#Eio.Fs.dir Eio.Path.t -> (Wav.reader -> 'a) -> 'a =
<fun>
We can then use it to read the header of the WAV file for example.
# Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.cwd env in
with_reader ~fs @@ fun r ->
Fmt.pr "%a%!" Wav.pp_header (Wav.header r);;
size: 19840738
fmt_size: 16
audio_format: PCM
num_channels: 1
sample_rate: 11025
byte_rate: 22050
block_align: 2
bits_per_sample: 16
data_size: 19840702
- : unit = ()
Reader's can also produce the next sample if available using the Wav.sample
function. This will move along every time it is called until reaching the end of the WAV file in which case it will return None
. Wav.sample_exn
is the same but raises Not_found
instead of wrapping the sample as an option
type.
# Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.cwd env in
with_reader ~fs @@ fun r ->
let rec loop acc =
match Wav.sample_exn r with
| s -> loop (s :: acc)
| exception Not_found -> List.rev acc
in
let samples = loop [] in
Fmt.pr "Number of samples: %i\nFirst sample: %a%!"
(List.length samples) Cstruct.hexdump_pp (List.hd samples);;
Number of samples: 9920607
First sample: d9 21
- : unit = ()
The initial motivation for building this OCaml library was to start constructing tools for analysing NOAA weather images which are transmitted in WAV format. In particular following An accessible browser-based decoder for NOAA images. Getting from the raw WAV file to an image should be good example of using the library.
The first part of the process is to have a look at our WAV file:
# Eio_main.run @@ fun env ->
let fs = Eio.Stdenv.cwd env in
with_reader ~fs @@ fun r ->
Fmt.pr "%a%!" Wav.pp_header (Wav.header r);;
size: 19840738
fmt_size: 16
audio_format: PCM
num_channels: 1
sample_rate: 11025
byte_rate: 22050
block_align: 2
bits_per_sample: 16
data_size: 19840702
- : unit = ()
We can see some important information, such as:
- There is only one channel.
- There are
11025
samples per second.