revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / flac.c
blob1ca9470d9a024622de335ffefbdea698aca08c1f
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "audio/flac.h"
28 #include <libraries/iffparse.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <string.h>
32 #include "endian.h"
33 #include "support.h"
35 #define NO_ERROR 0
36 #define ZERO MKBADDR(NULL)
38 #define ID_fLaC MAKE_ID('f','L','a','C')
40 BOOL FLAC_header(CONST_APTR p) {
41 return rbe32(p) == ID_fLaC;
44 static void FLAC_close(FLAC_STREAM *stream);
45 static LONG FLAC_read(FLAC_STREAM *stream, APTR buffer, ULONG offset, ULONG length);
47 static FLAC__StreamDecoderReadStatus FLAC_read_callback(const FLAC__StreamDecoder *decoder,
48 FLAC__byte buffer[], size_t *bytes, void *client_data);
49 static FLAC__StreamDecoderSeekStatus FLAC_seek_callback(const FLAC__StreamDecoder *decoder,
50 FLAC__uint64 absolute_byte_offset, void *client_data);
51 static FLAC__StreamDecoderTellStatus FLAC_tell_callback(const FLAC__StreamDecoder *decoder,
52 FLAC__uint64 *absolute_byte_offset, void *client_data);
53 static FLAC__StreamDecoderLengthStatus FLAC_length_callback(const FLAC__StreamDecoder *decoder,
54 FLAC__uint64 *stream_length, void *client_data);
55 static FLAC__bool FLAC_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
56 static FLAC__StreamDecoderWriteStatus FLAC_write_callback(const FLAC__StreamDecoder *decoder,
57 const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
58 static void FLAC_metadata_callback(const FLAC__StreamDecoder *decoder,
59 const FLAC__StreamMetadata *metadata, void *client_data);
60 static void FLAC_error_callback(const FLAC__StreamDecoder *decoder,
61 FLAC__StreamDecoderErrorStatus status, void *client_data);
63 FLAC_STREAM *FLAC_open(CONST_STRPTR filename, BOOL cuesheet) {
64 BPTR file = ZERO;
65 FLAC_STREAM *stream = NULL;
66 LONG error = NO_ERROR;
68 file = Open(filename, MODE_OLDFILE);
69 if (!file) {
70 error = IoErr();
71 goto error;
74 stream = AllocVec(sizeof(*stream), MEMF_CLEAR);
75 if (!stream) {
76 error = ERROR_NO_FREE_STORE;
77 Close(file);
78 goto error;
80 stream->close = FLAC_close;
81 stream->read = FLAC_read;
82 stream->file = file;
84 stream->decoder = FLAC__stream_decoder_new();
85 if (!stream->decoder) {
86 error = ERROR_NO_FREE_STORE;
87 goto error;
90 if (cuesheet) {
91 FLAC__stream_decoder_set_metadata_respond(stream->decoder, FLAC__METADATA_TYPE_CUESHEET);
94 stream->init_status = FLAC__stream_decoder_init_stream(stream->decoder,
95 FLAC_read_callback,
96 FLAC_seek_callback,
97 FLAC_tell_callback,
98 FLAC_length_callback,
99 FLAC_eof_callback,
100 FLAC_write_callback,
101 FLAC_metadata_callback,
102 FLAC_error_callback,
103 stream);
104 if (stream->init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
105 error = ERROR_OBJECT_WRONG_TYPE;
106 goto error;
109 if (!FLAC__stream_decoder_process_until_end_of_metadata(stream->decoder)) {
110 error = ERROR_OBJECT_WRONG_TYPE;
111 goto error;
114 if (stream->total_samples == 0 || stream->sample_rate != 44100 ||
115 stream->channels != 2 || stream->bits_per_sample != 16)
117 error = ERROR_OBJECT_WRONG_TYPE;
118 goto error;
121 return stream;
123 error:
124 FLAC_close(stream);
125 SetIoErr(error);
126 return NULL;
129 static void FLAC_close(FLAC_STREAM *stream) {
130 if (stream) {
131 if (stream->decoder) {
132 if (stream->cuesheet) {
133 FLAC__metadata_object_delete(stream->cuesheet);
135 if (stream->init_status == FLAC__STREAM_DECODER_INIT_STATUS_OK) {
136 FLAC__stream_decoder_finish(stream->decoder);
138 FLAC__stream_decoder_delete(stream->decoder);
140 Close(stream->file);
141 FreeVec(stream);
145 static LONG FLAC_read(FLAC_STREAM *stream, APTR buffer, ULONG offset, ULONG length) {
146 LONG sample_offset = offset >> 2;
147 LONG samples_to_read = length >> 2;
148 LONG samples_to_skip;
149 LONG samples_read;
150 LONG sample;
151 WORD *dst = buffer;
152 if (sample_offset >= stream->first_sample_in_pcm &&
153 sample_offset < (stream->first_sample_in_pcm + stream->samples_in_pcm))
155 samples_to_skip = sample_offset - stream->first_sample_in_pcm;
156 samples_read = stream->samples_in_pcm;
157 sample_offset = stream->first_sample_in_pcm + samples_read;
158 if (samples_read > samples_to_skip) {
159 if (samples_read > (samples_to_skip + samples_to_read)) {
160 samples_read = samples_to_skip + samples_to_read;
162 for (sample = samples_to_skip; sample < samples_read; sample++) {
163 wle16(dst, stream->pcm[0][sample]); dst++;
164 wle16(dst, stream->pcm[1][sample]); dst++;
166 samples_read -= samples_to_skip;
167 samples_to_read -= samples_read;
170 if (stream->sample_offset == -1 || sample_offset != stream->sample_offset) {
171 stream->sample_offset = -1;
172 stream->eof = FALSE;
173 if (!FLAC__stream_decoder_seek_absolute(stream->decoder, sample_offset)) {
174 return (int32)dst - (int32)buffer;
176 stream->sample_offset = sample_offset;
178 while (samples_to_read) {
179 if (stream->eof) {
180 memset(dst, 0, samples_to_read << 2);
181 dst += (samples_to_read << 1);
182 break;
184 if (sample_offset >= stream->first_sample_in_pcm &&
185 sample_offset < (stream->first_sample_in_pcm + stream->samples_in_pcm))
187 samples_to_skip = sample_offset - stream->first_sample_in_pcm;
188 samples_read = stream->samples_in_pcm;
189 sample_offset = stream->first_sample_in_pcm + samples_read;
190 if (samples_read > samples_to_skip) {
191 if (samples_read > (samples_to_skip + samples_to_read)) {
192 samples_read = samples_to_skip + samples_to_read;
194 for (sample = samples_to_skip; sample < samples_read; sample++) {
195 wle16(dst, stream->pcm[0][sample]); dst++;
196 wle16(dst, stream->pcm[1][sample]); dst++;
198 samples_read -= samples_to_skip;
199 samples_to_read -= samples_read;
202 if (!FLAC__stream_decoder_process_single(stream->decoder)) {
203 if (FLAC__stream_decoder_get_state(stream->decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) {
204 stream->eof = TRUE;
205 continue;
207 stream->sample_offset = -1;
208 break;
211 return (LONG)dst - (LONG)buffer;
214 static FLAC__StreamDecoderReadStatus FLAC_read_callback(const FLAC__StreamDecoder *decoder,
215 FLAC__byte buffer[], size_t *bytes, void *client_data)
217 FLAC_STREAM *stream = client_data;
218 BPTR file = stream->file;
219 if (*bytes > 0) {
220 *bytes = FRead(file, buffer, 1, *bytes);
221 if (*bytes == -1)
222 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
223 else if (*bytes == 0)
224 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
225 else
226 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
227 } else
228 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
231 static FLAC__StreamDecoderSeekStatus FLAC_seek_callback(const FLAC__StreamDecoder *decoder,
232 FLAC__uint64 absolute_byte_offset, void *client_data)
234 FLAC_STREAM *stream = client_data;
235 BPTR file = stream->file;
236 if (!ChangeFilePosition(file, absolute_byte_offset, OFFSET_BEGINNING))
237 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
238 else
239 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
242 static FLAC__StreamDecoderTellStatus FLAC_tell_callback(const FLAC__StreamDecoder *decoder,
243 FLAC__uint64 *absolute_byte_offset, void *client_data)
245 FLAC_STREAM *stream = client_data;
246 BPTR file = stream->file;
247 QUAD pos;
248 if ((pos = GetFilePosition(file)) == -1 && IoErr())
249 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
250 else {
251 *absolute_byte_offset = (FLAC__uint64)pos;
252 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
256 static FLAC__StreamDecoderLengthStatus FLAC_length_callback(const FLAC__StreamDecoder *decoder,
257 FLAC__uint64 *stream_length, void *client_data)
259 FLAC_STREAM *stream = client_data;
260 BPTR file = stream->file;
261 QUAD size;
262 if ((size = GetFileSize(file)) == -1 && IoErr())
263 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
264 else {
265 *stream_length = (FLAC__uint64)size;
266 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
270 static FLAC__bool FLAC_eof_callback(const FLAC__StreamDecoder *decoder, void *client_data) {
271 FLAC_STREAM *stream = client_data;
272 BPTR file = stream->file;
273 int byte;
274 if ((byte = FGetC(file)) == -1)
275 return TRUE;
276 else {
277 UnGetC(file, byte);
278 return FALSE;
282 static FLAC__StreamDecoderWriteStatus FLAC_write_callback(const FLAC__StreamDecoder *decoder,
283 const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
285 FLAC_STREAM *stream = client_data;
286 LONG sample;
287 if (stream->total_samples == 0 || stream->sample_rate != 44100 ||
288 stream->channels != 2 || stream->bits_per_sample != 16)
290 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
292 if (frame->header.blocksize > stream->pcm_size) {
293 FreeVec(stream->pcm[0]);
294 FreeVec(stream->pcm[1]);
295 stream->pcm_size = frame->header.blocksize;
296 stream->pcm[0] = AllocVec(stream->pcm_size * sizeof(int16), MEMF_ANY);
297 stream->pcm[1] = AllocVec(stream->pcm_size * sizeof(int16), MEMF_ANY);
298 if (!stream->pcm[0] || !stream->pcm[1]) {
299 FreeVec(stream->pcm[0]);
300 FreeVec(stream->pcm[1]);
301 stream->pcm[0] = stream->pcm[1] = NULL;
302 stream->pcm_size = 0;
303 stream->sample_offset = -1;
304 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
307 stream->first_sample_in_pcm = frame->header.number.sample_number;
308 stream->samples_in_pcm = frame->header.blocksize;
309 for (sample = 0; sample < stream->samples_in_pcm; sample++) {
310 stream->pcm[0][sample] = (int16)buffer[0][sample];
311 stream->pcm[1][sample] = (int16)buffer[1][sample];
313 stream->sample_offset = stream->first_sample_in_pcm + stream->samples_in_pcm;
314 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
317 static void FLAC_metadata_callback(const FLAC__StreamDecoder *decoder,
318 const FLAC__StreamMetadata *metadata, void *client_data)
320 FLAC_STREAM *stream = client_data;
321 switch (metadata->type) {
322 case FLAC__METADATA_TYPE_STREAMINFO:
323 stream->total_samples = metadata->data.stream_info.total_samples;
324 stream->sample_rate = metadata->data.stream_info.sample_rate;
325 stream->channels = metadata->data.stream_info.channels;
326 stream->bits_per_sample = metadata->data.stream_info.bits_per_sample;
327 stream->length = stream->total_samples << 2;
328 break;
329 case FLAC__METADATA_TYPE_CUESHEET:
330 stream->cuesheet = FLAC__metadata_object_clone(metadata);
331 break;
332 default:
333 break;
337 static void FLAC_error_callback(const FLAC__StreamDecoder *decoder,
338 FLAC__StreamDecoderErrorStatus status, void *client_data)