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); - - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - dpp->samples_A [k] = left; - dpp->samples_B [k] = right; - } - - 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); - } + 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]; - m = (m + 1) & (MAX_TERM - 1); - send_word_lossless (wps, left, 0); - send_word_lossless (wps, right, 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); } + } + + 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; + + return TRUE; +} + +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; + register struct entropy_data *c = w->c; - 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); - else { - wps->w.zeros_acc++; - return; + 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 (&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 (value - low < GET_MED (1)) { - ones_count = 1; - high = low + GET_MED (1) - 1; - DEC_MED1 (); - } - else { - low += GET_MED (1); - INC_MED1 (); - - if (value - low < GET_MED (2)) { - ones_count = 2; - high = low + GET_MED (2) - 1; - DEC_MED2 (); + else if (value) { + putbit_0 (bs); } else { - ones_count = 2 + (value - low) / GET_MED (2); - low += (ones_count - 2) * GET_MED (2); - high = low + GET_MED (2) - 1; - INC_MED2 (); + CLEAR (w->c [0].median); + CLEAR (w->c [1].median); + w->zeros_acc = 1; + continue; } } - } - if (wps->w.holding_zero) { - if (ones_count) - wps->w.holding_one++; + if (sign) + value = ~value; - flush_word (wps); + 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 (ones_count) { - wps->w.holding_zero = 1; - ones_count--; + if (value - low < GET_MED (1)) { + ones_count = 1; + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + 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 (w->holding_zero) { + if (ones_count) + w->holding_one++; + + flush_word (w, bs); + + 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++; + } } + + w->pend_data |= ((long) sign << w->pend_count++); + + if (!w->holding_zero) + flush_word (w, bs); } - - wps->w.pend_data |= ((long) sign << wps->w.pend_count++); - - if (!wps->w.holding_zero) - flush_word (wps); } // 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. +// 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. -ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count) +int WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count) +{ + if (!sample_count || pack_samples (wpc, sample_buffer, sample_count)) + return TRUE; + + strcpy_loc (wpc->error_message, "output buffer overflowed!"); + return FALSE; +} + +// 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. + +ulong WavpackFinishBlock (WavpackContext *wpc) { WavpackStream *wps = &wpc->stream; - ulong flags = wps->wphdr.flags; ulong bcount; - int result; - - flags &= ~MAG_MASK; - flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); - - wps->wphdr.block_index = wps->sample_index; - wps->wphdr.block_samples = sample_count; - wps->wphdr.flags = flags; - - result = pack_block (wpc, sample_buffer); - - if (!result) { - strcpy_loc (wpc->error_message, "output buffer overflowed!"); - return 0; - } + 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,34 +202,49 @@ 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; + WavpackStartBlock (wpc, output_buffer, output_buffer + 0x100000); + samples_to_pack = samples_count; + cp = (char *) input_buffer; - 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; - } + while (samples_to_pack) { + unsigned long samples_this_pass = TEMP_SAMPLES / num_chans; - bytes_count = WavpackPackSamples (wpc, input_buffer, samples_count); + if (samples_this_pass > samples_to_pack) + samples_this_pass = samples_to_pack; - if (!bytes_count) { - rb->splash(HZ*2, true, "internal error!"); - error = true; - break; + 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 (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!"); error = true;