Update
[pcsx_rearmed.git] / deps / libchdr / flac.c
CommitLineData
ce188d4d 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
19static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);\r
20FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes);\r
21static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);\r
22static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);\r
23static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);\r
24FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);\r
25static 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
28static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; }\r
29static uint8_t channels(flac_decoder *decoder) { return decoder->channels; }\r
30static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }\r
31static uint32_t total_samples(flac_decoder *decoder) { return FLAC__stream_decoder_get_total_samples(decoder->decoder); }\r
32static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); }\r
33static 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
39void 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
59void 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
71static 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
94int 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
135int 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
158bool 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
185uint32_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
208FLAC__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
213FLAC__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
248void 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
268FLAC__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
280FLAC__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
285FLAC__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
329void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)\r
330{\r
331}\r