~ubuntu-branches/ubuntu/hoary/flac/hoary

« back to all changes in this revision

Viewing changes to src/share/grabbag/cuesheet.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2004-04-16 15:14:31 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040416151431-eyloggqxpwbwpogz
Tags: 1.1.0-11
Ensure that libFLAC is linked with -lm on all architectures, and
regardless of whether nasm is present

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* grabbag - Convenience lib for various routines common to several tools
 
2
 * Copyright (C) 2002,2003  Josh Coalson
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
17
 */
 
18
 
 
19
#include "share/grabbag.h"
 
20
#include "FLAC/assert.h"
 
21
#include <stdio.h>
 
22
#include <stdlib.h>
 
23
#include <string.h>
 
24
 
 
25
unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames)
 
26
{
 
27
        return ((minutes * 60) + seconds) * 75 + frames;
 
28
}
 
29
 
 
30
void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames)
 
31
{
 
32
        *frames = frame % 75;
 
33
        frame /= 75;
 
34
        *seconds = frame % 60;
 
35
        frame /= 60;
 
36
        *minutes = frame;
 
37
}
 
38
 
 
39
/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
 
40
static int local__parse_int_(const char *s)
 
41
{
 
42
        int ret = 0;
 
43
        char c;
 
44
 
 
45
        if(*s == '\0')
 
46
                return -1;
 
47
 
 
48
        while('\0' != (c = *s++))
 
49
                if(c >= '0' && c <= '9')
 
50
                        ret = ret * 10 + (c - '0');
 
51
                else
 
52
                        return -1;
 
53
 
 
54
        return ret;
 
55
}
 
56
 
 
57
/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
 
58
static FLAC__int64 local__parse_int64_(const char *s)
 
59
{
 
60
        FLAC__int64 ret = 0;
 
61
        char c;
 
62
 
 
63
        if(*s == '\0')
 
64
                return -1;
 
65
 
 
66
        while('\0' != (c = *s++))
 
67
                if(c >= '0' && c <= '9')
 
68
                        ret = ret * 10 + (c - '0');
 
69
                else
 
70
                        return -1;
 
71
 
 
72
        return ret;
 
73
}
 
74
 
 
75
/* accept '[0-9]+:[0-9][0-9]?:[0-9][0-9]?', but max second of 59 and max frame of 74, e.g. 0:0:0, 123:45:67
 
76
 * return sample number or <0 for error
 
77
 */
 
78
static FLAC__int64 local__parse_msf_(const char *s)
 
79
{
 
80
        FLAC__int64 ret, field;
 
81
        char c;
 
82
 
 
83
        c = *s++;
 
84
        if(c >= '0' && c <= '9')
 
85
                field = (c - '0');
 
86
        else
 
87
                return -1;
 
88
        while(':' != (c = *s++)) {
 
89
                if(c >= '0' && c <= '9')
 
90
                        field = field * 10 + (c - '0');
 
91
                else
 
92
                        return -1;
 
93
        }
 
94
 
 
95
        ret = field * 60 * 44100;
 
96
 
 
97
        c = *s++;
 
98
        if(c >= '0' && c <= '9')
 
99
                field = (c - '0');
 
100
        else
 
101
                return -1;
 
102
        if(':' != (c = *s++)) {
 
103
                if(c >= '0' && c <= '9') {
 
104
                        field = field * 10 + (c - '0');
 
105
                        c = *s++;
 
106
                        if(c != ':')
 
107
                                return -1;
 
108
                }
 
109
                else
 
110
                        return -1;
 
111
        }
 
112
 
 
113
        if(field >= 60)
 
114
                return -1;
 
115
 
 
116
        ret += field * 44100;
 
117
 
 
118
        c = *s++;
 
119
        if(c >= '0' && c <= '9')
 
120
                field = (c - '0');
 
121
        else
 
122
                return -1;
 
123
        if('\0' != (c = *s++)) {
 
124
                if(c >= '0' && c <= '9') {
 
125
                        field = field * 10 + (c - '0');
 
126
                        c = *s++;
 
127
                }
 
128
                else
 
129
                        return -1;
 
130
        }
 
131
 
 
132
        if(c != '\0')
 
133
                return -1;
 
134
 
 
135
        if(field >= 75)
 
136
                return -1;
 
137
 
 
138
        ret += field * (44100 / 75);
 
139
 
 
140
        return ret;
 
141
}
 
142
 
 
143
static char *local__get_field_(char **s)
 
144
{
 
145
        char *p;
 
146
 
 
147
        FLAC__ASSERT(0 != s);
 
148
 
 
149
        if(0 == *s)
 
150
                return 0;
 
151
 
 
152
        /* skip leading whitespace */
 
153
        while(**s && 0 != strchr(" \t\r\n", **s))
 
154
                (*s)++;
 
155
 
 
156
        if(**s == 0)
 
157
                *s = 0;
 
158
 
 
159
        p = *s;
 
160
 
 
161
        if(p) {
 
162
                while(**s && 0 == strchr(" \t\r\n", **s))
 
163
                        (*s)++;
 
164
                if(**s) {
 
165
                        **s = '\0';
 
166
                        (*s)++;
 
167
                }
 
168
                else
 
169
                        *s = 0;
 
170
        }
 
171
 
 
172
        return p;
 
173
}
 
174
 
 
175
static FLAC__bool local__cuesheet_parse_(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__StreamMetadata *cuesheet, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
 
176
{
 
177
#if defined _MSC_VER || defined __MINGW32__
 
178
#define FLAC__STRCASECMP stricmp
 
179
#else
 
180
#define FLAC__STRCASECMP strcasecmp
 
181
#endif
 
182
        char buffer[4096], *line, *field;
 
183
        unsigned linelen, forced_leadout_track_num = 0;
 
184
        FLAC__uint64 forced_leadout_track_offset = 0;
 
185
        int in_track_num = -1, in_index_num = -1;
 
186
        FLAC__bool disc_has_catalog = false, track_has_flags = false, track_has_isrc = false, has_forced_leadout = false;
 
187
        FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
 
188
 
 
189
        cs->lead_in = is_cdda? 2 * 44100 /* The default lead-in size for CD-DA */ : 0;
 
190
        cs->is_cd = is_cdda;
 
191
 
 
192
        while(0 != fgets(buffer, sizeof(buffer), file)) {
 
193
                (*last_line_read)++;
 
194
                line = buffer;
 
195
 
 
196
                linelen = strlen(line);
 
197
                if(line[linelen-1] != '\n') {
 
198
                        *error_message = "line too long";
 
199
                        return false;
 
200
                }
 
201
 
 
202
                if(0 != (field = local__get_field_(&line))) {
 
203
                        if(0 == FLAC__STRCASECMP(field, "CATALOG")) {
 
204
                                if(disc_has_catalog) {
 
205
                                        *error_message = "found multiple CATALOG commands";
 
206
                                        return false;
 
207
                                }
 
208
                                if(0 == (field = local__get_field_(&line))) {
 
209
                                        *error_message = "CATALOG is missing catalog number";
 
210
                                        return false;
 
211
                                }
 
212
                                if(strlen(field) >= sizeof(cs->media_catalog_number)) {
 
213
                                        *error_message = "CATALOG number is too long";
 
214
                                        return false;
 
215
                                }
 
216
                                if(is_cdda && (strlen(field) != 13 || strspn(field, "0123456789") != 13)) {
 
217
                                        *error_message = "CD-DA CATALOG number must be 13 decimal digits";
 
218
                                        return false;
 
219
                                }
 
220
                                strcpy(cs->media_catalog_number, field);
 
221
                                disc_has_catalog = true;
 
222
                        }
 
223
                        else if(0 == FLAC__STRCASECMP(field, "FLAGS")) {
 
224
                                if(track_has_flags) {
 
225
                                        *error_message = "found multiple FLAGS commands";
 
226
                                        return false;
 
227
                                }
 
228
                                if(in_track_num < 0 || in_index_num >= 0) {
 
229
                                        *error_message = "FLAGS command must come after TRACK but before INDEX";
 
230
                                        return false;
 
231
                                }
 
232
                                while(0 != (field = local__get_field_(&line))) {
 
233
                                        if(0 == FLAC__STRCASECMP(field, "PRE"))
 
234
                                                cs->tracks[cs->num_tracks-1].pre_emphasis = 1;
 
235
                                }
 
236
                                track_has_flags = true;
 
237
                        }
 
238
                        else if(0 == FLAC__STRCASECMP(field, "INDEX")) {
 
239
                                FLAC__int64 xx;
 
240
                                FLAC__StreamMetadata_CueSheet_Track *track = &cs->tracks[cs->num_tracks-1];
 
241
                                if(in_track_num < 0) {
 
242
                                        *error_message = "found INDEX before any TRACK";
 
243
                                        return false;
 
244
                                }
 
245
                                if(0 == (field = local__get_field_(&line))) {
 
246
                                        *error_message = "INDEX is missing index number";
 
247
                                        return false;
 
248
                                }
 
249
                                in_index_num = local__parse_int_(field);
 
250
                                if(in_index_num < 0) {
 
251
                                        *error_message = "INDEX has invalid index number";
 
252
                                        return false;
 
253
                                }
 
254
                                FLAC__ASSERT(cs->num_tracks > 0);
 
255
                                if(track->num_indices == 0) {
 
256
                                        /* it's the first index point of the track */
 
257
                                        if(in_index_num > 1) {
 
258
                                                *error_message = "first INDEX number of a TRACK must be 0 or 1";
 
259
                                                return false;
 
260
                                        }
 
261
                                }
 
262
                                else {
 
263
                                        if(in_index_num != track->indices[track->num_indices-1].number + 1) {
 
264
                                                *error_message = "INDEX numbers must be sequential";
 
265
                                                return false;
 
266
                                        }
 
267
                                }
 
268
                                if(is_cdda && in_index_num > 99) {
 
269
                                        *error_message = "CD-DA INDEX number must be between 0 and 99, inclusive";
 
270
                                        return false;
 
271
                                }
 
272
                                /*@@@ search for duplicate track number? */
 
273
                                if(0 == (field = local__get_field_(&line))) {
 
274
                                        *error_message = "INDEX is missing an offset after the index number";
 
275
                                        return false;
 
276
                                }
 
277
                                xx = local__parse_msf_(field);
 
278
                                if(xx < 0) {
 
279
                                        if(is_cdda) {
 
280
                                                *error_message = "illegal INDEX offset (not of the form MM:SS:FF)";
 
281
                                                return false;
 
282
                                        }
 
283
                                        xx = local__parse_int64_(field);
 
284
                                        if(xx < 0) {
 
285
                                                *error_message = "illegal INDEX offset";
 
286
                                                return false;
 
287
                                        }
 
288
                                }
 
289
                                if(is_cdda && cs->num_tracks == 1 && cs->tracks[0].num_indices == 0 && xx != 0) {
 
290
                                        *error_message = "first INDEX of first TRACK must have an offset of 00:00:00";
 
291
                                        return false;
 
292
                                }
 
293
                                if(is_cdda && track->num_indices > 0 && (FLAC__uint64)xx <= track->indices[track->num_indices-1].offset) {
 
294
                                        *error_message = "CD-DA INDEX offsets must increase in time";
 
295
                                        return false;
 
296
                                }
 
297
                                /* fill in track offset if it's the first index of the track */
 
298
                                if(track->num_indices == 0)
 
299
                                        track->offset = (FLAC__uint64)xx;
 
300
                                if(is_cdda && cs->num_tracks > 1) {
 
301
                                        const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-2];
 
302
                                        if((FLAC__uint64)xx <= prev->offset + prev->indices[prev->num_indices-1].offset) {
 
303
                                                *error_message = "CD-DA INDEX offsets must increase in time";
 
304
                                                return false;
 
305
                                        }
 
306
                                }
 
307
                                if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, cs->num_tracks-1, track->num_indices)) {
 
308
                                        *error_message = "memory allocation error";
 
309
                                        return false;
 
310
                                }
 
311
                                track->indices[track->num_indices-1].offset = (FLAC__uint64)xx - track->offset;
 
312
                                track->indices[track->num_indices-1].number = in_index_num;
 
313
                        }
 
314
                        else if(0 == FLAC__STRCASECMP(field, "ISRC")) {
 
315
                                if(track_has_isrc) {
 
316
                                        *error_message = "found multiple ISRC commands";
 
317
                                        return false;
 
318
                                }
 
319
                                if(in_track_num < 0 || in_index_num >= 0) {
 
320
                                        *error_message = "ISRC command must come after TRACK but before INDEX";
 
321
                                        return false;
 
322
                                }
 
323
                                if(0 == (field = local__get_field_(&line))) {
 
324
                                        *error_message = "ISRC is missing ISRC number";
 
325
                                        return false;
 
326
                                }
 
327
                                if(strlen(field) != 12 || strspn(field, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") < 5 || strspn(field+5, "1234567890") != 7) {
 
328
                                        *error_message = "invalid ISRC number";
 
329
                                        return false;
 
330
                                }
 
331
                                strcpy(cs->tracks[cs->num_tracks-1].isrc, field);
 
332
                                track_has_isrc = true;
 
333
                        }
 
334
                        else if(0 == FLAC__STRCASECMP(field, "TRACK")) {
 
335
                                if(cs->num_tracks > 0) {
 
336
                                        const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
 
337
                                        if(
 
338
                                                prev->num_indices == 0 ||
 
339
                                                (
 
340
                                                        is_cdda &&
 
341
                                                        (
 
342
                                                                (prev->num_indices == 1 && prev->indices[0].number != 1) ||
 
343
                                                                (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
 
344
                                                        )
 
345
                                                )
 
346
                                        ) {
 
347
                                                *error_message = is_cdda?
 
348
                                                        "previous TRACK must specify at least one INDEX 01" :
 
349
                                                        "previous TRACK must specify at least one INDEX";
 
350
                                                return false;
 
351
                                        }
 
352
                                }
 
353
                                if(0 == (field = local__get_field_(&line))) {
 
354
                                        *error_message = "TRACK is missing track number";
 
355
                                        return false;
 
356
                                }
 
357
                                in_track_num = local__parse_int_(field);
 
358
                                if(in_track_num < 0) {
 
359
                                        *error_message = "TRACK has invalid track number";
 
360
                                        return false;
 
361
                                }
 
362
                                if(in_track_num == 0) {
 
363
                                        *error_message = "TRACK number must be greater than 0";
 
364
                                        return false;
 
365
                                }
 
366
                                if(is_cdda && in_track_num > 99) {
 
367
                                        *error_message = "CD-DA TRACK number must be between 1 and 99, inclusive";
 
368
                                        return false;
 
369
                                }
 
370
                                if(is_cdda && cs->num_tracks > 0 && in_track_num != cs->tracks[cs->num_tracks-1].number + 1) {
 
371
                                        *error_message = "CD-DA TRACK numbers must be sequential";
 
372
                                        return false;
 
373
                                }
 
374
                                /*@@@ search for duplicate track number? */
 
375
                                if(0 == (field = local__get_field_(&line))) {
 
376
                                        *error_message = "TRACK is missing a track type after the track number";
 
377
                                        return false;
 
378
                                }
 
379
                                if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
 
380
                                        *error_message = "memory allocation error";
 
381
                                        return false;
 
382
                                }
 
383
                                cs->tracks[cs->num_tracks-1].number = in_track_num;
 
384
                                cs->tracks[cs->num_tracks-1].type = (0 == FLAC__STRCASECMP(field, "AUDIO"))? 0 : 1; /*@@@ should we be more strict with the value here? */
 
385
                                in_index_num = -1;
 
386
                                track_has_flags = false;
 
387
                                track_has_isrc = false;
 
388
                        }
 
389
                        else if(0 == FLAC__STRCASECMP(field, "REM")) {
 
390
                                if(0 != (field = local__get_field_(&line))) {
 
391
                                        if(0 == strcmp(field, "FLAC__lead-in")) {
 
392
                                                FLAC__int64 xx;
 
393
                                                if(0 == (field = local__get_field_(&line))) {
 
394
                                                        *error_message = "FLAC__lead-in is missing offset";
 
395
                                                        return false;
 
396
                                                }
 
397
                                                xx = local__parse_int64_(field);
 
398
                                                if(xx < 0) {
 
399
                                                        *error_message = "illegal FLAC__lead-in offset";
 
400
                                                        return false;
 
401
                                                }
 
402
                                                if(is_cdda && xx % 588 != 0) {
 
403
                                                        *error_message = "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples";
 
404
                                                        return false;
 
405
                                                }
 
406
                                                cs->lead_in = (FLAC__uint64)xx;
 
407
                                        }
 
408
                                        else if(0 == strcmp(field, "FLAC__lead-out")) {
 
409
                                                int track_num;
 
410
                                                FLAC__int64 offset;
 
411
                                                if(has_forced_leadout) {
 
412
                                                        *error_message = "multiple FLAC__lead-out commands";
 
413
                                                        return false;
 
414
                                                }
 
415
                                                if(0 == (field = local__get_field_(&line))) {
 
416
                                                        *error_message = "FLAC__lead-out is missing track number";
 
417
                                                        return false;
 
418
                                                }
 
419
                                                track_num = local__parse_int_(field);
 
420
                                                if(track_num < 0) {
 
421
                                                        *error_message = "illegal FLAC__lead-out track number";
 
422
                                                        return false;
 
423
                                                }
 
424
                                                forced_leadout_track_num = (unsigned)track_num;
 
425
                                                /*@@@ search for duplicate track number? */
 
426
                                                if(0 == (field = local__get_field_(&line))) {
 
427
                                                        *error_message = "FLAC__lead-out is missing offset";
 
428
                                                        return false;
 
429
                                                }
 
430
                                                offset = local__parse_int64_(field);
 
431
                                                if(offset < 0) {
 
432
                                                        *error_message = "illegal FLAC__lead-out offset";
 
433
                                                        return false;
 
434
                                                }
 
435
                                                forced_leadout_track_offset = (FLAC__uint64)offset;
 
436
                                                if(forced_leadout_track_offset != lead_out_offset) {
 
437
                                                        *error_message = "FLAC__lead-out offset does not match end-of-stream offset";
 
438
                                                        return false;
 
439
                                                }
 
440
                                                has_forced_leadout = true;
 
441
                                        }
 
442
                                }
 
443
                        }
 
444
                }
 
445
        }
 
446
 
 
447
        if(cs->num_tracks == 0) {
 
448
                *error_message = "there must be at least one TRACK command";
 
449
                return false;
 
450
        }
 
451
        else {
 
452
                const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
 
453
                if(
 
454
                        prev->num_indices == 0 ||
 
455
                        (
 
456
                                is_cdda &&
 
457
                                (
 
458
                                        (prev->num_indices == 1 && prev->indices[0].number != 1) ||
 
459
                                        (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
 
460
                                )
 
461
                        )
 
462
                ) {
 
463
                        *error_message = is_cdda?
 
464
                                "previous TRACK must specify at least one INDEX 01" :
 
465
                                "previous TRACK must specify at least one INDEX";
 
466
                        return false;
 
467
                }
 
468
        }
 
469
 
 
470
        if(!has_forced_leadout) {
 
471
                forced_leadout_track_num = is_cdda? 170 : cs->num_tracks;
 
472
                forced_leadout_track_offset = lead_out_offset;
 
473
        }
 
474
        if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
 
475
                *error_message = "memory allocation error";
 
476
                return false;
 
477
        }
 
478
        cs->tracks[cs->num_tracks-1].number = forced_leadout_track_num;
 
479
        cs->tracks[cs->num_tracks-1].offset = forced_leadout_track_offset;
 
480
 
 
481
        if(!feof(file)) {
 
482
                *error_message = "read error";
 
483
                return false;
 
484
        }
 
485
        return true;
 
486
#undef FLAC__STRCASECMP
 
487
}
 
488
 
 
489
FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
 
490
{
 
491
        FLAC__StreamMetadata *cuesheet;
 
492
 
 
493
        FLAC__ASSERT(0 != file);
 
494
        FLAC__ASSERT(0 != error_message);
 
495
        FLAC__ASSERT(0 != last_line_read);
 
496
 
 
497
        *last_line_read = 0;
 
498
        cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
 
499
 
 
500
        if(0 == cuesheet) {
 
501
                *error_message = "memory allocation error";
 
502
                return 0;
 
503
        }
 
504
 
 
505
        if(!local__cuesheet_parse_(file, error_message, last_line_read, cuesheet, is_cdda, lead_out_offset)) {
 
506
                FLAC__metadata_object_delete(cuesheet);
 
507
                return 0;
 
508
        }
 
509
 
 
510
        return cuesheet;
 
511
}
 
512
 
 
513
void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference)
 
514
{
 
515
        const FLAC__StreamMetadata_CueSheet *cs;
 
516
        unsigned track_num, index_num;
 
517
 
 
518
        FLAC__ASSERT(0 != file);
 
519
        FLAC__ASSERT(0 != cuesheet);
 
520
        FLAC__ASSERT(cuesheet->type == FLAC__METADATA_TYPE_CUESHEET);
 
521
 
 
522
        cs = &cuesheet->data.cue_sheet;
 
523
 
 
524
        if(*(cs->media_catalog_number))
 
525
                fprintf(file, "CATALOG %s\n", cs->media_catalog_number);
 
526
        fprintf(file, "FILE %s\n", file_reference);
 
527
 
 
528
        for(track_num = 0; track_num < cs->num_tracks-1; track_num++) {
 
529
                const FLAC__StreamMetadata_CueSheet_Track *track = cs->tracks + track_num;
 
530
 
 
531
                fprintf(file, "  TRACK %02u %s\n", (unsigned)track->number, track->type == 0? "AUDIO" : "DATA");
 
532
 
 
533
                if(track->pre_emphasis)
 
534
                        fprintf(file, "    FLAGS PRE\n");
 
535
                if(*(track->isrc))
 
536
                        fprintf(file, "    ISRC %s\n", track->isrc);
 
537
 
 
538
                for(index_num = 0; index_num < track->num_indices; index_num++) {
 
539
                        const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + index_num;
 
540
 
 
541
                        fprintf(file, "    INDEX %02u ", (unsigned)index->number);
 
542
                        if(cs->is_cd) {
 
543
                                const unsigned logical_frame = (unsigned)((track->offset + index->offset) / (44100 / 75));
 
544
                                unsigned m, s, f;
 
545
                                grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f);
 
546
                                fprintf(file, "%02u:%02u:%02u\n", m, s, f);
 
547
                        }
 
548
                        else
 
549
                                fprintf(file, "%llu\n", track->offset + index->offset);
 
550
                }
 
551
        }
 
552
 
 
553
        fprintf(file, "REM FLAC__lead-in %llu\n", cs->lead_in);
 
554
        fprintf(file, "REM FLAC__lead-out %u %llu\n", (unsigned)cs->tracks[track_num].number, cs->tracks[track_num].offset);
 
555
}