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-2000 *
9 * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: train a VQ codebook
15 last mod: $Id: vqgen.c,v 1.31 2000/05/08 20:49:51 xiphmont Exp $
17 ********************************************************************/
19 /* This code is *not* part of libvorbis. It is used to generate
20 trained codebooks offline and then spit the results into a
21 pregenerated codebook that is compiled into libvorbis. It is an
22 expensive (but good) algorithm. Run it on big iron. */
24 /* There are so many optimizations to explore in *both* stages that
25 considering the undertaking is almost withering. For now, we brute
35 #include "../lib/sharedbook.h"
37 /* Codebook generation happens in two steps:
39 1) Train the codebook with data collected from the encoder: We use
40 one of a few error metrics (which represent the distance between a
41 given data point and a candidate point in the training set) to
42 divide the training set up into cells representing roughly equal
43 probability of occurring.
45 2) Generate the codebook and auxiliary data from the trained data set
48 /* Codebook training ****************************************************
50 * The basic idea here is that a VQ codebook is like an m-dimensional
51 * foam with n bubbles. The bubbles compete for space/volume and are
52 * 'pressurized' [biased] according to some metric. The basic alg
53 * iterates through allowing the bubbles to compete for space until
54 * they converge (if the damping is dome properly) on a steady-state
55 * solution. Individual input points, collected from libvorbis, are
56 * used to train the algorithm monte-carlo style. */
58 /* internal helpers *****************************************************/
59 #define vN(data,i) (data+v->elements*i)
61 /* default metric; squared 'distance' from desired value. */
62 double _dist(vqgen *v,double *a, double *b){
67 double val=(a[i]-b[i]);
73 double *_weight_null(vqgen *v,double *a){
77 /* *must* be beefed up. */
78 void _vqgen_seed(vqgen *v){
80 for(i=0;i<v->entries;i++)
81 memcpy(_now(v,i),_point(v,i),sizeof(double)*v->elements);
84 int directdsort(const void *a, const void *b){
85 double av=*((double *)a);
86 double bv=*((double *)b);
91 void vqgen_cellmetric(vqgen *v){
93 double min=-1.,max=-1.,mean=0.,acc=0.;
98 double spacings[v->entries];
101 sprintf(buff,"cellspace%d.m",v->it);
102 cells=fopen(buff,"w");
105 /* minimum, maximum, cell spacing */
106 for(j=0;j<v->entries;j++){
109 for(k=0;k<v->entries;k++){
111 double this=_dist(v,_now(v,j),_now(v,k));
113 if(v->assigned[k] && (localmin==-1 || this<localmin))
123 if(k<v->entries)continue;
125 if(v->assigned[j]==0){
130 localmin=v->max[j]+localmin/2; /* this gives us rough diameter */
131 if(min==-1 || localmin<min)min=localmin;
132 if(max==-1 || localmin>max)max=localmin;
136 spacings[count++]=localmin;
140 fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
141 min,mean/acc,max,unused,dup);
144 qsort(spacings,count,sizeof(double),directdsort);
146 fprintf(cells,"%g\n",spacings[i]);
152 /* External calls *******************************************************/
154 /* We have two forms of quantization; in the first, each vector
155 element in the codebook entry is orthogonal. Residues would use this
156 quantization for example.
158 In the second, we have a sequence of monotonically increasing
159 values that we wish to quantize as deltas (to save space). We
160 still need to quantize so that absolute values are accurate. For
161 example, LSP quantizes all absolute values, but the book encodes
162 distance between values because each successive value is larger
163 than the preceeding value. Thus the desired quantibits apply to
164 the encoded (delta) values, not abs positions. This requires minor
165 additional encode-side trickery. */
167 void vqgen_quantize(vqgen *v,quant_meta *q){
173 double maxquant=((1<<q->quant)-1);
177 mindel=maxdel=_now(v,0)[0];
179 for(j=0;j<v->entries;j++){
181 for(k=0;k<v->elements;k++){
182 if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
183 if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
184 if(q->sequencep)last=_now(v,j)[k];
189 /* first find the basic delta amount from the maximum span to be
190 encoded. Loosen the delta slightly to allow for additional error
191 during sequence quantization */
193 delta=(maxdel-mindel)/((1<<q->quant)-1.5);
195 q->min=_float32_pack(mindel);
196 q->delta=_float32_pack(delta);
198 mindel=_float32_unpack(q->min);
199 delta=_float32_unpack(q->delta);
201 for(j=0;j<v->entries;j++){
203 for(k=0;k<v->elements;k++){
204 double val=_now(v,j)[k];
205 double now=rint((val-last-mindel)/delta);
209 /* be paranoid; this should be impossible */
210 fprintf(stderr,"fault; quantized value<0\n");
215 /* be paranoid; this should be impossible */
216 fprintf(stderr,"fault; quantized value>max\n");
219 if(q->sequencep)last=(now*delta)+mindel+last;
224 /* much easier :-). Unlike in the codebook, we don't un-log log
225 scales; we just make sure they're properly offset. */
226 void vqgen_unquantize(vqgen *v,quant_meta *q){
228 double mindel=_float32_unpack(q->min);
229 double delta=_float32_unpack(q->delta);
231 for(j=0;j<v->entries;j++){
233 for(k=0;k<v->elements;k++){
234 double now=_now(v,j)[k];
235 now=fabs(now)*delta+last+mindel;
236 if(q->sequencep)last=now;
242 void vqgen_init(vqgen *v,int elements,int aux,int entries,double mindist,
243 double (*metric)(vqgen *,double *, double *),
244 double *(*weight)(vqgen *,double *)){
245 memset(v,0,sizeof(vqgen));
247 v->elements=elements;
251 v->pointlist=malloc(v->allocated*(v->elements+v->aux)*sizeof(double));
254 v->entrylist=malloc(v->entries*v->elements*sizeof(double));
255 v->assigned=malloc(v->entries*sizeof(long));
256 v->bias=calloc(v->entries,sizeof(double));
257 v->max=calloc(v->entries,sizeof(double));
259 v->metric_func=metric;
261 v->metric_func=_dist;
263 v->weight_func=weight;
265 v->weight_func=_weight_null;
269 void vqgen_addpoint(vqgen *v, double *p,double *a){
270 if(v->points>=v->allocated){
272 v->pointlist=realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
276 memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
277 if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(double)*v->aux);
279 if(v->points==v->entries)_vqgen_seed(v);
280 if(!(v->points&0xff))spinnit("loading... ",v->points);
283 double vqgen_iterate(vqgen *v,int biasp){
287 double fdesired=(double)v->points/v->entries;
288 long desired=fdesired;
289 long desired2=desired*2;
293 double *new=malloc(sizeof(double)*v->entries*v->elements);
294 long *nearcount=malloc(v->entries*sizeof(long));
295 double *nearbias=malloc(v->entries*desired2*sizeof(double));
301 sprintf(buff,"cells%d.m",v->it);
302 cells=fopen(buff,"w");
303 sprintf(buff,"assig%d.m",v->it);
304 assig=fopen(buff,"w");
305 sprintf(buff,"bias%d.m",v->it);
306 bias=fopen(buff,"w");
311 fprintf(stderr,"generation requires at least two entries\n");
315 /* fill in nearest points for entry biasing */
316 /*memset(v->bias,0,sizeof(double)*v->entries);*/
317 memset(nearcount,0,sizeof(long)*v->entries);
318 memset(v->assigned,0,sizeof(long)*v->entries);
321 for(i=0;i<v->points;i++){
322 double *ppt=v->weight_func(v,_point(v,i));
323 double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
324 double secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
329 if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
331 if(firstmetric>secondmetric){
332 double temp=firstmetric;
333 firstmetric=secondmetric;
339 for(j=2;j<v->entries;j++){
340 double thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
341 if(thismetric<secondmetric){
342 if(thismetric<firstmetric){
343 secondmetric=firstmetric;
344 secondentry=firstentry;
345 firstmetric=thismetric;
348 secondmetric=thismetric;
355 for(j=0;j<v->entries;j++){
357 double thismetric,localmetric;
358 double *nearbiasptr=nearbias+desired2*j;
361 localmetric=v->metric_func(v,_now(v,j),ppt);
362 /* 'thismetric' is to be the bias value necessary in the current
363 arrangement for entry j to capture point i */
365 /* use the secondary entry as the threshhold */
366 thismetric=secondmetric-localmetric;
368 /* use the primary entry as the threshhold */
369 thismetric=firstmetric-localmetric;
372 /* support the idea of 'minimum distance'... if we want the
373 cells in a codebook to be roughly some minimum size (as with
374 the low resolution residue books) */
376 if(localmetric>=v->mindist){
378 /* a cute two-stage delayed sorting hack */
380 nearbiasptr[k]=thismetric;
383 spinnit("biasing... ",v->points+v->points+v->entries-i);
384 qsort(nearbiasptr,desired,sizeof(double),directdsort);
387 }else if(thismetric>nearbiasptr[desired-1]){
388 nearbiasptr[k]=thismetric;
391 spinnit("biasing... ",v->points+v->points+v->entries-i);
392 qsort(nearbiasptr,desired2,sizeof(double),directdsort);
403 /* inflate/deflate */
405 for(i=0;i<v->entries;i++){
406 double *nearbiasptr=nearbias+desired2*i;
408 spinnit("biasing... ",v->points+v->entries-i);
410 /* due to the delayed sorting, we likely need to finish it off....*/
411 if(nearcount[i]>desired)
412 qsort(nearbiasptr,nearcount[i],sizeof(double),directdsort);
414 /* desired is the *maximum* bias queue size. If we're using
415 minimum distance, we're not interested in the max size... we're
416 interested in the biasable number of points */
418 long localdesired=(double)biasable/v->entries;
420 v->bias[i]=nearbiasptr[localdesired-1];
422 v->bias[i]=nearbiasptr[0];
426 memset(v->bias,0,v->entries*sizeof(double));
429 /* Now assign with new bias and find new midpoints */
430 for(i=0;i<v->points;i++){
431 double *ppt=v->weight_func(v,_point(v,i));
432 double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
435 if(!(i&0xff))spinnit("centering... ",v->points-i);
437 for(j=0;j<v->entries;j++){
438 double thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
439 if(thismetric<firstmetric){
440 firstmetric=thismetric;
448 fprintf(cells,"%g %g\n%g %g\n\n",
449 _now(v,j)[0],_now(v,j)[1],
453 firstmetric-=v->bias[firstentry];
454 meterror+=firstmetric;
455 /* set up midpoints for next iter */
456 if(v->assigned[j]++){
457 for(k=0;k<v->elements;k++)
458 vN(new,j)[k]+=ppt[k];
459 if(firstmetric>v->max[firstentry])v->max[firstentry]=firstmetric;
461 for(k=0;k<v->elements;k++)
463 v->max[firstentry]=firstmetric;
467 /* assign midpoints */
469 for(j=0;j<v->entries;j++){
471 fprintf(assig,"%ld\n",v->assigned[j]);
472 fprintf(bias,"%g\n",v->bias[j]);
474 asserror+=fabs(v->assigned[j]-fdesired);
476 for(k=0;k<v->elements;k++)
477 _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
480 asserror/=(v->entries*fdesired);
482 fprintf(stderr,"Pass #%d... ",v->it);
483 fprintf(stderr,": dist %g(%g) metric error=%g \n",
484 asserror,fdesired,meterror/v->points);