diff options
author | Dave Bryant <bryant@rockbox.org> | 2005-07-09 23:14:41 +0000 |
---|---|---|
committer | Dave Bryant <bryant@rockbox.org> | 2005-07-09 23:14:41 +0000 |
commit | 85e03767f7f59eabfdb2e6aaffdebb63e48a0d00 (patch) | |
tree | d2553b044d4a88d2ee49a3e358b74759e9d16f14 | |
parent | d1af08f9cb347009f57b282b734ae5f5abd878da (diff) | |
download | rockbox-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.c | 270 | ||||
-rw-r--r-- | apps/codecs/libwavpack/wavpack.h | 20 | ||||
-rw-r--r-- | apps/codecs/libwavpack/words.c | 256 | ||||
-rw-r--r-- | apps/codecs/libwavpack/wputils.c | 98 | ||||
-rw-r--r-- | apps/plugins/wav2wv.c | 74 |
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 | ||
30 | static const char default_terms [] = { 18,18,2,3,-2,0 }; | 30 | static const char default_terms [] = { 18,18,2,3,-2,0 }; |
31 | static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 }; | 31 | static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,0 }; |
32 | static const char fast_terms [] = { 17,17,0 }; | 32 | static 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 | |||
216 | static int pack_samples (WavpackContext *wpc, long *buffer); | ||
217 | |||
218 | int 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 | ||
268 | static int pack_samples (WavpackContext *wpc, long *buffer) | 218 | int 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 | |||
267 | static void decorr_stereo_pass (struct decorr_pass *dpp, long *bptr, long *eptr, int m); | ||
268 | static void decorr_stereo_pass_18 (struct decorr_pass *dpp, long *bptr, long *eptr); | ||
269 | static void decorr_stereo_pass_17 (struct decorr_pass *dpp, long *bptr, long *eptr); | ||
270 | static void decorr_stereo_pass_m2 (struct decorr_pass *dpp, long *bptr, long *eptr); | ||
271 | |||
272 | int 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); | 353 | static 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 | |||
372 | static 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 | |||
392 | static 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 | |||
407 | static 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 | |||
427 | int 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 | ||
366 | void pack_init (WavpackContext *wpc); | 362 | void pack_init (WavpackContext *wpc); |
367 | int pack_block (WavpackContext *wpc, long *buffer); | 363 | int pack_start_block (WavpackContext *wpc); |
364 | int pack_samples (WavpackContext *wpc, long *buffer, ulong sample_count); | ||
365 | int 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); | |||
381 | int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd); | 379 | int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd); |
382 | long get_words (long *buffer, int nsamples, ulong flags, | 380 | long get_words (long *buffer, int nsamples, ulong flags, |
383 | struct words_data *w, Bitstream *bs); | 381 | struct words_data *w, Bitstream *bs); |
384 | void send_word_lossless (WavpackStream *wps, long value, int chan); | 382 | void send_word_lossless (long value, int chan, |
385 | void flush_word (WavpackStream *wps); | 383 | struct words_data *w, Bitstream *bs); |
384 | void send_words (long *buffer, int nsamples, ulong flags, | ||
385 | struct words_data *w, Bitstream *bs); | ||
386 | void flush_word (struct words_data *w, Bitstream *bs); | ||
386 | int log2s (long value); | 387 | int log2s (long value); |
387 | long exp2s (int log); | 388 | long exp2s (int log); |
388 | char store_weight (int weight); | 389 | char store_weight (int weight); |
@@ -421,9 +422,10 @@ int WavpackGetBytesPerSample (WavpackContext *wpc); | |||
421 | int WavpackGetNumChannels (WavpackContext *wpc); | 422 | int WavpackGetNumChannels (WavpackContext *wpc); |
422 | int WavpackGetReducedChannels (WavpackContext *wpc); | 423 | int WavpackGetReducedChannels (WavpackContext *wpc); |
423 | WavpackContext *WavpackOpenFileOutput (void); | 424 | WavpackContext *WavpackOpenFileOutput (void); |
424 | void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end); | ||
425 | int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples); | 425 | int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples); |
426 | void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount); | 426 | void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount); |
427 | ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count); | 427 | int WavpackStartBlock (WavpackContext *wpc, uchar *begin, uchar *end); |
428 | int WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count); | ||
429 | ulong 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 | ||
69 | const 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 | |||
80 | const 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 | |||
91 | const char nbits_table [] = { | 69 | const 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 | 517 | void 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 | |||
543 | void 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 | ||
649 | void flush_word (WavpackStream *wps) | 633 | void 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 | |||
373 | void 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 | ||
483 | void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount) | 470 | void 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 | |||
480 | int 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 | |||
500 | ulong 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; | 496 | int 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) { | 509 | ulong 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 | |||
97 | static long temp_buffer [TEMP_SAMPLES] IDATA_ATTR; | ||
98 | |||
95 | static int wav2wv (char *filename) | 99 | static 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!"); |