comparison flac.c @ 2298:9d68799f945b

Added basic FLAC seek implementation and added support for FLAC tracks in CUE sheets
author Michael Pavone <pavone@retrodev.com>
date Thu, 09 Mar 2023 22:49:42 -0800
parents 789802d99629
children
comparison
equal deleted inserted replaced
2297:e6b2b2341c68 2298:9d68799f945b
15 static void seek_buffer(flac_file *f, uint32_t offset, uint8_t relative) 15 static void seek_buffer(flac_file *f, uint32_t offset, uint8_t relative)
16 { 16 {
17 f->offset = relative ? f->offset + offset : offset; 17 f->offset = relative ? f->offset + offset : offset;
18 } 18 }
19 19
20 static uint32_t tell_buffer(flac_file *f)
21 {
22 return f->offset;
23 }
24
20 static uint8_t read_byte_file(flac_file *f) 25 static uint8_t read_byte_file(flac_file *f)
21 { 26 {
22 int result = fgetc(f->read_data); 27 int result = fgetc(f->read_data);
23 if (result == EOF) { 28 if (result == EOF) {
24 return 0; 29 return 0;
29 static void seek_file(flac_file *f, uint32_t offset, uint8_t relative) 34 static void seek_file(flac_file *f, uint32_t offset, uint8_t relative)
30 { 35 {
31 fseek(f->read_data, offset, relative ? SEEK_CUR : SEEK_SET); 36 fseek(f->read_data, offset, relative ? SEEK_CUR : SEEK_SET);
32 } 37 }
33 38
39 static uint32_t tell_file(flac_file *f)
40 {
41 return ftell(f->read_data);
42 }
43
34 static void read_chars(flac_file *f, char *dest, uint32_t count) 44 static void read_chars(flac_file *f, char *dest, uint32_t count)
35 { 45 {
36 for (; count > 0; --count) 46 for (; count > 0; --count)
37 { 47 {
38 *(dest++) = f->read_byte(f); 48 *(dest++) = f->read_byte(f);
42 static uint16_t read16(flac_file *f) 52 static uint16_t read16(flac_file *f)
43 { 53 {
44 uint16_t ret = f->read_byte(f) << 8; 54 uint16_t ret = f->read_byte(f) << 8;
45 ret |= f->read_byte(f); 55 ret |= f->read_byte(f);
46 return ret; 56 return ret;
57 }
58
59 static uint64_t read64(flac_file *f)
60 {
61 uint64_t value = ((uint64_t)f->read_byte(f)) << 56;
62 value |= ((uint64_t)f->read_byte(f)) << 48;
63 value |= ((uint64_t)f->read_byte(f)) << 40;
64 value |= ((uint64_t)f->read_byte(f)) << 32;
65 value |= ((uint64_t)f->read_byte(f)) << 24;
66 value |= f->read_byte(f) << 16;
67 value |= f->read_byte(f) << 8;
68 value |= f->read_byte(f);
69 return value;
47 } 70 }
48 71
49 static uint32_t read_bits(flac_file *f, uint32_t num_bits) 72 static uint32_t read_bits(flac_file *f, uint32_t num_bits)
50 { 73 {
51 uint32_t ret = 0; 74 uint32_t ret = 0;
125 f->bits_per_sample = read_bits(f, 5) + 1; 148 f->bits_per_sample = read_bits(f, 5) + 1;
126 f->total_samples = read_bits64(f, 36); 149 f->total_samples = read_bits64(f, 36);
127 f->seek(f, 16, 1);//MD5 150 f->seek(f, 16, 1);//MD5
128 } 151 }
129 152
153 static void parse_seektable(flac_file *f, uint32_t size)
154 {
155 f->num_seekpoints = size / 18;
156 f->seekpoints = calloc(f->num_seekpoints, sizeof(flac_seekpoint));
157 for (uint32_t i = 0; i < f->num_seekpoints; i++)
158 {
159 f->seekpoints[i].sample_number = read64(f);
160 f->seekpoints[i].offset = read64(f);
161 f->seekpoints[i].sample_count = read16(f);
162 }
163 }
164
130 static uint8_t parse_header(flac_file *f) 165 static uint8_t parse_header(flac_file *f)
131 { 166 {
132 char id[4]; 167 char id[4];
133 read_chars(f, id, sizeof(id)); 168 read_chars(f, id, sizeof(id));
134 if (memcmp("fLaC", id, sizeof(id))) { 169 if (memcmp("fLaC", id, sizeof(id))) {
137 meta_block_header header; 172 meta_block_header header;
138 do { 173 do {
139 read_meta_block_header(f, &header); 174 read_meta_block_header(f, &header);
140 if (header.type == STREAMINFO) { 175 if (header.type == STREAMINFO) {
141 parse_streaminfo(f); 176 parse_streaminfo(f);
177 } else if (header.type == SEEKTABLE) {
178 parse_seektable(f, header.size);
142 } else { 179 } else {
143 f->seek(f, header.size, 1); 180 f->seek(f, header.size, 1);
144 } 181 }
145 } while (!header.is_last); 182 } while (!header.is_last);
183 f->first_frame_offset = f->tell(f);
146 return 1; 184 return 1;
147 } 185 }
148 186
149 flac_file *flac_file_from_buffer(void *buffer, uint32_t size) 187 flac_file *flac_file_from_buffer(void *buffer, uint32_t size)
150 { 188 {
151 flac_file *f = calloc(1, sizeof(flac_file)); 189 flac_file *f = calloc(1, sizeof(flac_file));
152 f->read_data = buffer; 190 f->read_data = buffer;
153 f->read_byte = read_byte_buffer; 191 f->read_byte = read_byte_buffer;
154 f->seek = seek_buffer; 192 f->seek = seek_buffer;
193 f->tell = tell_buffer;
155 f->buffer_size = size; 194 f->buffer_size = size;
156 if (parse_header(f)) { 195 if (parse_header(f)) {
157 return f; 196 return f;
158 } 197 }
159 free(f); 198 free(f);
164 { 203 {
165 flac_file *f = calloc(1, sizeof(flac_file)); 204 flac_file *f = calloc(1, sizeof(flac_file));
166 f->read_data = file; 205 f->read_data = file;
167 f->read_byte = read_byte_file; 206 f->read_byte = read_byte_file;
168 f->seek = seek_file; 207 f->seek = seek_file;
208 f->tell = tell_file;
169 if (parse_header(f)) { 209 if (parse_header(f)) {
170 return f; 210 return f;
171 } 211 }
172 free(f); 212 free(f);
173 return NULL; 213 return NULL;
184 while (byte & mask) 224 while (byte & mask)
185 { 225 {
186 mask >>= 1; 226 mask >>= 1;
187 length++; 227 length++;
188 } 228 }
189 uint64_t value = byte + (mask - 1); 229 uint64_t value = byte & (mask - 1);
190 for (uint8_t i = 0; i < length; i++) 230 for (uint8_t i = 0; i < length; i++)
191 { 231 {
192 value <<= 6; 232 value <<= 6;
193 value |= f->read_byte(f) & 0x3F; 233 value |= f->read_byte(f) & 0x3F;
194 } 234 }
206 while (byte & mask) 246 while (byte & mask)
207 { 247 {
208 mask >>= 1; 248 mask >>= 1;
209 length++; 249 length++;
210 } 250 }
211 uint32_t value = byte + (mask - 1); 251 uint32_t value = byte & (mask - 1);
212 for (uint8_t i = 0; i < length; i++) 252 for (uint8_t i = 0; i < length; i++)
213 { 253 {
214 value <<= 6; 254 value <<= 6;
215 value |= f->read_byte(f) & 0x3F; 255 value |= f->read_byte(f) & 0x3F;
216 } 256 }
578 } 618 }
579 f->frame_sample_pos++; 619 f->frame_sample_pos++;
580 620
581 return 1; 621 return 1;
582 } 622 }
623
624 void flac_seek(flac_file *f, uint64_t sample_number)
625 {
626 if (sample_number >= f->frame_start_sample && sample_number < f->frame_start_sample + f->frame_block_size) {
627 f->frame_sample_pos = sample_number - f->frame_start_sample;
628 return;
629 }
630 uint32_t best_seekpoint = f->num_seekpoints + 1;
631 if (f->num_seekpoints) {
632 uint64_t best_diff;
633 for (uint32_t i = 0; i < f->num_seekpoints; i++)
634 {
635 if (f->seekpoints[i].sample_number > sample_number) {
636 continue;
637 }
638 uint64_t diff = sample_number - f->seekpoints[i].sample_number;
639 if (best_seekpoint > f->num_seekpoints || diff < best_diff) {
640 best_seekpoint = i;
641 best_diff = diff;
642 }
643 }
644 }
645 //TODO: more efficient seeking
646 if (best_seekpoint > f->num_seekpoints) {
647 f->seek(f, f->first_frame_offset, 0);
648 } else if (f->seekpoints[best_seekpoint].sample_number > f->frame_start_sample || f->frame_start_sample > sample_number){
649 f->seek(f, f->seekpoints[best_seekpoint].offset + f->first_frame_offset, 0);
650 }
651 do {
652 if (!decode_frame(f)) {
653 return;
654 }
655 } while ((f->frame_start_sample + f->frame_block_size) <= sample_number);
656 f->frame_sample_pos = sample_number - f->frame_start_sample;
657 }