-
Notifications
You must be signed in to change notification settings - Fork 226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ADM (Audio Definition Model) and Dolby Metadata in WAV/RIFF #991
base: master
Are you sure you want to change the base?
Changes from 11 commits
7720af9
42cce66
d2c84e1
b55a837
1e0ba55
83abdda
f2a6987
04539fe
2e67911
5687b08
c009996
90adba3
202b723
351920d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,7 @@ | |
|[`csv`](#csv) |Comma separated values |<sub></sub>| | ||
|`dns` |DNS packet |<sub></sub>| | ||
|`dns_tcp` |DNS packet (TCP) |<sub></sub>| | ||
|[`dolby_metadata`](#dolby_metadata) |Dolby Metadata (Atmos, AC3, Dolby Digital) |<sub></sub>| | ||
|`elf` |Executable and Linkable Format |<sub></sub>| | ||
|`ether8023_frame` |Ethernet 802.3 frame |<sub>`inet_packet`</sub>| | ||
|`exif` |Exchangeable Image File Format |<sub></sub>| | ||
|
@@ -129,7 +130,7 @@ | |
|`vp9_frame` |VP9 frame |<sub></sub>| | ||
|`vpx_ccr` |VPX Codec Configuration Record |<sub></sub>| | ||
|[`wasm`](#wasm) |WebAssembly Binary Format |<sub></sub>| | ||
|`wav` |WAV file |<sub>`id3v2` `id3v1` `id3v11`</sub>| | ||
|`wav` |WAV file |<sub>`id3v2` `id3v1` `id3v11` `dolby_metadata`</sub>| | ||
|`webp` |WebP image |<sub>`exif` `vp8_frame` `icc_profile` `xml`</sub>| | ||
|[`xml`](#xml) |Extensible Markup Language |<sub></sub>| | ||
|`yaml` |YAML Ain't Markup Language |<sub></sub>| | ||
|
@@ -590,6 +591,33 @@ $ fq -d csv -o comma="\t" to_csv file.tsv | |
$ fq -d csv '.[0] as $t | .[1:] | map(with_entries(.key = $t[.key]))' file.csv | ||
``` | ||
|
||
## dolby_metadata | ||
Dolby Metadata (Atmos, AC3, Dolby Digital). | ||
|
||
Dolby Metadata from `<dbmd>` chunk of RIFF / WAV / Broadcast Wave Format (BWF), | ||
including Dolby Atmos, AC3, Dolby Digital \[Plus\], and Dolby Audio Info (e.g. LUFS, True Peak). | ||
|
||
### Examples | ||
Decode Dolby metadata from `<dbmd>` chunk: | ||
``` | ||
$ fq -d wav '.chunks[] | select(.id | IN("dbmd")) | tovalue' adm-bwf.wav | ||
``` | ||
|
||
RIFF / WAV / Broadcast Wave Format (BWF) chunks: | ||
- `<chna>` Track UIDs of Audio Definition Model | ||
- `<axml>` BWF XML Metadata, e.g. for Audio Definition Model ambisonics and elements | ||
|
||
### Authors | ||
- [@johnnymarnell](https://johnnymarnell.github.io), original author | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this to a doly_metadata.md file in format/tiff, formats.md is autogenerated via Same for adm above |
||
### References | ||
- https://adm.ebu.io/background/what_is_the_adm.html | ||
- https://tech.ebu.ch/publications/tech3285s7 | ||
- 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 | ||
|
||
## fit | ||
Garmin Flexible and Interoperable Data Transfer. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package riff | ||
|
||
// Audio Definition Model | ||
// https://adm.ebu.io/background/what_is_the_adm.html | ||
// https://tech.ebu.ch/publications/tech3285s7 | ||
// https://tech.ebu.ch/publications/tech3285s5 | ||
|
||
import ( | ||
"github.com/wader/fq/pkg/decode" | ||
) | ||
|
||
func chnaDecode(d *decode.D) { | ||
d.FieldU16("num_tracks") | ||
d.FieldU16("num_uids") | ||
d.FieldArray("audio_ids", func(d *decode.D) { | ||
for !d.End() { | ||
d.FieldStruct("audio_id", func(d *decode.D) { | ||
d.FieldU16("track_index") | ||
d.FieldUTF8("uid", 12) | ||
d.FieldUTF8("track_format_id_reference", 14) | ||
d.FieldUTF8("pack_format_id_reference", 11) | ||
d.FieldRawLen("padding", 8) | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
func axmlDecode(d *decode.D) { | ||
d.FieldUTF8("xml", int(d.BitsLeft())/8) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
[Audio Definition Model](https://adm.ebu.io/background/what_is_the_adm.html) including 3D Audio. | ||
|
||
RIFF / WAV / Broadcast Wave Format (BWF) chunks: | ||
- `<chna>` Chunk, Track UIDs of Audio Definition Model | ||
- `<axml>` Chunk, BWF XML Metadata, e.g. for Audio Definition Model ambisonics and elements | ||
|
||
### 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 | ||
- [@johnnymarnell](https://johnnymarnell.github.io), original author | ||
|
||
### References | ||
- https://adm.ebu.io/background/what_is_the_adm.html | ||
- https://tech.ebu.ch/publications/tech3285s7 | ||
- https://tech.ebu.ch/publications/tech3285s5 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe move to a wav.md file? only "real" formats can have .md-files, they get added via the |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,7 +54,7 @@ func aiffDecode(d *decode.D) any { | |
} | ||
return id, size | ||
}, | ||
func(d *decode.D, id string, path path) (bool, any) { | ||
func(d *decode.D, id string, path path, size int64) (bool, any) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
switch id { | ||
case "FORM": | ||
riffType = d.FieldUTF8("format", 4, d.StrAssert(aiffRiffType)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) (bool, any) { | ||
func(d *decode.D, id string, path path, size int64) (bool, any) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
switch id { | ||
case "RIFF": | ||
foundRiffType = d.FieldUTF8("type", 4, d.StrAssert(requiredRiffType)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) (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, size int64) (bool, any)) { | ||
id, size := headFn(d, path) | ||
|
||
d.FramedFn(size*8, func(d *decode.D) { | ||
hasChildren, data := chunkFn(d, id, path) | ||
hasChildren, data := chunkFn(d, id, path, size) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I may have been doing it wrong, but that's what I tried initially, hope to get to revisit soon! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okok yeah in this case i think relying on framing should work and i think it usually ends up with nicer code, let's try that first at least |
||
if hasChildren { | ||
np := append(path, pathEntry{id: id, data: data}) | ||
d.FieldArray("chunks", func(d *decode.D) { | ||
|
@@ -36,9 +36,9 @@ func riffDecode(d *decode.D, path path, headFn func(d *decode.D, path path) (str | |
} | ||
}) | ||
|
||
wordAlgin := d.AlignBits(16) | ||
if wordAlgin != 0 { | ||
d.FieldRawLen("align", int64(wordAlgin)) | ||
wordAlign := d.AlignBits(16) | ||
if wordAlign != 0 { | ||
d.FieldRawLen("align", int64(wordAlign)) | ||
} | ||
} | ||
|
||
|
@@ -58,6 +58,10 @@ var chunkIDDescriptions = scalar.StrMapDescription{ | |
|
||
"dmlh": "Extended AVI header", | ||
|
||
"chna": "Track UIDs of Audio Definition Model", | ||
"axml": "Audio Definition Model ambisonics and elements", | ||
"dbmd": "Dolby Metadata, e.g. Atmos, AC3, Dolby Digital [Plus]", | ||
|
||
"ISMP": "SMPTE timecode", | ||
"IDIT": "Time and date digitizing commenced", | ||
"IARL": "Archival Location. Indicates where the subject of the file is archived.", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably be
$ fq ...
. The.fqtest
files looks very much like shell scripts but they are more like "transcripts" that the fq test system deserialize/serialize and execute using the go test system, so no there is no external processes executed per test etc.