wav

tape
import wav from "wav";
import fs from "fs";
import io from "io";

var samples: [480000]i16;     // 5 s of 48 kHz stereo

fn main() -> i32 {
    let data: string = fs.read_file("ding.wav") or { return 1; };
    let w: wav.Info = wav.info(data) or {
        io.println("not a WAV file we can read: {err}");
        return 1;
    };
    io.println("{w.rate} Hz, {w.channels} channels, {w.frames} frames");
    let frames: i64 = wav.decode_into(data, samples[0..480000]) or { return 1; };
    io.println("decoded {frames} frames");
    return 0;
}

wav reads WAV files and nothing else: it allocates nothing, reads no files and needs no audio system, so it works anywhere, freestanding code included. To play what you read, use audio, whose decode_wav is built on this module.

FunctionDoes
info(data) -> Info or WavErrorWhat the file holds
decode_into(data, out) -> i64 or WavErrorThe samples as 16-bit integers into out, as many whole frames as fit; how many frames
tape
pub struct Info {
    rate: i64;        // frames a second
    channels: i64;
    bits: i64;        // bits a sample in the file
    is_float: bool;   // 32-bit IEEE floats rather than integers
    frames: i64;
    data_at: i64;     // where the samples are: data[data_at..data_at + data_len]
    data_len: i64;
}

pub enum WavError : u8 {
    Invalid = 1: "not a WAV file";
    Unsupported = 2: "a WAV encoding wav does not decode";
}

decode_into writes the samples interleaved, as the file has them: frame n starts at out[n * channels]. Size out from info: frames * channels samples hold the whole file. Every format becomes 16-bit:

In the fileAs 16-bit
8-bit PCM (unsigned)re-centred: 128 is 0
16-bit PCMas it is
24- and 32-bit PCMthe top 16 bits
32-bit floatscaled by 32767, clipped to ±32767

WAVE_FORMAT_EXTENSIBLE files work too, and any number of channels. Chunks other than fmt and data are skipped. A file cut short gives the frames it still has. Compressed WAV (ADPCM, A-law, mu-law) and 64-bit float are Unsupported.

Last modified: