/* * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * by the Xiph.Org Foundation http://www.xiph.org/ */ package org.xiph.libvorbis; import org.xiph.libvorbis.modes.setup_44; import static org.xiph.libvorbis.vorbis_constants.integer_constants.*; /** * ****************************************************************** * Encoding using a VBR quality mode. The usable range is -.1 * (lowest quality, smallest file) to 1. (highest quality, largest file). * Example quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR * <p/> * ret = vorbis_encode_init_vbr(&vi,2,44100,.4); * <p/> * --------------------------------------------------------------------- * <p/> * Encoding using an average bitrate mode (ABR). * example: 44kHz stereo coupled, average 128kbps VBR * <p/> * ret = vorbis_encode_init(&vi,2,44100,-1,128000,-1); * <p/> * --------------------------------------------------------------------- * <p/> * Encode using a quality mode, but select that quality mode by asking for * an approximate bitrate. This is not ABR, it is true VBR, but selected * using the bitrate interface, and then turning bitrate management off: * <p/> * ret = ( vorbis_encode_setup_managed(&vi,2,44100,-1,128000,-1) || * vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || * vorbis_encode_setup_init(&vi)); * <p/> * ******************************************************************* */ public class vorbisenc { private vorbis_info vi; private ve_setup_data_template[] setup_list; public vorbisenc() { setup_44 ve_setup_44_stereo = new org.xiph.libvorbis.modes.setup_44(); setup_list = new ve_setup_data_template[]{ve_setup_44_stereo.data}; } public boolean vorbis_encode_setup_vbr(int channels, int rate, float quality) { quality += .0000001; if (quality >= 1.) quality = .9999f; if (!get_setup_template(channels, rate, quality, 0)) { System.out.println("Unable to find setup template - " + channels + " channels, " + rate + " rate, " + quality + " quality"); return false; } return vorbis_encode_setup_setting(channels, rate); } public boolean vorbis_encode_init_vbr(vorbis_info _vi, int channels, int rate, float base_quality) { if (_vi == null) { System.out.println("vorbis_info doesnt exist"); return false; } vi = _vi; if (!vorbis_encode_setup_vbr(channels, rate, base_quality)) return false; return vorbis_encode_setup_init(); } public boolean vorbis_encode_setup_managed(vorbis_info _vi, int channels, int rate, int max_bitrate, int nominal_bitrate, int min_bitrate) { vi = _vi; float tnominal = new Integer(nominal_bitrate).floatValue(); if (nominal_bitrate <= 0.) { if (max_bitrate > 0.) { if (min_bitrate > 0.) nominal_bitrate = new Double((max_bitrate + min_bitrate) * .5).intValue(); else nominal_bitrate = new Double(max_bitrate * .875).intValue(); } else { if (min_bitrate > 0.) nominal_bitrate = min_bitrate; else return false; } } if (!get_setup_template(channels, rate, nominal_bitrate, 1)) { System.out.println("Unable to find setup template - " + channels + " channels, " + rate + " rate, " + nominal_bitrate + " nominal_bitrate"); return false; } vorbis_encode_setup_setting(channels, rate); highlevel_encode_setup hi = vi.codec_setup.hi; // initialize management with sane defaults hi.managed = 1; hi.bitrate_min = min_bitrate; hi.bitrate_max = max_bitrate; hi.bitrate_av = new Float(tnominal).intValue(); hi.bitrate_av_damp = 1.5f; hi.bitrate_reservoir = nominal_bitrate * 2; hi.bitrate_reservoir_bias = .1f; // bias toward hoarding bits return true; } public boolean vorbis_encode_init(vorbis_info _vi, int channels, int rate, int max_bitrate, int nominal_bitrate, int min_bitrate) { if (_vi == null) return false; if (!vorbis_encode_setup_managed(_vi, channels, rate, max_bitrate, nominal_bitrate, min_bitrate)) return false; return vorbis_encode_setup_init(); } public Object vorbis_encode_ctl(vorbis_info _vi, int number, Object arg) { if (_vi == null) return false; codec_setup_info ci = vi.codec_setup; highlevel_encode_setup hi = ci.hi; int setp = (number & 0xf); // a read request has a low nibble of 0 if ((setp > 0) && (hi.set_in_stone > 0)) return false; switch (number) { // now deprecated ***************** /* case OV_ECTL_RATEMANAGE_GET: { ovectl_ratemanage_arg ai= ( ovectl_ratemanage_arg )arg; ai.management_active=hi.managed; ai.bitrate_hard_window=ai.bitrate_av_window=(double)hi.bitrate_reservoir/vi.rate; ai.bitrate_av_window_center=1.; ai.bitrate_hard_min=hi.bitrate_min; ai.bitrate_hard_max=hi.bitrate_max; ai.bitrate_av_lo=hi.bitrate_av; ai.bitrate_av_hi=hi.bitrate_av; } return true; // now deprecated ***************** case OV_ECTL_RATEMANAGE_SET: { ovectl_ratemanage_arg ai= ( ovectl_ratemanage_arg )arg; if ( ai == null ) { hi.managed=0; } else { hi.managed=ai.management_active; vorbis_encode_ctl( vi, OV_ECTL_RATEMANAGE_AVG, arg ); vorbis_encode_ctl( vi, OV_ECTL_RATEMANAGE_HARD, arg ); } } return true; // now deprecated ***************** case OV_ECTL_RATEMANAGE_AVG: { ovectl_ratemanage_arg ai= ( ovectl_ratemanage_arg )arg; if (ai == null) { hi.bitrate_av=0; } else { hi.bitrate_av=(ai.bitrate_av_lo+ai.bitrate_av_hi)*.5; } } return true; // now deprecated ***************** case OV_ECTL_RATEMANAGE_HARD: { ovectl_ratemanage_arg ai= ( ovectl_ratemanage_arg )arg; if (ai == null ) { hi.bitrate_min=0; hi.bitrate_max=0; } else { hi.bitrate_min=ai.bitrate_hard_min; hi.bitrate_max=ai.bitrate_hard_max; hi.bitrate_reservoir=ai.bitrate_hard_window*(hi.bitrate_max+hi.bitrate_min)*.5; } if ( hi.bitrate_reservoir < 128.f ) hi.bitrate_reservoir=128; } return true; */ // replacement ratemanage interface case OV_ECTL_RATEMANAGE2_GET: { ovectl_ratemanage2_arg ai = (ovectl_ratemanage2_arg) arg; if (ai == null) return false; ai.management_active = hi.managed; ai.bitrate_limit_min_kbps = hi.bitrate_min / 1000; ai.bitrate_limit_max_kbps = hi.bitrate_max / 1000; ai.bitrate_average_kbps = hi.bitrate_av / 1000; ai.bitrate_average_damping = hi.bitrate_av_damp; ai.bitrate_limit_reservoir_bits = hi.bitrate_reservoir; ai.bitrate_limit_reservoir_bias = hi.bitrate_reservoir_bias; return ai; } case OV_ECTL_RATEMANAGE2_SET: { ovectl_ratemanage2_arg ai = (ovectl_ratemanage2_arg) arg; if (ai == null) { hi.managed = 0; } else { // sanity check; only catch invariant violations if (ai.bitrate_limit_min_kbps > 0 && ai.bitrate_average_kbps > 0 && ai.bitrate_limit_min_kbps > ai.bitrate_average_kbps) return false; if (ai.bitrate_limit_max_kbps > 0 && ai.bitrate_average_kbps > 0 && ai.bitrate_limit_max_kbps < ai.bitrate_average_kbps) return false; if (ai.bitrate_limit_min_kbps > 0 && ai.bitrate_limit_max_kbps > 0 && ai.bitrate_limit_min_kbps > ai.bitrate_limit_max_kbps) return false; if (ai.bitrate_average_damping <= 0.) return false; if (ai.bitrate_limit_reservoir_bits < 0) return false; if (ai.bitrate_limit_reservoir_bias < 0.) return false; if (ai.bitrate_limit_reservoir_bias > 1.) return false; hi.managed = ai.management_active; hi.bitrate_min = ai.bitrate_limit_min_kbps * 1000; hi.bitrate_max = ai.bitrate_limit_max_kbps * 1000; hi.bitrate_av = ai.bitrate_average_kbps * 1000; hi.bitrate_av_damp = ai.bitrate_average_damping; hi.bitrate_reservoir = ai.bitrate_limit_reservoir_bits; hi.bitrate_reservoir_bias = ai.bitrate_limit_reservoir_bias; } } return true; case OV_ECTL_LOWPASS_GET: { return hi.lowpass_kHz; } case OV_ECTL_LOWPASS_SET: { hi.lowpass_kHz = (Float) arg; if (hi.lowpass_kHz < 2.f) hi.lowpass_kHz = 2.f; if (hi.lowpass_kHz > 99.f) hi.lowpass_kHz = 99.f; } return true; case OV_ECTL_IBLOCK_GET: { return hi.impulse_noisetune; } case OV_ECTL_IBLOCK_SET: { hi.impulse_noisetune = (Float) arg; if (hi.impulse_noisetune > 0.f) hi.impulse_noisetune = 0.f; if (hi.impulse_noisetune < -15.f) hi.impulse_noisetune = -15.f; } return true; } return true; } private boolean get_setup_template(int ch, int srate, float req, int q_or_bitrate) { int j; highlevel_encode_setup hi = vi.codec_setup.hi; if (q_or_bitrate > 0) req /= ch; for (int i = 0; i < setup_list.length; i++) { if (setup_list[i].coupling_restriction == -1 || setup_list[i].coupling_restriction == ch) { if (srate >= setup_list[i].samplerate_min_restriction && srate <= setup_list[i].samplerate_max_restriction) { int mappings = setup_list[i].mappings; float[] map; if (q_or_bitrate > 0) map = setup_list[i].rate_mapping; else map = setup_list[i].quality_mapping; // the template matches. Does the requested quality mode fall within this templates modes? if (req < map[0]) { continue; } if (req > map[setup_list[i].mappings]) { continue; } for (j = 0; j < mappings; j++) if (req >= map[j] && req < map[j + 1]) break; // an all points match hi.setup = setup_list[i]; if (j == mappings) hi.base_setting = j - .001f; else { float low = map[j]; float high = map[j + 1]; float del = (req - low) / (high - low); hi.base_setting = j + del; } return true; } } } hi.setup = null; return false; } private boolean vorbis_encode_setup_setting(int channels, int rate) { int i, is; codec_setup_info ci = vi.codec_setup; highlevel_encode_setup hi = ci.hi; ve_setup_data_template setup = hi.setup; float ds; // double // vorbis_encode_toplevel_setup(vorbis_info *vi,int ch,long rate) vi.version = 0; vi.channels = channels; vi.rate = rate; is = new Float(hi.base_setting).intValue(); ds = hi.base_setting - is; hi.short_setting = hi.base_setting; hi.long_setting = hi.base_setting; hi.managed = 0; hi.impulse_block_p = 1; hi.noise_normalize_p = 1; hi.stereo_point_setting = hi.base_setting; hi.lowpass_kHz = setup.psy_lowpass[is] * (1.0f - ds) + setup.psy_lowpass[is + 1] * ds; hi.ath_floating_dB = setup.psy_ath_float[is] * (1.0f - ds) + setup.psy_ath_float[is + 1] * ds; hi.ath_absolute_dB = setup.psy_ath_abs[is] * (1.0f - ds) + setup.psy_ath_abs[is + 1] * ds; hi.amplitude_track_dBpersec = -6.0f; hi.trigger_setting = hi.base_setting; for (i = 0; i < 4; i++) hi.block[i] = new highlevel_byblocktype(hi.base_setting, hi.base_setting, hi.base_setting, hi.base_setting); return true; } public boolean vorbis_encode_setup_init() { // the final setup call int i0 = 0; int singleblock = 0; codec_setup_info ci = vi.codec_setup; ve_setup_data_template setup = null; highlevel_encode_setup hi = ci.hi; if (ci == null) { System.out.println("vorbis_info.codec_setup_info doesnt exist"); return false; } if (hi.impulse_block_p == 0) i0 = 1; // too low/high an ATH floater is nonsensical, but doesn't break anything if (hi.ath_floating_dB > -80) hi.ath_floating_dB = -80; if (hi.ath_floating_dB < -200) hi.ath_floating_dB = -200; // again, bound this to avoid the app shooting itself in the foot if (hi.amplitude_track_dBpersec > 0.) hi.amplitude_track_dBpersec = 0.0f; if (hi.amplitude_track_dBpersec < -99999.) hi.amplitude_track_dBpersec = -99999.0f; // get the appropriate setup template; matches the fetch in previous stages setup = hi.setup; if (setup == null) { System.out.println("vorbis_info.codec_setup.highlevel_encode_setup.ve_setup_data_template doesnt exist"); return false; } hi.set_in_stone = 1; // choose block sizes from configured sizes as well as paying attention // to long_block_p and short_block_p. If the configured short and long // blocks are the same length, we set long_block_p and unset short_block_p vorbis_encode_blocksize_setup(hi.base_setting, setup.blocksize_short, setup.blocksize_long); if (ci.blocksizes[0] == ci.blocksizes[1]) singleblock = 1; // floor setup; choose proper floor params. Allocated on the floor stack in order; if we alloc only long floor, it's 0 vorbis_encode_floor_setup(hi.short_setting, 0, setup.floor_books, setup.floor_params, setup.floor_short_mapping); if (singleblock == 0) vorbis_encode_floor_setup(hi.long_setting, 1, setup.floor_books, setup.floor_params, setup.floor_long_mapping); // setup of [mostly] short block detection and stereo vorbis_encode_global_psych_setup(hi.trigger_setting, setup.global_params, setup.global_mapping); vorbis_encode_global_stereo(hi, setup.stereo_modes); // basic psych setup and noise normalization vorbis_encode_psyset_setup(hi.short_setting, setup.psy_noise_normal_start[0], setup.psy_noise_normal_partition[0], setup.psy_noise_normal_thresh, 0); vorbis_encode_psyset_setup(hi.short_setting, setup.psy_noise_normal_start[0], setup.psy_noise_normal_partition[0], setup.psy_noise_normal_thresh, 1); if (singleblock == 0) { vorbis_encode_psyset_setup(hi.long_setting, setup.psy_noise_normal_start[1], setup.psy_noise_normal_partition[1], setup.psy_noise_normal_thresh, 2); vorbis_encode_psyset_setup(hi.long_setting, setup.psy_noise_normal_start[1], setup.psy_noise_normal_partition[1], setup.psy_noise_normal_thresh, 3); } // tone masking setup vorbis_encode_tonemask_setup(hi.block[i0].tone_mask_setting, 0, setup.psy_tone_masteratt, setup.psy_tone_0dB, setup.psy_tone_adj_impulse); vorbis_encode_tonemask_setup(hi.block[1].tone_mask_setting, 1, setup.psy_tone_masteratt, setup.psy_tone_0dB, setup.psy_tone_adj_other); if (singleblock == 0) { vorbis_encode_tonemask_setup(hi.block[2].tone_mask_setting, 2, setup.psy_tone_masteratt, setup.psy_tone_0dB, setup.psy_tone_adj_other); vorbis_encode_tonemask_setup(hi.block[3].tone_mask_setting, 3, setup.psy_tone_masteratt, setup.psy_tone_0dB, setup.psy_tone_adj_long); } // noise companding setup vorbis_encode_compand_setup(hi.block[i0].noise_compand_setting, 0, setup.psy_noise_compand, setup.psy_noise_compand_short_mapping); vorbis_encode_compand_setup(hi.block[1].noise_compand_setting, 1, setup.psy_noise_compand, setup.psy_noise_compand_short_mapping); if (singleblock == 0) { vorbis_encode_compand_setup(hi.block[2].noise_compand_setting, 2, setup.psy_noise_compand, setup.psy_noise_compand_long_mapping); vorbis_encode_compand_setup(hi.block[3].noise_compand_setting, 3, setup.psy_noise_compand, setup.psy_noise_compand_long_mapping); } // peak guarding setup vorbis_encode_peak_setup(hi.block[i0].tone_peaklimit_setting, 0, setup.psy_tone_dBsuppress); vorbis_encode_peak_setup(hi.block[1].tone_peaklimit_setting, 1, setup.psy_tone_dBsuppress); if (singleblock == 0) { vorbis_encode_peak_setup(hi.block[2].tone_peaklimit_setting, 2, setup.psy_tone_dBsuppress); vorbis_encode_peak_setup(hi.block[3].tone_peaklimit_setting, 3, setup.psy_tone_dBsuppress); } // noise bias setup float userbias = 0; if (i0 == 0) userbias = hi.impulse_noisetune; vorbis_encode_noisebias_setup(hi.block[i0].noise_bias_setting, 0, setup.psy_noise_dBsuppress, setup.psy_noise_bias_impulse, setup.psy_noiseguards, userbias); vorbis_encode_noisebias_setup(hi.block[1].noise_bias_setting, 1, setup.psy_noise_dBsuppress, setup.psy_noise_bias_padding, setup.psy_noiseguards, 0.0f); if (singleblock == 0) { vorbis_encode_noisebias_setup(hi.block[2].noise_bias_setting, 2, setup.psy_noise_dBsuppress, setup.psy_noise_bias_trans, setup.psy_noiseguards, 0.0f); vorbis_encode_noisebias_setup(hi.block[3].noise_bias_setting, 3, setup.psy_noise_dBsuppress, setup.psy_noise_bias_long, setup.psy_noiseguards, 0.0f); } vorbis_encode_ath_setup(0); vorbis_encode_ath_setup(1); if (singleblock == 0) { vorbis_encode_ath_setup(2); vorbis_encode_ath_setup(3); } vorbis_encode_map_n_res_setup(hi.base_setting, setup.maps); // set bitrate readonlies and management if (hi.bitrate_av > 0) vi.bitrate_nominal = hi.bitrate_av; else vi.bitrate_nominal = new Float(setting_to_approx_bitrate()).intValue(); vi.bitrate_lower = hi.bitrate_min; vi.bitrate_upper = hi.bitrate_max; if (hi.bitrate_av > 0) vi.bitrate_window = hi.bitrate_reservoir / hi.bitrate_av; else vi.bitrate_window = 0; if (hi.managed > 0) { ci.bi = new bitrate_manager_info( hi.bitrate_av, hi.bitrate_min, hi.bitrate_max, hi.bitrate_reservoir, hi.bitrate_reservoir_bias, hi.bitrate_av_damp); } return true; } private void vorbis_encode_blocksize_setup(float s, int[] shortb, int[] longb) { codec_setup_info ci = vi.codec_setup; int is = new Float(s).intValue(); int blockshort = shortb[is]; int blocklong = longb[is]; ci.blocksizes[0] = blockshort; ci.blocksizes[1] = blocklong; } private void vorbis_encode_floor_setup(float s, int block, static_codebook[][] books, vorbis_info_floor1[] in, int[] x) { int i, k; int is = new Float(s).intValue(); codec_setup_info ci = vi.codec_setup; // _ogg_calloc(1,sizeof(*f)) // memcpy(f,in+x[is],sizeof(*f)); vorbis_info_floor1 f = new vorbis_info_floor1(in[x[is]]); // fill in the lowpass field, even if it's temporary f.n = ci.blocksizes[block] >> 1; // books { int partitions = f.partitions; int maxclass = -1; int maxbook = -1; for (i = 0; i < partitions; i++) if (f.partitionclass[i] > maxclass) maxclass = f.partitionclass[i]; for (i = 0; i <= maxclass; i++) { if (f.class_book[i] > maxbook) maxbook = f.class_book[i]; f.class_book[i] += ci.books; for (k = 0; k < (1 << f.class_subs[i]); k++) { if (f.class_subbook[i][k] > maxbook) maxbook = f.class_subbook[i][k]; if (f.class_subbook[i][k] >= 0) f.class_subbook[i][k] += ci.books; } } for (i = 0; i <= maxbook; i++) { ci.book_param[ci.books++] = books[x[is]][i]; } } // for now, we're only using floor 1 ci.floor_type[ci.floors] = 1; ci.floor_param[ci.floors] = f; ci.floors++; } private void vorbis_encode_global_psych_setup(float s, vorbis_info_psy_global[] in, float[] x) { int i; int is = new Float(s).intValue(); float ds = s - is; codec_setup_info ci = vi.codec_setup; // memcpy(g,in+(int)x[is],sizeof(*g)); ci.psy_g_param = new vorbis_info_psy_global(in[new Float(x[is]).intValue()]); vorbis_info_psy_global g = ci.psy_g_param; ds = x[is] * (1.0f - ds) + x[is + 1] * ds; is = new Float(ds).intValue(); ds -= is; if (ds == 0 && is > 0) { is--; ds = 1.0f; } // interpolate the trigger threshholds for (i = 0; i < 4; i++) { g.preecho_thresh[i] = new Double(in[is].preecho_thresh[i] * (1. - ds) + in[is + 1].preecho_thresh[i] * ds).floatValue(); g.postecho_thresh[i] = new Double(in[is].postecho_thresh[i] * (1. - ds) + in[is + 1].postecho_thresh[i] * ds).floatValue(); } g.ampmax_att_per_sec = ci.hi.amplitude_track_dBpersec; } private void vorbis_encode_global_stereo(highlevel_encode_setup hi, adj_stereo[] p) { float s = hi.stereo_point_setting; int i; int is = new Float(s).intValue(); float ds = s - is; codec_setup_info ci = vi.codec_setup; vorbis_info_psy_global g = ci.psy_g_param; if (p != null) { // memcpy(g.coupling_prepointamp, p[is].pre, sizeof(*p[is].pre)*PACKETBLOBS); // memcpy(g.coupling_postpointamp, p[is].post, sizeof(*p[is].post)*PACKETBLOBS); g.coupling_prepointamp = (int[]) p[is].pre.clone(); g.coupling_postpointamp = (int[]) p[is].post.clone(); if (hi.managed != 0) { // interpolate the kHz threshholds for (i = 0; i < PACKETBLOBS; i++) { float kHz = new Double(p[is].kHz[i] * (1. - ds) + p[is + 1].kHz[i] * ds).floatValue(); g.coupling_pointlimit[0][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[0]).intValue(); g.coupling_pointlimit[1][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[1]).intValue(); g.coupling_pkHz[i] = new Float(kHz).intValue(); kHz = new Double(p[is].lowpasskHz[i] * (1. - ds) + p[is + 1].lowpasskHz[i] * ds).floatValue(); g.sliding_lowpass[0][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[0]).intValue(); g.sliding_lowpass[1][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[1]).intValue(); } } else { float kHz = new Double(p[is].kHz[PACKETBLOBS / 2] * (1. - ds) + p[is + 1].kHz[PACKETBLOBS / 2] * ds).floatValue(); for (i = 0; i < PACKETBLOBS; i++) { g.coupling_pointlimit[0][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[0]).intValue(); g.coupling_pointlimit[1][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[1]).intValue(); g.coupling_pkHz[i] = new Float(kHz).intValue(); } kHz = new Double(p[is].lowpasskHz[PACKETBLOBS / 2] * (1. - ds) + p[is + 1].lowpasskHz[PACKETBLOBS / 2] * ds).floatValue(); for (i = 0; i < PACKETBLOBS; i++) { g.sliding_lowpass[0][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[0]).intValue(); g.sliding_lowpass[1][i] = new Double(kHz * 1000. / vi.rate * ci.blocksizes[1]).intValue(); } } } else { for (i = 0; i < PACKETBLOBS; i++) { g.sliding_lowpass[0][i] = ci.blocksizes[0]; g.sliding_lowpass[1][i] = ci.blocksizes[1]; } } } private void vorbis_encode_psyset_setup(float s, int[] nn_start, int[] nn_partition, float[] nn_thresh, int block) { codec_setup_info ci = vi.codec_setup; highlevel_encode_setup hi = ci.hi; int is = new Float(s).intValue(); if (block >= ci.psys) ci.psys = block + 1; ci.psy_param[block] = new vorbis_info_psy( // static vorbis_info_psy _psy_info_template = { -1, -140.f, -140.f, // tonemask att boost/decay,suppr,curves new float[]{0.f, 0.f, 0.f}, 0.f, 0.f, -40.f, new float[]{0.f}, // noisemaskp,supp, low/high window, low/hi guard, minimum 1, -0.f, .5f, .5f, 0, 0, 0, new float[][]{{-1}, {-1}, {-1}}, new float[]{-1}, 105.f, 0, 0, -1, -1, 0.0f); vorbis_info_psy p = ci.psy_param[block]; p.blockflag = block >> 1; if (hi.noise_normalize_p != 0) { p.normal_channel_p = 1; p.normal_point_p = 1; p.normal_start = nn_start[is]; p.normal_partition = nn_partition[is]; p.normal_thresh = nn_thresh[is]; } } private void vorbis_encode_tonemask_setup(float s, int block, att3[] att, int[] max, vp_adjblock[] in) { int i; int is = new Float(s).intValue(); float ds = s - is; codec_setup_info ci = vi.codec_setup; vorbis_info_psy p = ci.psy_param[block]; // 0 and 2 are only used by bitmanagement, but there's no harm to always filling the values in here p.tone_masteratt[0] = new Double(att[is].att[0] * (1. - ds) + att[is + 1].att[0] * ds).floatValue(); p.tone_masteratt[1] = new Double(att[is].att[1] * (1. - ds) + att[is + 1].att[1] * ds).floatValue(); p.tone_masteratt[2] = new Double(att[is].att[2] * (1. - ds) + att[is + 1].att[2] * ds).floatValue(); p.tone_centerboost = new Double(att[is].boost * (1. - ds) + att[is + 1].boost * ds).floatValue(); p.tone_decay = new Double(att[is].decay * (1. - ds) + att[is + 1].decay * ds).floatValue(); p.max_curve_dB = new Double(max[is] * (1. - ds) + max[is + 1] * ds).floatValue(); for (i = 0; i < P_BANDS; i++) p.toneatt[i] = new Double(in[is].block[i] * (1. - ds) + in[is + 1].block[i] * ds).floatValue(); } private void vorbis_encode_compand_setup(float s, int block, compandblock[] in, float[] x) { int i; int is = new Float(s).intValue(); float ds = s - is; codec_setup_info ci = vi.codec_setup; vorbis_info_psy p = ci.psy_param[block]; ds = x[is] * (1.0f - ds) + x[is + 1] * ds; is = new Float(ds).intValue(); ds -= is; if (ds == 0 && is > 0) { is--; ds = 1.0f; } // interpolate the compander settings for (i = 0; i < NOISE_COMPAND_LEVELS; i++) p.noisecompand[i] = new Double(in[is].data[i] * (1. - ds) + in[is + 1].data[i] * ds).floatValue(); } private void vorbis_encode_peak_setup(float s, int block, int[] suppress) { int is = new Float(s).intValue(); float ds = s - is; codec_setup_info ci = vi.codec_setup; vorbis_info_psy p = ci.psy_param[block]; p.tone_abs_limit = new Double(suppress[is] * (1. - ds) + suppress[is + 1] * ds).floatValue(); } private void vorbis_encode_noisebias_setup(float s, int block, int[] suppress, noise3[] in, noiseguard[] guard, float userbias) { int i, j; int is = new Float(s).intValue(); float ds = s - is; codec_setup_info ci = vi.codec_setup; vorbis_info_psy p = ci.psy_param[block]; p.noisemaxsupp = new Double(suppress[is] * (1. - ds) + suppress[is + 1] * ds).floatValue(); p.noisewindowlomin = guard[block].lo; p.noisewindowhimin = guard[block].hi; p.noisewindowfixed = guard[block].fixed; for (j = 0; j < P_NOISECURVES; j++) for (i = 0; i < P_BANDS; i++) p.noiseoff[j][i] = new Double(in[is].data[j][i] * (1. - ds) + in[is + 1].data[j][i] * ds).floatValue(); // impulse blocks may take a user specified bias to boost the nominal/high noise encoding depth for (j = 0; j < P_NOISECURVES; j++) { float min = p.noiseoff[j][0] + 6; // the lowest it can go for (i = 0; i < P_BANDS; i++) { p.noiseoff[j][i] += userbias; if (p.noiseoff[j][i] < min) p.noiseoff[j][i] = min; } } } private void vorbis_encode_ath_setup(int block) { codec_setup_info ci = vi.codec_setup; vorbis_info_psy p = ci.psy_param[block]; p.ath_adjatt = ci.hi.ath_floating_dB; p.ath_maxatt = ci.hi.ath_absolute_dB; } private int book_dup_or_new(codec_setup_info ci, static_codebook book) { int i; for (i = 0; i < ci.books; i++) if (ci.book_param[i] == book) return (i); return (ci.books++); } private void vorbis_encode_residue_setup(int number, int block, vorbis_residue_template res) { codec_setup_info ci = vi.codec_setup; int i; // vorbis_info_residue0 *r = ci.residue_param[number] = _ogg_malloc(sizeof(*r)); // memcpy(r,res.res,sizeof(*r)); ci.residue_param[number] = new vorbis_info_residue0(res.res); vorbis_info_residue0 r = ci.residue_param[number]; if (ci.residues <= number) ci.residues = number + 1; switch (ci.blocksizes[block]) { case 64: case 128: case 256: r.grouping = 16; break; default: r.grouping = 32; break; } ci.residue_type[number] = res.res_type; // to be adjusted by lowpass/pointlimit later r.end = ci.blocksizes[block] >> 1; if (res.res_type == 2) { r.end *= vi.channels; } // fill in all the books { int booklist = 0, k; if (ci.hi.managed != 0) { for (i = 0; i < r.partitions; i++) for (k = 0; k < 3; k++) if (res.books_base_managed.books[i][k] != null) r.secondstages[i] |= (1 << k); r.groupbook = book_dup_or_new(ci, res.book_aux_managed); ci.book_param[r.groupbook] = res.book_aux_managed; for (i = 0; i < r.partitions; i++) { for (k = 0; k < 3; k++) { if (res.books_base_managed.books[i][k] != null) { int bookid = book_dup_or_new(ci, res.books_base_managed.books[i][k]); r.booklist[booklist++] = bookid; ci.book_param[bookid] = res.books_base_managed.books[i][k]; } } } } else { for (i = 0; i < r.partitions; i++) for (k = 0; k < 3; k++) if (res.books_base.books[i][k] != null) r.secondstages[i] |= (1 << k); r.groupbook = book_dup_or_new(ci, res.book_aux); ci.book_param[r.groupbook] = res.book_aux; for (i = 0; i < r.partitions; i++) { for (k = 0; k < 3; k++) { if (res.books_base.books[i][k] != null) { int bookid = book_dup_or_new(ci, res.books_base.books[i][k]); r.booklist[booklist++] = bookid; ci.book_param[bookid] = res.books_base.books[i][k]; } } } } } // lowpass setup/pointlimit { float freq = ci.hi.lowpass_kHz * 1000.0f; vorbis_info_floor1 f = ci.floor_param[block]; // by convention float nyq = vi.rate / 2.0f; int blocksize = ci.blocksizes[block] >> 1; // lowpass needs to be set in the floor and the residue. if (freq > nyq) freq = nyq; // in the floor, the granularity can be very fine; it doesn't alter the // encoding structure, only the samples used to fit the floor approximation f.n = new Double(freq / nyq * blocksize).intValue(); // this res may by limited by the maximum pointlimit of the mode, // not the lowpass. the floor is always lowpass limited. if (res.limit_type != 0) { if (ci.hi.managed != 0) freq = ci.psy_g_param.coupling_pkHz[PACKETBLOBS - 1] * 1000.0f; else freq = ci.psy_g_param.coupling_pkHz[PACKETBLOBS / 2] * 1000.0f; if (freq > nyq) freq = nyq; } // in the residue, we're constrained, physically, by partition // boundaries. We still lowpass 'wherever', but we have to round up // here to next boundary, or the vorbis spec will round it *down* to // previous boundary in encode/decode if (ci.residue_type[block] == 2) r.end = new Double((freq / nyq * blocksize * 2) / r.grouping + .9).intValue() * r.grouping; // round up only if we're well past else r.end = new Double((freq / nyq * blocksize) / r.grouping + .9).intValue() * r.grouping; // round up only if we're well past } } // we assume two maps in this encoder private void vorbis_encode_map_n_res_setup(float s, vorbis_mapping_template[] maps) { codec_setup_info ci = vi.codec_setup; int i, j; int is = new Float(s).intValue(); int modes = 2; vorbis_info_mapping0[] map = maps[is].map; vorbis_info_mode[] mode = {new vorbis_info_mode(0, 0, 0, 0), new vorbis_info_mode(1, 0, 0, 1)}; // _mode_template vorbis_residue_template[] res = maps[is].res; if (ci.blocksizes[0] == ci.blocksizes[1]) modes = 1; for (i = 0; i < modes; i++) { // ci.map_param[i] = _ogg_calloc(1,sizeof(*map)); // ci.mode_param[i] = _ogg_calloc(1,sizeof(*mode)); // memcpy(ci.mode_param[i],mode+i,sizeof(*_mode_template)); // memcpy(ci.map_param[i],map+i,sizeof(*map)); ci.mode_param[i] = new vorbis_info_mode(mode[i]); if (i >= ci.modes) ci.modes = i + 1; ci.map_type[i] = 0; ci.map_param[i] = new vorbis_info_mapping0(map[i]); if (i >= ci.maps) ci.maps = i + 1; for (j = 0; j < map[i].submaps; j++) vorbis_encode_residue_setup(map[i].residuesubmap[j], i, res[map[i].residuesubmap[j]]); } } private float setting_to_approx_bitrate() { codec_setup_info ci = vi.codec_setup; highlevel_encode_setup hi = ci.hi; ve_setup_data_template setup = hi.setup; int is = new Float(hi.base_setting).intValue(); float ds = hi.base_setting - is; int ch = vi.channels; float[] r = setup.rate_mapping; if (r == null) return (-1); return ((r[is] * (1.0f - ds) + r[is + 1] * ds) * ch); } }