/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ /* JOrbis * Copyright (C) 2000 ymnk, JCraft,Inc. * * Written by: 2000 ymnk<ymnk@jcraft.com> * * Many thanks to * Monty <monty@xiph.org> and * The XIPHOPHORUS Company http://www.xiph.org/ . * JOrbis has been based on their awesome works, Vorbis codec. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.jcraft.jorbis; import com.jcraft.jogg.Buffer; class CodeBook { int dim; // codebook dimensions (elements per vector) int entries; // codebook entries StaticCodeBook c = new StaticCodeBook(); float[] valuelist; // list of dim*entries actual entry values int[] codelist; // list of bitstream codewords for each entry DecodeAux decode_tree; // returns the number of bits int encode(int a, Buffer b) { b.write(codelist[a], c.lengthlist[a]); return (c.lengthlist[a]); } // One the encode side, our vector writers are each designed for a // specific purpose, and the encoder is not flexible without modification: // // The LSP vector coder uses a single stage nearest-match with no // interleave, so no step and no error return. This is specced by floor0 // and doesn't change. // // Residue0 encoding interleaves, uses multiple stages, and each stage // peels of a specific amount of resolution from a lattice (thus we want // to match by threshhold, not nearest match). Residue doesn't *have* to // be encoded that way, but to change it, one will need to add more // infrastructure on the encode side (decode side is specced and simpler) // floor0 LSP (single stage, non interleaved, nearest match) // returns entry number and *modifies a* to the quantization value int errorv(float[] a) { int best = best(a, 1); for (int k = 0; k < dim; k++) { a[k] = valuelist[best * dim + k]; } return (best); } // returns the number of bits and *modifies a* to the quantization value int encodev(int best, float[] a, Buffer b) { for (int k = 0; k < dim; k++) { a[k] = valuelist[best * dim + k]; } return (encode(best, b)); } // res0 (multistage, interleave, lattice) // returns the number of bits and *modifies a* to the remainder value int encodevs(float[] a, Buffer b, int step, int addmul) { int best = besterror(a, step, addmul); return (encode(best, b)); } private int[] t = new int[15]; // decodevs_add is synchronized for re-using t. synchronized int decodevs_add(float[] a, int offset, Buffer b, int n) { int step = n / dim; int entry; int i, j, o; if (t.length < step) { t = new int[step]; } for (i = 0; i < step; i++) { entry = decode(b); if (entry == -1) return (-1); t[i] = entry * dim; } for (i = 0, o = 0; i < dim; i++, o += step) { for (j = 0; j < step; j++) { a[offset + o + j] += valuelist[t[j] + i]; } } return (0); } int decodev_add(float[] a, int offset, Buffer b, int n) { int i, j, entry; int t; if (dim > 8) { for (i = 0; i < n;) { entry = decode(b); if (entry == -1) return (-1); t = entry * dim; for (j = 0; j < dim;) { a[offset + (i++)] += valuelist[t + (j++)]; } } } else { for (i = 0; i < n;) { entry = decode(b); if (entry == -1) return (-1); t = entry * dim; j = 0; switch (dim) { case 8: a[offset + (i++)] += valuelist[t + (j++)]; case 7: a[offset + (i++)] += valuelist[t + (j++)]; case 6: a[offset + (i++)] += valuelist[t + (j++)]; case 5: a[offset + (i++)] += valuelist[t + (j++)]; case 4: a[offset + (i++)] += valuelist[t + (j++)]; case 3: a[offset + (i++)] += valuelist[t + (j++)]; case 2: a[offset + (i++)] += valuelist[t + (j++)]; case 1: a[offset + (i++)] += valuelist[t + (j++)]; case 0: break; } } } return (0); } int decodev_set(float[] a, int offset, Buffer b, int n) { int i, j, entry; int t; for (i = 0; i < n;) { entry = decode(b); if (entry == -1) return (-1); t = entry * dim; for (j = 0; j < dim;) { a[offset + i++] = valuelist[t + (j++)]; } } return (0); } int decodevv_add(float[][] a, int offset, int ch, Buffer b, int n) { int i, j, entry; int chptr = 0; for (i = offset / ch; i < (offset + n) / ch;) { entry = decode(b); if (entry == -1) return (-1); int t = entry * dim; for (j = 0; j < dim; j++) { a[chptr++][i] += valuelist[t + j]; if (chptr == ch) { chptr = 0; i++; } } } return (0); } // 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. // stage==0 -> declarative (set the value) // stage==1 -> additive // stage==2 -> multiplicitive // returns the entry number or -1 on eof int decode(Buffer b) { int ptr = 0; DecodeAux t = decode_tree; int lok = b.look(t.tabn); if (lok >= 0) { ptr = t.tab[lok]; b.adv(t.tabl[lok]); if (ptr <= 0) { return -ptr; } } do { switch (b.read1()) { case 0: ptr = t.ptr0[ptr]; break; case 1: ptr = t.ptr1[ptr]; break; case -1: default: return (-1); } } while (ptr > 0); return (-ptr); } // returns the entry number or -1 on eof int decodevs(float[] a, int index, Buffer b, int step, int addmul) { int entry = decode(b); if (entry == -1) return (-1); switch (addmul) { case -1: for (int i = 0, o = 0; i < dim; i++, o += step) a[index + o] = valuelist[entry * dim + i]; break; case 0: for (int i = 0, o = 0; i < dim; i++, o += step) a[index + o] += valuelist[entry * dim + i]; break; case 1: for (int i = 0, o = 0; i < dim; i++, o += step) a[index + o] *= valuelist[entry * dim + i]; break; default: //System.err.println("CodeBook.decodeves: addmul="+addmul); } return (entry); } int best(float[] a, int step) { // brute force it! { int besti = -1; float best = 0.f; int e = 0; for (int i = 0; i < entries; i++) { if (c.lengthlist[i] > 0) { float _this = dist(dim, valuelist, e, a, step); if (besti == -1 || _this < best) { best = _this; besti = i; } } e += dim; } return (besti); } } // returns the entry number and *modifies a* to the remainder value int besterror(float[] a, int step, int addmul) { int best = best(a, step); switch (addmul) { case 0: for (int i = 0, o = 0; i < dim; i++, o += step) a[o] -= valuelist[best * dim + i]; break; case 1: for (int i = 0, o = 0; i < dim; i++, o += step) { float val = valuelist[best * dim + i]; if (val == 0) { a[o] = 0; } else { a[o] /= val; } } break; } return (best); } void clear() { } private static float dist(int el, float[] ref, int index, float[] b, int step) { float acc = (float) 0.; for (int i = 0; i < el; i++) { float val = (ref[index + i] - b[i * step]); acc += val * val; } return (acc); } int init_decode(StaticCodeBook s) { c = s; entries = s.entries; dim = s.dim; valuelist = s.unquantize(); decode_tree = make_decode_tree(); if (decode_tree == null) { clear(); return (-1); } return (0); } // 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) static int[] make_words(int[] l, int n) { int[] marker = new int[33]; int[] r = new int[n]; for (int i = 0; i < n; i++) { int length = l[i]; if (length > 0) { int entry = marker[length]; // 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 //free(r); return (null); } r[i] = 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; } } } } // bitreverse the words because our bitwise packer/unpacker is LSb // endian for (int i = 0; i < n; i++) { int temp = 0; for (int j = 0; j < l[i]; j++) { temp <<= 1; temp |= (r[i] >>> j) & 1; } r[i] = temp; } return (r); } // build the decode helper tree from the codewords DecodeAux make_decode_tree() { int top = 0; DecodeAux t = new DecodeAux(); int[] ptr0 = t.ptr0 = new int[entries * 2]; int[] ptr1 = t.ptr1 = new int[entries * 2]; int[] codelist = make_words(c.lengthlist, c.entries); if (codelist == null) return (null); t.aux = entries * 2; for (int i = 0; i < entries; i++) { if (c.lengthlist[i] > 0) { int ptr = 0; int j; for (j = 0; j < c.lengthlist[i] - 1; j++) { int bit = (codelist[i] >>> j) & 1; if (bit == 0) { if (ptr0[ptr] == 0) { ptr0[ptr] = ++top; } ptr = ptr0[ptr]; } else { if (ptr1[ptr] == 0) { ptr1[ptr] = ++top; } ptr = ptr1[ptr]; } } if (((codelist[i] >>> j) & 1) == 0) { ptr0[ptr] = -i; } else { ptr1[ptr] = -i; } } } t.tabn = Util.ilog(entries) - 4; if (t.tabn < 5) t.tabn = 5; int n = 1 << t.tabn; t.tab = new int[n]; t.tabl = new int[n]; for (int i = 0; i < n; i++) { int p = 0; int j = 0; for (j = 0; j < t.tabn && (p > 0 || j == 0); j++) { if ((i & (1 << j)) != 0) { p = ptr1[p]; } else { p = ptr0[p]; } } t.tab[i] = p; // -code t.tabl[i] = j; // length } return (t); } class DecodeAux { int[] tab; int[] tabl; int tabn; int[] ptr0; int[] ptr1; int aux; // number of tree entries } }