summaryrefslogtreecommitdiff
path: root/apps/codecs/libwavpack/pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libwavpack/pack.c')
-rw-r--r--apps/codecs/libwavpack/pack.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/apps/codecs/libwavpack/pack.c b/apps/codecs/libwavpack/pack.c
new file mode 100644
index 0000000000..e695388d45
--- /dev/null
+++ b/apps/codecs/libwavpack/pack.c
@@ -0,0 +1,450 @@
1////////////////////////////////////////////////////////////////////////////
2// **** WAVPACK **** //
3// Hybrid Lossless Wavefile Compressor //
4// Copyright (c) 1998 - 2005 Conifer Software. //
5// All Rights Reserved. //
6// Distributed under the BSD Software License (see license.txt) //
7////////////////////////////////////////////////////////////////////////////
8
9// pack.c
10
11// This module actually handles the compression of the audio data, except for
12// the entropy coding which is handled by the words? modules. For efficiency,
13// the conversion is isolated to tight loops that handle an entire buffer.
14
15#include "wavpack.h"
16
17#include <string.h>
18
19// This flag provides faster encoding speed at the expense of more code. The
20// improvement applies to 16-bit stereo lossless only.
21
22//////////////////////////////// local tables ///////////////////////////////
23
24// These two tables specify the characteristics of the decorrelation filters.
25// Each term represents one layer of the sequential filter, where positive
26// values indicate the relative sample involved from the same channel (1=prev),
27// 17 & 18 are special functions using the previous 2 samples, and negative
28// values indicate cross channel decorrelation (in stereo only).
29
30static const char default_terms [] = { 18,18,2,3,-2,0 };
31static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 };
32static const char fast_terms [] = { 17,17,0 };
33
34///////////////////////////// executable code ////////////////////////////////
35
36// This function initializes everything required to pack WavPack bitstreams
37// and must be called BEFORE any other function in this module.
38
39void pack_init (WavpackContext *wpc)
40{
41 WavpackStream *wps = &wpc->stream;
42 ulong flags = wps->wphdr.flags;
43 struct decorr_pass *dpp;
44 const char *term_string;
45 int ti;
46
47 wps->sample_index = 0;
48 CLEAR (wps->decorr_passes);
49
50 if (wpc->config.flags & CONFIG_HIGH_FLAG)
51 term_string = high_terms;
52 else if (wpc->config.flags & CONFIG_FAST_FLAG)
53 term_string = fast_terms;
54 else
55 term_string = default_terms;
56
57 for (dpp = wps->decorr_passes, ti = 0; term_string [ti]; ti++)
58 if (term_string [ti] >= 0 || (flags & CROSS_DECORR)) {
59 dpp->term = term_string [ti];
60 dpp++->delta = 2;
61 }
62 else if (!(flags & MONO_FLAG)) {
63 dpp->term = -3;
64 dpp++->delta = 2;
65 }
66
67 wps->num_terms = dpp - wps->decorr_passes;
68 init_words (wps);
69}
70
71// Allocate room for and copy the decorrelation terms from the decorr_passes
72// array into the specified metadata structure. Both the actual term id and
73// the delta are packed into single characters.
74
75static void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd)
76{
77 int tcount = wps->num_terms;
78 struct decorr_pass *dpp;
79 char *byteptr;
80
81 byteptr = wpmd->data = wpmd->temp_data;
82 wpmd->id = ID_DECORR_TERMS;
83
84 for (dpp = wps->decorr_passes; tcount--; ++dpp)
85 *byteptr++ = ((dpp->term + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0);
86
87 wpmd->byte_length = byteptr - (char *) wpmd->data;
88}
89
90// Allocate room for and copy the decorrelation term weights from the
91// decorr_passes array into the specified metadata structure. The weights
92// range +/-1024, but are rounded and truncated to fit in signed chars for
93// metadata storage. Weights are separate for the two channels
94
95static void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd)
96{
97 int tcount = wps->num_terms;
98 struct decorr_pass *dpp;
99 char *byteptr;
100
101 byteptr = wpmd->data = wpmd->temp_data;
102 wpmd->id = ID_DECORR_WEIGHTS;
103
104 for (dpp = wps->decorr_passes; tcount--; ++dpp) {
105 dpp->weight_A = restore_weight (*byteptr++ = store_weight (dpp->weight_A));
106
107 if (!(wps->wphdr.flags & MONO_FLAG))
108 dpp->weight_B = restore_weight (*byteptr++ = store_weight (dpp->weight_B));
109 }
110
111 wpmd->byte_length = byteptr - (char *) wpmd->data;
112}
113
114// Allocate room for and copy the decorrelation samples from the decorr_passes
115// array into the specified metadata structure. The samples are signed 32-bit
116// values, but are converted to signed log2 values for storage in metadata.
117// Values are stored for both channels and are specified from the first term
118// with unspecified samples set to zero. The number of samples stored varies
119// with the actual term value, so those must obviously be specified before
120// these in the metadata list. Any number of terms can have their samples
121// specified from no terms to all the terms, however I have found that
122// sending more than the first term's samples is a waste. The "wcount"
123// variable can be set to the number of terms to have their samples stored.
124
125static void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd)
126{
127 int tcount = wps->num_terms, wcount = 1, temp;
128 struct decorr_pass *dpp;
129 uchar *byteptr;
130
131 byteptr = wpmd->data = wpmd->temp_data;
132 wpmd->id = ID_DECORR_SAMPLES;
133
134 for (dpp = wps->decorr_passes; tcount--; ++dpp)
135 if (wcount) {
136 if (dpp->term > MAX_TERM) {
137 dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0]));
138 *byteptr++ = temp;
139 *byteptr++ = temp >> 8;
140 dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1]));
141 *byteptr++ = temp;
142 *byteptr++ = temp >> 8;
143
144 if (!(wps->wphdr.flags & MONO_FLAG)) {
145 dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0]));
146 *byteptr++ = temp;
147 *byteptr++ = temp >> 8;
148 dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1]));
149 *byteptr++ = temp;
150 *byteptr++ = temp >> 8;
151 }
152 }
153 else if (dpp->term < 0) {
154 dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0]));
155 *byteptr++ = temp;
156 *byteptr++ = temp >> 8;
157 dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0]));
158 *byteptr++ = temp;
159 *byteptr++ = temp >> 8;
160 }
161 else {
162 int m = 0, cnt = dpp->term;
163
164 while (cnt--) {
165 dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m]));
166 *byteptr++ = temp;
167 *byteptr++ = temp >> 8;
168
169 if (!(wps->wphdr.flags & MONO_FLAG)) {
170 dpp->samples_B [m] = exp2s (temp = log2s (dpp->samples_B [m]));
171 *byteptr++ = temp;
172 *byteptr++ = temp >> 8;
173 }
174
175 m++;
176 }
177 }
178
179 wcount--;
180 }
181 else {
182 CLEAR (dpp->samples_A);
183 CLEAR (dpp->samples_B);
184 }
185
186 wpmd->byte_length = byteptr - (uchar *) wpmd->data;
187}
188
189// Allocate room for and copy the configuration information into the specified
190// metadata structure. Currently, we just store the upper 3 bytes of
191// config.flags and only in the first block of audio data. Note that this is
192// for informational purposes not required for playback or decoding (like
193// whether high or fast mode was specified).
194
195static void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd)
196{
197 char *byteptr;
198
199 byteptr = wpmd->data = wpmd->temp_data;
200 wpmd->id = ID_CONFIG_BLOCK;
201 *byteptr++ = (char) (wpc->config.flags >> 8);
202 *byteptr++ = (char) (wpc->config.flags >> 16);
203 *byteptr++ = (char) (wpc->config.flags >> 24);
204 wpmd->byte_length = byteptr - (char *) wpmd->data;
205}
206
207// Pack an entire block of samples (either mono or stereo) into a completed
208// WavPack block. This function is actually a shell for pack_samples() and
209// performs tasks like handling any shift required by the format, preprocessing
210// of floating point data or integer data over 24 bits wide, and implementing
211// the "extra" mode (via the extra?.c modules). It is assumed that there is
212// sufficient space for the completed block at "wps->blockbuff" and that
213// "wps->blockend" points to the end of the available space. A return value of
214// FALSE indicates an error.
215
216static int pack_samples (WavpackContext *wpc, long *buffer);
217
218int pack_block (WavpackContext *wpc, long *buffer)
219{
220 WavpackStream *wps = &wpc->stream;
221 ulong flags = wps->wphdr.flags, sflags = wps->wphdr.flags;
222 ulong sample_count = wps->wphdr.block_samples;
223
224 if (flags & SHIFT_MASK) {
225 int shift = (flags & SHIFT_MASK) >> SHIFT_LSB;
226 int mag = (flags & MAG_MASK) >> MAG_LSB;
227 ulong cnt = sample_count;
228 long *ptr = buffer;
229
230 if (flags & MONO_FLAG)
231 while (cnt--)
232 *ptr++ >>= shift;
233 else
234 while (cnt--) {
235 *ptr++ >>= shift;
236 *ptr++ >>= shift;
237 }
238
239 if ((mag -= shift) < 0)
240 flags &= ~MAG_MASK;
241 else
242 flags -= (1 << MAG_LSB) * shift;
243
244 wps->wphdr.flags = flags;
245 }
246
247 if (!pack_samples (wpc, buffer)) {
248 wps->wphdr.flags = sflags;
249 return FALSE;
250 }
251 else {
252 wps->wphdr.flags = sflags;
253 return TRUE;
254 }
255}
256
257// Pack an entire block of samples (either mono or stereo) into a completed
258// WavPack block. It is assumed that there is sufficient space for the
259// completed block at "wps->blockbuff" and that "wps->blockend" points to the
260// end of the available space. A return value of FALSE indicates an error.
261// Any unsent metadata is transmitted first, then required metadata for this
262// block is sent, and finally the compressed integer data is sent. If a "wpx"
263// stream is required for floating point data or large integer data, then this
264// must be handled outside this function. To find out how much data was written
265// the caller must look at the ckSize field of the written WavpackHeader, NOT
266// the one in the WavpackStream.
267
268static int pack_samples (WavpackContext *wpc, long *buffer)
269{
270 WavpackStream *wps = &wpc->stream;
271 ulong sample_count = wps->wphdr.block_samples;
272 ulong flags = wps->wphdr.flags, data_count;
273 struct decorr_pass *dpp;
274 WavpackMetadata wpmd;
275 int tcount, m = 0;
276 ulong crc, i;
277 long *bptr;
278
279 crc = 0xffffffff;
280 wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
281 memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
282
283 if (wpc->wrapper_bytes) {
284 wpmd.id = ID_RIFF_HEADER;
285 wpmd.byte_length = wpc->wrapper_bytes;
286 wpmd.data = wpc->wrapper_data;
287 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
288 free_metadata (&wpmd);
289 wpc->wrapper_data = NULL;
290 wpc->wrapper_bytes = 0;
291 }
292
293 if (!sample_count)
294 return TRUE;
295
296 write_decorr_terms (wps, &wpmd);
297 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
298 free_metadata (&wpmd);
299
300 write_decorr_weights (wps, &wpmd);
301 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
302 free_metadata (&wpmd);
303
304 write_decorr_samples (wps, &wpmd);
305 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
306 free_metadata (&wpmd);
307
308 write_entropy_vars (wps, &wpmd);
309 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
310 free_metadata (&wpmd);
311
312 if ((flags & INITIAL_BLOCK) && !wps->sample_index) {
313 write_config_info (wpc, &wpmd);
314 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
315 free_metadata (&wpmd);
316 }
317
318 bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend);
319
320 /////////////////////// handle lossless mono mode /////////////////////////
321
322 if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG))
323 for (bptr = buffer, i = 0; i < sample_count; ++i) {
324 long code;
325
326 crc = crc * 3 + (code = *bptr++);
327
328 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
329 long sam;
330
331 if (dpp->term > MAX_TERM) {
332 if (dpp->term & 1)
333 sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
334 else
335 sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
336
337 dpp->samples_A [1] = dpp->samples_A [0];
338 dpp->samples_A [0] = code;
339 }
340 else {
341 sam = dpp->samples_A [m];
342 dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code;
343 }
344
345 code -= apply_weight_i (dpp->weight_A, sam);
346 update_weight (dpp->weight_A, 2, sam, code);
347 }
348
349 m = (m + 1) & (MAX_TERM - 1);
350 send_word_lossless (wps, code, 0);
351 }
352
353 //////////////////// handle the lossless stereo mode //////////////////////
354
355 else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG))
356 for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) {
357 long left, right, sam_A, sam_B;
358
359 crc = crc * 3 + (left = bptr [0]);
360 crc = crc * 3 + (right = bptr [1]);
361
362 if (flags & JOINT_STEREO)
363 right += ((left -= right) >> 1);
364
365 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) {
366 if (dpp->term > 0) {
367 if (dpp->term > MAX_TERM) {
368 if (dpp->term & 1) {
369 sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
370 sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
371 }
372 else {
373 sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
374 sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
375 }
376
377 dpp->samples_A [1] = dpp->samples_A [0];
378 dpp->samples_B [1] = dpp->samples_B [0];
379 dpp->samples_A [0] = left;
380 dpp->samples_B [0] = right;
381 }
382 else {
383 int k = (m + dpp->term) & (MAX_TERM - 1);
384
385 sam_A = dpp->samples_A [m];
386 sam_B = dpp->samples_B [m];
387 dpp->samples_A [k] = left;
388 dpp->samples_B [k] = right;
389 }
390
391 left -= apply_weight_i (dpp->weight_A, sam_A);
392 right -= apply_weight_i (dpp->weight_B, sam_B);
393 update_weight (dpp->weight_A, 2, sam_A, left);
394 update_weight (dpp->weight_B, 2, sam_B, right);
395 }
396 else {
397 sam_A = (dpp->term == -2) ? right : dpp->samples_A [0];
398 sam_B = (dpp->term == -1) ? left : dpp->samples_B [0];
399 dpp->samples_A [0] = right;
400 dpp->samples_B [0] = left;
401 left -= apply_weight_i (dpp->weight_A, sam_A);
402 right -= apply_weight_i (dpp->weight_B, sam_B);
403 update_weight_clip (dpp->weight_A, 2, sam_A, left);
404 update_weight_clip (dpp->weight_B, 2, sam_B, right);
405 }
406 }
407
408 m = (m + 1) & (MAX_TERM - 1);
409 send_word_lossless (wps, left, 0);
410 send_word_lossless (wps, right, 1);
411 }
412
413 if (m)
414 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
415 if (dpp->term > 0 && dpp->term <= MAX_TERM) {
416 long temp_A [MAX_TERM], temp_B [MAX_TERM];
417 int k;
418
419 memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A));
420 memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B));
421
422 for (k = 0; k < MAX_TERM; k++) {
423 dpp->samples_A [k] = temp_A [m];
424 dpp->samples_B [k] = temp_B [m];
425 m = (m + 1) & (MAX_TERM - 1);
426 }
427 }
428
429 flush_word (wps);
430 data_count = bs_close_write (&wps->wvbits);
431
432 if (data_count) {
433 if (data_count != (ulong) -1) {
434 uchar *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
435
436 *cptr++ = ID_WV_BITSTREAM | ID_LARGE;
437 *cptr++ = data_count >> 1;
438 *cptr++ = data_count >> 9;
439 *cptr++ = data_count >> 17;
440 ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4;
441 }
442 else
443 return FALSE;
444 }
445
446 ((WavpackHeader *) wps->blockbuff)->crc = crc;
447
448 wps->sample_index += sample_count;
449 return TRUE;
450}