Pular para o conteúdo

Escrever um WAV

O cabeçalho RIFF de 44 bytes, em little-endian, e um segundo de onda senoidal escrito amostra por amostra.

O WAV é o formato de áudio mais simples que existe: 44 bytes de cabeçalho little-endian e depois as amostras. É um bom exercício justamente por ser little-endian — ler com o molde padrão (big-endian) dá números absurdos e nenhum erro.

dataforge
adopt Arcane.Estrutura as Est
adopt Arcane.Bytes as Bytes
adopt Arcane.Math as M

Wav := Est.definir("Wav", [
    ["riff", "char", 4], ["tamanho", "u32"], ["wave", "char", 4],
    ["fmt", "char", 4], ["fmt_tamanho", "u32"], ["formato", "u16"], ["canais", "u16"],
    ["taxa", "u32"], ["bytes_por_segundo", "u32"], ["alinhamento", "u16"], ["bits", "u16"],
    ["data", "char", 4], ["data_tamanho", "u32"]], "intel", yes)
assert Wav.tamanho is 44

taxa := 8000
amostras := [int(M.sin(2 * M.PI * 440 * i / taxa) * 8000) cycle i in range(taxa)]
corpo := Bytes.escrever("<")
cycle a in amostras:
    corpo.escrever("i16", a)
audio := corpo.finalizar()

cab := Wav({"riff": "RIFF", "tamanho": 36 + len(audio), "wave": "WAVE", "fmt": "fmt ",
    "fmt_tamanho": 16, "formato": 1, "canais": 1, "taxa": taxa,
    "bytes_por_segundo": taxa * 2, "alinhamento": 2, "bits": 16,
    "data": "data", "data_tamanho": len(audio)})
arquivo := Bytes.concatenar(cab.bytes(), audio)

lido := Wav.ler(arquivo)
assert lido["riff"] is "RIFF" and lido["taxa"] is 8000
assert lido["data_tamanho"] is 16000                  // um segundo de 16 bits mono
assert len(arquivo) is 16044

Grave com IO.write_bytes("la.wav", arquivo) e qualquer tocador reproduz um lá de 440 Hz. IO.write não serve: ele abre em modo texto, e bytes de áudio não são texto.