From 85e03767f7f59eabfdb2e6aaffdebb63e48a0d00 Mon Sep 17 00:00:00 2001 From: Dave Bryant Date: Sat, 9 Jul 2005 23:14:41 +0000 Subject: 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 --- apps/codecs/libwavpack/pack.c | 270 +++++++++++++++++++++------------------ apps/codecs/libwavpack/wavpack.h | 20 +-- apps/codecs/libwavpack/words.c | 256 +++++++++++++++++-------------------- apps/codecs/libwavpack/wputils.c | 98 +++++++------- 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 @@ // values indicate cross channel decorrelation (in stereo only). static const char default_terms [] = { 18,18,2,3,-2,0 }; -static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 }; +static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,0 }; static const char fast_terms [] = { 17,17,0 }; ///////////////////////////// executable code //////////////////////////////// @@ -204,56 +204,6 @@ static void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) wpmd->byte_length = byteptr - (char *) wpmd->data; } -// Pack an entire block of samples (either mono or stereo) into a completed -// WavPack block. This function is actually a shell for pack_samples() and -// performs tasks like handling any shift required by the format, preprocessing -// of floating point data or integer data over 24 bits wide, and implementing -// the "extra" mode (via the extra?.c modules). It is assumed that there is -// sufficient space for the completed block at "wps->blockbuff" and that -// "wps->blockend" points to the end of the available space. A return value of -// FALSE indicates an error. - -static int pack_samples (WavpackContext *wpc, long *buffer); - -int pack_block (WavpackContext *wpc, long *buffer) -{ - WavpackStream *wps = &wpc->stream; - ulong flags = wps->wphdr.flags, sflags = wps->wphdr.flags; - ulong sample_count = wps->wphdr.block_samples; - - if (flags & SHIFT_MASK) { - int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; - int mag = (flags & MAG_MASK) >> MAG_LSB; - ulong cnt = sample_count; - long *ptr = buffer; - - if (flags & MONO_FLAG) - while (cnt--) - *ptr++ >>= shift; - else - while (cnt--) { - *ptr++ >>= shift; - *ptr++ >>= shift; - } - - if ((mag -= shift) < 0) - flags &= ~MAG_MASK; - else - flags -= (1 << MAG_LSB) * shift; - - wps->wphdr.flags = flags; - } - - if (!pack_samples (wpc, buffer)) { - wps->wphdr.flags = sflags; - return FALSE; - } - else { - wps->wphdr.flags = sflags; - return TRUE; - } -} - // Pack an entire block of samples (either mono or stereo) into a completed // WavPack block. It is assumed that there is sufficient space for the // completed block at "wps->blockbuff" and that "wps->blockend" points to the @@ -265,21 +215,18 @@ int pack_block (WavpackContext *wpc, long *buffer) // the caller must look at the ckSize field of the written WavpackHeader, NOT // the one in the WavpackStream. -static int pack_samples (WavpackContext *wpc, long *buffer) +int pack_start_block (WavpackContext *wpc) { WavpackStream *wps = &wpc->stream; - ulong sample_count = wps->wphdr.block_samples; - ulong flags = wps->wphdr.flags, data_count; - struct decorr_pass *dpp; WavpackMetadata wpmd; - int tcount, m = 0; - ulong crc, i; - long *bptr; - crc = 0xffffffff; - wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader)); + ((WavpackHeader *) wps->blockbuff)->ckSize = sizeof (WavpackHeader) - 8; + ((WavpackHeader *) wps->blockbuff)->block_index = wps->sample_index; + ((WavpackHeader *) wps->blockbuff)->block_samples = 0; + ((WavpackHeader *) wps->blockbuff)->crc = 0xffffffff; + if (wpc->wrapper_bytes) { wpmd.id = ID_RIFF_HEADER; wpmd.byte_length = wpc->wrapper_bytes; @@ -290,9 +237,6 @@ static int pack_samples (WavpackContext *wpc, long *buffer) wpc->wrapper_bytes = 0; } - if (!sample_count) - return TRUE; - write_decorr_terms (wps, &wpmd); copy_metadata (&wpmd, wps->blockbuff, wps->blockend); free_metadata (&wpmd); @@ -309,7 +253,7 @@ static int pack_samples (WavpackContext *wpc, long *buffer) copy_metadata (&wpmd, wps->blockbuff, wps->blockend); free_metadata (&wpmd); - if ((flags & INITIAL_BLOCK) && !wps->sample_index) { + if ((wps->wphdr.flags & INITIAL_BLOCK) && !wps->sample_index) { write_config_info (wpc, &wpmd); copy_metadata (&wpmd, wps->blockbuff, wps->blockend); free_metadata (&wpmd); @@ -317,13 +261,37 @@ static int pack_samples (WavpackContext *wpc, long *buffer) bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); + return TRUE; +} + +static void decorr_stereo_pass (struct decorr_pass *dpp, long *bptr, long *eptr, int m); +static void decorr_stereo_pass_18 (struct decorr_pass *dpp, long *bptr, long *eptr); +static void decorr_stereo_pass_17 (struct decorr_pass *dpp, long *bptr, long *eptr); +static void decorr_stereo_pass_m2 (struct decorr_pass *dpp, long *bptr, long *eptr); + +int pack_samples (WavpackContext *wpc, long *buffer, ulong sample_count) +{ + WavpackStream *wps = &wpc->stream; + ulong flags = wps->wphdr.flags; + struct decorr_pass *dpp; + long *bptr, *eptr; + int tcount, m; + ulong crc; + + if (!sample_count) + return TRUE; + + eptr = buffer + sample_count * ((flags & MONO_FLAG) ? 1 : 2); + m = ((WavpackHeader *) wps->blockbuff)->block_samples & (MAX_TERM - 1); + crc = ((WavpackHeader *) wps->blockbuff)->crc; + /////////////////////// handle lossless mono mode ///////////////////////// if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { + for (bptr = buffer; bptr < eptr;) { long code; - crc = crc * 3 + (code = *bptr++); + crc = crc * 3 + (code = *bptr); for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { long sam; @@ -347,68 +315,123 @@ static int pack_samples (WavpackContext *wpc, long *buffer) } m = (m + 1) & (MAX_TERM - 1); - send_word_lossless (wps, code, 0); + *bptr++ = code; } //////////////////// handle the lossless stereo mode ////////////////////// - else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) { - long left, right, sam_A, sam_B; - - crc = crc * 3 + (left = bptr [0]); - crc = crc * 3 + (right = bptr [1]); - - if (flags & JOINT_STEREO) - right += ((left -= right) >> 1); - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) { - if (dpp->term > 0) { - if (dpp->term > MAX_TERM) { - if (dpp->term & 1) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - } - else { - sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - } - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_A [0] = left; - dpp->samples_B [0] = right; - } - else { - int k = (m + dpp->term) & (MAX_TERM - 1); + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) { + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + crc = crc * 9 + (bptr [0] * 3) + bptr [1]; + bptr [1] += ((bptr [0] -= bptr [1]) >> 1); + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) + crc = crc * 9 + (bptr [0] * 3) + bptr [1]; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) { + if (dpp->term == 17) + decorr_stereo_pass_17 (dpp, buffer, eptr); + else if (dpp->term == 18) + decorr_stereo_pass_18 (dpp, buffer, eptr); + else if (dpp->term >= 1 && dpp->term <= 7) + decorr_stereo_pass (dpp, buffer, eptr, m); + else if (dpp->term == -2) + decorr_stereo_pass_m2 (dpp, buffer, eptr); + } + } - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - dpp->samples_A [k] = left; - dpp->samples_B [k] = right; - } + send_words (buffer, sample_count, flags, &wps->w, &wps->wvbits); + ((WavpackHeader *) wps->blockbuff)->crc = crc; + ((WavpackHeader *) wps->blockbuff)->block_samples += sample_count; + wps->sample_index += sample_count; - left -= apply_weight_i (dpp->weight_A, sam_A); - right -= apply_weight_i (dpp->weight_B, sam_B); - update_weight (dpp->weight_A, 2, sam_A, left); - update_weight (dpp->weight_B, 2, sam_B, right); - } - else { - sam_A = (dpp->term == -2) ? right : dpp->samples_A [0]; - sam_B = (dpp->term == -1) ? left : dpp->samples_B [0]; - dpp->samples_A [0] = right; - dpp->samples_B [0] = left; - left -= apply_weight_i (dpp->weight_A, sam_A); - right -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_A, 2, sam_A, left); - update_weight_clip (dpp->weight_B, 2, sam_B, right); - } - } + return TRUE; +} - m = (m + 1) & (MAX_TERM - 1); - send_word_lossless (wps, left, 0); - send_word_lossless (wps, right, 1); - } +static void decorr_stereo_pass (struct decorr_pass *dpp, long *bptr, long *eptr, int m) +{ + int k = (m + dpp->term) & (MAX_TERM - 1); + long sam; + + while (bptr < eptr) { + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, (sam = dpp->samples_A [m])); + update_weight (dpp->weight_A, 2, sam, bptr [0]); + bptr++; + dpp->samples_B [k] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_B, (sam = dpp->samples_B [m])); + update_weight (dpp->weight_B, 2, sam, bptr [0]); + bptr++; + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } +} + +static void decorr_stereo_pass_18 (struct decorr_pass *dpp, long *bptr, long *eptr) +{ + long sam; + + while (bptr < eptr) { + sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam); + update_weight (dpp->weight_A, 2, sam, bptr [0]); + bptr++; + sam = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_B, sam); + update_weight (dpp->weight_B, 2, sam, bptr [0]); + bptr++; + } +} + +static void decorr_stereo_pass_m2 (struct decorr_pass *dpp, long *bptr, long *eptr) +{ + long sam_A, sam_B; + + for (; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, 2, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, 2, sam_B, bptr [1]); + } +} + +static void decorr_stereo_pass_17 (struct decorr_pass *dpp, long *bptr, long *eptr) +{ + long sam; + + while (bptr < eptr) { + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam); + update_weight (dpp->weight_A, 2, sam, bptr [0]); + bptr++; + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_B, sam); + update_weight (dpp->weight_B, 2, sam, bptr [0]); + bptr++; + } +} + +int pack_finish_block (WavpackContext *wpc) +{ + WavpackStream *wps = &wpc->stream; + struct decorr_pass *dpp; + ulong data_count; + int tcount, m; + + m = ((WavpackHeader *) wps->blockbuff)->block_samples & (MAX_TERM - 1); if (m) for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) @@ -426,7 +449,7 @@ static int pack_samples (WavpackContext *wpc, long *buffer) } } - flush_word (wps); + flush_word (&wps->w, &wps->wvbits); data_count = bs_close_write (&wps->wvbits); if (data_count) { @@ -443,8 +466,5 @@ static int pack_samples (WavpackContext *wpc, long *buffer) return FALSE; } - ((WavpackHeader *) wps->blockbuff)->crc = crc; - - wps->sample_index += sample_count; return TRUE; } 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 { WavpackStream stream; WavpackConfig config; - WavpackMetadata *metadata; - ulong metabytes; - int metacount; - uchar *wrapper_data; int wrapper_bytes; @@ -364,7 +360,9 @@ int check_crc_error (WavpackContext *wpc); // pack.c void pack_init (WavpackContext *wpc); -int pack_block (WavpackContext *wpc, long *buffer); +int pack_start_block (WavpackContext *wpc); +int pack_samples (WavpackContext *wpc, long *buffer, ulong sample_count); +int pack_finish_block (WavpackContext *wpc); // metadata.c stuff @@ -381,8 +379,11 @@ void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd); int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd); long get_words (long *buffer, int nsamples, ulong flags, struct words_data *w, Bitstream *bs); -void send_word_lossless (WavpackStream *wps, long value, int chan); -void flush_word (WavpackStream *wps); +void send_word_lossless (long value, int chan, + struct words_data *w, Bitstream *bs); +void send_words (long *buffer, int nsamples, ulong flags, + struct words_data *w, Bitstream *bs); +void flush_word (struct words_data *w, Bitstream *bs); int log2s (long value); long exp2s (int log); char store_weight (int weight); @@ -421,9 +422,10 @@ int WavpackGetBytesPerSample (WavpackContext *wpc); int WavpackGetNumChannels (WavpackContext *wpc); int WavpackGetReducedChannels (WavpackContext *wpc); WavpackContext *WavpackOpenFileOutput (void); -void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end); int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples); void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount); -ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count); +int WavpackStartBlock (WavpackContext *wpc, uchar *begin, uchar *end); +int WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count); +ulong WavpackFinishBlock (WavpackContext *wpc); 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 @@ ///////////////////////////// local table storage //////////////////////////// -const ulong bitset [] = { - 1L << 0, 1L << 1, 1L << 2, 1L << 3, - 1L << 4, 1L << 5, 1L << 6, 1L << 7, - 1L << 8, 1L << 9, 1L << 10, 1L << 11, - 1L << 12, 1L << 13, 1L << 14, 1L << 15, - 1L << 16, 1L << 17, 1L << 18, 1L << 19, - 1L << 20, 1L << 21, 1L << 22, 1L << 23, - 1L << 24, 1L << 25, 1L << 26, 1L << 27, - 1L << 28, 1L << 29, 1L << 30, 1L << 31 -}; - -const ulong bitmask [] = { - (1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1, - (1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1, - (1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1, - (1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1, - (1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1, - (1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1, - (1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1, - (1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff -}; - const char nbits_table [] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15 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) return code; } -// This function is an optimized version of send_word() that only handles -// lossless (error_limit == 0). It does not return a value because it always -// encodes the exact value passed. - -void send_word_lossless (WavpackStream *wps, long value, int chan) +void send_words (long *buffer, int nsamples, ulong flags, + struct words_data *w, Bitstream *bs) { - register struct words_data *w = &wps->w; - register struct entropy_data *c = w->c + chan; - int sign = (value < 0) ? 1 : 0; - ulong ones_count, low, high; - - if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !(wps->w.c [1].median [0] & ~1)) { - if (wps->w.zeros_acc) { - if (value) - flush_word (wps); + register struct entropy_data *c = w->c; + + if (!(flags & MONO_FLAG)) + nsamples *= 2; + + while (nsamples--) { + long value = *buffer++; + int sign = (value < 0) ? 1 : 0; + ulong ones_count, low, high; + + if (!(flags & MONO_FLAG)) + c = w->c + (~nsamples & 1); + + if (!(w->c [0].median [0] & ~1) && !w->holding_zero && !(w->c [1].median [0] & ~1)) { + if (w->zeros_acc) { + if (value) + flush_word (w, bs); + else { + w->zeros_acc++; + continue; + } + } + else if (value) { + putbit_0 (bs); + } else { - wps->w.zeros_acc++; - return; + CLEAR (w->c [0].median); + CLEAR (w->c [1].median); + w->zeros_acc = 1; + continue; } } - else if (value) { - putbit_0 (&wps->wvbits); - } - else { - CLEAR (wps->w.c [0].median); - CLEAR (wps->w.c [1].median); - wps->w.zeros_acc = 1; - return; - } - } - - if (sign) - value = ~value; - if ((unsigned long) value < GET_MED (0)) { - ones_count = low = 0; - high = GET_MED (0) - 1; - DEC_MED0 (); - } - else { - low = GET_MED (0); - INC_MED0 (); + if (sign) + value = ~value; - if (value - low < GET_MED (1)) { - ones_count = 1; - high = low + GET_MED (1) - 1; - DEC_MED1 (); + if ((unsigned long) value < GET_MED (0)) { + ones_count = low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); } else { - low += GET_MED (1); - INC_MED1 (); + low = GET_MED (0); + INC_MED0 (); - if (value - low < GET_MED (2)) { - ones_count = 2; - high = low + GET_MED (2) - 1; - DEC_MED2 (); + if (value - low < GET_MED (1)) { + ones_count = 1; + high = low + GET_MED (1) - 1; + DEC_MED1 (); } else { - ones_count = 2 + (value - low) / GET_MED (2); - low += (ones_count - 2) * GET_MED (2); - high = low + GET_MED (2) - 1; - INC_MED2 (); + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + ones_count = 2; + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } } } - } - if (wps->w.holding_zero) { - if (ones_count) - wps->w.holding_one++; + if (w->holding_zero) { + if (ones_count) + w->holding_one++; - flush_word (wps); + flush_word (w, bs); - if (ones_count) { - wps->w.holding_zero = 1; - ones_count--; + if (ones_count) { + w->holding_zero = 1; + ones_count--; + } + else + w->holding_zero = 0; } else - wps->w.holding_zero = 0; - } - else - wps->w.holding_zero = 1; + w->holding_zero = 1; - wps->w.holding_one = ones_count * 2; + w->holding_one = ones_count * 2; - if (high != low) { - ulong maxcode = high - low, code = value - low; - int bitcount = count_bits (maxcode); - ulong extras = bitset [bitcount] - maxcode - 1; + if (high != low) { + ulong maxcode = high - low, code = value - low; + int bitcount = count_bits (maxcode); + ulong extras = (1L << bitcount) - maxcode - 1; - if (code < extras) { - wps->w.pend_data |= code << wps->w.pend_count; - wps->w.pend_count += bitcount - 1; - } - else { - wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; - wps->w.pend_count += bitcount - 1; - wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; + if (code < extras) { + w->pend_data |= code << w->pend_count; + w->pend_count += bitcount - 1; + } + else { + w->pend_data |= ((code + extras) >> 1) << w->pend_count; + w->pend_count += bitcount - 1; + w->pend_data |= ((code + extras) & 1) << w->pend_count++; + } } - } - wps->w.pend_data |= ((long) sign << wps->w.pend_count++); + w->pend_data |= ((long) sign << w->pend_count++); - if (!wps->w.holding_zero) - flush_word (wps); + if (!w->holding_zero) + flush_word (w, bs); + } } // Used by send_word() and send_word_lossless() to actually send most the // accumulated data onto the bitstream. This is also called directly from // clients when all words have been sent. -void flush_word (WavpackStream *wps) +void flush_word (struct words_data *w, Bitstream *bs) { - if (wps->w.zeros_acc) { - int cbits = count_bits (wps->w.zeros_acc); + int cbits; + + if (w->zeros_acc) { + cbits = count_bits (w->zeros_acc); while (cbits--) { - putbit_1 (&wps->wvbits); + putbit_1 (bs); } - putbit_0 (&wps->wvbits); + putbit_0 (bs); - while (wps->w.zeros_acc > 1) { - putbit (wps->w.zeros_acc & 1, &wps->wvbits); - wps->w.zeros_acc >>= 1; + while (w->zeros_acc > 1) { + putbit (w->zeros_acc & 1, bs); + w->zeros_acc >>= 1; } - wps->w.zeros_acc = 0; + w->zeros_acc = 0; } - if (wps->w.holding_one) { - if (wps->w.holding_one >= LIMIT_ONES) { - int cbits; - - putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits); - wps->w.holding_one -= LIMIT_ONES; - cbits = count_bits (wps->w.holding_one); + if (w->holding_one) { + if (w->holding_one >= LIMIT_ONES) { + putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, bs); + w->holding_one -= LIMIT_ONES; + cbits = count_bits (w->holding_one); while (cbits--) { - putbit_1 (&wps->wvbits); + putbit_1 (bs); } - putbit_0 (&wps->wvbits); + putbit_0 (bs); - while (wps->w.holding_one > 1) { - putbit (wps->w.holding_one & 1, &wps->wvbits); - wps->w.holding_one >>= 1; + while (w->holding_one > 1) { + putbit (w->holding_one & 1, bs); + w->holding_one >>= 1; } - wps->w.holding_zero = 0; + w->holding_zero = 0; } else - putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits); + putbits ((1L << w->holding_one) - 1, w->holding_one, bs); - wps->w.holding_one = 0; + w->holding_one = 0; } - if (wps->w.holding_zero) { - putbit_0 (&wps->wvbits); - wps->w.holding_zero = 0; + if (w->holding_zero) { + putbit_0 (bs); + w->holding_zero = 0; } - if (wps->w.pend_count) { + if (w->pend_count) { - while (wps->w.pend_count > 24) { - putbit (wps->w.pend_data & 1, &wps->wvbits); - wps->w.pend_data >>= 1; - wps->w.pend_count--; + while (w->pend_count > 24) { + putbit (w->pend_data & 1, bs); + w->pend_data >>= 1; + w->pend_count--; } - putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits); - wps->w.pend_data = wps->w.pend_count = 0; + putbits (w->pend_data, w->pend_count, bs); + w->pend_data = w->pend_count = 0; } } 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) return &wpc; } -// Set the output buffer limits. This must be done before calling -// WavpackPackSamples(), but also may be done afterward to adjust -// the usable buffer. Note that writing CANNOT wrap in the buffer; the -// entire output block must fit in the buffer. - -void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end) -{ - wpc->stream.blockbuff = begin; - wpc->stream.blockend = end; -} - // Set configuration for writing WavPack files. This must be done before // sending any actual samples, however it is okay to send wrapper or other // metadata before calling this. The "config" structure contains the following @@ -450,35 +439,33 @@ int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong t if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO)) flags |= JOINT_STEREO; + flags |= INITIAL_BLOCK | FINAL_BLOCK; + + if (num_chans == 1) { + flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); + flags |= MONO_FLAG; + } + + flags &= ~MAG_MASK; + flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); + memcpy (wps->wphdr.ckID, "wvpk", 4); wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; wps->wphdr.total_samples = wpc->total_samples; wps->wphdr.version = 0x403; wps->wphdr.flags = flags; - wps->wphdr.flags |= INITIAL_BLOCK; - wps->wphdr.flags |= FINAL_BLOCK; - - if (num_chans == 1) { - wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); - wps->wphdr.flags |= MONO_FLAG; - } - pack_init (wpc); return TRUE; } // Add wrapper (currently RIFF only) to WavPack blocks. This should be called -// before sending any audio samples for the RIFF header or after all samples -// have been sent for any RIFF trailer. WavpackFlushSamples() should be called -// between sending the last samples and calling this for trailer data to make -// sure that headers and trailers don't get mixed up in very short files. If -// the exact contents of the RIFF header are not known because, for example, -// the file duration is uncertain or trailing chunks are possible, simply write -// a "dummy" header of the correct length. When all data has been written it -// will be possible to read the first block written and update the header -// directly. An example of this can be found in the Audition filter. A -// return of FALSE indicates an error. +// before sending any audio samples. If the exact contents of the RIFF header +// are not known because, for example, the file duration is uncertain or +// trailing chunks are possible, simply write a "dummy" header of the correct +// length. When all data has been written it will be possible to read the +// first block written and update the header directly. An example of this can +// be found in the Audition filter. void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount) { @@ -486,38 +473,45 @@ void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount) wpc->wrapper_bytes = bcount; } +// Start a WavPack block to be stored in the specified buffer. This must be +// called before calling WavpackPackSamples(). Note that writing CANNOT wrap +// in the buffer; the entire output block must fit in the buffer. + +int WavpackStartBlock (WavpackContext *wpc, uchar *begin, uchar *end) +{ + wpc->stream.blockbuff = begin; + wpc->stream.blockend = end; + return pack_start_block (wpc); +} + // Pack the specified samples. Samples must be stored in longs in the native // endian format of the executing processor. The number of samples specified // indicates composite samples (sometimes called "frames"). So, the actual // number of data points would be this "sample_count" times the number of -// channels. Note that samples are accumulated here until enough exist to -// create a complete WavPack block (or several blocks for multichannel audio). -// If an application wants to break a block at a specific sample, then it must -// simply call WavpackFlushSamples() to force an early termination. Completed -// WavPack blocks are send to the function provided in the initial call to -// WavpackOpenFileOutput(). A return of FALSE indicates an error. - -ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count) -{ - WavpackStream *wps = &wpc->stream; - ulong flags = wps->wphdr.flags; - ulong bcount; - int result; +// channels. The caller must decide how many samples to place in each +// WavPack block (1/2 second is common), but this function may be called as +// many times as desired to build the final block (and performs the actual +// compression during the call). A return of FALSE indicates an error. - flags &= ~MAG_MASK; - flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); +int WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count) +{ + if (!sample_count || pack_samples (wpc, sample_buffer, sample_count)) + return TRUE; - wps->wphdr.block_index = wps->sample_index; - wps->wphdr.block_samples = sample_count; - wps->wphdr.flags = flags; + strcpy_loc (wpc->error_message, "output buffer overflowed!"); + return FALSE; +} - result = pack_block (wpc, sample_buffer); +// Finish the WavPack block being built, returning the total size of the +// block in bytes. Note that the possible conversion of the WavPack header to +// little-endian takes place here. - if (!result) { - strcpy_loc (wpc->error_message, "output buffer overflowed!"); - return 0; - } +ulong WavpackFinishBlock (WavpackContext *wpc) +{ + WavpackStream *wps = &wpc->stream; + ulong bcount; + pack_finish_block (wpc); bcount = ((WavpackHeader *) wps->blockbuff)->ckSize + 8; native_to_little_endian ((WavpackHeader *) wps->blockbuff, WavpackHeaderFormat); 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, #endif } +#define TEMP_SAMPLES 4096 + +static long temp_buffer [TEMP_SAMPLES] IDATA_ATTR; + static int wav2wv (char *filename) { int in_fd, out_fd, num_chans, error = false, last_buttons; @@ -144,7 +148,6 @@ static int wav2wv (char *filename) } wpc = WavpackOpenFileOutput (); - WavpackSetOutputBuffer (wpc, output_buffer, output_buffer + 0x100000); rb->memset (&config, 0, sizeof (config)); config.bits_per_sample = 16; @@ -153,6 +156,8 @@ static int wav2wv (char *filename) num_chans = config.num_channels = native_header.NumChannels; total_samples = native_header.data_ckSize / native_header.BlockAlign; +// config.flags |= CONFIG_HIGH_FLAG; + if (!WavpackSetConfiguration (wpc, &config, total_samples)) { rb->splash(HZ*2, true, "internal error!"); rb->close (in_fd); @@ -178,7 +183,7 @@ static int wav2wv (char *filename) wvupdate (start_tick, native_header.SampleRate, total_samples, 0, 0, 0); for (samples_remaining = total_samples; samples_remaining;) { - unsigned long samples_count, bytes_count; + unsigned long samples_count, samples_to_pack, bytes_count; int cnt, buttons; long value, *lp; char *cp; @@ -197,33 +202,48 @@ static int wav2wv (char *filename) } total_bytes_read += bytes_count; - cp = (char *) input_buffer + bytes_count; - lp = input_buffer + samples_count * num_chans; - cnt = samples_count; - - if (num_chans == 2) - while (cnt--) { - value = *--cp << 8; - value += *--cp & 0xff; - *--lp = value; - value = *--cp << 8; - value += *--cp & 0xff; - *--lp = value; - } - else - while (cnt--) { - value = *--cp << 8; - value += *--cp & 0xff; - *--lp = value; - } - - bytes_count = WavpackPackSamples (wpc, input_buffer, samples_count); + WavpackStartBlock (wpc, output_buffer, output_buffer + 0x100000); + samples_to_pack = samples_count; + cp = (char *) input_buffer; + + while (samples_to_pack) { + unsigned long samples_this_pass = TEMP_SAMPLES / num_chans; + + if (samples_this_pass > samples_to_pack) + samples_this_pass = samples_to_pack; + + lp = temp_buffer; + cnt = samples_this_pass; + + if (num_chans == 2) + while (cnt--) { + value = *cp++ & 0xff; + value += *cp++ << 8; + *lp++ = value; + value = *cp++ & 0xff; + value += *cp++ << 8; + *lp++ = value; + } + else + while (cnt--) { + value = *cp++ & 0xff; + value += *cp++ << 8; + *lp++ = value; + } + + if (!WavpackPackSamples (wpc, temp_buffer, samples_this_pass)) { + rb->splash(HZ*2, true, "internal error!"); + error = true; + break; + } + + samples_to_pack -= samples_this_pass; + } - if (!bytes_count) { - rb->splash(HZ*2, true, "internal error!"); - error = true; + if (error) break; - } + + bytes_count = WavpackFinishBlock (wpc); if (rb->write (out_fd, output_buffer, bytes_count) != (long) bytes_count) { rb->splash(HZ*2, true, "could not write file!"); -- cgit v1.2.3