package com.wavpack.decoder; import java.util.Arrays; /* ** UnpackUtils.java ** ** Copyright (c) 2007 - 2008 Peter McQuillan ** ** All Rights Reserved. ** ** Distributed under the BSD Software License (see license.txt) ** */ class UnpackUtils { ///////////////////////////// executable code //////////////////////////////// // This function initializes everything required to unpack a WavPack block // and must be called before unpack_samples() is called to obtain audio data. // It is assumed that the WavpackHeader has been read into the wps.wphdr // (in the current WavpackStream). This is where all the metadata blocks are // scanned up to the one containing the audio bitstream. static int unpack_init(WavpackContext wpc) { WavpackStream wps = wpc.stream; WavpackMetadata wpmd = new WavpackMetadata(); if (wps.wphdr.block_samples > 0 && wps.wphdr.block_index != -1) wps.sample_index = wps.wphdr.block_index; wps.mute_error = 0; wps.crc = 0xffffffff; wps.wvbits.sr = 0; while ((MetadataUtils.read_metadata_buff(wpc, wpmd)) == Defines.TRUE) { if ((MetadataUtils.process_metadata(wpc, wpmd)) == Defines.FALSE) { wpc.error = true; wpc.error_message = "invalid metadata!"; return Defines.FALSE; } if (wpmd.id == Defines.ID_WV_BITSTREAM) break; } if (wps.wphdr.block_samples != 0 && (null == wps.wvbits.file)) { wpc.error_message = "invalid WavPack file!"; wpc.error = true; return Defines.FALSE; } if (wps.wphdr.block_samples != 0) { if ((wps.wphdr.flags & Defines.INT32_DATA) != 0 && wps.int32_sent_bits != 0) wpc.lossy_blocks = 1; if ((wps.wphdr.flags & Defines.FLOAT_DATA) != 0 && (wps.float_flags & (Defines.FLOAT_EXCEPTIONS | Defines.FLOAT_ZEROS_SENT | Defines.FLOAT_SHIFT_SENT | Defines.FLOAT_SHIFT_SAME)) != 0) wpc.lossy_blocks = 1; } wpc.error = false; wpc.stream = wps; return Defines.TRUE; } // This function initialzes the main bitstream for audio samples, which must // be in the "wv" file. static int init_wv_bitstream(WavpackContext wpc, WavpackMetadata wpmd) { WavpackStream wps = wpc.stream; if (wpmd.hasdata == Defines.TRUE) wps.wvbits = BitsUtils.bs_open_read(wps.wvbits, wpmd.data, (short) 0, (short) wpmd.byte_length, wpc.infile, (long) 0, 0); else if (wpmd.byte_length > 0) { int len = wpmd.byte_length & 1; wps.wvbits = BitsUtils.bs_open_read(wps.wvbits, wpc.read_buffer, (short) -1, (short) wpc.read_buffer.length, wpc.infile, (long) (wpmd.byte_length + len), 1); } return Defines.TRUE; } // Read decorrelation terms from specified metadata block into the // decorr_passes array. The terms range from -3 to 8, plus 17 & 18; // other values are reserved and generate errors for now. The delta // ranges from 0 to 7 with all values valid. Note that the terms are // stored in the opposite order in the decorr_passes array compared // to packing. static int read_decorr_terms(WavpackStream wps, WavpackMetadata wpmd) { int termcnt = wpmd.byte_length; byte byteptr[] = wpmd.data; int counter = 0; int dcounter = 0; if (termcnt > Defines.MAX_NTERMS) return Defines.FALSE; wps.num_terms = termcnt; dcounter = termcnt - 1; for (dcounter = termcnt - 1; dcounter >= 0; dcounter--) { wps.decorr_passes[dcounter].term = (short) ((int) (byteptr[counter] & 0x1f) - 5); wps.decorr_passes[dcounter].delta = (short) ((byteptr[counter] >> 5) & 0x7); counter++; if (wps.decorr_passes[dcounter].term < -3 || (wps.decorr_passes[dcounter].term > Defines.MAX_TERM && wps.decorr_passes[dcounter].term < 17) || wps.decorr_passes[dcounter].term > 18) return Defines.FALSE; } wps.decorr_passes = wps.decorr_passes; wps.num_terms = wps.num_terms; return Defines.TRUE; } // Read decorrelation weights from specified metadata block into the // decorr_passes array. The weights range +/-1024, but are rounded and // truncated to fit in signed chars for metadata storage. Weights are // separate for the two channels and are specified from the "last" term // (first during encode). Unspecified weights are set to zero. static int read_decorr_weights(WavpackStream wps, WavpackMetadata wpmd) { int termcnt = wpmd.byte_length, tcount; byte byteptr[] = wpmd.data; decorr_pass dpp = new decorr_pass(); int counter = 0; int dpp_idx; int myiterator = 0; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) termcnt /= 2; if (termcnt > wps.num_terms) { return Defines.FALSE; } for (tcount = wps.num_terms; tcount > 0; tcount--) dpp.weight_A = dpp.weight_B = 0; myiterator = wps.num_terms; while (termcnt > 0) { dpp_idx = myiterator - 1; dpp.weight_A = (short) WordsUtils.restore_weight((byte) byteptr[counter]); wps.decorr_passes[dpp_idx].weight_A = dpp.weight_A; counter++; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { dpp.weight_B = (short) WordsUtils.restore_weight((byte) byteptr[counter]); counter++; } wps.decorr_passes[dpp_idx].weight_B = dpp.weight_B; myiterator--; termcnt--; } return Defines.TRUE; } // Read decorrelation samples from specified metadata block into the // decorr_passes array. The samples are signed 32-bit values, but are // converted to signed log2 values for storage in metadata. Values are // stored for both channels and are specified from the "last" term // (first during encode) with unspecified samples set to zero. The // number of samples stored varies with the actual term value, so // those must obviously come first in the metadata. static int read_decorr_samples(WavpackStream wps, WavpackMetadata wpmd) { byte byteptr[] = wpmd.data; decorr_pass dpp = new decorr_pass(); int tcount; int counter = 0; int dpp_index = 0; int uns_buf0, uns_buf1, uns_buf2, uns_buf3; int sample_counter = 0; dpp_index = 0; for (tcount = wps.num_terms; tcount > 0; tcount--) { dpp.term = wps.decorr_passes[dpp_index].term; for (int internalc = 0; internalc < Defines.MAX_TERM; internalc++) { dpp.samples_A[internalc] = 0; dpp.samples_B[internalc] = 0; wps.decorr_passes[dpp_index].samples_A[internalc] = 0; wps.decorr_passes[dpp_index].samples_B[internalc] = 0; } dpp_index++; } if (wps.wphdr.version == 0x402 && (wps.wphdr.flags & Defines.HYBRID_FLAG) > 0) { counter += 2; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) counter += 2; } dpp_index--; while (counter < wpmd.byte_length) { if (dpp.term > Defines.MAX_TERM) { uns_buf0 = (int) (byteptr[counter] & 0xff); uns_buf1 = (int) (byteptr[counter + 1] & 0xff); uns_buf2 = (int) (byteptr[counter + 2] & 0xff); uns_buf3 = (int) (byteptr[counter + 3] & 0xff); dpp.samples_A[0] = WordsUtils.exp2s((short) (uns_buf0 + (uns_buf1 << 8))); dpp.samples_A[1] = WordsUtils.exp2s((short) (uns_buf2 + (uns_buf3 << 8))); counter += 4; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { uns_buf0 = (int) (byteptr[counter] & 0xff); uns_buf1 = (int) (byteptr[counter + 1] & 0xff); uns_buf2 = (int) (byteptr[counter + 2] & 0xff); uns_buf3 = (int) (byteptr[counter + 3] & 0xff); dpp.samples_B[0] = WordsUtils.exp2s((short) (uns_buf0 + (uns_buf1 << 8))); dpp.samples_B[1] = WordsUtils.exp2s((short) (uns_buf2 + (uns_buf3 << 8))); counter += 4; } } else if (dpp.term < 0) { uns_buf0 = (int) (byteptr[counter] & 0xff); uns_buf1 = (int) (byteptr[counter + 1] & 0xff); uns_buf2 = (int) (byteptr[counter + 2] & 0xff); uns_buf3 = (int) (byteptr[counter + 3] & 0xff); dpp.samples_A[0] = WordsUtils.exp2s((short) (uns_buf0 + (uns_buf1 << 8))); dpp.samples_B[0] = WordsUtils.exp2s((short) (uns_buf2 + (uns_buf3 << 8))); counter += 4; } else { int m = 0, cnt = dpp.term; while (cnt > 0) { uns_buf0 = (int) (byteptr[counter] & 0xff); uns_buf1 = (int) (byteptr[counter + 1] & 0xff); dpp.samples_A[m] = WordsUtils.exp2s((short) (uns_buf0 + (uns_buf1 << 8))); counter += 2; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { uns_buf0 = (int) (byteptr[counter] & 0xff); uns_buf1 = (int) (byteptr[counter + 1] & 0xff); dpp.samples_B[m] = WordsUtils.exp2s((short) (uns_buf0 + (uns_buf1 << 8))); counter += 2; } m++; cnt--; } } for (sample_counter = 0; sample_counter < Defines.MAX_TERM; sample_counter++) { wps.decorr_passes[dpp_index].samples_A[sample_counter] = dpp.samples_A[sample_counter]; wps.decorr_passes[dpp_index].samples_B[sample_counter] = dpp.samples_B[sample_counter]; } dpp_index--; } return Defines.TRUE; } // Read the int32 data from the specified metadata into the specified stream. // This data is used for integer data that has more than 24 bits of magnitude // or, in some cases, used to eliminate redundant bits from any audio stream. static int read_int32_info(WavpackStream wps, WavpackMetadata wpmd) { int bytecnt = wpmd.byte_length; byte byteptr[] = wpmd.data; int counter = 0; if (bytecnt != 4) return Defines.FALSE; // should also return 0 wps.int32_sent_bits = byteptr[counter]; counter++; wps.int32_zeros = byteptr[counter]; counter++; wps.int32_ones = byteptr[counter]; counter++; wps.int32_dups = byteptr[counter]; return Defines.TRUE; } // Read multichannel information from metadata. The first byte is the total // number of channels and the following bytes represent the channel_mask // as described for Microsoft WAVEFORMATEX. static int read_channel_info(WavpackContext wpc, WavpackMetadata wpmd) { int bytecnt = wpmd.byte_length, shift = 0; byte byteptr[] = wpmd.data; int counter = 0; long mask = 0; if (bytecnt == 0 || bytecnt > 5) return Defines.FALSE; wpc.config.num_channels = byteptr[counter]; counter++; while (bytecnt >= 0) { mask |= (long) ((byteptr[counter] & 0xFF) << shift); counter++; shift += 8; bytecnt--; } wpc.config.channel_mask = mask; return Defines.TRUE; } // Read configuration information from metadata. static int read_config_info(WavpackContext wpc, WavpackMetadata wpmd) { int bytecnt = wpmd.byte_length; byte byteptr[] = wpmd.data; int counter = 0; if (bytecnt >= 3) { wpc.config.flags &= 0xff; wpc.config.flags |= (long) ((byteptr[counter] & 0xFF) << 8); counter++; wpc.config.flags |= (long) ((byteptr[counter] & 0xFF) << 16); counter++; wpc.config.flags |= (long) ((byteptr[counter] & 0xFF) << 24); } return Defines.TRUE; } // Read non-standard sampling rate from metadata. static int read_sample_rate(WavpackContext wpc, WavpackMetadata wpmd) { int bytecnt = wpmd.byte_length; byte byteptr[] = wpmd.data; int counter = 0; if (bytecnt == 3) { wpc.config.sample_rate = (long) (byteptr[counter] & 0xFF); counter++; wpc.config.sample_rate |= (long) ((byteptr[counter] & 0xFF) << 8); counter++; wpc.config.sample_rate |= (long) ((byteptr[counter] & 0xFF) << 16); } return Defines.TRUE; } // This monster actually unpacks the WavPack bitstream(s) into the specified // buffer as 32-bit integers or floats (depending on orignal data). Lossy // samples will be clipped to their original limits (i.e. 8-bit samples are // clipped to -128/+127) but are still returned in ints. It is up to the // caller to potentially reformat this for the final output including any // multichannel distribution, block alignment or endian compensation. The // function unpack_init() must have been called and the entire WavPack block // must still be visible (although wps.blockbuff will not be accessed again). // For maximum clarity, the function is broken up into segments that handle // various modes. This makes for a few extra infrequent flag checks, but // makes the code easier to follow because the nesting does not become so // deep. For maximum efficiency, the conversion is isolated to tight loops // that handle an entire buffer. The function returns the total number of // samples unpacked, which can be less than the number requested if an error // occurs or the end of the block is reached. static long unpack_samples(WavpackContext wpc, int[] buffer, long sample_count) { WavpackStream wps = wpc.stream; int[] temp_buffer = wpc.temp_buffer2; long flags = wps.wphdr.flags; long i; int crc = (int) wps.crc; int mute_limit = (int) ((1L << ((flags & Defines.MAG_MASK) >> Defines.MAG_LSB)) + 2); decorr_pass dpp; int tcount; int buffer_counter = 0; Arrays.fill(temp_buffer, 0); int samples_processed = 0; if (wps.sample_index + sample_count > wps.wphdr.block_index + wps.wphdr.block_samples) sample_count = wps.wphdr.block_index + wps.wphdr.block_samples - wps.sample_index; if (wps.mute_error > 0) { long tempc; if ((flags & Defines.MONO_FLAG) > 0) { tempc = sample_count; } else { tempc = 2 * sample_count; } while (tempc > 0) { buffer[buffer_counter] = 0; tempc--; buffer_counter++; } wps.sample_index += sample_count; return sample_count; } if ((flags & Defines.HYBRID_FLAG) > 0) mute_limit *= 2; ///////////////////// handle version 4 mono data ///////////////////////// if ((flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) > 0) { int dpp_index = 0; i = WordsUtils.get_words(sample_count, flags, wps.w, wps.wvbits, temp_buffer); System.arraycopy(temp_buffer, 0, buffer, 0, (int) sample_count); for (tcount = wps.num_terms - 1; tcount >= 0; tcount--) { dpp = wps.decorr_passes[dpp_index]; decorr_mono_pass(dpp, buffer, sample_count, buffer_counter); dpp_index++; } int bf_abs; for (int q = 0; q < sample_count; q++) { bf_abs = (buffer[buffer_counter] < 0 ? -buffer[buffer_counter] : buffer[buffer_counter]); if (bf_abs > mute_limit) { i = q; break; } crc = crc * 3 + buffer[q]; } } //////////////////// handle version 4 stereo data //////////////////////// else { samples_processed = WordsUtils.get_words(sample_count, flags, wps.w, wps.wvbits, temp_buffer); i = samples_processed; System.arraycopy(temp_buffer, 0, buffer, 0, (int) (sample_count * 2)); if (sample_count < 16) { int dpp_index = 0; for (tcount = wps.num_terms - 1; tcount >= 0; tcount--) { dpp = wps.decorr_passes[dpp_index]; decorr_stereo_pass(dpp, buffer, sample_count, buffer_counter); wps.decorr_passes[dpp_index] = dpp; dpp_index++; } } else { int dpp_index = 0; for (tcount = wps.num_terms - 1; tcount >= 0; tcount--) { dpp = wps.decorr_passes[dpp_index]; decorr_stereo_pass(dpp, buffer, 8, buffer_counter); decorr_stereo_pass_cont(dpp, buffer, sample_count - 8, buffer_counter + 16); wps.decorr_passes[dpp_index] = dpp; dpp_index++; } } if ((flags & Defines.JOINT_STEREO) > 0) { int bf_abs, bf1_abs; for (buffer_counter = 0; buffer_counter < sample_count * 2; buffer_counter += 2) { buffer[buffer_counter] += (buffer[buffer_counter + 1] -= (buffer[buffer_counter] >> 1)); bf_abs = (buffer[buffer_counter] < 0 ? -buffer[buffer_counter] : buffer[buffer_counter]); bf1_abs = (buffer[buffer_counter + 1] < 0 ? -buffer[buffer_counter + 1] : buffer[buffer_counter + 1]); if (bf_abs > mute_limit || bf1_abs > mute_limit) { i = buffer_counter / 2; break; } crc = (crc * 3 + buffer[buffer_counter]) * 3 + buffer[buffer_counter + 1]; } } else { int bf_abs, bf1_abs; for (buffer_counter = 0; buffer_counter < sample_count * 2; buffer_counter += 2) { bf_abs = (buffer[buffer_counter] < 0 ? -buffer[buffer_counter] : buffer[buffer_counter]); bf1_abs = (buffer[buffer_counter + 1] < 0 ? -buffer[buffer_counter + 1] : buffer[buffer_counter + 1]); if (bf_abs > mute_limit || bf1_abs > mute_limit) { i = buffer_counter / 2; break; } crc = (crc * 3 + buffer[buffer_counter]) * 3 + buffer[buffer_counter + 1]; } } } if (i != sample_count) { long sc = 0; if ((flags & Defines.MONO_FLAG) > 0) { sc = sample_count; } else { sc = 2 * sample_count; } buffer_counter = 0; while (sc > 0) { buffer[buffer_counter] = 0; sc--; buffer_counter++; } wps.mute_error = 1; i = sample_count; } buffer = fixup_samples(wps, buffer, i); if ((flags & Defines.FALSE_STEREO) > 0) { int dest_idx = (int) i * 2; int src_idx = (int) i; int c = (int) i; dest_idx--; src_idx--; while (c > 0) { buffer[dest_idx] = buffer[src_idx]; dest_idx--; buffer[dest_idx] = buffer[src_idx]; dest_idx--; src_idx--; c--; } } wps.sample_index += i; wps.crc = crc; return i; } static void decorr_stereo_pass(decorr_pass dpp, int[] buffer, long sample_count, int buf_idx) { int delta = dpp.delta; int weight_A = dpp.weight_A; int weight_B = dpp.weight_B; int sam_A, sam_B; int m, k; int bptr_counter = 0; switch (dpp.term) { case 17: for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count * 2; bptr_counter += 2) { sam_A = 2 * dpp.samples_A[0] - dpp.samples_A[1]; dpp.samples_A[1] = dpp.samples_A[0]; dpp.samples_A[0] = (int) ((weight_A * (long) sam_A + 512) >> 10) + buffer[bptr_counter]; if (sam_A != 0 && buffer[bptr_counter] != 0) { if ((sam_A ^ buffer[bptr_counter]) < 0) { weight_A = weight_A - delta; } else { weight_A = weight_A + delta; } } buffer[bptr_counter] = dpp.samples_A[0]; sam_A = 2 * dpp.samples_B[0] - dpp.samples_B[1]; dpp.samples_B[1] = dpp.samples_B[0]; dpp.samples_B[0] = (int) ((weight_B * (long) sam_A + 512) >> 10) + buffer[bptr_counter + 1]; if (sam_A != 0 && buffer[bptr_counter + 1] != 0) { if ((sam_A ^ buffer[bptr_counter + 1]) < 0) { weight_B = weight_B - delta; } else { weight_B = weight_B + delta; } } buffer[bptr_counter + 1] = dpp.samples_B[0]; } break; case 18: for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count * 2; bptr_counter += 2) { sam_A = (3 * dpp.samples_A[0] - dpp.samples_A[1]) >> 1; dpp.samples_A[1] = dpp.samples_A[0]; dpp.samples_A[0] = (int) ((weight_A * (long) sam_A + 512) >> 10) + buffer[bptr_counter]; if (sam_A != 0 && buffer[bptr_counter] != 0) { if ((sam_A ^ buffer[bptr_counter]) < 0) { weight_A = weight_A - delta; } else { weight_A = weight_A + delta; } } buffer[bptr_counter] = dpp.samples_A[0]; sam_A = (3 * dpp.samples_B[0] - dpp.samples_B[1]) >> 1; dpp.samples_B[1] = dpp.samples_B[0]; dpp.samples_B[0] = (int) ((weight_B * (long) sam_A + 512) >> 10) + buffer[bptr_counter + 1]; if (sam_A != 0 && buffer[bptr_counter + 1] != 0) { if ((sam_A ^ buffer[bptr_counter + 1]) < 0) { weight_B = weight_B - delta; } else { weight_B = weight_B + delta; } } buffer[bptr_counter + 1] = dpp.samples_B[0]; } break; case -1: for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count * 2; bptr_counter += 2) { sam_A = buffer[bptr_counter] + (int) ((weight_A * (long) dpp.samples_A[0] + 512) >> 10); if ((dpp.samples_A[0] ^ buffer[bptr_counter]) < 0) { if (dpp.samples_A[0] != 0 && buffer[bptr_counter] != 0 && (weight_A -= delta) < -1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } else { if (dpp.samples_A[0] != 0 && buffer[bptr_counter] != 0 && (weight_A += delta) > 1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } buffer[bptr_counter] = sam_A; dpp.samples_A[0] = buffer[bptr_counter + 1] + (int) ((weight_B * (long) sam_A + 512) >> 10); if ((sam_A ^ buffer[bptr_counter + 1]) < 0) { if (sam_A != 0 && buffer[bptr_counter + 1] != 0 && (weight_B -= delta) < -1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } else { if (sam_A != 0 && buffer[bptr_counter + 1] != 0 && (weight_B += delta) > 1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } buffer[bptr_counter + 1] = dpp.samples_A[0]; } break; case -2: sam_B = 0; sam_A = 0; for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count * 2; bptr_counter += 2) { sam_B = buffer[bptr_counter + 1] + (int) ((weight_B * (long) dpp.samples_B[0] + 512) >> 10); if ((dpp.samples_B[0] ^ buffer[bptr_counter + 1]) < 0) { if (dpp.samples_B[0] != 0 && buffer[bptr_counter + 1] != 0 && (weight_B -= delta) < -1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } else { if (dpp.samples_B[0] != 0 && buffer[bptr_counter + 1] != 0 && (weight_B += delta) > 1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } buffer[bptr_counter + 1] = sam_B; dpp.samples_B[0] = buffer[bptr_counter] + (int) ((weight_A * (long) sam_B + 512) >> 10); if ((sam_B ^ buffer[bptr_counter]) < 0) { if (sam_B != 0 && buffer[bptr_counter] != 0 && (weight_A -= delta) < -1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } else { if (sam_B != 0 && buffer[bptr_counter] != 0 && (weight_A += delta) > 1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } buffer[bptr_counter] = dpp.samples_B[0]; } break; case -3: sam_A = 0; for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count * 2; bptr_counter += 2) { sam_A = buffer[bptr_counter] + (int) ((weight_A * (long) dpp.samples_A[0] + 512) >> 10); if ((dpp.samples_A[0] ^ buffer[bptr_counter]) < 0) { if (dpp.samples_A[0] != 0 && buffer[bptr_counter] != 0 && (weight_A -= delta) < -1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } else { if (dpp.samples_A[0] != 0 && buffer[bptr_counter] != 0 && (weight_A += delta) > 1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } sam_B = buffer[bptr_counter + 1] + (int) ((weight_B * (long) dpp.samples_B[0] + 512) >> 10); if ((dpp.samples_B[0] ^ buffer[bptr_counter + 1]) < 0) { if (dpp.samples_B[0] != 0 && buffer[bptr_counter + 1] != 0 && (weight_B -= delta) < -1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } else { if (dpp.samples_B[0] != 0 && buffer[bptr_counter + 1] != 0 && (weight_B += delta) > 1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } buffer[bptr_counter] = dpp.samples_B[0] = sam_A; buffer[bptr_counter + 1] = dpp.samples_A[0] = sam_B; } break; default: sam_A = 0; for (m = 0, k = dpp.term & (Defines.MAX_TERM - 1), bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count * 2; bptr_counter += 2) { sam_A = dpp.samples_A[m]; dpp.samples_A[k] = (int) ((weight_A * (long) sam_A + 512) >> 10) + buffer[bptr_counter]; if (sam_A != 0 && buffer[bptr_counter] != 0) { if ((sam_A ^ buffer[bptr_counter]) < 0) { weight_A = weight_A - delta; } else { weight_A = weight_A + delta; } } buffer[bptr_counter] = dpp.samples_A[k]; sam_A = dpp.samples_B[m]; dpp.samples_B[k] = (int) ((weight_B * (long) sam_A + 512) >> 10) + buffer[bptr_counter + 1]; if (sam_A != 0 && buffer[bptr_counter + 1] != 0) { if ((sam_A ^ buffer[bptr_counter + 1]) < 0) { weight_B = weight_B - delta; } else { weight_B = weight_B + delta; } } buffer[bptr_counter + 1] = dpp.samples_B[k]; m = (m + 1) & (Defines.MAX_TERM - 1); k = (k + 1) & (Defines.MAX_TERM - 1); } if (m != 0) { int[] temp_samples = new int[Defines.MAX_TERM]; System.arraycopy(dpp.samples_A, 0, temp_samples, 0, dpp.samples_A.length); for (k = 0; k < Defines.MAX_TERM; k++, m++) dpp.samples_A[k] = temp_samples[m & (Defines.MAX_TERM - 1)]; System.arraycopy(dpp.samples_B, 0, temp_samples, 0, dpp.samples_B.length); for (k = 0; k < Defines.MAX_TERM; k++, m++) dpp.samples_B[k] = temp_samples[m & (Defines.MAX_TERM - 1)]; } break; } dpp.weight_A = (short) weight_A; dpp.weight_B = (short) weight_B; } static void decorr_stereo_pass_cont(decorr_pass dpp, int[] buffer, long sample_count, int buf_idx) { int delta = dpp.delta, weight_A = dpp.weight_A, weight_B = dpp.weight_B; int tptr; int sam_A, sam_B; int k, i; int buffer_index = buf_idx; long end_index = buf_idx + sample_count * 2; switch (dpp.term) { case 17: for (buffer_index = buf_idx; buffer_index < end_index; buffer_index += 2) { sam_A = 2 * buffer[buffer_index - 2] - buffer[buffer_index - 4]; buffer[buffer_index] = (int) ((weight_A * (long) sam_A + 512) >> 10) + (sam_B = buffer[buffer_index]); if (sam_A != 0 && sam_B != 0) weight_A += (((sam_A ^ sam_B) >> 30) | 1) * delta; //update_weight (weight_A, delta, sam_A, sam_B); sam_A = 2 * buffer[buffer_index - 1] - buffer[buffer_index - 3]; buffer[buffer_index + 1] = (int) ((weight_B * (long) sam_A + 512) >> 10) + (sam_B = buffer[buffer_index + 1]); if (sam_A != 0 && sam_B != 0) weight_B += (((sam_A ^ sam_B) >> 30) | 1) * delta; } dpp.samples_B[0] = buffer[buffer_index - 1]; dpp.samples_A[0] = buffer[buffer_index - 2]; dpp.samples_B[1] = buffer[buffer_index - 3]; dpp.samples_A[1] = buffer[buffer_index - 4]; break; case 18: for (buffer_index = buf_idx; buffer_index < end_index; buffer_index += 2) { sam_A = (3 * buffer[buffer_index - 2] - buffer[buffer_index - 4]) >> 1; buffer[buffer_index] = (int) ((weight_A * (long) sam_A + 512) >> 10) + (sam_B = buffer[buffer_index]); if (sam_A != 0 && sam_B != 0) weight_A += (((sam_A ^ sam_B) >> 30) | 1) * delta; sam_A = (3 * buffer[buffer_index - 1] - buffer[buffer_index - 3]) >> 1; buffer[buffer_index + 1] = (int) ((weight_B * (long) sam_A + 512) >> 10) + (sam_B = buffer[buffer_index + 1]); if (sam_A != 0 && sam_B != 0) weight_B += (((sam_A ^ sam_B) >> 30) | 1) * delta; } dpp.samples_B[0] = buffer[buffer_index - 1]; dpp.samples_A[0] = buffer[buffer_index - 2]; dpp.samples_B[1] = buffer[buffer_index - 3]; dpp.samples_A[1] = buffer[buffer_index - 4]; break; case -1: for (buffer_index = buf_idx; buffer_index < end_index; buffer_index += 2) { buffer[buffer_index] = (int) ((weight_A * (long) buffer[buffer_index - 1] + 512) >> 10) + (sam_A = buffer[buffer_index]); if ((buffer[buffer_index - 1] ^ sam_A) < 0) { if (buffer[buffer_index - 1] != 0 && sam_A != 0 && (weight_A -= delta) < -1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } else { if (buffer[buffer_index - 1] != 0 && sam_A != 0 && (weight_A += delta) > 1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } buffer[buffer_index + 1] = (int) ((weight_B * (long) buffer[buffer_index] + 512) >> 10) + (sam_A = buffer[buffer_index + 1]); if ((buffer[buffer_index] ^ sam_A) < 0) { if (buffer[buffer_index] != 0 && sam_A != 0 && (weight_B -= delta) < -1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } else { if (buffer[buffer_index] != 0 && sam_A != 0 && (weight_B += delta) > 1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } } dpp.samples_A[0] = buffer[buffer_index - 1]; break; case -2: sam_A = 0; sam_B = 0; for (buffer_index = buf_idx; buffer_index < end_index; buffer_index += 2) { buffer[buffer_index + 1] = (int) ((weight_B * (long) buffer[buffer_index - 2] + 512) >> 10) + (sam_A = buffer[buffer_index + 1]); if ((buffer[buffer_index - 2] ^ sam_A) < 0) { if (buffer[buffer_index - 2] != 0 && sam_A != 0 && (weight_B -= delta) < -1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } else { if (buffer[buffer_index - 2] != 0 && sam_A != 0 && (weight_B += delta) > 1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } buffer[buffer_index] = (int) ((weight_A * (long) buffer[buffer_index + 1] + 512) >> 10) + (sam_A = buffer[buffer_index]); if ((buffer[buffer_index + 1] ^ sam_A) < 0) { if (buffer[buffer_index + 1] != 0 && sam_A != 0 && (weight_A -= delta) < -1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } else { if (buffer[buffer_index + 1] != 0 && sam_A != 0 && (weight_A += delta) > 1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } } dpp.samples_B[0] = buffer[buffer_index - 2]; break; case -3: for (buffer_index = buf_idx; buffer_index < end_index; buffer_index += 2) { buffer[buffer_index] = (int) ((weight_A * (long) buffer[buffer_index - 1] + 512) >> 10) + (sam_A = buffer[buffer_index]); if ((buffer[buffer_index - 1] ^ sam_A) < 0) { if (buffer[buffer_index - 1] != 0 && sam_A != 0 && (weight_A -= delta) < -1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } else { if (buffer[buffer_index - 1] != 0 && sam_A != 0 && (weight_A += delta) > 1024) { if (weight_A < 0) { weight_A = -1024; } else { weight_A = 1024; } } } buffer[buffer_index + 1] = (int) ((weight_B * (long) buffer[buffer_index - 2] + 512) >> 10) + (sam_A = buffer[buffer_index + 1]); if ((buffer[buffer_index - 2] ^ sam_A) < 0) { if (buffer[buffer_index - 2] != 0 && sam_A != 0 && (weight_B -= delta) < -1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } else { if (buffer[buffer_index - 2] != 0 && sam_A != 0 && (weight_B += delta) > 1024) { if (weight_B < 0) { weight_B = -1024; } else { weight_B = 1024; } } } } dpp.samples_A[0] = buffer[buffer_index - 1]; dpp.samples_B[0] = buffer[buffer_index - 2]; break; default: tptr = buf_idx - (dpp.term * 2); for (buffer_index = buf_idx; buffer_index < end_index; buffer_index += 2) { buffer[buffer_index] = (int) ((weight_A * (long) buffer[tptr] + 512) >> 10) + (sam_A = buffer[buffer_index]); if (buffer[tptr] != 0 && sam_A != 0) weight_A += (((buffer[tptr] ^ sam_A) >> 30) | 1) * delta; buffer[buffer_index + 1] = (int) ((weight_B * (long) buffer[tptr + 1] + 512) >> 10) + (sam_A = buffer[buffer_index + 1]); if (buffer[tptr + 1] != 0 && sam_A != 0) weight_B += (((buffer[tptr + 1] ^ sam_A) >> 30) | 1) * delta; tptr += 2; } buffer_index--; for (k = dpp.term - 1, i = 8; i > 0; k--) { i--; dpp.samples_B[k & (Defines.MAX_TERM - 1)] = buffer[buffer_index]; buffer_index--; dpp.samples_A[k & (Defines.MAX_TERM - 1)] = buffer[buffer_index]; buffer_index--; } break; } dpp.weight_A = (short) weight_A; dpp.weight_B = (short) weight_B; } static void decorr_mono_pass(decorr_pass dpp, int[] buffer, long sample_count, int buf_idx) { int delta = dpp.delta, weight_A = dpp.weight_A; int sam_A; int m, k; int bptr_counter = 0; switch (dpp.term) { case 17: for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count; bptr_counter++) { sam_A = 2 * dpp.samples_A[0] - dpp.samples_A[1]; dpp.samples_A[1] = dpp.samples_A[0]; dpp.samples_A[0] = (int) ((weight_A * (long) sam_A + 512) >> 10) + buffer[bptr_counter]; if (sam_A != 0 && buffer[bptr_counter] != 0) { if ((sam_A ^ buffer[bptr_counter]) < 0) { weight_A = weight_A - delta; } else { weight_A = weight_A + delta; } } buffer[bptr_counter] = dpp.samples_A[0]; } break; case 18: for (bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count; bptr_counter++) { sam_A = (3 * dpp.samples_A[0] - dpp.samples_A[1]) >> 1; dpp.samples_A[1] = dpp.samples_A[0]; dpp.samples_A[0] = (int) ((weight_A * (long) sam_A + 512) >> 10) + buffer[bptr_counter]; if (sam_A != 0 && buffer[bptr_counter] != 0) { if ((sam_A ^ buffer[bptr_counter]) < 0) { weight_A = weight_A - delta; } else { weight_A = weight_A + delta; } } buffer[bptr_counter] = dpp.samples_A[0]; } break; default: for (m = 0, k = dpp.term & (Defines.MAX_TERM - 1), bptr_counter = buf_idx; bptr_counter < buf_idx + sample_count; bptr_counter++) { sam_A = dpp.samples_A[m]; dpp.samples_A[k] = (int) ((weight_A * (long) sam_A + 512) >> 10) + buffer[bptr_counter]; if (sam_A != 0 && buffer[bptr_counter] != 0) { if ((sam_A ^ buffer[bptr_counter]) < 0) { weight_A = weight_A - delta; } else { weight_A = weight_A + delta; } } buffer[bptr_counter] = dpp.samples_A[k]; m = (m + 1) & (Defines.MAX_TERM - 1); k = (k + 1) & (Defines.MAX_TERM - 1); } if (m != 0) { int[] temp_samples = new int[Defines.MAX_TERM]; System.arraycopy(dpp.samples_A, 0, temp_samples, 0, dpp.samples_A.length); for (k = 0; k < Defines.MAX_TERM; k++, m++) dpp.samples_A[k] = temp_samples[m & (Defines.MAX_TERM - 1)]; } break; } dpp.weight_A = (short) weight_A; } // This is a helper function for unpack_samples() that applies several final // operations. First, if the data is 32-bit float data, then that conversion // is done in the float.c module (whether lossy or lossless) and we return. // Otherwise, if the extended integer data applies, then that operation is // executed first. If the unpacked data is lossy (and not corrected) then // it is clipped and shifted in a single operation. Otherwise, if it's // lossless then the last step is to apply the final shift (if any). static int[] fixup_samples(WavpackStream wps, int[] buffer, long sample_count) { long flags = wps.wphdr.flags; int shift = (int) ((flags & Defines.SHIFT_MASK) >> Defines.SHIFT_LSB); if ((flags & Defines.FLOAT_DATA) > 0) { long sc = 0; if ((flags & Defines.MONO_FLAG) > 0) { sc = sample_count; } else { sc = sample_count * 2; } buffer = FloatUtils.float_values(wps, buffer, sc); } if ((flags & Defines.INT32_DATA) > 0) { int sent_bits = wps.int32_sent_bits, zeros = wps.int32_zeros; int ones = wps.int32_ones, dups = wps.int32_dups; int buffer_counter = 0; long count; if ((flags & Defines.MONO_FLAG) > 0) { count = sample_count; } else { count = sample_count * 2; } if ((flags & Defines.HYBRID_FLAG) == 0 && sent_bits == 0 && (zeros + ones + dups) != 0) while (count > 0) { if (zeros != 0) buffer[buffer_counter] <<= zeros; else if (ones != 0) buffer[buffer_counter] = ((buffer[buffer_counter] + 1) << ones) - 1; else if (dups != 0) buffer[buffer_counter] = ((buffer[buffer_counter] + (buffer[buffer_counter] & 1)) << dups) - (buffer[buffer_counter] & 1); buffer_counter++; count--; } else shift += zeros + sent_bits + ones + dups; } if ((flags & Defines.HYBRID_FLAG) > 0) { int min_value, max_value, min_shifted, max_shifted; int buffer_counter = 0; switch ((int) (flags & (long) Defines.BYTES_STORED)) { case 0: min_shifted = (min_value = -128 >> shift) << shift; max_shifted = (max_value = 127 >> shift) << shift; break; case 1: min_shifted = (min_value = -32768 >> shift) << shift; max_shifted = (max_value = 32767 >> shift) << shift; break; case 2: min_shifted = (min_value = -8388608 >> shift) << shift; max_shifted = (max_value = 8388607 >> shift) << shift; break; case 3: default: min_shifted = (min_value = (int) 0x80000000 >> shift) << shift; max_shifted = (max_value = (int) 0x7FFFFFFF >> shift) << shift; break; } if ((flags & Defines.MONO_FLAG) == 0) sample_count *= 2; while (sample_count > 0) { if (buffer[buffer_counter] < min_value) buffer[buffer_counter] = min_shifted; else if (buffer[buffer_counter] > max_value) buffer[buffer_counter] = max_shifted; else buffer[buffer_counter] <<= shift; buffer_counter++; sample_count--; } } else if (shift != 0) { int buffer_counter = 0; if ((flags & Defines.MONO_FLAG) == 0) sample_count *= 2; while (sample_count > 0) { buffer[buffer_counter] = buffer[buffer_counter] << shift; buffer_counter++; sample_count--; } } return buffer; } // This function checks the crc value(s) for an unpacked block, returning the // number of actual crc errors detected for the block. The block must be // completely unpacked before this test is valid. For losslessly unpacked // blocks of float or extended integer data the extended crc is also checked. // Note that WavPack's crc is not a CCITT approved polynomial algorithm, but // is a much simpler method that is virtually as robust for real world data. static int check_crc_error(WavpackContext wpc) { WavpackStream wps = wpc.stream; int result = 0; if (wps.crc != wps.wphdr.crc) { ++result; } return result; } }