1 /********************************************************************
3 * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS DISTRIBUTING. *
8 * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *
9 * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: build a VQ codebook
15 author: Monty <xiphmont@mit.edu>
16 modifications by: Monty
17 last modification date: Dec 27 1999
19 ********************************************************************/
21 /* This code is *not* part of libvorbis. It is used to generate
22 trained codebooks offline and then spit the results into a
23 pregenerated codebook that is compiled into libvorbis. It is an
24 expensive (but good) algorithm. Run it on big iron. */
26 /* There are so many optimizations to explore in *both* stages that
27 considering the undertaking is almost withering. For now, we brute
36 /* Codebook generation happens in two steps:
38 1) Train the codebook with data collected from the encoder: We use
39 one of a few error metrics (which represent the distance between a
40 given data point and a candidate point in the training set) to
41 divide the training set up into cells representing roughly equal
42 probability of occurring.
44 2) Generate the codebook and auxiliary data from the trained data set
47 /* Codebook training ****************************************************
49 * The basic idea here is that a VQ codebook is like an m-dimensional
50 * foam with n bubbles. The bubbles compete for space/volume and are
51 * 'pressurized' [biased] according to some metric. The basic alg
52 * iterates through allowing the bubbles to compete for space until
53 * they converge (if the damping is dome properly) on a steady-state
54 * solution. Individual input points, collected from libvorbis, are
55 * used to train the algorithm monte-carlo style. */
57 /* internal helpers *****************************************************/
58 #define vN(data,i) (data+v->elements*i)
60 /* default metric; squared 'distance' from desired value. */
61 double _dist_sq(vqgen *v,double *a, double *b){
66 double val=(a[i]-b[i]);
72 double *_weight_null(vqgen *v,double *a){
76 /* *must* be beefed up. */
77 void _vqgen_seed(vqgen *v){
79 for(i=0;i<v->entries;i++)
80 memcpy(_now(v,i),_point(v,i),sizeof(double)*v->elements);
83 /* External calls *******************************************************/
85 /* We have two forms of quantization; in the first, each vector
86 element in the codebook entry is orthogonal. Residues would use this
87 quantization for example.
89 In the second, we have a sequence of monotonically increasing
90 values that we wish to quantize as deltas (to save space). We
91 still need to quantize so that absolute values are accurate. For
92 example, LSP quantizes all absolute values, but the book encodes
93 distance between values because each successive value is larger
94 than the preceeding value. Thus the desired quantibits apply to
95 the encoded (delta) values, not abs positions. This requires minor
96 additional encode-side trickery. */
98 /* 24 bit float (not IEEE; nonnormalized mantissa +
99 biased exponent ): neeeeemm mmmmmmmm mmmmmmmm */
101 #define VQ_FEXP_BIAS 20 /* bias toward values smaller than 1. */
102 long float24_pack(double val){
110 exp= floor(log(val)/log(2));
111 mant=rint(ldexp(val,17-exp));
112 exp=(exp+VQ_FEXP_BIAS)<<18;
114 return(sign|exp|mant);
117 double float24_unpack(long val){
118 double mant=val&0x3ffff;
119 double sign=val&0x800000;
120 double exp =(val&0x7c0000)>>18;
122 return(ldexp(mant,exp-17-VQ_FEXP_BIAS));
125 void vqgen_quantize(vqgen *v,quant_meta *q){
131 double maxquant=((1<<q->quant)-1);
135 mindel=maxdel=_now(v,0)[0];
137 for(j=0;j<v->entries;j++){
139 for(k=0;k<v->elements;k++){
140 if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
141 if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
142 if(q->sequencep)last=_now(v,j)[k];
147 /* first find the basic delta amount from the maximum span to be
148 encoded. Loosen the delta slightly to allow for additional error
149 during sequence quantization */
151 delta=(maxdel-mindel)/((1<<q->quant)-1.5);
153 q->min=float24_pack(mindel);
154 q->delta=float24_pack(delta);
156 for(j=0;j<v->entries;j++){
158 for(k=0;k<v->elements;k++){
159 double val=_now(v,j)[k];
160 double now=rint((val-last-mindel)/delta);
164 /* be paranoid; this should be impossible */
165 fprintf(stderr,"fault; quantized value<0\n");
170 /* be paranoid; this should be impossible */
171 fprintf(stderr,"fault; quantized value>max\n");
174 if(q->sequencep)last=(now*delta)+mindel+last;
179 /* much easier :-) */
180 void vqgen_unquantize(vqgen *v,quant_meta *q){
182 double mindel=float24_unpack(q->min);
183 double delta=float24_unpack(q->delta);
185 for(j=0;j<v->entries;j++){
187 for(k=0;k<v->elements;k++){
188 double now=_now(v,j)[k]*delta+last+mindel;
190 if(q->sequencep)last=now;
196 void vqgen_init(vqgen *v,int elements,int aux,int entries,
197 double (*metric)(vqgen *,double *, double *),
198 double *(*weight)(vqgen *,double *)){
199 memset(v,0,sizeof(vqgen));
201 v->elements=elements;
203 v->pointlist=malloc(v->allocated*(v->elements+v->aux)*sizeof(double));
206 v->entrylist=malloc(v->entries*v->elements*sizeof(double));
207 v->assigned=malloc(v->entries*sizeof(long));
208 v->bias=calloc(v->entries,sizeof(double));
210 v->metric_func=metric;
212 v->metric_func=_dist_sq;
214 v->weight_func=weight;
216 v->weight_func=_weight_null;
220 void vqgen_addpoint(vqgen *v, double *p,double *a){
221 if(v->points>=v->allocated){
223 v->pointlist=realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
227 memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
228 if(v->aux)memcpy(_point(v,v->points)+v->elements,p,sizeof(double)*v->aux);
230 if(v->points==v->entries)_vqgen_seed(v);
233 double vqgen_iterate(vqgen *v){
235 double fdesired=(double)v->points/v->entries;
236 long desired=fdesired;
239 double *new=malloc(sizeof(double)*v->entries*v->elements);
240 long *nearcount=malloc(v->entries*sizeof(long));
241 double *nearbias=malloc(v->entries*desired*sizeof(double));
248 sprintf(buff,"cells%d.m",v->it);
249 cells=fopen(buff,"w");
250 sprintf(buff,"assig%d.m",v->it);
251 assig=fopen(buff,"w");
252 sprintf(buff,"bias%d.m",v->it);
253 bias=fopen(buff,"w");
256 fprintf(stderr,"Pass #%d... ",v->it);
259 fprintf(stderr,"generation requires at least two entries\n");
263 /* fill in nearest points for entries */
264 /*memset(v->bias,0,sizeof(double)*v->entries);*/
265 memset(nearcount,0,sizeof(long)*v->entries);
266 memset(v->assigned,0,sizeof(long)*v->entries);
267 for(i=0;i<v->points;i++){
268 double *ppt=_point(v,i);
269 double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
270 double secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
273 if(firstmetric>secondmetric){
274 double temp=firstmetric;
275 firstmetric=secondmetric;
281 for(j=2;j<v->entries;j++){
282 double thismetric=v->metric_func(v,_now(v,j),_point(v,i))+v->bias[j];
283 if(thismetric<secondmetric){
284 if(thismetric<firstmetric){
285 secondmetric=firstmetric;
286 secondentry=firstentry;
287 firstmetric=thismetric;
290 secondmetric=thismetric;
297 meterror+=sqrt(_dist_sq(v,_now(v,j),_point(v,i)));
298 /* set up midpoints for next iter */
300 for(k=0;k<v->elements;k++)
301 vN(new,j)[k]+=_point(v,i)[k];
303 for(k=0;k<v->elements;k++)
304 vN(new,j)[k]=_point(v,i)[k];
308 fprintf(cells,"%g %g\n%g %g\n\n",
309 _now(v,j)[0],_now(v,j)[1],
310 _point(v,i)[0],_point(v,i)[1]);
313 for(j=0;j<v->entries;j++){
316 double *nearbiasptr=nearbias+desired*j;
317 long k=nearcount[j]-1;
319 /* 'thismetric' is to be the bias value necessary in the current
320 arrangement for entry j to capture point i */
322 /* use the secondary entry as the threshhold */
323 thismetric=secondmetric-v->metric_func(v,_now(v,j),_point(v,i));
325 /* use the primary entry as the threshhold */
326 thismetric=firstmetric-v->metric_func(v,_now(v,j),_point(v,i));
329 if(k>=0 && thismetric>nearbiasptr[k]){
331 /* start at the end and search backward for where this entry
334 for(;k>0;k--) if(nearbiasptr[k-1]>=thismetric)break;
336 /* insert at k. Shift and inject. */
337 memmove(nearbiasptr+k+1,nearbiasptr+k,(desired-k-1)*sizeof(double));
338 nearbiasptr[k]=thismetric;
340 if(nearcount[j]<desired)nearcount[j]++;
343 if(nearcount[j]<desired){
344 /* we checked the thresh earlier. We know this is the
346 nearbiasptr[nearcount[j]++]=thismetric;
352 /* inflate/deflate */
353 for(i=0;i<v->entries;i++)
354 v->bias[i]=nearbias[(i+1)*desired-1];
356 /* assign midpoints */
358 for(j=0;j<v->entries;j++){
359 asserror+=fabs(v->assigned[j]-fdesired);
361 for(k=0;k<v->elements;k++)
362 _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
364 fprintf(assig,"%ld\n",v->assigned[j]);
365 fprintf(bias,"%g\n",v->bias[j]);
369 asserror/=(v->entries*fdesired);
370 fprintf(stderr,": dist %g(%g) metric error=%g \n",
371 asserror,fdesired,meterror/v->points/v->elements);