/* -*-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 sound.jcraft.jorbis;
import sound.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
}
}