chiark / gitweb /
Disobedience: basic support for required/prohibited tags.
[disorder] / plugins / tracklength-flac.c
CommitLineData
28e9141a
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2004, 2005, 2007 Richard Kettlewell
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18/** @file plugins/tracklength-flac.c
19 * @brief Compute track lengths for FLAC files
20 */
21#include "tracklength.h"
22#include <FLAC/stream_decoder.h>
23
24/* libFLAC's "simplified" interface is rather heavyweight... */
25
26struct flac_state {
27 long duration;
28 const char *path;
29};
30
31static void flac_metadata(const FLAC__StreamDecoder attribute((unused)) *decoder,
32 const FLAC__StreamMetadata *metadata,
33 void *client_data) {
34 struct flac_state *const state = client_data;
35 const FLAC__StreamMetadata_StreamInfo *const stream_info
36 = &metadata->data.stream_info;
37
38 if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
39 /* FLAC uses 0 to mean unknown and conveniently so do we */
40 state->duration = (stream_info->total_samples
41 + stream_info->sample_rate - 1)
42 / stream_info->sample_rate;
43}
44
45static void flac_error(const FLAC__StreamDecoder attribute((unused)) *decoder,
46 FLAC__StreamDecoderErrorStatus status,
47 void *client_data) {
48 const struct flac_state *const state = client_data;
49
50 disorder_error(0, "error decoding %s: %s", state->path,
51 FLAC__StreamDecoderErrorStatusString[status]);
52}
53
54static FLAC__StreamDecoderWriteStatus flac_write
55 (const FLAC__StreamDecoder attribute((unused)) *decoder,
56 const FLAC__Frame attribute((unused)) *frame,
57 const FLAC__int32 attribute((unused)) *const buffer_[],
58 void attribute((unused)) *client_data) {
59 const struct flac_state *const state = client_data;
60
61 if(state->duration >= 0)
62 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
63 else
64 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
65}
66
67long tl_flac(const char *path) {
68 FLAC__StreamDecoder *sd = 0;
69 FLAC__StreamDecoderInitStatus is;
70 struct flac_state state[1];
71
72 state->duration = -1; /* error */
73 state->path = path;
74 if(!(sd = FLAC__stream_decoder_new())) {
75 disorder_error(0, "FLAC__stream_decoder_new failed");
76 goto fail;
77 }
78 if((is = FLAC__stream_decoder_init_file(sd, path, flac_write, flac_metadata,
79 flac_error, state))) {
80 disorder_error(0, "FLAC__stream_decoder_init_file %s: %s",
81 path, FLAC__StreamDecoderInitStatusString[is]);
82 goto fail;
83 }
84 FLAC__stream_decoder_process_until_end_of_metadata(sd);
85fail:
86 if(sd)
87 FLAC__stream_decoder_delete(sd);
88 return state->duration;
89}
90
91/*
92Local Variables:
93c-basic-offset:2
94comment-column:40
95fill-column:79
96End:
97*/