diff options
author | Christian Gmeiner <christian.gmeiner@gmail.com> | 2005-02-25 17:05:30 +0000 |
---|---|---|
committer | Christian Gmeiner <christian.gmeiner@gmail.com> | 2005-02-25 17:05:30 +0000 |
commit | e449d88b3e6b584998f8f38ed61467c35ca74466 (patch) | |
tree | 307e87242fd5fbf45d7424bb5afad17b9dd34429 /apps/codecs/libwavpack/unpack.c | |
parent | 234489a449e13d99b76daff61ff7774226d21a5b (diff) | |
download | rockbox-e449d88b3e6b584998f8f38ed61467c35ca74466.tar.gz rockbox-e449d88b3e6b584998f8f38ed61467c35ca74466.zip |
Initial import of libwavpack
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6056 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libwavpack/unpack.c')
-rw-r--r-- | apps/codecs/libwavpack/unpack.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/apps/codecs/libwavpack/unpack.c b/apps/codecs/libwavpack/unpack.c new file mode 100644 index 0000000000..e2e27b4999 --- /dev/null +++ b/apps/codecs/libwavpack/unpack.c | |||
@@ -0,0 +1,576 @@ | |||
1 | //////////////////////////////////////////////////////////////////////////// | ||
2 | // **** WAVPACK **** // | ||
3 | // Hybrid Lossless Wavefile Compressor // | ||
4 | // Copyright (c) 1998 - 2004 Conifer Software. // | ||
5 | // All Rights Reserved. // | ||
6 | // Distributed under the BSD Software License (see license.txt) // | ||
7 | //////////////////////////////////////////////////////////////////////////// | ||
8 | |||
9 | // unpack.c | ||
10 | |||
11 | // This module actually handles the decompression of the audio data, except | ||
12 | // for the entropy decoding which is handled by the words.c module. For | ||
13 | // maximum efficiency, the conversion is isolated to tight loops that handle | ||
14 | // an entire buffer. | ||
15 | |||
16 | #include "wavpack.h" | ||
17 | |||
18 | #include <string.h> | ||
19 | #include <math.h> | ||
20 | |||
21 | #define LOSSY_MUTE | ||
22 | |||
23 | //////////////////////////////// local macros ///////////////////////////////// | ||
24 | |||
25 | #define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10) | ||
26 | |||
27 | #define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \ | ||
28 | (((sample & ~0xffff) >> 9) * weight) + 1) >> 1) | ||
29 | |||
30 | #define apply_weight(weight, sample) (sample != (short) sample ? \ | ||
31 | apply_weight_f (weight, sample) : apply_weight_i (weight, sample)) | ||
32 | |||
33 | #define update_weight(weight, delta, source, result) \ | ||
34 | if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta; | ||
35 | |||
36 | #define update_weight_clip(weight, delta, source, result) \ | ||
37 | if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \ | ||
38 | weight = weight < 0 ? -1024 : 1024; | ||
39 | |||
40 | ///////////////////////////// executable code //////////////////////////////// | ||
41 | |||
42 | // This function initializes everything required to unpack a WavPack block | ||
43 | // and must be called before unpack_samples() is called to obtain audio data. | ||
44 | // It is assumed that the WavpackHeader has been read into the wps->wphdr | ||
45 | // (in the current WavpackStream). This is where all the metadata blocks are | ||
46 | // scanned up to the one containing the audio bitstream. | ||
47 | |||
48 | int unpack_init (WavpackContext *wpc) | ||
49 | { | ||
50 | WavpackStream *wps = &wpc->stream; | ||
51 | WavpackMetadata wpmd; | ||
52 | |||
53 | if (wps->wphdr.block_samples && wps->wphdr.block_index != (ulong) -1) | ||
54 | wps->sample_index = wps->wphdr.block_index; | ||
55 | |||
56 | wps->mute_error = FALSE; | ||
57 | wps->crc = 0xffffffff; | ||
58 | CLEAR (wps->wvbits); | ||
59 | CLEAR (wps->decorr_passes); | ||
60 | CLEAR (wps->w); | ||
61 | |||
62 | while (read_metadata_buff (wpc, &wpmd)) { | ||
63 | if (!process_metadata (wpc, &wpmd)) { | ||
64 | strcpy (wpc->error_message, "invalid metadata!"); | ||
65 | return FALSE; | ||
66 | } | ||
67 | |||
68 | if (wpmd.id == ID_WV_BITSTREAM) | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) { | ||
73 | strcpy (wpc->error_message, "invalid WavPack file!"); | ||
74 | return FALSE; | ||
75 | } | ||
76 | |||
77 | if (wps->wphdr.block_samples) { | ||
78 | if ((wps->wphdr.flags & INT32_DATA) && wps->int32_sent_bits) | ||
79 | wpc->lossy_blocks = TRUE; | ||
80 | |||
81 | if ((wps->wphdr.flags & FLOAT_DATA) && | ||
82 | wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) | ||
83 | wpc->lossy_blocks = TRUE; | ||
84 | } | ||
85 | |||
86 | return TRUE; | ||
87 | } | ||
88 | |||
89 | // This function initialzes the main bitstream for audio samples, which must | ||
90 | // be in the "wv" file. | ||
91 | |||
92 | int init_wv_bitstream (WavpackContext *wpc, WavpackMetadata *wpmd) | ||
93 | { | ||
94 | WavpackStream *wps = &wpc->stream; | ||
95 | |||
96 | if (wpmd->data) | ||
97 | bs_open_read (&wps->wvbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length, NULL, 0); | ||
98 | else if (wpmd->byte_length) | ||
99 | bs_open_read (&wps->wvbits, wpc->read_buffer, wpc->read_buffer + sizeof (wpc->read_buffer), | ||
100 | wpc->infile, wpmd->byte_length + (wpmd->byte_length & 1)); | ||
101 | |||
102 | return TRUE; | ||
103 | } | ||
104 | |||
105 | // Read decorrelation terms from specified metadata block into the | ||
106 | // decorr_passes array. The terms range from -3 to 8, plus 17 & 18; | ||
107 | // other values are reserved and generate errors for now. The delta | ||
108 | // ranges from 0 to 7 with all values valid. Note that the terms are | ||
109 | // stored in the opposite order in the decorr_passes array compared | ||
110 | // to packing. | ||
111 | |||
112 | int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) | ||
113 | { | ||
114 | int termcnt = wpmd->byte_length; | ||
115 | uchar *byteptr = wpmd->data; | ||
116 | struct decorr_pass *dpp; | ||
117 | |||
118 | if (termcnt > MAX_NTERMS) | ||
119 | return FALSE; | ||
120 | |||
121 | wps->num_terms = termcnt; | ||
122 | |||
123 | for (dpp = wps->decorr_passes + termcnt - 1; termcnt--; dpp--) { | ||
124 | dpp->term = (int)(*byteptr & 0x1f) - 5; | ||
125 | dpp->delta = (*byteptr++ >> 5) & 0x7; | ||
126 | |||
127 | if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18) | ||
128 | return FALSE; | ||
129 | } | ||
130 | |||
131 | return TRUE; | ||
132 | } | ||
133 | |||
134 | // Read decorrelation weights from specified metadata block into the | ||
135 | // decorr_passes array. The weights range +/-1024, but are rounded and | ||
136 | // truncated to fit in signed chars for metadata storage. Weights are | ||
137 | // separate for the two channels and are specified from the "last" term | ||
138 | // (first during encode). Unspecified weights are set to zero. | ||
139 | |||
140 | int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) | ||
141 | { | ||
142 | int termcnt = wpmd->byte_length, tcount; | ||
143 | char *byteptr = wpmd->data; | ||
144 | struct decorr_pass *dpp; | ||
145 | |||
146 | if (!(wps->wphdr.flags & MONO_FLAG)) | ||
147 | termcnt /= 2; | ||
148 | |||
149 | if (termcnt > wps->num_terms) | ||
150 | return FALSE; | ||
151 | |||
152 | for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) | ||
153 | dpp->weight_A = dpp->weight_B = 0; | ||
154 | |||
155 | while (--dpp >= wps->decorr_passes && termcnt--) { | ||
156 | dpp->weight_A = restore_weight (*byteptr++); | ||
157 | |||
158 | if (!(wps->wphdr.flags & MONO_FLAG)) | ||
159 | dpp->weight_B = restore_weight (*byteptr++); | ||
160 | } | ||
161 | |||
162 | return TRUE; | ||
163 | } | ||
164 | |||
165 | // Read decorrelation samples from specified metadata block into the | ||
166 | // decorr_passes array. The samples are signed 32-bit values, but are | ||
167 | // converted to signed log2 values for storage in metadata. Values are | ||
168 | // stored for both channels and are specified from the "last" term | ||
169 | // (first during encode) with unspecified samples set to zero. The | ||
170 | // number of samples stored varies with the actual term value, so | ||
171 | // those must obviously come first in the metadata. | ||
172 | |||
173 | int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) | ||
174 | { | ||
175 | uchar *byteptr = wpmd->data; | ||
176 | uchar *endptr = byteptr + wpmd->byte_length; | ||
177 | struct decorr_pass *dpp; | ||
178 | int tcount; | ||
179 | |||
180 | for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { | ||
181 | CLEAR (dpp->samples_A); | ||
182 | CLEAR (dpp->samples_B); | ||
183 | } | ||
184 | |||
185 | if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) { | ||
186 | byteptr += 2; | ||
187 | |||
188 | if (!(wps->wphdr.flags & MONO_FLAG)) | ||
189 | byteptr += 2; | ||
190 | } | ||
191 | |||
192 | while (dpp-- > wps->decorr_passes && byteptr < endptr) | ||
193 | if (dpp->term > MAX_TERM) { | ||
194 | dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); | ||
195 | dpp->samples_A [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); | ||
196 | byteptr += 4; | ||
197 | |||
198 | if (!(wps->wphdr.flags & MONO_FLAG)) { | ||
199 | dpp->samples_B [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); | ||
200 | dpp->samples_B [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); | ||
201 | byteptr += 4; | ||
202 | } | ||
203 | } | ||
204 | else if (dpp->term < 0) { | ||
205 | dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); | ||
206 | dpp->samples_B [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); | ||
207 | byteptr += 4; | ||
208 | } | ||
209 | else { | ||
210 | int m = 0, cnt = dpp->term; | ||
211 | |||
212 | while (cnt--) { | ||
213 | dpp->samples_A [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); | ||
214 | byteptr += 2; | ||
215 | |||
216 | if (!(wps->wphdr.flags & MONO_FLAG)) { | ||
217 | dpp->samples_B [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); | ||
218 | byteptr += 2; | ||
219 | } | ||
220 | |||
221 | m++; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return byteptr == endptr; | ||
226 | } | ||
227 | |||
228 | // Read the int32 data from the specified metadata into the specified stream. | ||
229 | // This data is used for integer data that has more than 24 bits of magnitude | ||
230 | // or, in some cases, used to eliminate redundant bits from any audio stream. | ||
231 | |||
232 | int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) | ||
233 | { | ||
234 | int bytecnt = wpmd->byte_length; | ||
235 | char *byteptr = wpmd->data; | ||
236 | |||
237 | if (bytecnt != 4) | ||
238 | return FALSE; | ||
239 | |||
240 | wps->int32_sent_bits = *byteptr++; | ||
241 | wps->int32_zeros = *byteptr++; | ||
242 | wps->int32_ones = *byteptr++; | ||
243 | wps->int32_dups = *byteptr; | ||
244 | return TRUE; | ||
245 | } | ||
246 | |||
247 | // Read multichannel information from metadata. The first byte is the total | ||
248 | // number of channels and the following bytes represent the channel_mask | ||
249 | // as described for Microsoft WAVEFORMATEX. | ||
250 | |||
251 | int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) | ||
252 | { | ||
253 | int bytecnt = wpmd->byte_length, shift = 0; | ||
254 | char *byteptr = wpmd->data; | ||
255 | ulong mask = 0; | ||
256 | |||
257 | if (!bytecnt || bytecnt > 5) | ||
258 | return FALSE; | ||
259 | |||
260 | wpc->config.num_channels = *byteptr++; | ||
261 | |||
262 | while (--bytecnt) { | ||
263 | mask |= (ulong) *byteptr++ << shift; | ||
264 | shift += 8; | ||
265 | } | ||
266 | |||
267 | wpc->config.channel_mask = mask; | ||
268 | return TRUE; | ||
269 | } | ||
270 | |||
271 | // Read configuration information from metadata. | ||
272 | |||
273 | int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) | ||
274 | { | ||
275 | int bytecnt = wpmd->byte_length; | ||
276 | uchar *byteptr = wpmd->data; | ||
277 | |||
278 | if (bytecnt >= 3) { | ||
279 | wpc->config.flags &= 0xff; | ||
280 | wpc->config.flags |= (long) *byteptr++ << 8; | ||
281 | wpc->config.flags |= (long) *byteptr++ << 16; | ||
282 | wpc->config.flags |= (long) *byteptr << 24; | ||
283 | } | ||
284 | |||
285 | return TRUE; | ||
286 | } | ||
287 | |||
288 | // This monster actually unpacks the WavPack bitstream(s) into the specified | ||
289 | // buffer as 32-bit integers or floats (depending on orignal data). Lossy | ||
290 | // samples will be clipped to their original limits (i.e. 8-bit samples are | ||
291 | // clipped to -128/+127) but are still returned in longs. It is up to the | ||
292 | // caller to potentially reformat this for the final output including any | ||
293 | // multichannel distribution, block alignment or endian compensation. The | ||
294 | // function unpack_init() must have been called and the entire WavPack block | ||
295 | // must still be visible (although wps->blockbuff will not be accessed again). | ||
296 | // For maximum clarity, the function is broken up into segments that handle | ||
297 | // various modes. This makes for a few extra infrequent flag checks, but | ||
298 | // makes the code easier to follow because the nesting does not become so | ||
299 | // deep. For maximum efficiency, the conversion is isolated to tight loops | ||
300 | // that handle an entire buffer. The function returns the total number of | ||
301 | // samples unpacked, which can be less than the number requested if an error | ||
302 | // occurs or the end of the block is reached. | ||
303 | |||
304 | static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count); | ||
305 | |||
306 | long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count) | ||
307 | { | ||
308 | WavpackStream *wps = &wpc->stream; | ||
309 | ulong flags = wps->wphdr.flags, crc = wps->crc, i; | ||
310 | long mute_limit = (1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2; | ||
311 | struct decorr_pass *dpp; | ||
312 | long read_word, *bptr; | ||
313 | int tcount, m = 0; | ||
314 | |||
315 | if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples) | ||
316 | sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; | ||
317 | |||
318 | if (wps->mute_error) { | ||
319 | memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); | ||
320 | wps->sample_index += sample_count; | ||
321 | return sample_count; | ||
322 | } | ||
323 | |||
324 | if (flags & HYBRID_FLAG) | ||
325 | mute_limit *= 2; | ||
326 | |||
327 | ///////////////////// handle version 4 mono data ///////////////////////// | ||
328 | |||
329 | if (flags & MONO_FLAG) | ||
330 | for (bptr = buffer, i = 0; i < sample_count; ++i) { | ||
331 | if ((read_word = get_word (wps, 0)) == WORD_EOF) | ||
332 | break; | ||
333 | |||
334 | for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { | ||
335 | long sam, temp; | ||
336 | int k; | ||
337 | |||
338 | if (dpp->term > MAX_TERM) { | ||
339 | if (dpp->term & 1) | ||
340 | sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; | ||
341 | else | ||
342 | sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; | ||
343 | |||
344 | dpp->samples_A [1] = dpp->samples_A [0]; | ||
345 | k = 0; | ||
346 | } | ||
347 | else { | ||
348 | sam = dpp->samples_A [m]; | ||
349 | k = (m + dpp->term) & (MAX_TERM - 1); | ||
350 | } | ||
351 | |||
352 | temp = apply_weight (dpp->weight_A, sam) + read_word; | ||
353 | update_weight (dpp->weight_A, dpp->delta, sam, read_word); | ||
354 | dpp->samples_A [k] = read_word = temp; | ||
355 | } | ||
356 | |||
357 | if (labs (read_word) > mute_limit) | ||
358 | break; | ||
359 | |||
360 | m = (m + 1) & (MAX_TERM - 1); | ||
361 | crc = crc * 3 + read_word; | ||
362 | *bptr++ = read_word; | ||
363 | } | ||
364 | |||
365 | //////////////////// handle version 4 stereo data //////////////////////// | ||
366 | |||
367 | else | ||
368 | for (bptr = buffer, i = 0; i < sample_count; ++i) { | ||
369 | long left, right, left2, right2; | ||
370 | |||
371 | if ((left = get_word (wps, 0)) == WORD_EOF || | ||
372 | (right = get_word (wps, 1)) == WORD_EOF) | ||
373 | break; | ||
374 | |||
375 | for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) | ||
376 | if (dpp->term > 0) { | ||
377 | long sam_A, sam_B; | ||
378 | int k; | ||
379 | |||
380 | if (dpp->term > MAX_TERM) { | ||
381 | if (dpp->term & 1) { | ||
382 | sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; | ||
383 | sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; | ||
384 | } | ||
385 | else { | ||
386 | sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; | ||
387 | sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; | ||
388 | } | ||
389 | |||
390 | dpp->samples_A [1] = dpp->samples_A [0]; | ||
391 | dpp->samples_B [1] = dpp->samples_B [0]; | ||
392 | k = 0; | ||
393 | } | ||
394 | else { | ||
395 | sam_A = dpp->samples_A [m]; | ||
396 | sam_B = dpp->samples_B [m]; | ||
397 | k = (m + dpp->term) & (MAX_TERM - 1); | ||
398 | } | ||
399 | |||
400 | left2 = apply_weight (dpp->weight_A, sam_A) + left; | ||
401 | right2 = apply_weight (dpp->weight_B, sam_B) + right; | ||
402 | |||
403 | update_weight (dpp->weight_A, dpp->delta, sam_A, left); | ||
404 | update_weight (dpp->weight_B, dpp->delta, sam_B, right); | ||
405 | |||
406 | dpp->samples_A [k] = left = left2; | ||
407 | dpp->samples_B [k] = right = right2; | ||
408 | } | ||
409 | else if (dpp->term == -1) { | ||
410 | left2 = left + apply_weight (dpp->weight_A, dpp->samples_A [0]); | ||
411 | update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); | ||
412 | left = left2; | ||
413 | right2 = right + apply_weight (dpp->weight_B, left2); | ||
414 | update_weight_clip (dpp->weight_B, dpp->delta, left2, right); | ||
415 | dpp->samples_A [0] = right = right2; | ||
416 | } | ||
417 | else { | ||
418 | right2 = right + apply_weight (dpp->weight_B, dpp->samples_B [0]); | ||
419 | update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); | ||
420 | right = right2; | ||
421 | |||
422 | if (dpp->term == -3) { | ||
423 | right2 = dpp->samples_A [0]; | ||
424 | dpp->samples_A [0] = right; | ||
425 | } | ||
426 | |||
427 | left2 = left + apply_weight (dpp->weight_A, right2); | ||
428 | update_weight_clip (dpp->weight_A, dpp->delta, right2, left); | ||
429 | dpp->samples_B [0] = left = left2; | ||
430 | } | ||
431 | |||
432 | m = (m + 1) & (MAX_TERM - 1); | ||
433 | |||
434 | if (flags & JOINT_STEREO) | ||
435 | left += (right -= (left >> 1)); | ||
436 | |||
437 | if (labs (left) > mute_limit || labs (right) > mute_limit) | ||
438 | break; | ||
439 | |||
440 | crc = (crc * 3 + left) * 3 + right; | ||
441 | *bptr++ = left; | ||
442 | *bptr++ = right; | ||
443 | } | ||
444 | |||
445 | if (i != sample_count) { | ||
446 | memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); | ||
447 | wps->mute_error = TRUE; | ||
448 | i = sample_count; | ||
449 | } | ||
450 | |||
451 | while (m--) | ||
452 | for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) | ||
453 | if (dpp->term > 0 && dpp->term <= MAX_TERM) { | ||
454 | long temp = dpp->samples_A [0]; | ||
455 | memcpy (dpp->samples_A, dpp->samples_A + 1, sizeof (dpp->samples_A) - sizeof (dpp->samples_A [0])); | ||
456 | dpp->samples_A [MAX_TERM - 1] = temp; | ||
457 | temp = dpp->samples_B [0]; | ||
458 | memcpy (dpp->samples_B, dpp->samples_B + 1, sizeof (dpp->samples_B) - sizeof (dpp->samples_B [0])); | ||
459 | dpp->samples_B [MAX_TERM - 1] = temp; | ||
460 | } | ||
461 | |||
462 | fixup_samples (wps, buffer, i); | ||
463 | |||
464 | if (flags & FLOAT_DATA) | ||
465 | float_normalize (buffer, (flags & MONO_FLAG) ? i : i * 2, | ||
466 | 127 - wps->float_norm_exp + wpc->norm_offset); | ||
467 | |||
468 | wps->sample_index += i; | ||
469 | wps->crc = crc; | ||
470 | |||
471 | return i; | ||
472 | } | ||
473 | |||
474 | // This is a helper function for unpack_samples() that applies several final | ||
475 | // operations. First, if the data is 32-bit float data, then that conversion | ||
476 | // is done in the float.c module (whether lossy or lossless) and we return. | ||
477 | // Otherwise, if the extended integer data applies, then that operation is | ||
478 | // executed first. If the unpacked data is lossy (and not corrected) then | ||
479 | // it is clipped and shifted in a single operation. Otherwise, if it's | ||
480 | // lossless then the last step is to apply the final shift (if any). | ||
481 | |||
482 | static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count) | ||
483 | { | ||
484 | ulong flags = wps->wphdr.flags; | ||
485 | int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; | ||
486 | |||
487 | if (flags & FLOAT_DATA) { | ||
488 | float_values (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2); | ||
489 | return; | ||
490 | } | ||
491 | |||
492 | if (flags & INT32_DATA) { | ||
493 | ulong count = (flags & MONO_FLAG) ? sample_count : sample_count * 2; | ||
494 | int sent_bits = wps->int32_sent_bits, zeros = wps->int32_zeros; | ||
495 | int ones = wps->int32_ones, dups = wps->int32_dups; | ||
496 | // ulong mask = (1 << sent_bits) - 1; | ||
497 | long *dptr = buffer; | ||
498 | |||
499 | if (!(flags & HYBRID_FLAG) && !sent_bits && (zeros + ones + dups)) | ||
500 | while (count--) { | ||
501 | if (zeros) | ||
502 | *dptr <<= zeros; | ||
503 | else if (ones) | ||
504 | *dptr = ((*dptr + 1) << ones) - 1; | ||
505 | else if (dups) | ||
506 | *dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1); | ||
507 | |||
508 | dptr++; | ||
509 | } | ||
510 | else | ||
511 | shift += zeros + sent_bits + ones + dups; | ||
512 | } | ||
513 | |||
514 | if (flags & HYBRID_FLAG) { | ||
515 | long min_value, max_value, min_shifted, max_shifted; | ||
516 | |||
517 | switch (flags & BYTES_STORED) { | ||
518 | case 0: | ||
519 | min_shifted = (min_value = -128 >> shift) << shift; | ||
520 | max_shifted = (max_value = 127 >> shift) << shift; | ||
521 | break; | ||
522 | |||
523 | case 1: | ||
524 | min_shifted = (min_value = -32768 >> shift) << shift; | ||
525 | max_shifted = (max_value = 32767 >> shift) << shift; | ||
526 | break; | ||
527 | |||
528 | case 2: | ||
529 | min_shifted = (min_value = -8388608 >> shift) << shift; | ||
530 | max_shifted = (max_value = 8388607 >> shift) << shift; | ||
531 | break; | ||
532 | |||
533 | case 3: | ||
534 | min_shifted = (min_value = -(long)2147483648 >> shift) << shift; | ||
535 | max_shifted = (max_value = (long) 2147483647 >> shift) << shift; | ||
536 | break; | ||
537 | } | ||
538 | |||
539 | if (!(flags & MONO_FLAG)) | ||
540 | sample_count *= 2; | ||
541 | |||
542 | while (sample_count--) { | ||
543 | if (*buffer < min_value) | ||
544 | *buffer++ = min_shifted; | ||
545 | else if (*buffer > max_value) | ||
546 | *buffer++ = max_shifted; | ||
547 | else | ||
548 | *buffer++ <<= shift; | ||
549 | } | ||
550 | } | ||
551 | else if (shift) { | ||
552 | if (!(flags & MONO_FLAG)) | ||
553 | sample_count *= 2; | ||
554 | |||
555 | while (sample_count--) | ||
556 | *buffer++ <<= shift; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | // This function checks the crc value(s) for an unpacked block, returning the | ||
561 | // number of actual crc errors detected for the block. The block must be | ||
562 | // completely unpacked before this test is valid. For losslessly unpacked | ||
563 | // blocks of float or extended integer data the extended crc is also checked. | ||
564 | // Note that WavPack's crc is not a CCITT approved polynomial algorithm, but | ||
565 | // is a much simpler method that is virtually as robust for real world data. | ||
566 | |||
567 | int check_crc_error (WavpackContext *wpc) | ||
568 | { | ||
569 | WavpackStream *wps = &wpc->stream; | ||
570 | int result = 0; | ||
571 | |||
572 | if (wps->crc != wps->wphdr.crc) | ||
573 | ++result; | ||
574 | |||
575 | return result; | ||
576 | } | ||