Skip to content

Commit

Permalink
aiff: Add basic decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
wader committed Mar 9, 2023
1 parent 73ab188 commit dc4a82e
Show file tree
Hide file tree
Showing 9 changed files with 819 additions and 435 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ In summary it aims to be jq, hexdump, dd and gdb for files combined into one.
[aac_frame](doc/formats.md#aac_frame),
adts,
adts_frame,
aiff,
amf0,
apev2,
[apple_bookmark](doc/formats.md#apple_bookmark),
Expand Down
3 changes: 2 additions & 1 deletion doc/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
|[`aac_frame`](#aac_frame) |Advanced&nbsp;Audio&nbsp;Coding&nbsp;frame |<sub></sub>|
|`adts` |Audio&nbsp;Data&nbsp;Transport&nbsp;Stream |<sub>`adts_frame`</sub>|
|`adts_frame` |Audio&nbsp;Data&nbsp;Transport&nbsp;Stream&nbsp;frame |<sub>`aac_frame`</sub>|
|`aiff` |Audio&nbsp;Interchange&nbsp;File&nbsp;Format |<sub></sub>|
|`amf0` |Action&nbsp;Message&nbsp;Format&nbsp;0 |<sub></sub>|
|`apev2` |APEv2&nbsp;metadata&nbsp;tag |<sub>`image`</sub>|
|[`apple_bookmark`](#apple_bookmark) |Apple&nbsp;BookmarkData |<sub></sub>|
Expand Down Expand Up @@ -123,7 +124,7 @@
|`ip_packet` |Group |<sub>`icmp` `icmpv6` `tcp_segment` `udp_datagram`</sub>|
|`link_frame` |Group |<sub>`bsd_loopback_frame` `ether8023_frame` `ipv4_packet` `ipv6_packet` `sll2_packet` `sll_packet`</sub>|
|`mp3_frame_tags` |Group |<sub>`mp3_frame_vbri` `mp3_frame_xing`</sub>|
|`probe` |Group |<sub>`adts` `apple_bookmark` `ar` `avi` `avro_ocf` `bitcoin_blkdat` `bplist` `bzip2` `elf` `flac` `gif` `gzip` `jpeg` `json` `jsonl` `macho` `macho_fat` `matroska` `mp3` `mp4` `mpeg_ts` `ogg` `pcap` `pcapng` `png` `tar` `tiff` `toml` `tzif` `wasm` `wav` `webp` `xml` `yaml` `zip`</sub>|
|`probe` |Group |<sub>`adts` `aiff` `apple_bookmark` `ar` `avi` `avro_ocf` `bitcoin_blkdat` `bplist` `bzip2` `elf` `flac` `gif` `gzip` `jpeg` `json` `jsonl` `macho` `macho_fat` `matroska` `mp3` `mp4` `mpeg_ts` `ogg` `pcap` `pcapng` `png` `tar` `tiff` `toml` `tzif` `wasm` `wav` `webp` `xml` `yaml` `zip`</sub>|
|`tcp_stream` |Group |<sub>`dns_tcp` `rtmp` `tls`</sub>|
|`udp_payload` |Group |<sub>`dns`</sub>|

Expand Down
880 changes: 446 additions & 434 deletions doc/formats.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions format/all/all.fqtest
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ $ fq -n _registry.groups.probe
"wasm",
"webp",
"zip",
"aiff",
"mp3",
"mpeg_ts",
"wav",
Expand All @@ -40,6 +41,7 @@ $ fq --help formats
aac_frame Advanced Audio Coding frame
adts Audio Data Transport Stream
adts_frame Audio Data Transport Stream frame
aiff Audio Interchange File Format
amf0 Action Message Format 0
apev2 APEv2 metadata tag
apple_bookmark Apple BookmarkData
Expand Down
1 change: 1 addition & 0 deletions format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
AAC_FRAME = "aac_frame"
ADTS = "adts"
ADTS_FRAME = "adts_frame"
AIFF = "aiff"
AMF0 = "amf0"
APEV2 = "apev2"
APPLE_BOOKMARK = "apple_bookmark"
Expand Down
117 changes: 117 additions & 0 deletions format/riff/aiff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package riff

// http://midi.teragonaudio.com/tech/aiff.htm

import (
"github.com/wader/fq/format"
"github.com/wader/fq/internal/mathex"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
)

func init() {
interp.RegisterFormat(decode.Format{
Name: format.AIFF,
ProbeOrder: format.ProbeOrderBinFuzzy,
Description: "Audio Interchange File Format",
Groups: []string{format.PROBE},
DecodeFn: aiffDecode,
})
}

const aiffRiffType = "AIFF"

// pstring:
// > Pascal-style string, a one-byte count followed by that many text bytes. The total number of bytes in this data type should be even.
// > A pad byte can be added to the end of the text to accomplish this. This pad byte is not reflected in the count.
func aiffPString(d *decode.D) string {
l := d.U8()
pad := (l + 1) % 2
s := d.UTF8(int(l + pad))
return s[0 : l+1-pad]
}

func aiffDecode(d *decode.D) any {
var riffType string
riffDecode(
d,
nil,
func(d *decode.D, path path) (string, int64) {
id := d.FieldUTF8("id", 4, chunkIDDescriptions)

const restOfFileLen = 0xffffffff
size := int64(d.FieldScalarUintFn("size", func(d *decode.D) scalar.Uint {
l := d.U32()
if l == restOfFileLen {
return scalar.Uint{Actual: l, DisplayFormat: scalar.NumberHex, Description: "Rest of file"}
}
return scalar.Uint{Actual: l, DisplayFormat: scalar.NumberDecimal}
}).Actual)

if size == restOfFileLen {
size = d.BitsLeft() / 8
}
return id, size
},
func(d *decode.D, id string, path path) (bool, any) {
switch id {
case "FORM":
riffType = d.FieldUTF8("format", 4, d.StrAssert(aiffRiffType))
return true, nil
case "COMT":
numComments := d.FieldU16("num_comments")
d.FieldArray("comments", func(d *decode.D) {
for i := 0; i < int(numComments); i++ {
d.FieldStruct("comment", func(d *decode.D) {
d.FieldU32("timestamp")
d.FieldU16("marker_id")
count := d.FieldU16("count")
pad := count % 2
d.FieldUTF8("text", int(count))
if pad != 0 {
d.FieldRawLen("pad", int64(pad)*8)
}
})
}
})
return false, nil
case "COMM":
d.FieldU16("num_channels")
d.FieldU32("num_sample_frames")
d.FieldU16("sample_size")
// TODO: support big float?
d.FieldFltFn("sample_rate", func(d *decode.D) float64 {
return mathex.NewFloat80FromBytes(d.BytesLen(10)).Float64()
})
return false, nil
case "SSND":
d.FieldU32("offset")
d.FieldU32("block_size")
d.FieldRawLen("data", d.BitsLeft())
return false, nil
case "MARK":
numMarkers := d.FieldU16("num_markers")
d.FieldArray("markers", func(d *decode.D) {
for i := 0; i < int(numMarkers); i++ {
d.FieldStruct("marker", func(d *decode.D) {
d.FieldU16("id")
d.FieldU32("position")
d.FieldStrFn("name", aiffPString)
})
}
})
return false, nil
default:
d.FieldRawLen("data", d.BitsLeft())
return false, nil
}
},
)

if riffType != aiffRiffType {
d.Errorf("wrong or no AIFF riff type found (%s)", riffType)
}

return nil
}
Binary file added format/riff/testdata/sox.aiff
Binary file not shown.
35 changes: 35 additions & 0 deletions format/riff/testdata/sox.aiff.fqtest
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ffmpeg -f lavfi -i sine -t 100ms -f wav sox.wav; sox sox.wav six.aiff
$ fq dv sox.aiff
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef|.{}: sox.aiff (aiff) 0x0-0x22cb.7 (8908)
0x0000|46 4f 52 4d |FORM | id: "FORM" 0x0-0x3.7 (4)
0x0000| 00 00 22 c4 | ..". | size: 8900 0x4-0x7.7 (4)
0x0000| 41 49 46 46 | AIFF | format: "AIFF" (valid) 0x8-0xb.7 (4)
| | | chunks[0:3]: 0xc-0x22cb.7 (8896)
| | | [0]{}: chunk 0xc-0x2d.7 (34)
0x0000| 43 4f 4d 54| COMT| id: "COMT" 0xc-0xf.7 (4)
0x0010|00 00 00 1a |.... | size: 26 0x10-0x13.7 (4)
0x0010| 00 01 | .. | num_comments: 1 0x14-0x15.7 (2)
| | | comments[0:1]: 0x16-0x2d.7 (24)
| | | [0]{}: comment 0x16-0x2d.7 (24)
0x0010| e0 2f 99 4b | ./.K | timestamp: 3761215819 0x16-0x19.7 (4)
0x0010| 00 00 | .. | marker_id: 0 0x1a-0x1b.7 (2)
0x0010| 00 10 | .. | count: 16 0x1c-0x1d.7 (2)
0x0010| 50 72| Pr| text: "Processed by SoX" 0x1e-0x2d.7 (16)
0x0020|6f 63 65 73 73 65 64 20 62 79 20 53 6f 58 |ocessed by SoX |
| | | [1]{}: chunk 0x2e-0x47.7 (26)
0x0020| 43 4f| CO| id: "COMM" 0x2e-0x31.7 (4)
0x0030|4d 4d |MM |
0x0030| 00 00 00 12 | .... | size: 18 0x32-0x35.7 (4)
0x0030| 00 01 | .. | num_channels: 1 0x36-0x37.7 (2)
0x0030| 00 00 11 3a | ...: | num_sample_frames: 4410 0x38-0x3b.7 (4)
0x0030| 00 10 | .. | sample_size: 16 0x3c-0x3d.7 (2)
0x0030| 40 0e| @.| sample_rate: 44100 0x3e-0x47.7 (10)
0x0040|ac 44 00 00 00 00 00 00 |.D...... |
| | | [2]{}: chunk 0x48-0x22cb.7 (8836)
0x0040| 53 53 4e 44 | SSND | id: "SSND" 0x48-0x4b.7 (4)
0x0040| 00 00 22 7c| .."|| size: 8828 0x4c-0x4f.7 (4)
0x0050|00 00 00 00 |.... | offset: 0 0x50-0x53.7 (4)
0x0050| 00 00 00 00 | .... | block_size: 0 0x54-0x57.7 (4)
0x0050| 00 00 01 00 01 ff 02 fd| ........| data: raw bits 0x58-0x22cb.7 (8820)
0x0060|03 f8 04 ee 05 e0 06 cc 07 b0 08 8d 09 62 0a 2d|.............b.-|
* |until 0x22cb.7 (end) (8820) | |

0 comments on commit dc4a82e

Please sign in to comment.