Update Lightrec API
[pcsx_rearmed.git] / deps / libchdr / flac.c
1 // license:BSD-3-Clause\r
2 // copyright-holders:Aaron Giles\r
3 /***************************************************************************\r
4 \r
5     flac.c\r
6 \r
7     FLAC compression wrappers\r
8 \r
9 ***************************************************************************/\r
10 \r
11 #include <assert.h>\r
12 #include <string.h>\r
13 #include "flac.h"\r
14 \r
15 //**************************************************************************\r
16 //  FLAC DECODER\r
17 //**************************************************************************\r
18 \r
19 static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);\r
20 FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes);\r
21 static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);\r
22 static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);\r
23 static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);\r
24 FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);\r
25 static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);\r
26 \r
27 // getters (valid after reset)\r
28 static uint32_t sample_rate(flac_decoder *decoder)  { return decoder->sample_rate; }\r
29 static uint8_t channels(flac_decoder *decoder)  { return decoder->channels; }\r
30 static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }\r
31 static uint32_t total_samples(flac_decoder *decoder)  { return FLAC__stream_decoder_get_total_samples(decoder->decoder); }\r
32 static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); }\r
33 static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); }\r
34 \r
35 //-------------------------------------------------\r
36 //  flac_decoder - constructor\r
37 //-------------------------------------------------\r
38 \r
39 void flac_decoder_init(flac_decoder *decoder)\r
40 {\r
41         decoder->decoder = FLAC__stream_decoder_new();\r
42         decoder->sample_rate = 0;\r
43         decoder->channels = 0;\r
44         decoder->bits_per_sample = 0;\r
45         decoder->compressed_offset = 0;\r
46         decoder->compressed_start = NULL;\r
47         decoder->compressed_length = 0;\r
48         decoder->compressed2_start = NULL;\r
49         decoder->compressed2_length = 0;\r
50         decoder->uncompressed_offset = 0;\r
51         decoder->uncompressed_length = 0;\r
52         decoder->uncompressed_swap = 0;\r
53 }\r
54 \r
55 //-------------------------------------------------\r
56 //  flac_decoder - destructor\r
57 //-------------------------------------------------\r
58 \r
59 void flac_decoder_free(flac_decoder* decoder)\r
60 {\r
61         if ((decoder != NULL) && (decoder->decoder != NULL))\r
62                 FLAC__stream_decoder_delete(decoder->decoder);\r
63 }\r
64 \r
65 \r
66 //-------------------------------------------------\r
67 //  reset - reset state with the original\r
68 //  parameters\r
69 //-------------------------------------------------\r
70 \r
71 static int flac_decoder_internal_reset(flac_decoder* decoder)\r
72 {\r
73         decoder->compressed_offset = 0;\r
74         if (FLAC__stream_decoder_init_stream(decoder->decoder,\r
75                                 &flac_decoder_read_callback_static,\r
76                                 NULL,\r
77                                 &flac_decoder_tell_callback_static,\r
78                                 NULL,\r
79                                 NULL,\r
80                                 &flac_decoder_write_callback_static,\r
81                                 &flac_decoder_metadata_callback_static,\r
82                                 &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK)\r
83                 return 0;\r
84         return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder);\r
85 }\r
86 \r
87 \r
88 \r
89 //-------------------------------------------------\r
90 //  reset - reset state with new memory parameters\r
91 //  and a custom-generated header\r
92 //-------------------------------------------------\r
93 \r
94 int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)\r
95 {\r
96         // modify the template header with our parameters\r
97         static const uint8_t s_header_template[0x2a] =\r
98         {\r
99                 0x66, 0x4C, 0x61, 0x43,                         // +00: 'fLaC' stream header\r
100                 0x80,                                           // +04: metadata block type 0 (STREAMINFO),\r
101                                                                                                                 //      flagged as last block\r
102                 0x00, 0x00, 0x22,                               // +05: metadata block length = 0x22\r
103                 0x00, 0x00,                                     // +08: minimum block size\r
104                 0x00, 0x00,                                     // +0A: maximum block size\r
105                 0x00, 0x00, 0x00,                               // +0C: minimum frame size (0 == unknown)\r
106                 0x00, 0x00, 0x00,                               // +0F: maximum frame size (0 == unknown)\r
107                 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100),\r
108                                                                                                                 //      numchannels (2), sample bits (16),\r
109                                                                                                                 //      samples in stream (0 == unknown)\r
110                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none)\r
111                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  //\r
112                                                                                                                 // +2A: start of stream data\r
113         };\r
114         memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));\r
115         decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8;\r
116         decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff;\r
117         decoder->custom_header[0x12] = sample_rate >> 12;\r
118         decoder->custom_header[0x13] = sample_rate >> 4;\r
119         decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);\r
120 \r
121         // configure the header ahead of the provided buffer\r
122         decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header);\r
123         decoder->compressed_length = sizeof(decoder->custom_header);\r
124         decoder->compressed2_start = (const FLAC__byte *)(buffer);\r
125         decoder->compressed2_length = length;\r
126         return flac_decoder_internal_reset(decoder);\r
127 }\r
128 \r
129 \r
130 //-------------------------------------------------\r
131 //  decode_interleaved - decode to an interleaved\r
132 //  sound stream\r
133 //-------------------------------------------------\r
134 \r
135 int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)\r
136 {\r
137         // configure the uncompressed buffer\r
138         memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));\r
139         decoder->uncompressed_start[0] = samples;\r
140         decoder->uncompressed_offset = 0;\r
141         decoder->uncompressed_length = num_samples;\r
142         decoder->uncompressed_swap = swap_endian;\r
143 \r
144         // loop until we get everything we want\r
145         while (decoder->uncompressed_offset < decoder->uncompressed_length)\r
146                 if (!FLAC__stream_decoder_process_single(decoder->decoder))\r
147                         return 0;\r
148         return 1;\r
149 }\r
150 \r
151 \r
152 /*\r
153 //-------------------------------------------------\r
154 //  decode - decode to an multiple independent\r
155 //  data streams\r
156 //-------------------------------------------------\r
157 \r
158 bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)\r
159 {\r
160         // make sure we don't have too many channels\r
161         int chans = channels();\r
162         if (chans > ARRAY_LENGTH(m_uncompressed_start))\r
163                 return false;\r
164 \r
165         // configure the uncompressed buffer\r
166         memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));\r
167         for (int curchan = 0; curchan < chans; curchan++)\r
168                 m_uncompressed_start[curchan] = samples[curchan];\r
169         m_uncompressed_offset = 0;\r
170         m_uncompressed_length = num_samples;\r
171         m_uncompressed_swap = swap_endian;\r
172 \r
173         // loop until we get everything we want\r
174         while (m_uncompressed_offset < m_uncompressed_length)\r
175                 if (!FLAC__stream_decoder_process_single(m_decoder))\r
176                         return false;\r
177         return true;\r
178 }\r
179 */\r
180 \r
181 //-------------------------------------------------\r
182 //  finish - finish up the decode\r
183 //-------------------------------------------------\r
184 \r
185 uint32_t flac_decoder_finish(flac_decoder* decoder)\r
186 {\r
187         // get the final decoding position and move forward\r
188         FLAC__uint64 position = 0;\r
189         FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);\r
190         FLAC__stream_decoder_finish(decoder->decoder);\r
191 \r
192         // adjust position if we provided the header\r
193         if (position == 0)\r
194                 return 0;\r
195         if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header))\r
196                 position -= decoder->compressed_length;\r
197         return position;\r
198 }\r
199 \r
200 \r
201 //-------------------------------------------------\r
202 //  read_callback - handle reads from the input\r
203 //  stream\r
204 //-------------------------------------------------\r
205 \r
206 #define MIN(x, y) ((x) < (y) ? (x) : (y))\r
207 \r
208 FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)\r
209 {\r
210         return flac_decoder_read_callback(client_data, buffer, bytes);\r
211 }\r
212 \r
213 FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes)\r
214 {\r
215         flac_decoder* decoder = (flac_decoder*)client_data;\r
216 \r
217         uint32_t expected = *bytes;\r
218 \r
219         // copy from primary buffer first\r
220         uint32_t outputpos = 0;\r
221         if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length)\r
222         {\r
223                 uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);\r
224                 memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);\r
225                 outputpos += bytes_to_copy;\r
226                 decoder->compressed_offset += bytes_to_copy;\r
227         }\r
228 \r
229         // once we're out of that, copy from the secondary buffer\r
230         if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)\r
231         {\r
232                 uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));\r
233                 memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);\r
234                 outputpos += bytes_to_copy;\r
235                 decoder->compressed_offset += bytes_to_copy;\r
236         }\r
237         *bytes = outputpos;\r
238 \r
239         // return based on whether we ran out of data\r
240         return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;\r
241 }\r
242 \r
243 \r
244 //-------------------------------------------------\r
245 //  metadata_callback - handle STREAMINFO metadata\r
246 //-------------------------------------------------\r
247 \r
248 void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)\r
249 {\r
250    flac_decoder *fldecoder;\r
251         // ignore all but STREAMINFO metadata\r
252         if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)\r
253                 return;\r
254 \r
255         // parse out the data we care about\r
256         fldecoder = (flac_decoder *)(client_data);\r
257         fldecoder->sample_rate = metadata->data.stream_info.sample_rate;\r
258         fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;\r
259         fldecoder->channels = metadata->data.stream_info.channels;\r
260 }\r
261 \r
262 \r
263 //-------------------------------------------------\r
264 //  tell_callback - handle requests to find out\r
265 //  where in the input stream we are\r
266 //-------------------------------------------------\r
267 \r
268 FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)\r
269 {\r
270         *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset;\r
271         return FLAC__STREAM_DECODER_TELL_STATUS_OK;\r
272 }\r
273 \r
274 \r
275 //-------------------------------------------------\r
276 //  write_callback - handle writes to the output\r
277 //  stream\r
278 //-------------------------------------------------\r
279 \r
280 FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)\r
281 {\r
282         return flac_decoder_write_callback(client_data, frame, buffer);\r
283 }\r
284 \r
285 FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])\r
286 {\r
287    int shift, blocksize;\r
288         flac_decoder * decoder = (flac_decoder *)client_data;\r
289 \r
290         assert(frame->header.channels == channels(decoder));\r
291 \r
292         // interleaved case\r
293         shift = decoder->uncompressed_swap ? 8 : 0;\r
294         blocksize = frame->header.blocksize;\r
295 \r
296         if (decoder->uncompressed_start[1] == NULL)\r
297         {\r
298       int sampnum, chan;\r
299                 int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;\r
300                 for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)\r
301                         for (chan = 0; chan < frame->header.channels; chan++)\r
302                                 *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));\r
303         }\r
304 \r
305         // non-interleaved case\r
306         else\r
307         {\r
308       int sampnum, chan;\r
309                 for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)\r
310                         for (chan = 0; chan < frame->header.channels; chan++)\r
311                                 if (decoder->uncompressed_start[chan] != NULL)\r
312                                         decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) );\r
313         }\r
314         return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;\r
315 }\r
316 \r
317 /**\r
318  * @fn  void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)\r
319  *\r
320  * @brief   -------------------------------------------------\r
321  *            error_callback - handle errors (ignore them)\r
322  *          -------------------------------------------------.\r
323  *\r
324  * @param   decoder             The decoder.\r
325  * @param   status              The status.\r
326  * @param [in,out]  client_data If non-null, information describing the client.\r
327  */\r
328 \r
329 void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)\r
330 {\r
331 }\r