2020-06-08 03:29:51 +03:00
|
|
|
|
package vorbis
|
|
|
|
|
|
|
|
|
|
// https://xiph.org/vorbis/doc/Vorbis_I_spec.html
|
|
|
|
|
// TODO: setup? more audio?
|
|
|
|
|
// TODO: end padding? byte align?
|
|
|
|
|
|
|
|
|
|
import (
|
2021-08-17 13:06:32 +03:00
|
|
|
|
"github.com/wader/fq/format"
|
|
|
|
|
"github.com/wader/fq/pkg/decode"
|
2022-07-16 19:39:57 +03:00
|
|
|
|
"github.com/wader/fq/pkg/interp"
|
2021-12-02 00:48:25 +03:00
|
|
|
|
"github.com/wader/fq/pkg/scalar"
|
2020-06-08 03:29:51 +03:00
|
|
|
|
)
|
|
|
|
|
|
2021-11-17 18:46:10 +03:00
|
|
|
|
var vorbisComment decode.Group
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
|
|
func init() {
|
2022-07-16 19:39:57 +03:00
|
|
|
|
interp.RegisterFormat(decode.Format{
|
2020-06-08 03:29:51 +03:00
|
|
|
|
Name: format.VORBIS_PACKET,
|
|
|
|
|
Description: "Vorbis packet",
|
|
|
|
|
DecodeFn: vorbisDecode,
|
|
|
|
|
Dependencies: []decode.Dependency{
|
2021-11-17 18:46:10 +03:00
|
|
|
|
{Names: []string{format.VORBIS_COMMENT}, Group: &vorbisComment},
|
2020-06-08 03:29:51 +03:00
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
packetTypeAudio = 0
|
|
|
|
|
packetTypeIdentification = 1
|
|
|
|
|
packetTypeComment = 3
|
|
|
|
|
packetTypeSetup = 5
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var packetTypeNames = map[uint]string{
|
|
|
|
|
packetTypeAudio: "Audio",
|
|
|
|
|
packetTypeIdentification: "Identification",
|
|
|
|
|
packetTypeComment: "Comment",
|
|
|
|
|
packetTypeSetup: "Setup",
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-19 19:33:50 +03:00
|
|
|
|
func vorbisDecode(d *decode.D, _ any) any {
|
2021-12-04 21:12:03 +03:00
|
|
|
|
d.Endian = decode.LittleEndian
|
|
|
|
|
|
2021-12-02 00:48:25 +03:00
|
|
|
|
packetType := d.FieldUScalarFn("packet_type", func(d *decode.D) scalar.S {
|
2020-06-08 03:29:51 +03:00
|
|
|
|
packetTypeName := "unknown"
|
|
|
|
|
t := d.U8()
|
|
|
|
|
// 4.2.1. Common header decode
|
|
|
|
|
// "these types are all odd as a packet with a leading single bit of ’0’ is an audio packet"
|
|
|
|
|
if t&1 == 0 {
|
|
|
|
|
t = packetTypeAudio
|
|
|
|
|
}
|
|
|
|
|
if n, ok := packetTypeNames[uint(t)]; ok {
|
|
|
|
|
packetTypeName = n
|
|
|
|
|
}
|
2021-12-02 00:48:25 +03:00
|
|
|
|
return scalar.S{Actual: t, Sym: packetTypeName}
|
2020-06-08 03:29:51 +03:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
switch packetType {
|
|
|
|
|
case packetTypeIdentification, packetTypeSetup, packetTypeComment:
|
2021-11-05 17:04:26 +03:00
|
|
|
|
d.FieldUTF8("magic", 6, d.AssertStr("vorbis"))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
case packetTypeAudio:
|
|
|
|
|
default:
|
2021-11-17 18:26:13 +03:00
|
|
|
|
d.Fatalf("unknown packet type %d", packetType)
|
2020-06-08 03:29:51 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch packetType {
|
|
|
|
|
case packetTypeAudio:
|
|
|
|
|
case packetTypeIdentification:
|
|
|
|
|
// 1 1) [vorbis_version] = read 32 bits as unsigned integer
|
|
|
|
|
// 2 2) [audio_channels] = read 8 bit integer as unsigned
|
|
|
|
|
// 3 3) [audio_sample_rate] = read 32 bits as unsigned integer
|
|
|
|
|
// 4 4) [bitrate_maximum] = read 32 bits as signed integer
|
|
|
|
|
// 5 5) [bitrate_nominal] = read 32 bits as signed integer
|
|
|
|
|
// 6 6) [bitrate_minimum] = read 32 bits as signed integer
|
|
|
|
|
// 7 7) [blocksize_0] = 2 exponent (read 4 bits as unsigned integer)
|
|
|
|
|
// 8 8) [blocksize_1] = 2 exponent (read 4 bits as unsigned integer)
|
|
|
|
|
// 9 9) [framing_flag] = read one bit
|
2021-12-04 21:12:03 +03:00
|
|
|
|
d.FieldU32("vorbis_version", d.ValidateU(0))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
d.FieldU8("audio_channels")
|
2021-12-04 21:12:03 +03:00
|
|
|
|
d.FieldU32("audio_sample_rate")
|
|
|
|
|
d.FieldU32("bitrate_maximum")
|
|
|
|
|
d.FieldU32("bitrate_nominal")
|
|
|
|
|
d.FieldU32("bitrate_minimum")
|
2020-06-08 03:29:51 +03:00
|
|
|
|
// TODO: code/comment about 2.1.4. coding bits into byte sequences
|
2021-11-05 17:04:26 +03:00
|
|
|
|
d.FieldUFn("blocksize_1", func(d *decode.D) uint64 { return 1 << d.U4() })
|
|
|
|
|
d.FieldUFn("blocksize_0", func(d *decode.D) uint64 { return 1 << d.U4() })
|
2020-06-08 03:29:51 +03:00
|
|
|
|
// TODO: warning if blocksize0 > blocksize1
|
|
|
|
|
// TODO: warning if not 64-8192
|
2021-12-02 00:48:25 +03:00
|
|
|
|
d.FieldRawLen("padding0", 7, d.BitBufIsZero())
|
2021-11-05 17:04:26 +03:00
|
|
|
|
d.FieldU1("framing_flag", d.ValidateU(1))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
case packetTypeSetup:
|
2021-11-05 17:04:26 +03:00
|
|
|
|
d.FieldUFn("vorbis_codebook_count", func(d *decode.D) uint64 { return d.U8() + 1 })
|
2022-05-07 13:46:34 +03:00
|
|
|
|
d.FieldU24("codecooke_sync", d.ValidateU(0x564342), scalar.ActualHex)
|
2021-12-04 21:12:03 +03:00
|
|
|
|
d.FieldU16("codebook_dimensions")
|
|
|
|
|
d.FieldU24("codebook_entries")
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
|
|
// d.SeekRel(7)
|
|
|
|
|
// ordered := d.FieldBool("ordered")
|
|
|
|
|
|
|
|
|
|
// if ordered {
|
|
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
// d.SeekRel(-2)
|
|
|
|
|
// sparse := d.FieldBool("sparse")
|
|
|
|
|
// d.SeekRel(1)
|
|
|
|
|
|
|
|
|
|
// if sparse {
|
|
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
// d.SeekRel(-7)
|
|
|
|
|
// d.FieldU5("length")
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
case packetTypeComment:
|
2021-09-16 16:29:11 +03:00
|
|
|
|
d.FieldFormat("comment", vorbisComment, nil)
|
2020-06-08 03:29:51 +03:00
|
|
|
|
|
|
|
|
|
// note this uses vorbis bitpacking convention, bits are added LSB first per byte
|
2021-12-02 00:48:25 +03:00
|
|
|
|
d.FieldRawLen("padding0", 7, d.BitBufIsZero())
|
2021-11-05 17:04:26 +03:00
|
|
|
|
d.FieldU1("frame_bit", d.ValidateU(1))
|
2020-06-08 03:29:51 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|