chiark / gitweb /
Typo.
[disorder] / plugins / tracklength-flac.c
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
26 struct flac_state {
27   long duration;
28   const char *path;
29 };
30
31 static 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
45 static 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
54 static 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
67 long 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);
85 fail:
86   if(sd)
87     FLAC__stream_decoder_delete(sd);
88   return state->duration;
89 }
90
91 /*
92 Local Variables:
93 c-basic-offset:2
94 comment-column:40
95 fill-column:79
96 End:
97 */