Skip to content

Commit

Permalink
Address latest CR, temp using old code as supplemental segment broke?
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnnyMarnell committed Oct 31, 2024
1 parent c009996 commit 90adba3
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 124 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ vp9_cfm,
vp9_frame,
vpx_ccr,
[wasm](doc/formats.md#wasm),
wav,
[wav](doc/formats.md#wav),
webp,
[xml](doc/formats.md#xml),
yaml,
Expand Down
47 changes: 45 additions & 2 deletions doc/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
|`vp9_frame` |VP9&nbsp;frame |<sub></sub>|
|`vpx_ccr` |VPX&nbsp;Codec&nbsp;Configuration&nbsp;Record |<sub></sub>|
|[`wasm`](#wasm) |WebAssembly&nbsp;Binary&nbsp;Format |<sub></sub>|
|`wav` |WAV&nbsp;file |<sub>`id3v2` `id3v1` `id3v11` `dolby_metadata`</sub>|
|[`wav`](#wav) |WAV&nbsp;file |<sub>`id3v2` `id3v1` `id3v11` `dolby_metadata`</sub>|
|`webp` |WebP&nbsp;image |<sub>`exif` `vp8_frame` `icc_profile` `xml`</sub>|
|[`xml`](#xml) |Extensible&nbsp;Markup&nbsp;Language |<sub></sub>|
|`yaml` |YAML&nbsp;Ain't&nbsp;Markup&nbsp;Language |<sub></sub>|
Expand Down Expand Up @@ -616,7 +616,7 @@ RIFF / WAV / Broadcast Wave Format (BWF) chunks:
- https://tech.ebu.ch/publications/tech3285s5
- https://tech.ebu.ch/files/live/sites/tech/files/shared/tech/tech3285s6.pdf
- https://github.com/DolbyLaboratories/dbmd-atmos-parser
- https://github.com/MediaArea/MediaInfoLib/tree/Source/MediaInfo/Audio/File_DolbyAudioMetadata.cpp
- https://github.com/MediaArea/MediaInfoLib/blob/master/Source/MediaInfo/Audio/File_DolbyAudioMetadata.cpp

## fit
Garmin Flexible and Interoperable Data Transfer.
Expand Down Expand Up @@ -1470,6 +1470,49 @@ $ fq '.sections | {import: map(select(.id == "import_section").content.im.x[].nm
### References
- https://webassembly.github.io/spec/core/

## wav
WAV file.

WAVE audio file format.

Also includes support for [Audio Definition Model](https://adm.ebu.io/background/what_is_the_adm.html) and 3D Audio.

RIFF / WAV / Broadcast Wave Format (BWF) chunks:

- `RIFF`: primary container chunk specifying the file type and containing sub-chunks (e.g., fmt, data)
- `fmt`: describes format / stream encoding in data chunk
- `data`: indicates size and contains encoded raw sound data
- `bext`: broadcast extension chunk, containing broadcast-specific metadata such as description, originator, creation date, time reference, and more
- `LIST`: organizes additional metadata in sub-chunks, often used to include information like artist, genre, or title in INFO or other standardized formats
- `smpl`: sample metadata chunk, containing looping and sampling information, such as start and end points for loops, sample rate, and MIDI pitch
- `fact`: contains metadata on the original uncompressed data, such as the number of samples, typically used in non-PCM (compressed) formats to aid in playback and synchronization
- `chna`: track UIDs of Audio Definition Model
- `axml`: XML metadata, e.g. for Audio Definition Model ambisonics and elements as in [EBUCore spec](https://tech.ebu.ch/docs/tech/tech3293.pdf)
- `dbmd`: Dolby specific metadata like loudness and binaural settings, see also [`dolby_metadata` format](#dolby_metadata)


### Examples
Decode ADM configuration from `<chna>` and `<axml>` chunks:
```bash
$ fq -d wav '.chunks[] | select(.id | IN("chna", "axml")) | tovalue' amd-bwf.wav

# Extract ADM <axml> chunk objects definitions xml content
$ fq -r -d wav '.chunks[] | select(.id | IN("axml")) | .xml | tovalue' amd-bwf.wav | tee axml-content.xml
```

### Authors
- [@wader](https://github.com/wader), original author
- [@johnnymarnell](https://johnnymarnell.github.io), ADM support

### References
- http://soundfile.sapp.org/doc/WaveFormat/
- https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/wavdec.c
- https://tech.ebu.ch/docs/tech/tech3285.pdf
- http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
- https://adm.ebu.io/background/what_is_the_adm.html
- https://tech.ebu.ch/docs/tech/tech3285s7.pdf
- https://tech.ebu.ch/docs/tech/tech3285s5.pdf

## xml
Extensible Markup Language.

Expand Down
30 changes: 0 additions & 30 deletions format/riff/adm.go

This file was deleted.

22 changes: 0 additions & 22 deletions format/riff/adm.md

This file was deleted.

2 changes: 1 addition & 1 deletion format/riff/aiff.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func aiffDecode(d *decode.D) any {
}
return id, size
},
func(d *decode.D, id string, path path, size int64) (bool, any) {
func(d *decode.D, id string, path path) (bool, any) {
switch id {
case "FORM":
riffType = d.FieldUTF8("format", 4, d.StrAssert(aiffRiffType))
Expand Down
2 changes: 1 addition & 1 deletion format/riff/avi.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func aviDecodeEx(d *decode.D, ai format.AVI_In, extendedChunk bool) {
size := d.FieldU32("size")
return id, int64(size)
},
func(d *decode.D, id string, path path, size int64) (bool, any) {
func(d *decode.D, id string, path path) (bool, any) {
switch id {
case "RIFF":
foundRiffType = d.FieldUTF8("type", 4, d.StrAssert(requiredRiffType))
Expand Down
10 changes: 8 additions & 2 deletions format/riff/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ func (p path) topData() any {
return p[len(p)-1].data
}

func riffDecode(d *decode.D, path path, headFn func(d *decode.D, path path) (string, int64), chunkFn func(d *decode.D, id string, path path, size int64) (bool, any)) {
func riffDecode(d *decode.D, path path, headFn func(d *decode.D, path path) (string, int64), chunkFn func(d *decode.D, id string, path path) (bool, any)) {
id, size := headFn(d, path)

d.FramedFn(size*8, func(d *decode.D) {
hasChildren, data := chunkFn(d, id, path, size)
hasChildren, data := chunkFn(d, id, path)
if hasChildren {
np := append(path, pathEntry{id: id, data: data})
d.FieldArray("chunks", func(d *decode.D) {
Expand Down Expand Up @@ -58,6 +58,12 @@ var chunkIDDescriptions = scalar.StrMapDescription{

"dmlh": "Extended AVI header",

"data": "Raw sound encoded data",
"bext": "Broadcast extension, e.g. creator, date, etc.",
"smpl": "Sample metadata, e.g. loop points",
"fact": "Original info used for compression, e.g. sample length",

// BWF ADM master and Dolby Metadata
"chna": "Track UIDs of Audio Definition Model",
"axml": "Audio Definition Model ambisonics and elements",
"dbmd": "Dolby Metadata, e.g. Atmos, AC3, Dolby Digital [Plus]",
Expand Down
34 changes: 17 additions & 17 deletions format/riff/dolby.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/wader/fq/pkg/scalar"
)

func tmp_dbmdDecode(d *decode.D, size int64) any {
func old_dbmdDecode(d *decode.D) any {
version := d.U32()
major := (version >> 24) & 0xFF
minor := (version >> 16) & 0xFF
Expand All @@ -35,32 +35,32 @@ func tmp_dbmdDecode(d *decode.D, size int64) any {
}

segmentSize := d.FieldU16("metadata_segment_size")
bitsLeft := d.BitsLeft()
// bitsLeft := d.BitsLeft()

switch segmentID {
case 1:
parseDolbyE(d)
tmp_parseDolbyE(d)
case 3:
parseDolbyDigital(d)
tmp_parseDolbyDigital(d)
case 7:
parseDolbyDigitalPlus(d)
tmp_parseDolbyDigitalPlus(d)
case 8:
parseAudioInfo(d)
tmp_parseAudioInfo(d)
case 9:
parseDolbyAtmos(d)
tmp_parseDolbyAtmos(d)
case 10:
parseDolbyAtmosSupplemental(d)
tmp_parseDolbyAtmosSupplemental(d)
default:
d.FieldRawLen("unknown_segment_raw", int64(segmentSize*8))
}

bytesRemaining := (bitsLeft-d.BitsLeft())/8 - int64(segmentSize)
if bytesRemaining < 0 {
d.Fatalf("Read too many bytes for segment %d, read %d over, expected %d", segmentID, -bytesRemaining, segmentSize)
} else if bytesRemaining > 0 {
d.FieldValueUint("SKIPPED_BYTES", uint64(bytesRemaining))
d.SeekRel((int64(segmentSize) - bytesRemaining) * 8)
}
// bytesRemaining := (bitsLeft-d.BitsLeft())/8 - int64(segmentSize)
// if bytesRemaining < 0 {
// d.Fatalf("Read too many bytes for segment %d, read %d over, expected %d", segmentID, -bytesRemaining, segmentSize)
// } else if bytesRemaining > 0 {
// d.FieldValueUint("SKIPPED_BYTES", uint64(bytesRemaining))
// d.SeekRel((int64(segmentSize) - bytesRemaining) * 8)
// }

d.FieldU8("metadata_segment_checksum")
})
Expand Down Expand Up @@ -224,7 +224,7 @@ func tmp_parseAudioInfo(d *decode.D) {
d.FieldUTF8("segment_modified_date", 32)
}

func tmp_parseDolbyAtmos(d *decode.D, size uint64) {
func tmp_parseDolbyAtmos(d *decode.D) {
d.FieldValueStr("metadata_segment_type", "dolby_atmos")

// d.SeekRel(32 * 8)
Expand All @@ -248,7 +248,7 @@ func tmp_parseDolbyAtmos(d *decode.D, size uint64) {
d.SeekRel(80 * 8)
}

func tmp_parseDolbyAtmosSupplemental(d *decode.D, size uint64) {
func tmp_parseDolbyAtmosSupplemental(d *decode.D) {
d.FieldValueStr("metadata_segment_type", "dolby_atmos_supplemental")

sync := d.FieldU32LE("dasms_sync")
Expand Down
79 changes: 37 additions & 42 deletions format/riff/dolby_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,21 @@ func dbmdDecode(d *decode.D) any {
for !seenEnd {
d.FieldStruct("metadata_segment", func(d *decode.D) {
segmentID := d.FieldU8("id", metadataSegmentTypeMap)
if segmentID == 0 {

// TODO(jmarnell): This will always make an empty end segment, I think it would be better to omit it
if segmentID == metadataSegmentTypeEnd {
seenEnd = true
return
}

segmentSize := d.FieldU16("size")

switch segmentID {
case metadataSegmentTypeDolbyEMetadata:
case metadataSegmentTypeDolbyE:
parseDolbyE(d)
case metadataSegmentTypeDolbyEDigitaletadata:
case metadataSegmentTypeDolbyDigital:
parseDolbyDigital(d)
case metadataSegmentTypeDolbyDigitalPlusMetadata:
case metadataSegmentTypeDolbyDigitalPlus:
parseDolbyDigitalPlus(d)
case metadataSegmentTypeAudioInfo:
parseAudioInfo(d)
Expand All @@ -66,6 +68,7 @@ func dbmdDecode(d *decode.D) any {
d.FieldRawLen("unknown", int64(segmentSize*8))
}

// TODO: use this to validate parsing
d.FieldU8("checksum", scalar.UintHex)
})
}
Expand Down Expand Up @@ -138,31 +141,31 @@ var trimConfigName = scalar.UintMapDescription{
}

const (
metadataSegmentTypeEnd = 0
metadataSegmentTypeDolbyEMetadata = 1
metadataSegmentTypeDolbyReserved2 = 2
metadataSegmentTypeDolbyEDigitaletadata = 3
metadataSegmentTypeDolbyReserved4 = 4
metadataSegmentTypeDolbyReserved5 = 5
metadataSegmentTypeDolbyReserved6 = 6
metadataSegmentTypeDolbyDigitalPlusMetadata = 7
metadataSegmentTypeAudioInfo = 8
metadataSegmentTypeDolbyAtmos = 9
metadataSegmentTypeDolbyAtmosSupplemental = 10
metadataSegmentTypeEnd = 0
metadataSegmentTypeDolbyE = 1
metadataSegmentTypeDolbyReserved2 = 2
metadataSegmentTypeDolbyDigital = 3
metadataSegmentTypeDolbyReserved4 = 4
metadataSegmentTypeDolbyReserved5 = 5
metadataSegmentTypeDolbyReserved6 = 6
metadataSegmentTypeDolbyDigitalPlus = 7
metadataSegmentTypeAudioInfo = 8
metadataSegmentTypeDolbyAtmos = 9
metadataSegmentTypeDolbyAtmosSupplemental = 10
)

var metadataSegmentTypeMap = scalar.UintMapSymStr{
metadataSegmentTypeEnd: "end",
metadataSegmentTypeDolbyEMetadata: "dolby_e_metadata",
metadataSegmentTypeDolbyReserved2: "reserved2",
metadataSegmentTypeDolbyEDigitaletadata: "dolby_e_digitale_tadata",
metadataSegmentTypeDolbyReserved4: "reserved4",
metadataSegmentTypeDolbyReserved5: "reserved5",
metadataSegmentTypeDolbyReserved6: "reserved6",
metadataSegmentTypeDolbyDigitalPlusMetadata: "dolby_digital_plus_metadata",
metadataSegmentTypeAudioInfo: "audio_info",
metadataSegmentTypeDolbyAtmos: "dolby_atmos",
metadataSegmentTypeDolbyAtmosSupplemental: "dolby_atmos_supplemental",
metadataSegmentTypeEnd: "end",
metadataSegmentTypeDolbyE: "dolby_e_metadata",
metadataSegmentTypeDolbyReserved2: "reserved2",
metadataSegmentTypeDolbyDigital: "dolby_digital_metadata",
metadataSegmentTypeDolbyReserved4: "reserved4",
metadataSegmentTypeDolbyReserved5: "reserved5",
metadataSegmentTypeDolbyReserved6: "reserved6",
metadataSegmentTypeDolbyDigitalPlus: "dolby_digital_plus_metadata",
metadataSegmentTypeAudioInfo: "audio_info",
metadataSegmentTypeDolbyAtmos: "dolby_atmos",
metadataSegmentTypeDolbyAtmosSupplemental: "dolby_atmos_supplemental",
}

func parseDolbyE(d *decode.D) {
Expand Down Expand Up @@ -283,27 +286,19 @@ func parseDolbyAtmosSupplemental(d *decode.D) {

i := 0
d.FieldStructNArray("trim_configs", "trim_config", 9, func(d *decode.D) {
d.FieldRawLen("reserved", 7)
d.FieldU1("type", scalar.UintMapSymStr{
d.FieldRawLen("reserved0", 7)
trimType := d.FieldU1("type", scalar.UintMapSymStr{
0: "manual",
1: "automatic",
})
d.FieldValueStr("config_name", trimConfigName[uint64(i)])

// TODO: this is null separted list of def strings?
d.FieldUTF8("raw", 14)
// str := d.UTF8(14)
// bytes := []byte(str)
// var nonZeroBytes []string
// for _, b := range bytes {
// if b != 0 {
// nonZeroBytes = append(nonZeroBytes, fmt.Sprintf("%d", b))
// }
// }
// TODO(jmarnell): I think the +3dB trim settings are here.
// Would like this at least as an array of numbers, instead of this CSV string
// d.FieldValueStr("trim_defs", strings.Join(nonZeroBytes, ", "))

if trimType == 1 {
d.FieldUTF8("reserved1", 14)
} else {
// TODO: Reference MediaInfo's logic and Dolby pdf's
d.FieldUTF8("manual_trim_raw_config", 14)
}
i++
})

Expand Down
2 changes: 1 addition & 1 deletion format/riff/dolby_metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ RIFF / WAV / Broadcast Wave Format (BWF) chunks:
- https://tech.ebu.ch/publications/tech3285s5
- https://tech.ebu.ch/files/live/sites/tech/files/shared/tech/tech3285s6.pdf
- https://github.com/DolbyLaboratories/dbmd-atmos-parser
- https://github.com/MediaArea/MediaInfoLib/tree/Source/MediaInfo/Audio/File_DolbyAudioMetadata.cpp
- https://github.com/MediaArea/MediaInfoLib/blob/master/Source/MediaInfo/Audio/File_DolbyAudioMetadata.cpp
Loading

0 comments on commit 90adba3

Please sign in to comment.