/* csvorbis * Copyright (C) 2000 ymnk, JCraft,Inc. * * Written by: 2000 ymnk * Ported to C# from JOrbis by: Mark Crichton * * Thanks go to the JOrbis team, for licencing the code under the * LGPL, making my job a lot easier. * * 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. */ using System; using csogg; namespace csvorbis { class StaticCodeBook { internal int dim; // codebook dimensions (elements per vector) internal int entries; // codebook entries internal int[] lengthlist; // codeword lengths in bits // mapping internal int maptype; // 0=none // 1=implicitly populated values from map column // 2=listed arbitrary values // The below does a linear, single monotonic sequence mapping. internal int q_min; // packed 32 bit float; quant value 0 maps to minval internal int q_delta; // packed 32 bit float; val 1 - val 0 == delta internal int q_quant; // bits: 0 < quant <= 16 internal int q_sequencep; // bitflag // additional information for log (dB) mapping; the linear mapping // is assumed to actually be values in dB. encodebias is used to // assign an error weight to 0 dB. We have two additional flags: // zeroflag indicates if entry zero is to represent -Inf dB; negflag // indicates if we're to represent negative linear values in a // mirror of the positive mapping. internal int[] quantlist; // map == 1: (int)(entries/dim) element column map // map == 2: list of dim*entries quantized entry vals // encode helpers internal EncodeAuxNearestMatch nearest_tree; internal EncodeAuxThreshMatch thresh_tree; internal StaticCodeBook(){} internal StaticCodeBook(int dim, int entries, int[] lengthlist, int maptype, int q_min, int q_delta, int q_quant, int q_sequencep, int[] quantlist, //EncodeAuxNearestmatch nearest_tree, Object nearest_tree, // EncodeAuxThreshmatch thresh_tree, Object thresh_tree ) : this() { this.dim=dim; this.entries=entries; this.lengthlist=lengthlist; this.maptype=maptype; this.q_min=q_min; this.q_delta=q_delta; this.q_quant=q_quant; this.q_sequencep=q_sequencep; this.quantlist=quantlist; } internal int pack(csBuffer opb) { int i; bool ordered=false; opb.write(0x564342,24); opb.write(dim, 16); opb.write(entries, 24); // pack the codewords. There are two packings; length ordered and // length random. Decide between the two now. for(i=1;i_last) { for(int j=_last;j<_this;j++) { opb.write(i-count,ilog(entries-count)); count=i; } } } opb.write(i-count,ilog(entries-count)); } else { // length random. Again, we don't code the codeword itself, just // the length. This time, though, we have to encode each length opb.write(0,1); // unordered // algortihmic mapping has use for 'unused entries', which we tag // here. The algorithmic mapping happens as usual, but the unused // entry has no codeword. for(i=0;ientries/c->dim) quantized values for // building a full value list algorithmically (square lattice) quantvals=maptype1_quantvals(); break; case 2: // every value (c->entries*c->dim total) specified explicitly quantvals=entries*dim; break; } // quantized values for(i=0;ibim <= b->entries // treat the above as an initial guess while(true) { int acc=1; int acc1=1; for(int i=0;ientries){ return(vals); } else { if(acc>entries){ vals--; } else{ vals++; } } } } internal void clear() { // if(quantlist!=null)free(b->quantlist); // if(lengthlist!=null)free(b->lengthlist); // if(nearest_tree!=null){ // free(b->nearest_tree->ptr0); // free(b->nearest_tree->ptr1); // free(b->nearest_tree->p); // free(b->nearest_tree->q); // memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch)); // free(b->nearest_tree); // } // if(thresh_tree!=null){ // free(b->thresh_tree->quantthresh); // free(b->thresh_tree->quantmap); // memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch)); // free(b->thresh_tree); // } // memset(b,0,sizeof(static_codebook)); } // unpack the quantized list of values for encode/decode // we need to deal with two map types: in map type 1, the values are // generated algorithmically (each column of the vector counts through // the values in the quant vector). in map type 2, all the values came // in in an explicit list. Both value lists must be unpacked internal float[] unquantize() { if(maptype==1 || maptype==2) { int quantvals; float mindel=float32_unpack(q_min); float delta=float32_unpack(q_delta); float[] r=new float[entries*dim]; //System.err.println("q_min="+q_min+", mindel="+mindel); // maptype 1 and 2 both use a quantized value vector, but // different sizes switch(maptype) { case 1: // most of the time, entries%dimensions == 0, but we need to be // well defined. We define that the possible vales at each // scalar is values == entries/dim. If entries%dim != 0, we'll // have 'too few' values (values*dim "+val+" | ");} val=Math.Abs(val)*delta+mindel+last; if(q_sequencep!=0)last=val; r[j*dim+k]=val; //if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");} } } //System.err.println("\nr[0]="+r[0]); break; default: break; } return(r); } return(null); } internal static int ilog(int v) { int ret=0; while(v!=0) { ret++; v = (int)((uint)v >> 1); } return(ret); } // 32 bit float (not IEEE; nonnormalized mantissa + // biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm // Why not IEEE? It's just not that important here. //static int VQ_FEXP=10; static int VQ_FMAN=21; static int VQ_FEXP_BIAS=768; // bias toward values smaller than 1. // doesn't currently guard under/overflow internal static long float32_pack(float val) { uint sign=0; int exp; int mant; if(val<0) { sign = 0x80000000; val = -val; } exp=(int)Math.Floor(Math.Log(val)/Math.Log(2)); mant=(int)Math.Round(Math.Pow(val,(VQ_FMAN-1)-exp)); exp=(exp+VQ_FEXP_BIAS)<> VQ_FMAN; //System.err.println("mant="+mant+", sign="+sign+", exp="+exp); //if(sign!=0.0)mant= -mant; if((val&0x80000000)!=0)mant= -mant; //System.err.println("mant="+mant); return(ldexp(mant,((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS)); } internal static float ldexp(float foo, int e) { return (float)(foo*Math.Pow(2, e)); } } }