Standard library · Encoding and data

audio/au

Reading and writing the Sun and NeXT au format.

import audio.au

The au format is the simplest real sound file there is: a 24 byte big-endian header and then the samples. It came from Sun, it is what /dev/audio spoke, and it is still a pleasant way to hand raw audio between programs because there is almost nothing to get wrong.

It carries more encodings than its size suggests: mu-law and A-law, signed PCM at 8, 16, 24 and 32 bits, and IEEE floating point at 32 and 64. Everything is big-endian.

Things to know

  • 8 bit au PCM is signed, where 8 bit WAVE is unsigned. The shared helpers in audio take that as an argument, so neither format has to guess.
  • A companded file decodes to a clip marked 16 bit, because that is the depth mu-law and A-law reconstruct to.
  • data_offset may be larger than HeaderSize; the gap is a text note, and this package steps over it.
  • A data size of 0xFFFFFFFF means unknown, which this package treats as everything to the end of the file.

Types

struct Header
The whole of an au header: where the samples are, how they are coded, and their shape.
NameTypeDescription
data_offsetint = 0Where the samples start. At least HeaderSize, and anything between is a text note.
data_sizeint = 0How many bytes of samples there are, held inside the file.
encodingint = 0Which Enc number the samples use.
rateint = 0Frames per second.
channelsint = 0How many channels.
au-Read.salam
import audio
import audio.au
import compress
import filepath
import math
import mem
import os

func main:
    mut c := audio.New(22050, 1, 64)
    audio.SetSample(c, 3, 0, 0.5)
    buf := au.EncodeAUEncoding(c, au.EncPcm16)
    println au.IsAU(buf.data, buf.len), au.IsAU(buf.data, 8)
    println audio.FormatName(audio.DetectFormat(buf.data, buf.len))

    mut h := au.Header {}
    println au.ReadHeader(buf.data, buf.len, h)
    println h.data_offset == au.HeaderSize, h.encoding == au.EncPcm16
    println h.rate, h.channels, h.data_size

    mut ok := false
    info := au.ProbeAU(buf.data, buf.len, ok)
    println ok, info.rate, info.channels, info.bits, info.frames, info.lossless

    mut dok := false
    back := au.DecodeAU(buf.data, buf.len, dok)
    println dok, back.frames, back.bits, audio.Sample(back, 3, 0)

    fbuf := au.EncodeAUEncoding(c, au.EncFloat32)
    mut fok := false
    fback := au.DecodeAU(fbuf.data, fbuf.len, fok)
    println fok, fback.bits, audio.Sample(fback, 3, 0) == audio.Sample(c, 3, 0)

    mbuf := au.EncodeAUEncoding(c, au.EncMuLaw)
    mut mok := false
    mback := au.DecodeAU(mbuf.data, mbuf.len, mok)
    println mok, mback.bits, math.Abs(audio.Sample(mback, 3, 0) - 0.5) < 0.02
    mut minfo := false
    println au.ProbeAU(mbuf.data, mbuf.len, minfo).lossless
    println compress.BufLen(mbuf) == au.HeaderSize + 64

    println compress.BufLen(au.EncodeAUEncoding(c, 99))

    path := filepath.Join(os.TempDir(), "salam_au_example.au")
    defer mem.Free(path as void*)
    println au.SaveAU(c, path)
    mut diskok := false
    disk := au.OpenAU(path, diskok)
    println diskok, disk.frames, disk.rate
    mut gone := false
    missing := filepath.Join(os.TempDir(), "salam_au_none.au")
    defer mem.Free(missing as void*)
    au.OpenAU(missing, gone)
    println gone

    compress.BufFree(buf)
    compress.BufFree(fbuf)
    compress.BufFree(mbuf)
    audio.Free(c)
    audio.Free(back)
    audio.Free(fback)
    audio.Free(mback)
    audio.Free(disk)
end
Outputtrue false au true true true 22050 1 128 true 22050 1 16 64 true true 64 16 0.5 true 32 true true 16 true false true 0 true true 64 22050 false

Constants and variables

HeaderSize

const HeaderSize: i32 = 24
The 24 bytes an au header always takes, before any text note.

The example for this item is shown with the ones above: au-Read.salam

Encoding numbers Enc…

Which encoding an au header declares.
NameValue
EncMuLaw1
EncPcm82
EncPcm163
EncPcm244
EncPcm325
EncFloat326
EncFloat647
EncALaw27

The example for this item is shown with the ones above: au-Read.salam

Functions

IsAU

func IsAU(p: void*, n: int): bool
True when these bytes start with the .snd magic number.

The example for this item is shown with the ones above: au-Read.salam

ReadHeader

func ReadHeader(p: void*, n: int, out &: Header): bool
Reads the whole header and checks it against the file length.

The example for this item is shown with the ones above: au-Read.salam

ProbeAU

func ProbeAU(p: void*, n: int, ok &: bool): audio.Info
Reads only the header, so you learn the length and rate without decoding.

The example for this item is shown with the ones above: au-Read.salam

DecodeAU

func DecodeAU(p: void*, n: int, ok &: bool): audio.Clip
Decodes a whole au file from memory into a clip.

The example for this item is shown with the ones above: au-Read.salam

EncodeAUEncoding

func EncodeAUEncoding(c: audio.Clip, encoding: int): compress.ByteBuf
Encodes a clip as au in the encoding you name, including the two companded ones.

The example for this item is shown with the ones above: au-Read.salam

EncodeAU

func EncodeAU(c: audio.Clip): compress.ByteBuf
Encodes a clip as au, picking the integer encoding from the depth the clip remembers.

The example for this item is shown with the ones above: au-Read.salam

OpenAU

func OpenAU(path: str, ok &: bool): audio.Clip
Reads an au file from disk into a clip.

The example for this item is shown with the ones above: au-Read.salam

SaveAU

func SaveAU(c: audio.Clip, path: str): bool
Writes a clip to an au file.

The example for this item is shown with the ones above: au-Read.salam