summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Bryant <bryant@rockbox.org>2005-07-09 23:14:41 +0000
committerDave Bryant <bryant@rockbox.org>2005-07-09 23:14:41 +0000
commit85e03767f7f59eabfdb2e6aaffdebb63e48a0d00 (patch)
treed2553b044d4a88d2ee49a3e358b74759e9d16f14
parentd1af08f9cb347009f57b282b734ae5f5abd878da (diff)
downloadrockbox-85e03767f7f59eabfdb2e6aaffdebb63e48a0d00.tar.gz
rockbox-85e03767f7f59eabfdb2e6aaffdebb63e48a0d00.zip
Reorganized encoder to allow compressing blocks in smaller chunks and
improved efficiency somewhat by looping through data in tighter passes. Code is basically ready for an attempt at direct recording. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7088 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/libwavpack/pack.c270
-rw-r--r--apps/codecs/libwavpack/wavpack.h20
-rw-r--r--apps/codecs/libwavpack/words.c256
-rw-r--r--apps/codecs/libwavpack/wputils.c98
-rw-r--r--apps/plugins/wav2wv.c74
5 files changed, 369 insertions, 349 deletions
diff --git a/apps/codecs/libwavpack/pack.c b/apps/codecs/libwavpack/pack.c
index e695388d45..ef5feca367 100644
--- a/apps/codecs/libwavpack/pack.c
+++ b/apps/codecs/libwavpack/pack.c
@@ -28,7 +28,7 @@
28// values indicate cross channel decorrelation (in stereo only). 28// values indicate cross channel decorrelation (in stereo only).
29 29
30static const char default_terms [] = { 18,18,2,3,-2,0 }; 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 }; 31static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,0 };
32static const char fast_terms [] = { 17,17,0 }; 32static const char fast_terms [] = { 17,17,0 };
33 33
34///////////////////////////// executable code //////////////////////////////// 34///////////////////////////// executable code ////////////////////////////////
@@ -205,56 +205,6 @@ static void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd)
205} 205}
206 206
207// Pack an entire block of samples (either mono or stereo) into a completed 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 208// 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 209// 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. 210// end of the available space. A return value of FALSE indicates an error.
@@ -265,21 +215,18 @@ int pack_block (WavpackContext *wpc, long *buffer)
265// the caller must look at the ckSize field of the written WavpackHeader, NOT 215// the caller must look at the ckSize field of the written WavpackHeader, NOT
266// the one in the WavpackStream. 216// the one in the WavpackStream.
267 217
268static int pack_samples (WavpackContext *wpc, long *buffer) 218int pack_start_block (WavpackContext *wpc)
269{ 219{
270 WavpackStream *wps = &wpc->stream; 220 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; 221 WavpackMetadata wpmd;
275 int tcount, m = 0;
276 ulong crc, i;
277 long *bptr;
278 222
279 crc = 0xffffffff;
280 wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
281 memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader)); 223 memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
282 224
225 ((WavpackHeader *) wps->blockbuff)->ckSize = sizeof (WavpackHeader) - 8;
226 ((WavpackHeader *) wps->blockbuff)->block_index = wps->sample_index;
227 ((WavpackHeader *) wps->blockbuff)->block_samples = 0;
228 ((WavpackHeader *) wps->blockbuff)->crc = 0xffffffff;
229
283 if (wpc->wrapper_bytes) { 230 if (wpc->wrapper_bytes) {
284 wpmd.id = ID_RIFF_HEADER; 231 wpmd.id = ID_RIFF_HEADER;
285 wpmd.byte_length = wpc->wrapper_bytes; 232 wpmd.byte_length = wpc->wrapper_bytes;
@@ -290,9 +237,6 @@ static int pack_samples (WavpackContext *wpc, long *buffer)
290 wpc->wrapper_bytes = 0; 237 wpc->wrapper_bytes = 0;
291 } 238 }
292 239
293 if (!sample_count)
294 return TRUE;
295
296 write_decorr_terms (wps, &wpmd); 240 write_decorr_terms (wps, &wpmd);
297 copy_metadata (&wpmd, wps->blockbuff, wps->blockend); 241 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
298 free_metadata (&wpmd); 242 free_metadata (&wpmd);
@@ -309,7 +253,7 @@ static int pack_samples (WavpackContext *wpc, long *buffer)
309 copy_metadata (&wpmd, wps->blockbuff, wps->blockend); 253 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
310 free_metadata (&wpmd); 254 free_metadata (&wpmd);
311 255
312 if ((flags & INITIAL_BLOCK) && !wps->sample_index) { 256 if ((wps->wphdr.flags & INITIAL_BLOCK) && !wps->sample_index) {
313 write_config_info (wpc, &wpmd); 257 write_config_info (wpc, &wpmd);
314 copy_metadata (&wpmd, wps->blockbuff, wps->blockend); 258 copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
315 free_metadata (&wpmd); 259 free_metadata (&wpmd);
@@ -317,13 +261,37 @@ static int pack_samples (WavpackContext *wpc, long *buffer)
317 261
318 bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); 262 bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend);
319 263
264 return TRUE;
265}
266
267static void decorr_stereo_pass (struct decorr_pass *dpp, long *bptr, long *eptr, int m);
268static void decorr_stereo_pass_18 (struct decorr_pass *dpp, long *bptr, long *eptr);
269static void decorr_stereo_pass_17 (struct decorr_pass *dpp, long *bptr, long *eptr);
270static void decorr_stereo_pass_m2 (struct decorr_pass *dpp, long *bptr, long *eptr);
271
272int pack_samples (WavpackContext *wpc, long *buffer, ulong sample_count)
273{
274 WavpackStream *wps = &wpc->stream;
275 ulong flags = wps->wphdr.flags;
276 struct decorr_pass *dpp;
277 long *bptr, *eptr;
278 int tcount, m;
279 ulong crc;
280
281 if (!sample_count)
282 return TRUE;
283
284 eptr = buffer + sample_count * ((flags & MONO_FLAG) ? 1 : 2);
285 m = ((WavpackHeader *) wps->blockbuff)->block_samples & (MAX_TERM - 1);
286 crc = ((WavpackHeader *) wps->blockbuff)->crc;
287
320 /////////////////////// handle lossless mono mode ///////////////////////// 288 /////////////////////// handle lossless mono mode /////////////////////////
321 289
322 if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG)) 290 if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG))
323 for (bptr = buffer, i = 0; i < sample_count; ++i) { 291 for (bptr = buffer; bptr < eptr;) {
324 long code; 292 long code;
325 293
326 crc = crc * 3 + (code = *bptr++); 294 crc = crc * 3 + (code = *bptr);
327 295
328 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { 296 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
329 long sam; 297 long sam;
@@ -347,68 +315,123 @@ static int pack_samples (WavpackContext *wpc, long *buffer)
347 } 315 }
348 316
349 m = (m + 1) & (MAX_TERM - 1); 317 m = (m + 1) & (MAX_TERM - 1);
350 send_word_lossless (wps, code, 0); 318 *bptr++ = code;
351 } 319 }
352 320
353 //////////////////// handle the lossless stereo mode ////////////////////// 321 //////////////////// handle the lossless stereo mode //////////////////////
354 322
355 else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) 323 else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) {
356 for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) { 324 if (flags & JOINT_STEREO)
357 long left, right, sam_A, sam_B; 325 for (bptr = buffer; bptr < eptr; bptr += 2) {
358 326 crc = crc * 9 + (bptr [0] * 3) + bptr [1];
359 crc = crc * 3 + (left = bptr [0]); 327 bptr [1] += ((bptr [0] -= bptr [1]) >> 1);
360 crc = crc * 3 + (right = bptr [1]); 328 }
361 329 else
362 if (flags & JOINT_STEREO) 330 for (bptr = buffer; bptr < eptr; bptr += 2)
363 right += ((left -= right) >> 1); 331 crc = crc * 9 + (bptr [0] * 3) + bptr [1];
364 332
365 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) { 333 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) {
366 if (dpp->term > 0) { 334 if (dpp->term == 17)
367 if (dpp->term > MAX_TERM) { 335 decorr_stereo_pass_17 (dpp, buffer, eptr);
368 if (dpp->term & 1) { 336 else if (dpp->term == 18)
369 sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; 337 decorr_stereo_pass_18 (dpp, buffer, eptr);
370 sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; 338 else if (dpp->term >= 1 && dpp->term <= 7)
371 } 339 decorr_stereo_pass (dpp, buffer, eptr, m);
372 else { 340 else if (dpp->term == -2)
373 sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; 341 decorr_stereo_pass_m2 (dpp, buffer, eptr);
374 sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; 342 }
375 } 343 }
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 344
385 sam_A = dpp->samples_A [m]; 345 send_words (buffer, sample_count, flags, &wps->w, &wps->wvbits);
386 sam_B = dpp->samples_B [m]; 346 ((WavpackHeader *) wps->blockbuff)->crc = crc;
387 dpp->samples_A [k] = left; 347 ((WavpackHeader *) wps->blockbuff)->block_samples += sample_count;
388 dpp->samples_B [k] = right; 348 wps->sample_index += sample_count;
389 }
390 349
391 left -= apply_weight_i (dpp->weight_A, sam_A); 350 return TRUE;
392 right -= apply_weight_i (dpp->weight_B, sam_B); 351}
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 352
408 m = (m + 1) & (MAX_TERM - 1); 353static void decorr_stereo_pass (struct decorr_pass *dpp, long *bptr, long *eptr, int m)
409 send_word_lossless (wps, left, 0); 354{
410 send_word_lossless (wps, right, 1); 355 int k = (m + dpp->term) & (MAX_TERM - 1);
411 } 356 long sam;
357
358 while (bptr < eptr) {
359 dpp->samples_A [k] = bptr [0];
360 bptr [0] -= apply_weight_i (dpp->weight_A, (sam = dpp->samples_A [m]));
361 update_weight (dpp->weight_A, 2, sam, bptr [0]);
362 bptr++;
363 dpp->samples_B [k] = bptr [0];
364 bptr [0] -= apply_weight_i (dpp->weight_B, (sam = dpp->samples_B [m]));
365 update_weight (dpp->weight_B, 2, sam, bptr [0]);
366 bptr++;
367 m = (m + 1) & (MAX_TERM - 1);
368 k = (k + 1) & (MAX_TERM - 1);
369 }
370}
371
372static void decorr_stereo_pass_18 (struct decorr_pass *dpp, long *bptr, long *eptr)
373{
374 long sam;
375
376 while (bptr < eptr) {
377 sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
378 dpp->samples_A [1] = dpp->samples_A [0];
379 dpp->samples_A [0] = bptr [0];
380 bptr [0] -= apply_weight_i (dpp->weight_A, sam);
381 update_weight (dpp->weight_A, 2, sam, bptr [0]);
382 bptr++;
383 sam = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
384 dpp->samples_B [1] = dpp->samples_B [0];
385 dpp->samples_B [0] = bptr [0];
386 bptr [0] -= apply_weight_i (dpp->weight_B, sam);
387 update_weight (dpp->weight_B, 2, sam, bptr [0]);
388 bptr++;
389 }
390}
391
392static void decorr_stereo_pass_m2 (struct decorr_pass *dpp, long *bptr, long *eptr)
393{
394 long sam_A, sam_B;
395
396 for (; bptr < eptr; bptr += 2) {
397 sam_A = bptr [1];
398 sam_B = dpp->samples_B [0];
399 dpp->samples_B [0] = bptr [0];
400 bptr [0] -= apply_weight_i (dpp->weight_A, sam_A);
401 update_weight_clip (dpp->weight_A, 2, sam_A, bptr [0]);
402 bptr [1] -= apply_weight_i (dpp->weight_B, sam_B);
403 update_weight_clip (dpp->weight_B, 2, sam_B, bptr [1]);
404 }
405}
406
407static void decorr_stereo_pass_17 (struct decorr_pass *dpp, long *bptr, long *eptr)
408{
409 long sam;
410
411 while (bptr < eptr) {
412 sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
413 dpp->samples_A [1] = dpp->samples_A [0];
414 dpp->samples_A [0] = bptr [0];
415 bptr [0] -= apply_weight_i (dpp->weight_A, sam);
416 update_weight (dpp->weight_A, 2, sam, bptr [0]);
417 bptr++;
418 sam = 2 * dpp->samples_B [0] - dpp->samples_B [1];
419 dpp->samples_B [1] = dpp->samples_B [0];
420 dpp->samples_B [0] = bptr [0];
421 bptr [0] -= apply_weight_i (dpp->weight_B, sam);
422 update_weight (dpp->weight_B, 2, sam, bptr [0]);
423 bptr++;
424 }
425}
426
427int pack_finish_block (WavpackContext *wpc)
428{
429 WavpackStream *wps = &wpc->stream;
430 struct decorr_pass *dpp;
431 ulong data_count;
432 int tcount, m;
433
434 m = ((WavpackHeader *) wps->blockbuff)->block_samples & (MAX_TERM - 1);
412 435
413 if (m) 436 if (m)
414 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) 437 for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
@@ -426,7 +449,7 @@ static int pack_samples (WavpackContext *wpc, long *buffer)
426 } 449 }
427 } 450 }
428 451
429 flush_word (wps); 452 flush_word (&wps->w, &wps->wvbits);
430 data_count = bs_close_write (&wps->wvbits); 453 data_count = bs_close_write (&wps->wvbits);
431 454
432 if (data_count) { 455 if (data_count) {
@@ -443,8 +466,5 @@ static int pack_samples (WavpackContext *wpc, long *buffer)
443 return FALSE; 466 return FALSE;
444 } 467 }
445 468
446 ((WavpackHeader *) wps->blockbuff)->crc = crc;
447
448 wps->sample_index += sample_count;
449 return TRUE; 469 return TRUE;
450} 470}
diff --git a/apps/codecs/libwavpack/wavpack.h b/apps/codecs/libwavpack/wavpack.h
index 12212bb0f8..bf9b95424e 100644
--- a/apps/codecs/libwavpack/wavpack.h
+++ b/apps/codecs/libwavpack/wavpack.h
@@ -234,10 +234,6 @@ typedef struct {
234 WavpackStream stream; 234 WavpackStream stream;
235 WavpackConfig config; 235 WavpackConfig config;
236 236
237 WavpackMetadata *metadata;
238 ulong metabytes;
239 int metacount;
240
241 uchar *wrapper_data; 237 uchar *wrapper_data;
242 int wrapper_bytes; 238 int wrapper_bytes;
243 239
@@ -364,7 +360,9 @@ int check_crc_error (WavpackContext *wpc);
364// pack.c 360// pack.c
365 361
366void pack_init (WavpackContext *wpc); 362void pack_init (WavpackContext *wpc);
367int pack_block (WavpackContext *wpc, long *buffer); 363int pack_start_block (WavpackContext *wpc);
364int pack_samples (WavpackContext *wpc, long *buffer, ulong sample_count);
365int pack_finish_block (WavpackContext *wpc);
368 366
369// metadata.c stuff 367// metadata.c stuff
370 368
@@ -381,8 +379,11 @@ void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
381int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd); 379int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
382long get_words (long *buffer, int nsamples, ulong flags, 380long get_words (long *buffer, int nsamples, ulong flags,
383 struct words_data *w, Bitstream *bs); 381 struct words_data *w, Bitstream *bs);
384void send_word_lossless (WavpackStream *wps, long value, int chan); 382void send_word_lossless (long value, int chan,
385void flush_word (WavpackStream *wps); 383 struct words_data *w, Bitstream *bs);
384void send_words (long *buffer, int nsamples, ulong flags,
385 struct words_data *w, Bitstream *bs);
386void flush_word (struct words_data *w, Bitstream *bs);
386int log2s (long value); 387int log2s (long value);
387long exp2s (int log); 388long exp2s (int log);
388char store_weight (int weight); 389char store_weight (int weight);
@@ -421,9 +422,10 @@ int WavpackGetBytesPerSample (WavpackContext *wpc);
421int WavpackGetNumChannels (WavpackContext *wpc); 422int WavpackGetNumChannels (WavpackContext *wpc);
422int WavpackGetReducedChannels (WavpackContext *wpc); 423int WavpackGetReducedChannels (WavpackContext *wpc);
423WavpackContext *WavpackOpenFileOutput (void); 424WavpackContext *WavpackOpenFileOutput (void);
424void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end);
425int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples); 425int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples);
426void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount); 426void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount);
427ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count); 427int WavpackStartBlock (WavpackContext *wpc, uchar *begin, uchar *end);
428int WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count);
429ulong WavpackFinishBlock (WavpackContext *wpc);
428 430
429 431
diff --git a/apps/codecs/libwavpack/words.c b/apps/codecs/libwavpack/words.c
index 75d8a86af7..d46bb56911 100644
--- a/apps/codecs/libwavpack/words.c
+++ b/apps/codecs/libwavpack/words.c
@@ -66,28 +66,6 @@
66 66
67///////////////////////////// local table storage //////////////////////////// 67///////////////////////////// local table storage ////////////////////////////
68 68
69const ulong bitset [] = {
70 1L << 0, 1L << 1, 1L << 2, 1L << 3,
71 1L << 4, 1L << 5, 1L << 6, 1L << 7,
72 1L << 8, 1L << 9, 1L << 10, 1L << 11,
73 1L << 12, 1L << 13, 1L << 14, 1L << 15,
74 1L << 16, 1L << 17, 1L << 18, 1L << 19,
75 1L << 20, 1L << 21, 1L << 22, 1L << 23,
76 1L << 24, 1L << 25, 1L << 26, 1L << 27,
77 1L << 28, 1L << 29, 1L << 30, 1L << 31
78};
79
80const ulong bitmask [] = {
81 (1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1,
82 (1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1,
83 (1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1,
84 (1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1,
85 (1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1,
86 (1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1,
87 (1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1,
88 (1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff
89};
90
91const char nbits_table [] = { 69const char nbits_table [] = {
92 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15 70 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15
93 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31 71 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31
@@ -536,177 +514,183 @@ static ulong read_code (Bitstream *bs, ulong maxcode)
536 return code; 514 return code;
537} 515}
538 516
539// This function is an optimized version of send_word() that only handles 517void send_words (long *buffer, int nsamples, ulong flags,
540// lossless (error_limit == 0). It does not return a value because it always 518 struct words_data *w, Bitstream *bs)
541// encodes the exact value passed.
542
543void send_word_lossless (WavpackStream *wps, long value, int chan)
544{ 519{
545 register struct words_data *w = &wps->w; 520 register struct entropy_data *c = w->c;
546 register struct entropy_data *c = w->c + chan; 521
547 int sign = (value < 0) ? 1 : 0; 522 if (!(flags & MONO_FLAG))
548 ulong ones_count, low, high; 523 nsamples *= 2;
549 524
550 if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !(wps->w.c [1].median [0] & ~1)) { 525 while (nsamples--) {
551 if (wps->w.zeros_acc) { 526 long value = *buffer++;
552 if (value) 527 int sign = (value < 0) ? 1 : 0;
553 flush_word (wps); 528 ulong ones_count, low, high;
529
530 if (!(flags & MONO_FLAG))
531 c = w->c + (~nsamples & 1);
532
533 if (!(w->c [0].median [0] & ~1) && !w->holding_zero && !(w->c [1].median [0] & ~1)) {
534 if (w->zeros_acc) {
535 if (value)
536 flush_word (w, bs);
537 else {
538 w->zeros_acc++;
539 continue;
540 }
541 }
542 else if (value) {
543 putbit_0 (bs);
544 }
554 else { 545 else {
555 wps->w.zeros_acc++; 546 CLEAR (w->c [0].median);
556 return; 547 CLEAR (w->c [1].median);
548 w->zeros_acc = 1;
549 continue;
557 } 550 }
558 } 551 }
559 else if (value) {
560 putbit_0 (&wps->wvbits);
561 }
562 else {
563 CLEAR (wps->w.c [0].median);
564 CLEAR (wps->w.c [1].median);
565 wps->w.zeros_acc = 1;
566 return;
567 }
568 }
569
570 if (sign)
571 value = ~value;
572 552
573 if ((unsigned long) value < GET_MED (0)) { 553 if (sign)
574 ones_count = low = 0; 554 value = ~value;
575 high = GET_MED (0) - 1;
576 DEC_MED0 ();
577 }
578 else {
579 low = GET_MED (0);
580 INC_MED0 ();
581 555
582 if (value - low < GET_MED (1)) { 556 if ((unsigned long) value < GET_MED (0)) {
583 ones_count = 1; 557 ones_count = low = 0;
584 high = low + GET_MED (1) - 1; 558 high = GET_MED (0) - 1;
585 DEC_MED1 (); 559 DEC_MED0 ();
586 } 560 }
587 else { 561 else {
588 low += GET_MED (1); 562 low = GET_MED (0);
589 INC_MED1 (); 563 INC_MED0 ();
590 564
591 if (value - low < GET_MED (2)) { 565 if (value - low < GET_MED (1)) {
592 ones_count = 2; 566 ones_count = 1;
593 high = low + GET_MED (2) - 1; 567 high = low + GET_MED (1) - 1;
594 DEC_MED2 (); 568 DEC_MED1 ();
595 } 569 }
596 else { 570 else {
597 ones_count = 2 + (value - low) / GET_MED (2); 571 low += GET_MED (1);
598 low += (ones_count - 2) * GET_MED (2); 572 INC_MED1 ();
599 high = low + GET_MED (2) - 1; 573
600 INC_MED2 (); 574 if (value - low < GET_MED (2)) {
575 ones_count = 2;
576 high = low + GET_MED (2) - 1;
577 DEC_MED2 ();
578 }
579 else {
580 ones_count = 2 + (value - low) / GET_MED (2);
581 low += (ones_count - 2) * GET_MED (2);
582 high = low + GET_MED (2) - 1;
583 INC_MED2 ();
584 }
601 } 585 }
602 } 586 }
603 }
604 587
605 if (wps->w.holding_zero) { 588 if (w->holding_zero) {
606 if (ones_count) 589 if (ones_count)
607 wps->w.holding_one++; 590 w->holding_one++;
608 591
609 flush_word (wps); 592 flush_word (w, bs);
610 593
611 if (ones_count) { 594 if (ones_count) {
612 wps->w.holding_zero = 1; 595 w->holding_zero = 1;
613 ones_count--; 596 ones_count--;
597 }
598 else
599 w->holding_zero = 0;
614 } 600 }
615 else 601 else
616 wps->w.holding_zero = 0; 602 w->holding_zero = 1;
617 }
618 else
619 wps->w.holding_zero = 1;
620 603
621 wps->w.holding_one = ones_count * 2; 604 w->holding_one = ones_count * 2;
622 605
623 if (high != low) { 606 if (high != low) {
624 ulong maxcode = high - low, code = value - low; 607 ulong maxcode = high - low, code = value - low;
625 int bitcount = count_bits (maxcode); 608 int bitcount = count_bits (maxcode);
626 ulong extras = bitset [bitcount] - maxcode - 1; 609 ulong extras = (1L << bitcount) - maxcode - 1;
627 610
628 if (code < extras) { 611 if (code < extras) {
629 wps->w.pend_data |= code << wps->w.pend_count; 612 w->pend_data |= code << w->pend_count;
630 wps->w.pend_count += bitcount - 1; 613 w->pend_count += bitcount - 1;
631 } 614 }
632 else { 615 else {
633 wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; 616 w->pend_data |= ((code + extras) >> 1) << w->pend_count;
634 wps->w.pend_count += bitcount - 1; 617 w->pend_count += bitcount - 1;
635 wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; 618 w->pend_data |= ((code + extras) & 1) << w->pend_count++;
619 }
636 } 620 }
637 }
638 621
639 wps->w.pend_data |= ((long) sign << wps->w.pend_count++); 622 w->pend_data |= ((long) sign << w->pend_count++);
640 623
641 if (!wps->w.holding_zero) 624 if (!w->holding_zero)
642 flush_word (wps); 625 flush_word (w, bs);
626 }
643} 627}
644 628
645// Used by send_word() and send_word_lossless() to actually send most the 629// Used by send_word() and send_word_lossless() to actually send most the
646// accumulated data onto the bitstream. This is also called directly from 630// accumulated data onto the bitstream. This is also called directly from
647// clients when all words have been sent. 631// clients when all words have been sent.
648 632
649void flush_word (WavpackStream *wps) 633void flush_word (struct words_data *w, Bitstream *bs)
650{ 634{
651 if (wps->w.zeros_acc) { 635 int cbits;
652 int cbits = count_bits (wps->w.zeros_acc); 636
637 if (w->zeros_acc) {
638 cbits = count_bits (w->zeros_acc);
653 639
654 while (cbits--) { 640 while (cbits--) {
655 putbit_1 (&wps->wvbits); 641 putbit_1 (bs);
656 } 642 }
657 643
658 putbit_0 (&wps->wvbits); 644 putbit_0 (bs);
659 645
660 while (wps->w.zeros_acc > 1) { 646 while (w->zeros_acc > 1) {
661 putbit (wps->w.zeros_acc & 1, &wps->wvbits); 647 putbit (w->zeros_acc & 1, bs);
662 wps->w.zeros_acc >>= 1; 648 w->zeros_acc >>= 1;
663 } 649 }
664 650
665 wps->w.zeros_acc = 0; 651 w->zeros_acc = 0;
666 } 652 }
667 653
668 if (wps->w.holding_one) { 654 if (w->holding_one) {
669 if (wps->w.holding_one >= LIMIT_ONES) { 655 if (w->holding_one >= LIMIT_ONES) {
670 int cbits; 656 putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, bs);
671 657 w->holding_one -= LIMIT_ONES;
672 putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits); 658 cbits = count_bits (w->holding_one);
673 wps->w.holding_one -= LIMIT_ONES;
674 cbits = count_bits (wps->w.holding_one);
675 659
676 while (cbits--) { 660 while (cbits--) {
677 putbit_1 (&wps->wvbits); 661 putbit_1 (bs);
678 } 662 }
679 663
680 putbit_0 (&wps->wvbits); 664 putbit_0 (bs);
681 665
682 while (wps->w.holding_one > 1) { 666 while (w->holding_one > 1) {
683 putbit (wps->w.holding_one & 1, &wps->wvbits); 667 putbit (w->holding_one & 1, bs);
684 wps->w.holding_one >>= 1; 668 w->holding_one >>= 1;
685 } 669 }
686 670
687 wps->w.holding_zero = 0; 671 w->holding_zero = 0;
688 } 672 }
689 else 673 else
690 putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits); 674 putbits ((1L << w->holding_one) - 1, w->holding_one, bs);
691 675
692 wps->w.holding_one = 0; 676 w->holding_one = 0;
693 } 677 }
694 678
695 if (wps->w.holding_zero) { 679 if (w->holding_zero) {
696 putbit_0 (&wps->wvbits); 680 putbit_0 (bs);
697 wps->w.holding_zero = 0; 681 w->holding_zero = 0;
698 } 682 }
699 683
700 if (wps->w.pend_count) { 684 if (w->pend_count) {
701 685
702 while (wps->w.pend_count > 24) { 686 while (w->pend_count > 24) {
703 putbit (wps->w.pend_data & 1, &wps->wvbits); 687 putbit (w->pend_data & 1, bs);
704 wps->w.pend_data >>= 1; 688 w->pend_data >>= 1;
705 wps->w.pend_count--; 689 w->pend_count--;
706 } 690 }
707 691
708 putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits); 692 putbits (w->pend_data, w->pend_count, bs);
709 wps->w.pend_data = wps->w.pend_count = 0; 693 w->pend_data = w->pend_count = 0;
710 } 694 }
711} 695}
712 696
diff --git a/apps/codecs/libwavpack/wputils.c b/apps/codecs/libwavpack/wputils.c
index 7f2ab14c44..479c18028f 100644
--- a/apps/codecs/libwavpack/wputils.c
+++ b/apps/codecs/libwavpack/wputils.c
@@ -365,17 +365,6 @@ WavpackContext *WavpackOpenFileOutput (void)
365 return &wpc; 365 return &wpc;
366} 366}
367 367
368// Set the output buffer limits. This must be done before calling
369// WavpackPackSamples(), but also may be done afterward to adjust
370// the usable buffer. Note that writing CANNOT wrap in the buffer; the
371// entire output block must fit in the buffer.
372
373void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end)
374{
375 wpc->stream.blockbuff = begin;
376 wpc->stream.blockend = end;
377}
378
379// Set configuration for writing WavPack files. This must be done before 368// Set configuration for writing WavPack files. This must be done before
380// sending any actual samples, however it is okay to send wrapper or other 369// sending any actual samples, however it is okay to send wrapper or other
381// metadata before calling this. The "config" structure contains the following 370// metadata before calling this. The "config" structure contains the following
@@ -450,35 +439,33 @@ int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong t
450 if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO)) 439 if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO))
451 flags |= JOINT_STEREO; 440 flags |= JOINT_STEREO;
452 441
442 flags |= INITIAL_BLOCK | FINAL_BLOCK;
443
444 if (num_chans == 1) {
445 flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE);
446 flags |= MONO_FLAG;
447 }
448
449 flags &= ~MAG_MASK;
450 flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7);
451
453 memcpy (wps->wphdr.ckID, "wvpk", 4); 452 memcpy (wps->wphdr.ckID, "wvpk", 4);
454 wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; 453 wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
455 wps->wphdr.total_samples = wpc->total_samples; 454 wps->wphdr.total_samples = wpc->total_samples;
456 wps->wphdr.version = 0x403; 455 wps->wphdr.version = 0x403;
457 wps->wphdr.flags = flags; 456 wps->wphdr.flags = flags;
458 457
459 wps->wphdr.flags |= INITIAL_BLOCK;
460 wps->wphdr.flags |= FINAL_BLOCK;
461
462 if (num_chans == 1) {
463 wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE);
464 wps->wphdr.flags |= MONO_FLAG;
465 }
466
467 pack_init (wpc); 458 pack_init (wpc);
468 return TRUE; 459 return TRUE;
469} 460}
470 461
471// Add wrapper (currently RIFF only) to WavPack blocks. This should be called 462// Add wrapper (currently RIFF only) to WavPack blocks. This should be called
472// before sending any audio samples for the RIFF header or after all samples 463// before sending any audio samples. If the exact contents of the RIFF header
473// have been sent for any RIFF trailer. WavpackFlushSamples() should be called 464// are not known because, for example, the file duration is uncertain or
474// between sending the last samples and calling this for trailer data to make 465// trailing chunks are possible, simply write a "dummy" header of the correct
475// sure that headers and trailers don't get mixed up in very short files. If 466// length. When all data has been written it will be possible to read the
476// the exact contents of the RIFF header are not known because, for example, 467// first block written and update the header directly. An example of this can
477// the file duration is uncertain or trailing chunks are possible, simply write 468// be found in the Audition filter.
478// a "dummy" header of the correct length. When all data has been written it
479// will be possible to read the first block written and update the header
480// directly. An example of this can be found in the Audition filter. A
481// return of FALSE indicates an error.
482 469
483void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount) 470void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount)
484{ 471{
@@ -486,38 +473,45 @@ void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount)
486 wpc->wrapper_bytes = bcount; 473 wpc->wrapper_bytes = bcount;
487} 474}
488 475
476// Start a WavPack block to be stored in the specified buffer. This must be
477// called before calling WavpackPackSamples(). Note that writing CANNOT wrap
478// in the buffer; the entire output block must fit in the buffer.
479
480int WavpackStartBlock (WavpackContext *wpc, uchar *begin, uchar *end)
481{
482 wpc->stream.blockbuff = begin;
483 wpc->stream.blockend = end;
484 return pack_start_block (wpc);
485}
486
489// Pack the specified samples. Samples must be stored in longs in the native 487// Pack the specified samples. Samples must be stored in longs in the native
490// endian format of the executing processor. The number of samples specified 488// endian format of the executing processor. The number of samples specified
491// indicates composite samples (sometimes called "frames"). So, the actual 489// indicates composite samples (sometimes called "frames"). So, the actual
492// number of data points would be this "sample_count" times the number of 490// number of data points would be this "sample_count" times the number of
493// channels. Note that samples are accumulated here until enough exist to 491// channels. The caller must decide how many samples to place in each
494// create a complete WavPack block (or several blocks for multichannel audio). 492// WavPack block (1/2 second is common), but this function may be called as
495// If an application wants to break a block at a specific sample, then it must 493// many times as desired to build the final block (and performs the actual
496// simply call WavpackFlushSamples() to force an early termination. Completed 494// compression during the call). A return of FALSE indicates an error.
497// WavPack blocks are send to the function provided in the initial call to
498// WavpackOpenFileOutput(). A return of FALSE indicates an error.
499
500ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count)
501{
502 WavpackStream *wps = &wpc->stream;
503 ulong flags = wps->wphdr.flags;
504 ulong bcount;
505 int result;
506 495
507 flags &= ~MAG_MASK; 496int WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count)
508 flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); 497{
498 if (!sample_count || pack_samples (wpc, sample_buffer, sample_count))
499 return TRUE;
509 500
510 wps->wphdr.block_index = wps->sample_index; 501 strcpy_loc (wpc->error_message, "output buffer overflowed!");
511 wps->wphdr.block_samples = sample_count; 502 return FALSE;
512 wps->wphdr.flags = flags; 503}
513 504
514 result = pack_block (wpc, sample_buffer); 505// Finish the WavPack block being built, returning the total size of the
506// block in bytes. Note that the possible conversion of the WavPack header to
507// little-endian takes place here.
515 508
516 if (!result) { 509ulong WavpackFinishBlock (WavpackContext *wpc)
517 strcpy_loc (wpc->error_message, "output buffer overflowed!"); 510{
518 return 0; 511 WavpackStream *wps = &wpc->stream;
519 } 512 ulong bcount;
520 513
514 pack_finish_block (wpc);
521 bcount = ((WavpackHeader *) wps->blockbuff)->ckSize + 8; 515 bcount = ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
522 native_to_little_endian ((WavpackHeader *) wps->blockbuff, WavpackHeaderFormat); 516 native_to_little_endian ((WavpackHeader *) wps->blockbuff, WavpackHeaderFormat);
523 517
diff --git a/apps/plugins/wav2wv.c b/apps/plugins/wav2wv.c
index 24a7f8be6d..4cb7b14f2a 100644
--- a/apps/plugins/wav2wv.c
+++ b/apps/plugins/wav2wv.c
@@ -92,6 +92,10 @@ static void wvupdate (long start_tick,
92#endif 92#endif
93} 93}
94 94
95#define TEMP_SAMPLES 4096
96
97static long temp_buffer [TEMP_SAMPLES] IDATA_ATTR;
98
95static int wav2wv (char *filename) 99static int wav2wv (char *filename)
96{ 100{
97 int in_fd, out_fd, num_chans, error = false, last_buttons; 101 int in_fd, out_fd, num_chans, error = false, last_buttons;
@@ -144,7 +148,6 @@ static int wav2wv (char *filename)
144 } 148 }
145 149
146 wpc = WavpackOpenFileOutput (); 150 wpc = WavpackOpenFileOutput ();
147 WavpackSetOutputBuffer (wpc, output_buffer, output_buffer + 0x100000);
148 151
149 rb->memset (&config, 0, sizeof (config)); 152 rb->memset (&config, 0, sizeof (config));
150 config.bits_per_sample = 16; 153 config.bits_per_sample = 16;
@@ -153,6 +156,8 @@ static int wav2wv (char *filename)
153 num_chans = config.num_channels = native_header.NumChannels; 156 num_chans = config.num_channels = native_header.NumChannels;
154 total_samples = native_header.data_ckSize / native_header.BlockAlign; 157 total_samples = native_header.data_ckSize / native_header.BlockAlign;
155 158
159// config.flags |= CONFIG_HIGH_FLAG;
160
156 if (!WavpackSetConfiguration (wpc, &config, total_samples)) { 161 if (!WavpackSetConfiguration (wpc, &config, total_samples)) {
157 rb->splash(HZ*2, true, "internal error!"); 162 rb->splash(HZ*2, true, "internal error!");
158 rb->close (in_fd); 163 rb->close (in_fd);
@@ -178,7 +183,7 @@ static int wav2wv (char *filename)
178 wvupdate (start_tick, native_header.SampleRate, total_samples, 0, 0, 0); 183 wvupdate (start_tick, native_header.SampleRate, total_samples, 0, 0, 0);
179 184
180 for (samples_remaining = total_samples; samples_remaining;) { 185 for (samples_remaining = total_samples; samples_remaining;) {
181 unsigned long samples_count, bytes_count; 186 unsigned long samples_count, samples_to_pack, bytes_count;
182 int cnt, buttons; 187 int cnt, buttons;
183 long value, *lp; 188 long value, *lp;
184 char *cp; 189 char *cp;
@@ -197,33 +202,48 @@ static int wav2wv (char *filename)
197 } 202 }
198 203
199 total_bytes_read += bytes_count; 204 total_bytes_read += bytes_count;
200 cp = (char *) input_buffer + bytes_count; 205 WavpackStartBlock (wpc, output_buffer, output_buffer + 0x100000);
201 lp = input_buffer + samples_count * num_chans; 206 samples_to_pack = samples_count;
202 cnt = samples_count; 207 cp = (char *) input_buffer;
203 208
204 if (num_chans == 2) 209 while (samples_to_pack) {
205 while (cnt--) { 210 unsigned long samples_this_pass = TEMP_SAMPLES / num_chans;
206 value = *--cp << 8; 211
207 value += *--cp & 0xff; 212 if (samples_this_pass > samples_to_pack)
208 *--lp = value; 213 samples_this_pass = samples_to_pack;
209 value = *--cp << 8; 214
210 value += *--cp & 0xff; 215 lp = temp_buffer;
211 *--lp = value; 216 cnt = samples_this_pass;
212 } 217
213 else 218 if (num_chans == 2)
214 while (cnt--) { 219 while (cnt--) {
215 value = *--cp << 8; 220 value = *cp++ & 0xff;
216 value += *--cp & 0xff; 221 value += *cp++ << 8;
217 *--lp = value; 222 *lp++ = value;
218 } 223 value = *cp++ & 0xff;
219 224 value += *cp++ << 8;
220 bytes_count = WavpackPackSamples (wpc, input_buffer, samples_count); 225 *lp++ = value;
226 }
227 else
228 while (cnt--) {
229 value = *cp++ & 0xff;
230 value += *cp++ << 8;
231 *lp++ = value;
232 }
233
234 if (!WavpackPackSamples (wpc, temp_buffer, samples_this_pass)) {
235 rb->splash(HZ*2, true, "internal error!");
236 error = true;
237 break;
238 }
239
240 samples_to_pack -= samples_this_pass;
241 }
221 242
222 if (!bytes_count) { 243 if (error)
223 rb->splash(HZ*2, true, "internal error!");
224 error = true;
225 break; 244 break;
226 } 245
246 bytes_count = WavpackFinishBlock (wpc);
227 247
228 if (rb->write (out_fd, output_buffer, bytes_count) != (long) bytes_count) { 248 if (rb->write (out_fd, output_buffer, bytes_count) != (long) bytes_count) {
229 rb->splash(HZ*2, true, "could not write file!"); 249 rb->splash(HZ*2, true, "could not write file!");