All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.axet.libvorbis.Jcodebook Maven / Gradle / Ivy

There is a newer version: 2.1.0
Show newest version
package com.github.axet.libvorbis;

import com.github.axet.libogg.Joggpack_buffer;

final class Jcodebook implements Icomparator {
	/** codebook dimensions (elements per vector) */
	int dim = 0;
	/** codebook entries */
	int entries = 0;
	/** populated codebook entries */
	int used_entries = 0;
	Jstatic_codebook c = null;

	/* for encode, the below are entry-ordered, fully populated
for decode, the below are ordered by bitreversed codeword and only used entries are populated */ /** list of dim*entries actual entry values */ float[] valuelist = null; /** list of bitstream codewords for each entry * c-version: ogg_uint32_t *codelist; * java to compare must use: long val = (((long)codelist[offset]) & 0xffffffffL); */ int[] codelist; /* only used if sparseness collapsed */ int[] dec_index = null; // FIXME is this a bug? char* dec_codelengths, may be int* ? int[] dec_codelengths = null; int[] dec_firsttable;// c-version: ogg_uint32_t *dec_firsttable; int dec_firsttablen = 0; int dec_maxlength = 0; /* The current encoder uses only centered, integer-only lattice books. */ int quantvals = 0; int minval = 0; int delta = 0; // private final void clear() { dim = 0; entries = 0; used_entries = 0; c = null; valuelist = null; codelist = null; dec_index = null; dec_codelengths = null; dec_firsttable = null; dec_firsttablen = 0; dec_maxlength = 0; quantvals = 0; minval = 0; delta = 0; } // sharedbook.c /** given a list of word lengths, generate a list of codewords. Works for length ordered or unordered, always assigns the lowest valued codewords first. Extended to handle unused entries (length 0) */ private static int[] _make_words(final byte[] l, final int n, final int sparsecount) { int i, count = 0; final int[] marker = new int[33];// already zeroed, uint32 final int[] r = new int[sparsecount != 0 ? sparsecount : n]; for( i = 0; i < n; i++ ) { final int length = l[i]; if( length > 0 ) { int entry = marker[length];// uint32 /* when we claim a node for an entry, we also claim the nodes below it (pruning off the imagined tree that may have dangled from it) as well as blocking the use of any nodes directly above for leaves */ /* update ourself */ if( length < 32 && (entry >>> length) != 0 ) { /* error condition; the lengths must specify an overpopulated tree */ // r = null; return (null); } r[count++] = entry; /* Look to see if the next shorter marker points to the node above. if so, update it and repeat. */ { for( int j = length; j > 0; j-- ) { if( (marker[j] & 1) != 0 ) { /* have to jump branches */ if( j == 1 ) { marker[1]++; } else { marker[j] = marker[j - 1] << 1; } break; /* invariant says next upper marker would already have been moved if it was on the same path */ } marker[j]++; } } /* prune the tree; the implicit invariant says all the longer markers were dangling from our just-taken node. Dangle them from our *new* node. */ for( int j = length + 1; j < 33; j++ ) { if( (marker[j] >>> 1) == entry ) { entry = marker[j]; marker[j] = marker[j - 1] << 1; } else { break; } } } else if( sparsecount == 0 ) { count++; } } /* any underpopulated tree must be rejected. */ /* Single-entry codebooks are a retconned extension to the spec. They have a single codeword '0' of length 1 that results in an underpopulated tree. Shield that case from the underformed tree check. */ if( ! (count == 1 && marker[2] == 2) ) { for( i = 1; i < 33; i++ ) { if( (marker[i] & (0xffffffff >>> (32 - i))) != 0 ) { // r = null; return (null); } } } /* bitreverse the words because our bitwise packer/unpacker is LSb endian */ for( i = 0, count = 0; i < n; i++ ) { int temp = 0;// uint32 for( int j = 0; j < l[i]; j++ ) { temp <<= 1; temp |= (r[count] >>> j) & 1; } if( sparsecount != 0 ) { if( l[i] != 0 ) { r[count++] = temp; } } else { r[count++] = temp; } } return (r); } // codebook.c /** returns the number of bits */ final int vorbis_book_encode(final int a, final Joggpack_buffer b) { if( a < 0 || a >= this.c.entries) { return (0); } b.oggpack_write( this.codelist[a], this.c.lengthlist[a] ); return (this.c.lengthlist[a]); } /** the 'eliminate the decode tree' optimization actually requires the codewords to be MSb first, not LSb. This is an annoying inelegancy (and one of the first places where carefully thought out design turned out to be wrong; Vorbis II and future Ogg codecs should go to an MSb bitpacker), but not actually the huge hit it appears to be. The first-stage decode table catches most words so that bitreverse is not in the main execution path. */ private static int bitreverse(int x) {// uint32 x = ((x >>> 16) & 0x0000ffff) | ((x << 16) & 0xffff0000); x = ((x >>> 8) & 0x00ff00ff) | ((x << 8) & 0xff00ff00); x = ((x >>> 4) & 0x0f0f0f0f) | ((x << 4) & 0xf0f0f0f0); x = ((x >>> 2) & 0x33333333) | ((x << 2) & 0xcccccccc); return ((x >>> 1) & 0x55555555) | ((x << 1) & 0xaaaaaaaa); } final int decode_packed_entry_number(final Joggpack_buffer b) { int read = this.dec_maxlength; int lo, hi; int lok = b.oggpack_look( this.dec_firsttablen ); if( lok >= 0 ) { final int entry = this.dec_firsttable[lok];// FIXME is this correct? hidden convert uint32 to long if( (entry & 0x80000000) != 0 ) { lo = (entry >>> 15) & 0x7fff; hi = this.used_entries - (entry & 0x7fff); } else { b.oggpack_adv( this.dec_codelengths[entry - 1] ); return (entry - 1); } } else { lo = 0; hi = this.used_entries; } /* Single entry codebooks use a firsttablen of 1 and a dec_maxlength of 1. If a single-entry codebook gets here (due to failure to read one bit above), the next look attempt will also fail and we'll correctly kick out instead of trying to walk the underformed tree */ lok = b.oggpack_look( read ); while( lok < 0 && read > 1 ) { lok = b.oggpack_look( --read ); } if( lok < 0 ) { return -1; } /* bisect search for the codeword in the ordered list */ { final int testword = bitreverse( lok ) + Integer.MIN_VALUE;// uint32 comparing final int[] cd = this.codelist;// java while( hi - lo > 1 ) { final int p = (hi - lo) >> 1; final int test = ((cd[lo + p] + Integer.MIN_VALUE) > testword) ? 1 : 0; lo += p & (test - 1); hi -= p & (-test); } if( this.dec_codelengths[lo] <= read ) { b.oggpack_adv( this.dec_codelengths[lo] ); return (lo); } } b.oggpack_adv( read ); return (-1); } /** Decode side is specced and easier, because we don't need to find matches using different criteria; we simply read and map. There are two things we need to do 'depending':

We may need to support interleave. We don't really, but it's convenient to do it here rather than rebuild the vector later.

Cascades may be additive or multiplicitive; this is not inherent in the codebook, but set in the code using the codebook. Like interleaving, it's easiest to do it here.
addmul==0 -> declarative (set the value)
addmul==1 -> additive
addmul==2 -> multiplicitive
* @return returns the [original, not compacted] entry number or -1 on eof */ final int vorbis_book_decode(final Joggpack_buffer b) { if( this.used_entries > 0 ) { final int packed_entry = decode_packed_entry_number( b ); if( packed_entry >= 0 ) { return (this.dec_index[packed_entry]); } } /* if there's no dec_index, the codebook unpacking isn't collapsed */ return (-1); } // sharedbook.c final void vorbis_book_clear() { /* static book is not cleared; we're likely called on the lookup and the static codebook belongs to the info struct */ /* if( b.valuelist != null ) b.valuelist = null; if( b.codelist != null ) b.codelist = null; if( b.dec_index != null ) b.dec_index = null; if( b.dec_codelengths != null ) b.dec_codelengths = null; if( b.dec_firsttable != null ) b.dec_firsttable = null; */ clear();// memset(b,0,sizeof(*b)); } final int vorbis_book_init_encode(final Jstatic_codebook s) { clear();// memset(c,0,sizeof(*c)); this.c = s; this.entries = s.entries; this.used_entries = s.entries; this.dim = s.dim; this.codelist = _make_words( s.lengthlist, s.entries, 0 ); //this.valuelist=_book_unquantize(s,s.entries,NULL); FIXME why valuelist not initialized? this.quantvals = s._book_maptype1_quantvals(); this.minval = (int)Math.rint( Jcodec._float32_unpack( s.q_min ) ); this.delta = (int)Math.rint( Jcodec._float32_unpack( s.q_delta ) ); return (0); } /** array to sort */ private int[] d; private final Icomparator sort_comparator_set(final int[] a) { this.d = a; return this; } @Override public int compare(final int a, final int b) { final int[] data = this.d;// uint32 comparing final int d1 = data[a] + Integer.MIN_VALUE; final int d2 = data[b] + Integer.MIN_VALUE; if( d1 > d2 ) { return 1; } if( d1 < d2 ) { return -1; } return 0; } //private final Icomparator sort32a = this; /** decode codebook arrangement is more heavily optimized than encode */ final int vorbis_book_init_decode(final Jstatic_codebook s) { clear(); /* count actually used entries and find max length */ int n = 0; final int s_entries = s.entries;// java final byte[] lengthlist = s.lengthlist;// java for( int i = 0; i < s_entries; i++ ) { if( lengthlist[i] > 0 ) { n++; } } this.entries = s_entries; this.used_entries = n; this.dim = s.dim; if( n > 0 ) { /* two different remappings go on here. First, we collapse the likely sparse codebook down only to actually represented values/words. This collapsing needs to be indexed as map-valueless books are used to encode original entry positions as integers. Second, we reorder all vectors, including the entry index above, by sorted bitreversed codeword to allow treeless decode. */ /* perform sort */ int[] codes = _make_words( lengthlist, s_entries, this.used_entries ); if( codes == null ) {// goto err_out; vorbis_book_clear(); return (-1); } final int[] codep = new int[n]; for( int i = 0; i < n; i++ ) { codes[i] = bitreverse( codes[i] ); codep[i] = i; } FastQSortAlgorithm.sort( codep, 0, n, sort_comparator_set( codes ) ); final int[] sortindex = new int[n]; final int[] code_list = new int[n];// java this.codelist = code_list; /* the index is a reverse index */ for( int i = 0; i < n; i++ ) { sortindex[ codep[i] ] = i; } for( int i = 0; i < n; i++ ) { code_list[ sortindex[i] ] = codes[i]; } codes = null; this.valuelist = s._book_unquantize( n, sortindex ); this.dec_index = new int[n]; int i; for( n = 0, i = 0; i < s_entries; i++ ) { if( lengthlist[i] > 0 ) { this.dec_index[ sortindex[n++] ] = i; } } final int[] dec_code_lengths = new int[n];// java this.dec_codelengths = dec_code_lengths; this.dec_maxlength = 0; for( n = 0, i = 0; i < s_entries; i++ ) { if( lengthlist[i] > 0 ) { dec_code_lengths[ sortindex[n++] ] = lengthlist[i]; if( s.lengthlist[i] > this.dec_maxlength ) { this.dec_maxlength = s.lengthlist[i]; } } } if( n == 1 && this.dec_maxlength == 1 ) { /* special case the 'single entry codebook' with a single bit fastpath table (that always returns entry 0 )in order to use unmodified decode paths. */ this.dec_firsttablen = 1; this.dec_firsttable = new int[2]; this.dec_firsttable[0] = this.dec_firsttable[1] = 1; } else { this.dec_firsttablen = Jcodec.ov_ilog( this.used_entries ) - 4; /* this is magic */ if( this.dec_firsttablen < 5 ) { this.dec_firsttablen = 5; } if( this.dec_firsttablen > 8 ) { this.dec_firsttablen = 8; } final int tabn = 1 << this.dec_firsttablen; final int[] dec_first_table = new int[tabn];// java this.dec_firsttable = dec_first_table; for( i = 0; i < n; i++ ) { final int length = dec_code_lengths[i];// java if( length <= this.dec_firsttablen ) { final int orig = bitreverse( code_list[i] ); for( int j = 0, je = (1 << (this.dec_firsttablen - length)); j < je; j++ ) { dec_first_table[orig | (j << length)] = i + 1; } } } /* now fill in 'unused' entries in the firsttable with hi/lo search hints for the non-direct-hits */ { // correct variant: // long mask = (0xfffffffe << (31 - this.m_dec_firsttablen)) & 0xffffffffL; // but mask uses only to mask low 32 bits, so: final int mask = 0xfffffffe << (31 - this.dec_firsttablen);// uint32 int lo = 0, hi = 0; for( i = 0; i < tabn; i++ ) { final int word = i << (32 - this.dec_firsttablen);// uint32 final int bit_rev = bitreverse( word );// java if( dec_first_table[ bit_rev ] == 0 ) { final int uint_word = word + Integer.MIN_VALUE;// java word copy for uint32 comparing while( (lo + 1) < n && (code_list[lo + 1] + Integer.MIN_VALUE) <= uint_word ) { lo++; } while( hi < n && uint_word >= ((code_list[hi] & mask) + Integer.MIN_VALUE) ) { hi++; } /* we only actually have 15 bits per hint to play with here. In order to overflow gracefully (nothing breaks, efficiency just drops), encode as the difference from the extremes. */ { int loval = lo;// uint32 int hival = n - hi;// uint32 if( loval > 0x7fff ) { loval = 0x7fff; } if( hival > 0x7fff ) { hival = 0x7fff; } dec_first_table[ bit_rev ] = 0x80000000 | (loval << 15) | hival; } } } } } } return (0); //err_out: // vorbis_book_clear( c ); // return (-1); } // FIXME never used private final int vorbis_book_codeword(int entry) { // if( this.c != null ) /* only use with encode; decode optimizations are allowed to break this */ // return this.m_codelist[entry];// FIXME is this a bug? using hidden convert from uint32 to long // return -1; //} // FIXME never used private final int vorbis_book_codelen(int entry) { // if( this.c != null ) /* only use with encode; decode optimizations are allowed to break this */ // return this.c.lengthlist[entry]; // return -1; //} /** unlike the others, we guard against n not being an integer number of internally rather than in the upper layer (called only by floor0) */ final int vorbis_book_decodev_set(final float[] a, final Joggpack_buffer b, final int n) { if( this.used_entries > 0 ) { final int size = this.dim;// java final float list[] = this.valuelist;// java for( int i = 0; i < n; ) { int entry = decode_packed_entry_number( b ); if( entry == -1 ) { return (-1); } entry *= size; final int end = entry + size; while( i < n && entry < end ) { a[i++] = list[entry++]; } } } else { for( int i = 0; i < n; ) { a[i++] = 0.f; } } return (0); } final int vorbis_book_decodevv_add(final float[][] a, final int offset, final int ch, final Joggpack_buffer b, int n ) { int chptr = 0; if( this.used_entries > 0 ) { n += offset; n /= ch; final int size = this.dim;// java final float list[] = this.valuelist;// java for( int i = offset / ch; i < n; ) { int entry = decode_packed_entry_number( b ); if( entry == -1 ) { return (-1); } { entry *= size; final int end = entry + size; while( i < n && entry < end ) { a[chptr++][i] += list[entry++]; if( chptr == ch ) { chptr = 0; i++; } } } } } return (0); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy