/* ** PackUtils.java ** ** Copyright (c) 2008 Peter McQuillan ** ** All Rights Reserved. ** ** Distributed under the BSD Software License (see license.txt) ** */ package com.wavpack.encoder; class PackUtils { //////////////////////////////// local tables /////////////////////////////// // These two tables specify the characteristics of the decorrelation filters. // Each term represents one layer of the sequential filter, where positive // values indicate the relative sample involved from the same channel (1=prev), // 17 & 18 are special functions using the previous 2 samples, and negative // values indicate cross channel decorrelation (in stereo only). static short[] very_high_terms = {18, 18, 2, 3, -2, 18, 2, 4, 7, 5, 3, 6, 8, -1, 18, 2, 0}; static short[] high_terms = {18, 18, 18, -2, 2, 3, 5, -1, 17, 4, 0}; static short[] default_terms = {18, 18, 2, 17, 3, 0}; static short[] fast_terms = {18, 17, 0}; ///////////////////////////// executable code //////////////////////////////// // This function initializes everything required to pack WavPack bitstreams // and must be called BEFORE any other function in this module. static void pack_init(WavpackContext wpc) { WavpackStream wps = wpc.stream; long flags = wps.wphdr.flags; short[] term_string; int dpp_idx = 0; int ti; wps.sample_index = 0; if ((flags & Defines.HYBRID_SHAPE) > 0) { int weight = wpc.config.shaping_weight; if (weight <= -1000) { weight = -1000; } wps.dc.shaping_acc[0] = wps.dc.shaping_acc[1] = weight << 16; } if ((wpc.config.flags & Defines.CONFIG_VERY_HIGH_FLAG) > 0) { term_string = very_high_terms; } else if ((wpc.config.flags & Defines.CONFIG_HIGH_FLAG) > 0) { term_string = high_terms; } else if ((wpc.config.flags & Defines.CONFIG_FAST_FLAG) > 0) { term_string = fast_terms; } else { term_string = default_terms; } for (ti = 0; ti < (term_string.length - 1); ti++) { if ((term_string[ti] >= 0) || ((flags & Defines.CROSS_DECORR) > 0)) { wps.decorr_passes[dpp_idx].term = term_string[ti]; wps.decorr_passes[dpp_idx].delta = 2; dpp_idx++; } else if ((flags & Defines.MONO_FLAG) == 0) { wps.decorr_passes[dpp_idx].term = -3; wps.decorr_passes[dpp_idx].delta = 2; dpp_idx++; } } wps.num_terms = dpp_idx; WordsUtils.init_words(wps); } // Allocate room for and copy the decorrelation terms from the decorr_passes // array into the specified metadata structure. Both the actual term id and // the delta are packed into single characters. static void write_decorr_terms(WavpackStream wps, WavpackMetadata wpmd) { int tcount; byte[] byteptr; int byte_idx = 0; int dpp_idx = 0; byteptr = wpmd.data = wpmd.temp_data; wpmd.id = Defines.ID_DECORR_TERMS; for (tcount = wps.num_terms; tcount > 0; ++dpp_idx) { byteptr[byte_idx] = (byte) (((wps.decorr_passes[dpp_idx].term + 5) & 0x1f) | ((wps.decorr_passes[dpp_idx].delta << 5) & 0xe0)); byte_idx++; tcount--; } wpmd.byte_length = byte_idx; } // Allocate room for and copy the decorrelation term weights from the // decorr_passes array into the specified metadata structure. The weights // range +/-1024, but are rounded and truncated to fit in signed chars for // metadata storage. Weights are separate for the two channels static void write_decorr_weights(WavpackStream wps, WavpackMetadata wpmd) { int tcount; int i; byte[] byteptr; int byte_idx = 0; byteptr = wpmd.data = wpmd.temp_data; wpmd.id = Defines.ID_DECORR_WEIGHTS; for (i = wps.num_terms - 1; i >= 0; --i) { if ((WordsUtils.store_weight(wps.decorr_passes[i].weight_A) != 0) || (((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) && (WordsUtils.store_weight(wps.decorr_passes[i].weight_B) != 0))) { break; } } tcount = i + 1; for (i = 0; i < wps.num_terms; ++i) { if (i < tcount) { wps.decorr_passes[i].weight_A = (short) (WordsUtils.restore_weight(byteptr[byte_idx] = WordsUtils.store_weight( wps.decorr_passes[i].weight_A))); byte_idx++; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { wps.decorr_passes[i].weight_B = (short) (WordsUtils.restore_weight(byteptr[byte_idx] = WordsUtils.store_weight( wps.decorr_passes[i].weight_B))); byte_idx++; } } else { wps.decorr_passes[i].weight_A = wps.decorr_passes[i].weight_B = 0; } } wpmd.byte_length = byte_idx; } // Allocate room for and copy the decorrelation samples from the decorr_passes // array into the specified metadata structure. 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 first term // with unspecified samples set to zero. The number of samples stored varies // with the actual term value, so those must obviously be specified before // these in the metadata list. Any number of terms can have their samples // specified from no terms to all the terms, however I have found that // sending more than the first term's samples is a waste. The "wcount" // variable can be set to the number of terms to have their samples stored. static void write_decorr_samples(WavpackStream wps, WavpackMetadata wpmd) { int tcount; int wcount = 1; int temp; byte[] byteptr; int byte_idx = 0; int dpp_idx = 0; byteptr = wpmd.data = wpmd.temp_data; wpmd.id = Defines.ID_DECORR_SAMPLES; for (tcount = wps.num_terms; tcount > 0; tcount--) { if (wcount != 0) { if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { wps.decorr_passes[dpp_idx].samples_A[0] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_A[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; wps.decorr_passes[dpp_idx].samples_A[1] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_A[1])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { wps.decorr_passes[dpp_idx].samples_B[0] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_B[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; wps.decorr_passes[dpp_idx].samples_B[1] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_B[1])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; } } else if (wps.decorr_passes[dpp_idx].term < 0) { wps.decorr_passes[dpp_idx].samples_A[0] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_A[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; wps.decorr_passes[dpp_idx].samples_B[0] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_B[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; } else { int m = 0; int cnt = wps.decorr_passes[dpp_idx].term; while (cnt > 0) { wps.decorr_passes[dpp_idx].samples_A[m] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_A[m])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { wps.decorr_passes[dpp_idx].samples_B[m] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.decorr_passes[dpp_idx].samples_B[m])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; } m++; cnt--; } } wcount--; } else { for (int internalc = 0; internalc < Defines.MAX_TERM; internalc++) { wps.decorr_passes[dpp_idx].samples_A[internalc] = 0; wps.decorr_passes[dpp_idx].samples_B[internalc] = 0; } } dpp_idx++; } wpmd.byte_length = byte_idx; } // Allocate room for and copy the noise shaping info into the specified // metadata structure. These would normally be written to the // "correction" file and are used for lossless reconstruction of // hybrid data. The "delta" parameter is not yet used in encoding as it // will be part of the "quality" mode. static void write_shaping_info(WavpackStream wps, WavpackMetadata wpmd) { byte[] byteptr; int byte_idx = 0; int temp; byteptr = wpmd.data = wpmd.temp_data; wpmd.id = Defines.ID_SHAPING_WEIGHTS; wps.dc.error[0] = WordsUtils.exp2s(temp = WordsUtils.log2s(wps.dc.error[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; wps.dc.shaping_acc[0] = WordsUtils.exp2s(temp = WordsUtils.log2s(wps.dc.shaping_acc[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { wps.dc.error[1] = WordsUtils.exp2s(temp = WordsUtils.log2s(wps.dc.error[1])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; wps.dc.shaping_acc[1] = WordsUtils.exp2s(temp = WordsUtils.log2s(wps.dc.shaping_acc[1])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; } if ((wps.dc.shaping_delta[0] | wps.dc.shaping_delta[1]) != 0) { wps.dc.shaping_delta[0] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.dc.shaping_delta[0])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; if ((wps.wphdr.flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0) { wps.dc.shaping_delta[1] = WordsUtils.exp2s(temp = WordsUtils.log2s( wps.dc.shaping_delta[1])); byteptr[byte_idx] = (byte) temp; byte_idx++; byteptr[byte_idx] = (byte) (temp >> 8); byte_idx++; } } wpmd.byte_length = byte_idx; } // Allocate room for and copy the configuration information into the specified // metadata structure. Currently, we just store the upper 3 bytes of // config.flags and only in the first block of audio data. Note that this is // for informational purposes not required for playback or decoding (like // whether high or fast mode was specified). static void write_config_info(WavpackContext wpc, WavpackMetadata wpmd) { byte[] byteptr; int byte_idx = 0; byteptr = wpmd.data = wpmd.temp_data; wpmd.id = Defines.ID_CONFIG_BLOCK; byteptr[byte_idx] = (byte) (wpc.config.flags >> 8); byte_idx++; byteptr[byte_idx] = (byte) (wpc.config.flags >> 16); byte_idx++; byteptr[byte_idx] = (byte) (wpc.config.flags >> 24); byte_idx++; wpmd.byte_length = byte_idx; } // Allocate room for and copy the non-standard sampling rateinto the specified // metadata structure. We just store the lower 3 bytes of the sampling rate. // Note that this would only be used when the sampling rate was not included // in the table of 15 "standard" values. static void write_sample_rate(WavpackContext wpc, WavpackMetadata wpmd) { byte[] byteptr; int byte_idx = 0; byteptr = wpmd.data = wpmd.temp_data; wpmd.id = Defines.ID_SAMPLE_RATE; byteptr[byte_idx] = (byte) (wpc.config.sample_rate); byte_idx++; byteptr[byte_idx] = (byte) (wpc.config.sample_rate >> 8); byte_idx++; byteptr[byte_idx] = (byte) (wpc.config.sample_rate >> 16); byte_idx++; wpmd.byte_length = byte_idx; } static int pack_start_block(WavpackContext wpc) { WavpackStream wps = wpc.stream; long flags = wps.wphdr.flags; WavpackMetadata wpmd = new WavpackMetadata(); int i = 0; long chunkSize; wps.lossy_block = Defines.FALSE; wps.wphdr.crc = 0xffffffff; wps.wphdr.block_samples = 0; wps.wphdr.ckSize = Defines.WAVPACK_HEADER_SIZE - 8; wps.blockbuff[0] = (byte) wps.wphdr.ckID[0]; wps.blockbuff[1] = (byte) wps.wphdr.ckID[1]; wps.blockbuff[2] = (byte) wps.wphdr.ckID[2]; wps.blockbuff[3] = (byte) wps.wphdr.ckID[3]; wps.blockbuff[4] = (byte) (wps.wphdr.ckSize); wps.blockbuff[5] = (byte) (wps.wphdr.ckSize >>> 8); wps.blockbuff[6] = (byte) (wps.wphdr.ckSize >>> 16); wps.blockbuff[7] = (byte) (wps.wphdr.ckSize >>> 24); wps.blockbuff[8] = (byte) (wps.wphdr.version); wps.blockbuff[9] = (byte) (wps.wphdr.version >>> 8); wps.blockbuff[10] = (byte) (wps.wphdr.track_no); wps.blockbuff[11] = (byte) (wps.wphdr.index_no); wps.blockbuff[12] = (byte) (wps.wphdr.total_samples); wps.blockbuff[13] = (byte) (wps.wphdr.total_samples >>> 8); wps.blockbuff[14] = (byte) (wps.wphdr.total_samples >>> 16); wps.blockbuff[15] = (byte) (wps.wphdr.total_samples >>> 24); wps.blockbuff[16] = (byte) (wps.wphdr.block_index); wps.blockbuff[17] = (byte) (wps.wphdr.block_index >>> 8); wps.blockbuff[18] = (byte) (wps.wphdr.block_index >>> 16); wps.blockbuff[19] = (byte) (wps.wphdr.block_index >>> 24); wps.blockbuff[20] = (byte) (wps.wphdr.block_samples); wps.blockbuff[21] = (byte) (wps.wphdr.block_samples >>> 8); wps.blockbuff[22] = (byte) (wps.wphdr.block_samples >>> 16); wps.blockbuff[23] = (byte) (wps.wphdr.block_samples >>> 24); wps.blockbuff[24] = (byte) (wps.wphdr.flags); wps.blockbuff[25] = (byte) (wps.wphdr.flags >>> 8); wps.blockbuff[26] = (byte) (wps.wphdr.flags >>> 16); wps.blockbuff[27] = (byte) (wps.wphdr.flags >>> 24); wps.blockbuff[28] = (byte) (wps.wphdr.crc); wps.blockbuff[29] = (byte) (wps.wphdr.crc >>> 8); wps.blockbuff[30] = (byte) (wps.wphdr.crc >>> 16); wps.blockbuff[31] = (byte) (wps.wphdr.crc >>> 24); write_decorr_terms(wps, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); write_decorr_weights(wps, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); write_decorr_samples(wps, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); WordsUtils.write_entropy_vars(wps, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); if (((flags & Defines.SRATE_MASK) == Defines.SRATE_MASK) && (wpc.config.sample_rate != 44100)) { write_sample_rate(wpc, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); } if ((flags & Defines.HYBRID_FLAG) != 0) { WordsUtils.write_hybrid_profile(wps, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); } if (((flags & Defines.INITIAL_BLOCK) > 0) && (wps.sample_index == 0)) { write_config_info(wpc, wpmd); copy_metadata(wpmd, wps.blockbuff, wps.blockend); } chunkSize = (wps.blockbuff[4] & 0xff) + ((wps.blockbuff[5] & 0xff) << 8) + ((wps.blockbuff[6] & 0xff) << 16) + ((wps.blockbuff[7] & 0xff) << 24); BitsUtils.bs_open_write(wps.wvbits, (int) (chunkSize + 12), wps.blockend); if (wpc.wvc_flag != 0) { wps.block2buff[0] = (byte) wps.wphdr.ckID[0]; wps.block2buff[1] = (byte) wps.wphdr.ckID[1]; wps.block2buff[2] = (byte) wps.wphdr.ckID[2]; wps.block2buff[3] = (byte) wps.wphdr.ckID[3]; wps.block2buff[4] = (byte) (wps.wphdr.ckSize); wps.block2buff[5] = (byte) (wps.wphdr.ckSize >>> 8); wps.block2buff[6] = (byte) (wps.wphdr.ckSize >>> 16); wps.block2buff[7] = (byte) (wps.wphdr.ckSize >>> 24); wps.block2buff[8] = (byte) (wps.wphdr.version); wps.block2buff[9] = (byte) (wps.wphdr.version >>> 8); wps.block2buff[10] = (byte) (wps.wphdr.track_no); wps.block2buff[11] = (byte) (wps.wphdr.index_no); wps.block2buff[12] = (byte) (wps.wphdr.total_samples); wps.block2buff[13] = (byte) (wps.wphdr.total_samples >>> 8); wps.block2buff[14] = (byte) (wps.wphdr.total_samples >>> 16); wps.block2buff[15] = (byte) (wps.wphdr.total_samples >>> 24); wps.block2buff[16] = (byte) (wps.wphdr.block_index); wps.block2buff[17] = (byte) (wps.wphdr.block_index >>> 8); wps.block2buff[18] = (byte) (wps.wphdr.block_index >>> 16); wps.block2buff[19] = (byte) (wps.wphdr.block_index >>> 24); wps.block2buff[20] = (byte) (wps.wphdr.block_samples); wps.block2buff[21] = (byte) (wps.wphdr.block_samples >>> 8); wps.block2buff[22] = (byte) (wps.wphdr.block_samples >>> 16); wps.block2buff[23] = (byte) (wps.wphdr.block_samples >>> 24); wps.block2buff[24] = (byte) (wps.wphdr.flags); wps.block2buff[25] = (byte) (wps.wphdr.flags >>> 8); wps.block2buff[26] = (byte) (wps.wphdr.flags >>> 16); wps.block2buff[27] = (byte) (wps.wphdr.flags >>> 24); wps.block2buff[28] = (byte) (wps.wphdr.crc); wps.block2buff[29] = (byte) (wps.wphdr.crc >>> 8); wps.block2buff[30] = (byte) (wps.wphdr.crc >>> 16); wps.block2buff[31] = (byte) (wps.wphdr.crc >>> 24); if ((flags & Defines.HYBRID_SHAPE) != 0) { write_shaping_info(wps, wpmd); copy_metadata(wpmd, wps.block2buff, wps.block2end); } chunkSize = (wps.block2buff[4] & 0xff) + ((wps.block2buff[5] & 0xff) << 8) + ((wps.block2buff[6] & 0xff) << 16) + ((wps.block2buff[7] & 0xff) << 24); BitsUtils.bs_open_write(wps.wvcbits, (int) (chunkSize + 12), wps.block2end); } return Defines.TRUE; } // Pack the given samples into the block currently being assembled. This function // checks the available space each sample so that it can return prematurely to // indicate that the blocks must be terminated. The return value is the number // of actual samples packed and will be the same as the provided sample_count // in no error occurs. static long pack_samples(WavpackContext wpc, long[] buffer, long sample_count) { WavpackStream wps = wpc.stream; long flags = wps.wphdr.flags; int tcount; int lossy = 0; int m; int byte_idx = 0; int dpp_idx = 0; long crc; long crc2; long i; long[] bptr; long block_samples; if (sample_count == 0) { return (long) 0; } byte_idx = wpc.byte_idx; // Get the index position for the buffer holding the input WAV data i = 0; block_samples = (long) ((wps.blockbuff[23] & 0xFF) << 24); block_samples += (long) ((wps.blockbuff[22] & 0xFF) << 16); block_samples += (long) ((wps.blockbuff[21] & 0xFF) << 8); block_samples += (long) (wps.blockbuff[20] & 0XFF); m = (int) (block_samples & (long) (Defines.MAX_TERM - 1)); crc = (long) ((wps.blockbuff[31] & 0xFF) << 24); crc += (long) ((wps.blockbuff[30] & 0xFF) << 16); crc += (long) ((wps.blockbuff[29] & 0xFF) << 8); crc += (long) (wps.blockbuff[28] & 0xFF); crc2 = 0; if (wpc.wvc_flag != 0) { crc2 = (long) ((wps.block2buff[31] & 0xFF) << 24); crc2 += (long) ((wps.block2buff[30] & 0xFF) << 16); crc2 += (long) ((wps.block2buff[29] & 0xFF) << 8); crc2 += (long) (wps.block2buff[28] & 0xFF); } /////////////////////// handle lossless mono mode ///////////////////////// if (((flags & Defines.HYBRID_FLAG) == 0) && ((flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) != 0)) { for (bptr = buffer, i = 0; i < sample_count; ++i) { int code; if (BitsUtils.bs_remain_write(wps.wvbits) < 64) { break; } crc = (crc * 3) + (code = (int) (bptr[byte_idx])); byte_idx++; dpp_idx = 0; for (tcount = wps.num_terms; tcount > 0; tcount--) { int sam; if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { if ((wps.decorr_passes[dpp_idx].term & 1) != 0) { sam = (2 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]; } else { sam = ((3 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]) >> 1; } wps.decorr_passes[dpp_idx].samples_A[1] = wps.decorr_passes[dpp_idx].samples_A[0]; wps.decorr_passes[dpp_idx].samples_A[0] = code; } else { sam = wps.decorr_passes[dpp_idx].samples_A[m]; wps.decorr_passes[dpp_idx].samples_A[(m + wps.decorr_passes[dpp_idx].term) & (Defines.MAX_TERM - 1)] = code; } code -= apply_weight(wps.decorr_passes[dpp_idx].weight_A, sam); wps.decorr_passes[dpp_idx].weight_A = update_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, sam, code); dpp_idx++; } m = (m + 1) & (Defines.MAX_TERM - 1); WordsUtils.send_word_lossless(wps, code, 0); } wpc.byte_idx = byte_idx; } //////////////////// handle the lossless stereo mode ////////////////////// else if (((flags & Defines.HYBRID_FLAG) == 0) && ((flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0)) { for (bptr = buffer, i = 0; i < sample_count; ++i, byte_idx += 2) { int left; int right; int sam_A; int sam_B; if (BitsUtils.bs_remain_write(wps.wvbits) < 128) { break; } crc = (crc * 3) + (left = (int) bptr[byte_idx]); crc = (crc * 3) + (right = (int) bptr[byte_idx + 1]); if ((flags & Defines.JOINT_STEREO) > 0) { right += ((left -= right) >> 1); } dpp_idx = 0; for (tcount = wps.num_terms; tcount > 0; tcount--) { if (wps.decorr_passes[dpp_idx].term > 0) { if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { if ((wps.decorr_passes[dpp_idx].term & 1) != 0) { sam_A = (2 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]; sam_B = (2 * wps.decorr_passes[dpp_idx].samples_B[0]) - wps.decorr_passes[dpp_idx].samples_B[1]; } else { sam_A = ((3 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]) >> 1; sam_B = ((3 * wps.decorr_passes[dpp_idx].samples_B[0]) - wps.decorr_passes[dpp_idx].samples_B[1]) >> 1; } wps.decorr_passes[dpp_idx].samples_A[1] = wps.decorr_passes[dpp_idx].samples_A[0]; wps.decorr_passes[dpp_idx].samples_B[1] = wps.decorr_passes[dpp_idx].samples_B[0]; wps.decorr_passes[dpp_idx].samples_A[0] = left; wps.decorr_passes[dpp_idx].samples_B[0] = right; } else { int k = (m + wps.decorr_passes[dpp_idx].term) & (Defines.MAX_TERM - 1); sam_A = wps.decorr_passes[dpp_idx].samples_A[m]; sam_B = wps.decorr_passes[dpp_idx].samples_B[m]; wps.decorr_passes[dpp_idx].samples_A[k] = left; wps.decorr_passes[dpp_idx].samples_B[k] = right; } left -= apply_weight(wps.decorr_passes[dpp_idx].weight_A, sam_A); right -= apply_weight(wps.decorr_passes[dpp_idx].weight_B, sam_B); wps.decorr_passes[dpp_idx].weight_A = update_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, sam_A, left); wps.decorr_passes[dpp_idx].weight_B = update_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].delta, sam_B, right); } else { sam_A = (wps.decorr_passes[dpp_idx].term == -2) ? right : wps.decorr_passes[dpp_idx].samples_A[0]; sam_B = (wps.decorr_passes[dpp_idx].term == -1) ? left : wps.decorr_passes[dpp_idx].samples_B[0]; wps.decorr_passes[dpp_idx].samples_A[0] = right; wps.decorr_passes[dpp_idx].samples_B[0] = left; left -= apply_weight(wps.decorr_passes[dpp_idx].weight_A, sam_A); right -= apply_weight(wps.decorr_passes[dpp_idx].weight_B, sam_B); wps.decorr_passes[dpp_idx].weight_A = update_weight_clip(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, sam_A, left); wps.decorr_passes[dpp_idx].weight_B = update_weight_clip(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].delta, sam_B, right); } dpp_idx++; } m = (m + 1) & (Defines.MAX_TERM - 1); WordsUtils.send_word_lossless(wps, left, 0); WordsUtils.send_word_lossless(wps, right, 1); } wpc.byte_idx = byte_idx; } /////////////////// handle the lossy/hybrid mono mode ///////////////////// else if (((flags & Defines.HYBRID_FLAG) != 0) && ((flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) != 0)) { for (bptr = buffer, i = 0; i < sample_count; ++i) { int code; int temp; if ((BitsUtils.bs_remain_write(wps.wvbits) < 64) || ((wpc.wvc_flag != 0) && (BitsUtils.bs_remain_write(wps.wvcbits) < 64))) { break; } crc2 = (crc2 * 3) + (code = (int) (bptr[byte_idx])); byte_idx++; if ((flags & Defines.HYBRID_SHAPE) != 0) { int shaping_weight = (wps.dc.shaping_acc[0] += wps.dc.shaping_delta[0]) >> 16; temp = -apply_weight(shaping_weight, wps.dc.error[0]); if (((flags & Defines.NEW_SHAPING) != 0) && (shaping_weight < 0) && (temp != 0)) { if (temp == wps.dc.error[0]) { temp = (temp < 0) ? (temp + 1) : (temp - 1); } wps.dc.error[0] = -code; code += temp; } else { wps.dc.error[0] = -(code += temp); } } dpp_idx = 0; for (tcount = wps.num_terms; tcount > 0; tcount--) { if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { if ((wps.decorr_passes[dpp_idx].term & 1) != 0) { wps.decorr_passes[dpp_idx].samples_A[2] = (2 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]; } else { wps.decorr_passes[dpp_idx].samples_A[2] = ((3 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]) >> 1; } code -= (wps.decorr_passes[dpp_idx].aweight_A = apply_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].samples_A[2])); } else { code -= (wps.decorr_passes[dpp_idx].aweight_A = apply_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].samples_A[m])); } dpp_idx++; } code = WordsUtils.send_word(wps, code, 0); dpp_idx--; while (dpp_idx >= 0) { if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { wps.decorr_passes[dpp_idx].weight_A = update_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_A[2], code); wps.decorr_passes[dpp_idx].samples_A[1] = wps.decorr_passes[dpp_idx].samples_A[0]; wps.decorr_passes[dpp_idx].samples_A[0] = (code += wps.decorr_passes[dpp_idx].aweight_A); } else { int sam = wps.decorr_passes[dpp_idx].samples_A[m]; wps.decorr_passes[dpp_idx].weight_A = update_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, sam, code); wps.decorr_passes[dpp_idx].samples_A[(m + wps.decorr_passes[dpp_idx].term) & (Defines.MAX_TERM - 1)] = (code += wps.decorr_passes[dpp_idx].aweight_A); } dpp_idx--; } wps.dc.error[0] += code; m = (m + 1) & (Defines.MAX_TERM - 1); if ((crc = (crc * 3) + code) != crc2) { lossy = Defines.TRUE; } } wpc.byte_idx = byte_idx; } /////////////////// handle the lossy/hybrid stereo mode /////////////////// else if (((flags & Defines.HYBRID_FLAG) != 0) && ((flags & (Defines.MONO_FLAG | Defines.FALSE_STEREO)) == 0)) { for (bptr = buffer, i = 0; i < sample_count; ++i) { int left; int right; int temp; int shaping_weight; if ((BitsUtils.bs_remain_write(wps.wvbits) < 128) || ((wpc.wvc_flag != 0) && (BitsUtils.bs_remain_write(wps.wvcbits) < 128))) { break; } left = (int) (bptr[byte_idx]); byte_idx++; crc2 = (((crc2 * 3) + left) * 3) + (right = (int) (bptr[byte_idx])); byte_idx++; if ((flags & Defines.HYBRID_SHAPE) != 0) { shaping_weight = (wps.dc.shaping_acc[0] += wps.dc.shaping_delta[0]) >> 16; temp = -apply_weight(shaping_weight, wps.dc.error[0]); if (((flags & Defines.NEW_SHAPING) != 0) && (shaping_weight < 0) && (temp != 0)) { if (temp == wps.dc.error[0]) { temp = (temp < 0) ? (temp + 1) : (temp - 1); } wps.dc.error[0] = -left; left += temp; } else { wps.dc.error[0] = -(left += temp); } shaping_weight = (wps.dc.shaping_acc[1] += wps.dc.shaping_delta[1]) >> 16; temp = -apply_weight(shaping_weight, wps.dc.error[1]); if (((flags & Defines.NEW_SHAPING) != 0) && (shaping_weight < 0) && (temp != 0)) { if (temp == wps.dc.error[1]) { temp = (temp < 0) ? (temp + 1) : (temp - 1); } wps.dc.error[1] = -right; right += temp; } else { wps.dc.error[1] = -(right += temp); } } if ((flags & Defines.JOINT_STEREO) != 0) { right += ((left -= right) >> 1); } dpp_idx = 0; for (tcount = wps.num_terms; tcount > 0; tcount--) { if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { if ((wps.decorr_passes[dpp_idx].term & 1) != 0) { wps.decorr_passes[dpp_idx].samples_A[2] = (2 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]; wps.decorr_passes[dpp_idx].samples_B[2] = (2 * wps.decorr_passes[dpp_idx].samples_B[0]) - wps.decorr_passes[dpp_idx].samples_B[1]; } else { wps.decorr_passes[dpp_idx].samples_A[2] = ((3 * wps.decorr_passes[dpp_idx].samples_A[0]) - wps.decorr_passes[dpp_idx].samples_A[1]) >> 1; wps.decorr_passes[dpp_idx].samples_B[2] = ((3 * wps.decorr_passes[dpp_idx].samples_B[0]) - wps.decorr_passes[dpp_idx].samples_B[1]) >> 1; } left -= (wps.decorr_passes[dpp_idx].aweight_A = apply_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].samples_A[2])); right -= (wps.decorr_passes[dpp_idx].aweight_B = apply_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].samples_B[2])); } else if (wps.decorr_passes[dpp_idx].term > 0) { left -= (wps.decorr_passes[dpp_idx].aweight_A = apply_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].samples_A[m])); right -= (wps.decorr_passes[dpp_idx].aweight_B = apply_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].samples_B[m])); } else { if (wps.decorr_passes[dpp_idx].term == -1) { wps.decorr_passes[dpp_idx].samples_B[0] = left; } else if (wps.decorr_passes[dpp_idx].term == -2) { wps.decorr_passes[dpp_idx].samples_A[0] = right; } left -= (wps.decorr_passes[dpp_idx].aweight_A = apply_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].samples_A[0])); right -= (wps.decorr_passes[dpp_idx].aweight_B = apply_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].samples_B[0])); } dpp_idx++; } left = WordsUtils.send_word(wps, left, 0); right = WordsUtils.send_word(wps, right, 1); dpp_idx--; while (dpp_idx >= 0) { if (wps.decorr_passes[dpp_idx].term > Defines.MAX_TERM) { wps.decorr_passes[dpp_idx].weight_A = update_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_A[2], left); wps.decorr_passes[dpp_idx].weight_B = update_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_B[2], right); wps.decorr_passes[dpp_idx].samples_A[1] = wps.decorr_passes[dpp_idx].samples_A[0]; wps.decorr_passes[dpp_idx].samples_B[1] = wps.decorr_passes[dpp_idx].samples_B[0]; wps.decorr_passes[dpp_idx].samples_A[0] = (left += wps.decorr_passes[dpp_idx].aweight_A); wps.decorr_passes[dpp_idx].samples_B[0] = (right += wps.decorr_passes[dpp_idx].aweight_B); } else if (wps.decorr_passes[dpp_idx].term > 0) { int k = (m + wps.decorr_passes[dpp_idx].term) & (Defines.MAX_TERM - 1); wps.decorr_passes[dpp_idx].weight_A = update_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_A[m], left); wps.decorr_passes[dpp_idx].samples_A[k] = (left += wps.decorr_passes[dpp_idx].aweight_A); wps.decorr_passes[dpp_idx].weight_B = update_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_B[m], right); wps.decorr_passes[dpp_idx].samples_B[k] = (right += wps.decorr_passes[dpp_idx].aweight_B); } else { if (wps.decorr_passes[dpp_idx].term == -1) { wps.decorr_passes[dpp_idx].samples_B[0] = left + wps.decorr_passes[dpp_idx].aweight_A; wps.decorr_passes[dpp_idx].aweight_B = apply_weight(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].samples_B[0]); } else if (wps.decorr_passes[dpp_idx].term == -2) { wps.decorr_passes[dpp_idx].samples_A[0] = right + wps.decorr_passes[dpp_idx].aweight_B; wps.decorr_passes[dpp_idx].aweight_A = apply_weight(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].samples_A[0]); } wps.decorr_passes[dpp_idx].weight_A = update_weight_clip(wps.decorr_passes[dpp_idx].weight_A, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_A[0], left); wps.decorr_passes[dpp_idx].weight_B = update_weight_clip(wps.decorr_passes[dpp_idx].weight_B, wps.decorr_passes[dpp_idx].delta, wps.decorr_passes[dpp_idx].samples_B[0], right); wps.decorr_passes[dpp_idx].samples_B[0] = (left += wps.decorr_passes[dpp_idx].aweight_A); wps.decorr_passes[dpp_idx].samples_A[0] = (right += wps.decorr_passes[dpp_idx].aweight_B); } dpp_idx--; } if ((flags & Defines.JOINT_STEREO) != 0) { left += (right -= (left >> 1)); } wps.dc.error[0] += left; wps.dc.error[1] += right; m = (m + 1) & (Defines.MAX_TERM - 1); if ((crc = (((crc * 3) + left) * 3) + right) != crc2) { lossy = Defines.TRUE; } } wpc.byte_idx = byte_idx; } block_samples = (long) ((wps.blockbuff[23] & 0xFF) << 24); block_samples += (long) ((wps.blockbuff[22] & 0xFF) << 16); block_samples += (long) ((wps.blockbuff[21] & 0xFF) << 8); block_samples += (long) (wps.blockbuff[20] & 0XFF); block_samples = block_samples + i; wps.blockbuff[20] = (byte) block_samples; wps.blockbuff[21] = (byte) (block_samples >>> 8); wps.blockbuff[22] = (byte) (block_samples >>> 16); wps.blockbuff[23] = (byte) (block_samples >>> 24); wps.blockbuff[28] = (byte) crc; wps.blockbuff[29] = (byte) (crc >>> 8); wps.blockbuff[30] = (byte) (crc >>> 16); wps.blockbuff[31] = (byte) (crc >>> 24); if (wpc.wvc_flag != 0) { block_samples = (long) ((wps.block2buff[23] & 0xFF) << 24); block_samples += (long) ((wps.block2buff[22] & 0xFF) << 16); block_samples += (long) ((wps.block2buff[21] & 0xFF) << 8); block_samples += (long) (wps.block2buff[20] & 0XFF); block_samples = block_samples + i; wps.block2buff[20] = (byte) block_samples; wps.block2buff[21] = (byte) (block_samples >>> 8); wps.block2buff[22] = (byte) (block_samples >>> 16); wps.block2buff[23] = (byte) (block_samples >>> 24); wps.block2buff[28] = (byte) crc2; wps.block2buff[29] = (byte) (crc2 >>> 8); wps.block2buff[30] = (byte) (crc2 >>> 16); wps.block2buff[31] = (byte) (crc2 >>> 24); } if (lossy != 0) { wps.lossy_block = Defines.TRUE; } wps.sample_index += i; return i; } static int apply_weight(int weight, int sample) { return ((int) (((weight * (long) sample) + 512) >> 10)); } static short update_weight(short weight, short delta, int source, int result) { if ((source != 0) && (result != 0)) { weight += ((((source ^ result) >> 30) | 1) * delta); } return weight; } static short update_weight_clip(short weight, short delta, int source, long result) { if ((source != 0) && (result != 0) && (((source ^ result) < 0) ? ((weight -= delta) < -1024) : ((weight += delta) > 1024))) { if (weight < 0) { weight = -1024; } else { weight = 1024; } } return weight; } // Once all the desired samples have been packed into the WavPack block being // built, this function is called to prepare it for writing. Basically, this // means just closing the bitstreams because the block_samples and crc fields // of the WavpackHeader are updated during packing. static int pack_finish_block(WavpackContext wpc) { WavpackStream wps = wpc.stream; int lossy = wps.lossy_block; int tcount; int m; long data_count; long block_samples; long chunkSize = 0; int dpp_idx = 0; block_samples = (long) ((wps.blockbuff[23] & 0xFF) << 24); block_samples += (long) ((wps.blockbuff[22] & 0xFF) << 16); block_samples += (long) ((wps.blockbuff[21] & 0xFF) << 8); block_samples += (long) (wps.blockbuff[20] & 0XFF); m = (int) (block_samples & (long) (Defines.MAX_TERM - 1)); if (m != 0) { for (tcount = wps.num_terms; tcount > 0; dpp_idx++) { if ((wps.decorr_passes[dpp_idx].term > 0) && (wps.decorr_passes[dpp_idx].term <= Defines.MAX_TERM)) { int[] temp_A = new int[Defines.MAX_TERM]; int[] temp_B = new int[Defines.MAX_TERM]; int k; System.arraycopy(wps.decorr_passes[dpp_idx].samples_A, 0, temp_A, 0, wps.decorr_passes[dpp_idx].samples_A.length); System.arraycopy(wps.decorr_passes[dpp_idx].samples_B, 0, temp_B, 0, wps.decorr_passes[dpp_idx].samples_B.length); for (k = 0; k < Defines.MAX_TERM; k++) { wps.decorr_passes[dpp_idx].samples_A[k] = temp_A[m]; wps.decorr_passes[dpp_idx].samples_B[k] = temp_B[m]; m = (m + 1) & (Defines.MAX_TERM - 1); } } tcount--; } } WordsUtils.flush_word(wps); data_count = BitsUtils.bs_close_write(wps); if (data_count != 0) { if (data_count != (long) -1) { int cptr_idx = 0; chunkSize = (wps.blockbuff[4] & 0xff) + ((wps.blockbuff[5] & 0xff) << 8) + ((wps.blockbuff[6] & 0xff) << 16) + ((wps.blockbuff[7] & 0xff) << 24); cptr_idx = (int) chunkSize + 8; wps.blockbuff[cptr_idx] = (byte) (Defines.ID_WV_BITSTREAM | Defines.ID_LARGE); cptr_idx++; wps.blockbuff[cptr_idx] = (byte) (data_count >> 1); cptr_idx++; wps.blockbuff[cptr_idx] = (byte) (data_count >> 9); cptr_idx++; wps.blockbuff[cptr_idx] = (byte) (data_count >> 17); chunkSize = chunkSize + data_count + 4; wps.blockbuff[4] = (byte) (chunkSize); wps.blockbuff[5] = (byte) (chunkSize >> 8); wps.blockbuff[6] = (byte) (chunkSize >> 16); wps.blockbuff[7] = (byte) (chunkSize >> 24); } else { return Defines.FALSE; } } if (wpc.wvc_flag != 0) { data_count = BitsUtils.bs_close_correction_write(wps); if ((data_count != 0) && (lossy != 0)) { if (data_count != (long) -1) { int cptr_idx = 0; chunkSize = (wps.block2buff[4] & 0xff) + ((wps.block2buff[5] & 0xff) << 8) + ((wps.block2buff[6] & 0xff) << 16) + ((wps.block2buff[7] & 0xff) << 24); cptr_idx = (int) chunkSize + 8; wps.block2buff[cptr_idx] = (byte) (Defines.ID_WVC_BITSTREAM | Defines.ID_LARGE); cptr_idx++; wps.block2buff[cptr_idx] = (byte) (data_count >> 1); cptr_idx++; wps.block2buff[cptr_idx] = (byte) (data_count >> 9); cptr_idx++; wps.block2buff[cptr_idx] = (byte) (data_count >> 17); cptr_idx++; chunkSize = chunkSize + data_count + 4; wps.block2buff[4] = (byte) (chunkSize); wps.block2buff[5] = (byte) (chunkSize >> 8); wps.block2buff[6] = (byte) (chunkSize >> 16); wps.block2buff[7] = (byte) (chunkSize >> 24); } else { return Defines.FALSE; } } } else if (lossy != 0) { wpc.lossy_blocks = Defines.TRUE; } return Defines.TRUE; } // Copy the specified metadata item to the WavPack block being contructed. This // function tests for writing past the end of the available space, however the // rest of the code is designed so that can't occur. // Prepare a WavPack block for writing. The block will be written at // "wps.blockbuff" and "wps.blockend" points to the end of the available // space. If a wvc file is being written, then block2buff and block2end are // also used. This also sets up the bitstreams so that pack_samples() can be // called next with actual sample data. To find out how much data was written // the caller must look at the ckSize field of the written WavpackHeader, NOT // the one in the WavpackStream. A return value of FALSE indicates an error. static int copy_metadata(WavpackMetadata wpmd, byte[] buffer_start, int buffer_end) { long mdsize = wpmd.byte_length + (wpmd.byte_length & 1); long chunkSize; int bufIdx = 0; if ((wpmd.byte_length & 1) != 0) { (wpmd.data)[wpmd.byte_length] = 0; } mdsize += ((wpmd.byte_length > 510) ? 4 : 2); chunkSize = (buffer_start[4] & 0xff) + ((buffer_start[5] & 0xff) << 8) + ((buffer_start[6] & 0xff) << 16) + ((buffer_start[7] & 0xff) << 24); bufIdx = (int) (chunkSize + 8); if ((bufIdx + mdsize) >= buffer_end) { return Defines.FALSE; } buffer_start[bufIdx] = (byte) (wpmd.id | (((wpmd.byte_length & 1) != 0) ? Defines.ID_ODD_SIZE : 0)); buffer_start[bufIdx + 1] = (byte) ((wpmd.byte_length + 1) >> 1); if (wpmd.byte_length > 510) { buffer_start[bufIdx] |= Defines.ID_LARGE; buffer_start[bufIdx + 2] = (byte) ((wpmd.byte_length + 1) >> 9); buffer_start[bufIdx + 3] = (byte) ((wpmd.byte_length + 1) >> 17); } if ((wpmd.data.length != 0) && (wpmd.byte_length != 0)) { if (wpmd.byte_length > 510) { buffer_start[bufIdx] |= Defines.ID_LARGE; buffer_start[bufIdx + 2] = (byte) ((wpmd.byte_length + 1) >> 9); buffer_start[bufIdx + 3] = (byte) ((wpmd.byte_length + 1) >> 17); System.arraycopy(wpmd.data, 0, buffer_start, bufIdx + 4, (int) (mdsize - 4)); } else { System.arraycopy(wpmd.data, 0, buffer_start, bufIdx + 2, (int) (mdsize - 2)); } } chunkSize += mdsize; buffer_start[4] = (byte) (chunkSize); buffer_start[5] = (byte) (chunkSize >>> 8); buffer_start[6] = (byte) (chunkSize >>> 16); buffer_start[7] = (byte) (chunkSize >>> 24); return Defines.TRUE; } }