summaryrefslogtreecommitdiff
path: root/spec/flac.fspec
blob: b4f0dab4eaf501f8633080bce4cbfa845654f9db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
enum block_type {
   STREAMINFO,
   PADDING,
   APPLICATION,
   SEEKTABLE,
   VORBIS_COMMENT,
   CUESHEET,
   PICTURE,
   INVALID = 127
};

struct utf8_string {
   u32 length;
   u8 string[length] | encoding('utf8') str;
};

struct ascii_string {
   u32 length;
   u8 string[length] | encoding('ascii') str;
};

struct flac {
   u8 header[4] | matches('fLaC') str;
   struct {
      u1 last_metadata_block;
      enum block_type u7 block_type;
      u24 length;
      select (block_type) {
         STREAMINFO)
            struct {
               u16 min_block_size_in_samples;
               u16 max_block_size_in_samples;
               u24 min_frame_size_in_bytes;
               u24 max_frame_size_in_bytes;
               u20 sample_rate_in_hz;
               u3 channels;
               u5 bps;
               u36 total_samples;
               u128 md5 hex;
            } streaminfo;
         PADDING)
            struct {
               u8 zero[length] nul;
            } padding;
         APPLICATION)
            struct {
               u32 id;
               u8 data[length] hex;
            } application;
         SEEKTABLE)
            struct {
               struct {
                  u64 sample_no;
                  u64 offset_in_bytes;
                  u16 num_samples;
               } seekpoint[length / 18];
            } seektable;
         VORBIS_COMMENT)
            struct {
               struct utf8_string vendor;
               u32 user_comment_list_length;
               struct utf8_string user_comment[user_comment_list_length];
               u1 framing_bit | matches(true);
            } vorbis_comment | endianess('le');
         CUESHEET)
            struct {
               u8 catalog[128] | encoding('ascii') str;
               u64 lead_in_samples;
               u1 is_compact_disc;
               u2071 reserved nul;
               u8 num_tracks;
               struct {
                  u64 offset_in_samples;
                  u8 index;
                  u8 isrc[12] | encoding('ascii') str;
                  u1 type;
                  u1 pre_emphasis;
                  u110 reserved nul;
                  u8 num_index_points;
                  struct {
                     u64 offset_in_samples;
                     u8 index;
                     u24 reserved nul;
                  } indices[num_index_points];
               } track[num_tracks];
            } cuesheet;
         PICTURE)
            struct {
               u32 type;
               struct ascii_string mime;
               struct utf8_string description;
               u32 width;
               u32 height;
               u32 color_depth_in_bps;
               u32 num_colors_for_indexed;
               u32 length;
               u8 data[length] hex;
            } picture;
         *)
            u8 any[length] hex;
      } data;
   } metadata[until (metadata.last_metadata_block)];
   struct {
      u14 sync_code | matches(0b11111111111110);
      u1 reserved1 nul;
      u1 blocking_strategy;
      u4 block_size_in_inter_channel_samples;
      u4 sample_rate;
      u4 channel_assignment;
      u3 sample_size_in_bits;
      u1 reserved2 nul;
      select (blocking_strategy) {
         0) u8 frame['\0':7] | encoding('utf8') hex;
         1) u8 sample['\0':6] | encoding('utf8') hex;
      } index;
      select (block_size_in_inter_channel_samples) {
         0b0110) u8 value1;
         0b0111) u16 value2;
      } block_size_bit;
      select (sample_rate) {
         0b1100) u8 value_in_kHz;
         0b1101) u16 value_in_Hz;
         0b1110) u16 value_in_tens_of_Hz;
      } sample_rate_bit;
      u8 crc_8 hex;
      struct {
         u1 padding nul;
         u6 type;
         u1 wasted_bits_per_sample[until (wasted_bits_per_sample)];
         select (type) {
            // missing verbatim and lpc
            0b000000)
               struct {
                  select (sample_size_in_bits) {
                     0b000) u1 v[metadata[0].data.streaminfo.bps];
                     0b001) u8 v8;
                     0b011) u12 v12;
                     0b100) u16 v16;
                     0b101) u20 v20;
                     0b110) u24 v24;
                  } value;
               } constant;
            testbits(type, '001xxxx'))
               struct {
                  u1 warmup[bps * (type & 7)] hex;
                  struct {
                     u2 method_type;
                     select (method_type) {
                        0b00)
                           struct {
                              u4 order;
                              struct {
                                 // this format is annoying.. :D
                                 u1 todo;
                              } partition;
                           } partitioned_rice;
                        0b01)
                           struct {
                              u4 order;
                              struct {
                                 // this format is annoying.. :D
                                 u1 todo;
                              } partition;
                           } partitioned_rice2;
                     } method;
                  } residual;
               } fixed;
         } data;
      } subframe;
      u16 crc_16 hex;
   } frame[until (false)];
} | endianess('be');