chiark / gitweb /
Split up disorder-decode source into one file per format.
[disorder] / server / decode-flac.c
... / ...
CommitLineData
1/*
2 * This file is part of DisOrder
3 * Copyright (C) 2007-2010 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 server/decode.c
19 * @brief General-purpose decoder for use by speaker process
20 */
21#include "decode.h"
22#include <FLAC/stream_decoder.h>
23
24/** @brief Metadata callback for FLAC decoder
25 *
26 * This is a no-op here.
27 */
28static void flac_metadata(const FLAC__StreamDecoder attribute((unused)) *decoder,
29 const FLAC__StreamMetadata attribute((unused)) *metadata,
30 void attribute((unused)) *client_data) {
31}
32
33/** @brief Error callback for FLAC decoder */
34static void flac_error(const FLAC__StreamDecoder attribute((unused)) *decoder,
35 FLAC__StreamDecoderErrorStatus status,
36 void attribute((unused)) *client_data) {
37 disorder_fatal(0, "error decoding %s: %s", path,
38 FLAC__StreamDecoderErrorStatusString[status]);
39}
40
41/** @brief Write callback for FLAC decoder */
42static FLAC__StreamDecoderWriteStatus flac_write
43 (const FLAC__StreamDecoder attribute((unused)) *decoder,
44 const FLAC__Frame *frame,
45 const FLAC__int32 *const buffer[],
46 void attribute((unused)) *client_data) {
47 size_t n, c;
48
49 output_header(frame->header.sample_rate,
50 frame->header.channels,
51 frame->header.bits_per_sample,
52 (frame->header.channels * frame->header.blocksize
53 * frame->header.bits_per_sample) / 8,
54 ENDIAN_BIG);
55 for(n = 0; n < frame->header.blocksize; ++n) {
56 for(c = 0; c < frame->header.channels; ++c) {
57 switch(frame->header.bits_per_sample) {
58 case 8: output_8(buffer[c][n]); break;
59 case 16: output_16(buffer[c][n]); break;
60 case 24: output_24(buffer[c][n]); break;
61 case 32: output_32(buffer[c][n]); break;
62 }
63 }
64 }
65 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
66}
67
68static FLAC__StreamDecoderReadStatus flac_read(const FLAC__StreamDecoder attribute((unused)) *decoder,
69 FLAC__byte buffer[],
70 size_t *bytes,
71 void *client_data) {
72 struct hreader *flacinput = client_data;
73 int n = hreader_read(flacinput, buffer, *bytes);
74 if(n == 0) {
75 *bytes = 0;
76 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
77 }
78 if(n < 0) {
79 *bytes = 0;
80 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
81 }
82 *bytes = n;
83 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
84}
85
86static FLAC__StreamDecoderSeekStatus flac_seek(const FLAC__StreamDecoder attribute((unused)) *decoder,
87 FLAC__uint64 absolute_byte_offset,
88 void *client_data) {
89 struct hreader *flacinput = client_data;
90 if(hreader_seek(flacinput, absolute_byte_offset, SEEK_SET) < 0)
91 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
92 else
93 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
94}
95
96static FLAC__StreamDecoderTellStatus flac_tell(const FLAC__StreamDecoder attribute((unused)) *decoder,
97 FLAC__uint64 *absolute_byte_offset,
98 void *client_data) {
99 struct hreader *flacinput = client_data;
100 off_t offset = hreader_seek(flacinput, 0, SEEK_CUR);
101 if(offset < 0)
102 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
103 *absolute_byte_offset = offset;
104 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
105}
106
107static FLAC__StreamDecoderLengthStatus flac_length(const FLAC__StreamDecoder attribute((unused)) *decoder,
108 FLAC__uint64 *stream_length,
109 void *client_data) {
110 struct hreader *flacinput = client_data;
111 *stream_length = hreader_size(flacinput);
112 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
113}
114
115static FLAC__bool flac_eof(const FLAC__StreamDecoder attribute((unused)) *decoder,
116 void *client_data) {
117 struct hreader *flacinput = client_data;
118 return hreader_eof(flacinput);
119}
120
121/** @brief FLAC file decoder */
122void decode_flac(void) {
123 FLAC__StreamDecoder *sd = FLAC__stream_decoder_new();
124 FLAC__StreamDecoderInitStatus is;
125 struct hreader flacinput[1];
126
127 if (!sd)
128 disorder_fatal(0, "FLAC__stream_decoder_new failed");
129 if(hreader_init(path, flacinput))
130 disorder_fatal(errno, "error opening %s", path);
131
132 if((is = FLAC__stream_decoder_init_stream(sd,
133 flac_read,
134 flac_seek,
135 flac_tell,
136 flac_length,
137 flac_eof,
138 flac_write, flac_metadata,
139 flac_error,
140 flacinput)))
141 disorder_fatal(0, "FLAC__stream_decoder_init_stream %s: %s",
142 path, FLAC__StreamDecoderInitStatusString[is]);
143
144 FLAC__stream_decoder_process_until_end_of_stream(sd);
145 FLAC__stream_decoder_finish(sd);
146 FLAC__stream_decoder_delete(sd);
147}
148
149/*
150Local Variables:
151c-basic-offset:2
152comment-column:40
153fill-column:79
154indent-tabs-mode:nil
155End:
156*/