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.
| Function | Does |
|---|---|
info(data) -> Info or WavError | What the file holds |
decode_into(data, out) -> i64 or WavError | The 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 file | As 16-bit |
|---|---|
| 8-bit PCM (unsigned) | re-centred: 128 is 0 |
| 16-bit PCM | as it is |
| 24- and 32-bit PCM | the top 16 bits |
| 32-bit float | scaled 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: