1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
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>
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
) {
65 FLAC_STREAM
*stream
= NULL
;
66 LONG error
= NO_ERROR
;
68 file
= Open(filename
, MODE_OLDFILE
);
74 stream
= AllocVec(sizeof(*stream
), MEMF_CLEAR
);
76 error
= ERROR_NO_FREE_STORE
;
80 stream
->close
= FLAC_close
;
81 stream
->read
= FLAC_read
;
84 stream
->decoder
= FLAC__stream_decoder_new();
85 if (!stream
->decoder
) {
86 error
= ERROR_NO_FREE_STORE
;
91 FLAC__stream_decoder_set_metadata_respond(stream
->decoder
, FLAC__METADATA_TYPE_CUESHEET
);
94 stream
->init_status
= FLAC__stream_decoder_init_stream(stream
->decoder
,
101 FLAC_metadata_callback
,
104 if (stream
->init_status
!= FLAC__STREAM_DECODER_INIT_STATUS_OK
) {
105 error
= ERROR_OBJECT_WRONG_TYPE
;
109 if (!FLAC__stream_decoder_process_until_end_of_metadata(stream
->decoder
)) {
110 error
= ERROR_OBJECT_WRONG_TYPE
;
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
;
129 static void FLAC_close(FLAC_STREAM
*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
);
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
;
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;
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
) {
180 memset(dst
, 0, samples_to_read
<< 2);
181 dst
+= (samples_to_read
<< 1);
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
) {
207 stream
->sample_offset
= -1;
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
;
220 *bytes
= FRead(file
, buffer
, 1, *bytes
);
222 return FLAC__STREAM_DECODER_READ_STATUS_ABORT
;
223 else if (*bytes
== 0)
224 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
226 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
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
;
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
;
248 if ((pos
= GetFilePosition(file
)) == -1 && IoErr())
249 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR
;
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
;
262 if ((size
= GetFileSize(file
)) == -1 && IoErr())
263 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR
;
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
;
274 if ((byte
= FGetC(file
)) == -1)
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
;
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;
329 case FLAC__METADATA_TYPE_CUESHEET
:
330 stream
->cuesheet
= FLAC__metadata_object_clone(metadata
);
337 static void FLAC_error_callback(const FLAC__StreamDecoder
*decoder
,
338 FLAC__StreamDecoderErrorStatus status
, void *client_data
)