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 10 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 /* *must* be beefed up. */
73 void _vqgen_seed(vqgen *v){
74 memcpy(v->entrylist,v->pointlist,sizeof(double)*v->entries*v->elements);
77 /* External calls *******************************************************/
79 /* We have two forms of quantization; in the first, each vector
80 element in the codebook entry is orthogonal. Residues would use this
81 quantization for example.
83 In the second, we have a sequence of monotonically increasing
84 values that we wish to quantize as deltas (to save space). We
85 still need to quantize so that absolute values are accurate. For
86 example, LSP quantizes all absolute values, but the book encodes
87 distance between values because each successive value is larger
88 than the preceeding value. Thus the desired quantibits apply to
89 the encoded (delta) values, not abs positions. This requires minor
90 additional encode-side trickery. */
92 /* 24 bit float (not IEEE; nonnormalized mantissa +
93 biased exponent ): neeeeemm mmmmmmmm mmmmmmmm */
95 #define VQ_FEXP_BIAS 20 /* bias toward values smaller than 1. */
96 long float24_pack(double val){
104 exp= floor(log(val)/log(2));
105 mant=rint(ldexp(val,17-exp));
106 exp=(exp+VQ_FEXP_BIAS)<<18;
108 return(sign|exp|mant);
111 double float24_unpack(long val){
112 double mant=val&0x3ffff;
113 double sign=val&0x800000;
114 double exp =(val&0x7c0000)>>18;
116 return(ldexp(mant,exp-17-VQ_FEXP_BIAS));
119 void vqgen_quantize(vqgen *v,quant_meta *q){
125 double maxquant=((1<<q->quant)-1);
129 mindel=maxdel=_now(v,0)[0];
131 for(j=0;j<v->entries;j++){
133 for(k=0;k<v->elements;k++){
134 if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
135 if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
136 if(q->sequencep)last=_now(v,j)[k];
141 /* first find the basic delta amount from the maximum span to be
142 encoded. Loosen the delta slightly to allow for additional error
143 during sequence quantization */
145 delta=(maxdel-mindel)/((1<<q->quant)-1.5);
147 q->min=float24_pack(mindel);
148 q->delta=float24_pack(delta);
150 for(j=0;j<v->entries;j++){
152 for(k=0;k<v->elements;k++){
153 double val=_now(v,j)[k];
154 double now=rint((val-last-mindel)/delta);
158 /* be paranoid; this should be impossible */
159 fprintf(stderr,"fault; quantized value<0\n");
164 /* be paranoid; this should be impossible */
165 fprintf(stderr,"fault; quantized value>max\n");
168 if(q->sequencep)last=(now*delta)+mindel+last;
173 /* much easier :-) */
174 void vqgen_unquantize(vqgen *v,quant_meta *q){
176 double mindel=float24_unpack(q->min);
177 double delta=float24_unpack(q->delta);
179 for(j=0;j<v->entries;j++){
181 for(k=0;k<v->elements;k++){
182 double now=_now(v,j)[k]*delta+last+mindel;
184 if(q->sequencep)last=now;
190 void vqgen_init(vqgen *v,int elements,int entries,
191 double (*metric)(vqgen *,double *, double *)){
192 memset(v,0,sizeof(vqgen));
194 v->elements=elements;
196 v->pointlist=malloc(v->allocated*v->elements*sizeof(double));
199 v->entrylist=malloc(v->entries*v->elements*sizeof(double));
200 v->assigned=malloc(v->entries*sizeof(long));
201 v->bias=calloc(v->entries,sizeof(double));
203 v->metric_func=metric;
205 v->metric_func=_dist_sq;
208 void vqgen_addpoint(vqgen *v, double *p){
209 if(v->points>=v->allocated){
211 v->pointlist=realloc(v->pointlist,v->allocated*v->elements*sizeof(double));
214 memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
216 if(v->points==v->entries)_vqgen_seed(v);
219 double vqgen_iterate(vqgen *v){
221 double fdesired=(double)v->points/v->entries;
222 long desired=fdesired;
225 double *new=malloc(sizeof(double)*v->entries*v->elements);
226 long *nearcount=malloc(v->entries*sizeof(long));
227 double *nearbias=malloc(v->entries*desired*sizeof(double));
234 sprintf(buff,"cells%d.m",v->it);
235 cells=fopen(buff,"w");
236 sprintf(buff,"assig%d.m",v->it);
237 assig=fopen(buff,"w");
238 sprintf(buff,"bias%d.m",v->it);
239 bias=fopen(buff,"w");
242 fprintf(stderr,"Pass #%d... ",v->it);
245 fprintf(stderr,"generation requires at least two entries\n");
249 /* fill in nearest points for entries */
250 /*memset(v->bias,0,sizeof(double)*v->entries);*/
251 memset(nearcount,0,sizeof(long)*v->entries);
252 memset(v->assigned,0,sizeof(long)*v->entries);
253 for(i=0;i<v->points;i++){
254 double *ppt=_point(v,i);
255 double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
256 double secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
259 if(firstmetric>secondmetric){
260 double temp=firstmetric;
261 firstmetric=secondmetric;
267 for(j=2;j<v->entries;j++){
268 double thismetric=v->metric_func(v,_now(v,j),_point(v,i))+v->bias[j];
269 if(thismetric<secondmetric){
270 if(thismetric<firstmetric){
271 secondmetric=firstmetric;
272 secondentry=firstentry;
273 firstmetric=thismetric;
276 secondmetric=thismetric;
283 meterror+=sqrt(_dist_sq(v,_now(v,j),_point(v,i)));
284 /* set up midpoints for next iter */
286 for(k=0;k<v->elements;k++)
287 vN(new,j)[k]+=_point(v,i)[k];
289 for(k=0;k<v->elements;k++)
290 vN(new,j)[k]=_point(v,i)[k];
294 fprintf(cells,"%g %g\n%g %g\n\n",
295 _now(v,j)[0],_now(v,j)[1],
296 _point(v,i)[0],_point(v,i)[1]);
299 for(j=0;j<v->entries;j++){
302 double *nearbiasptr=nearbias+desired*j;
303 long k=nearcount[j]-1;
305 /* 'thismetric' is to be the bias value necessary in the current
306 arrangement for entry j to capture point i */
308 /* use the secondary entry as the threshhold */
309 thismetric=secondmetric-v->metric_func(v,_now(v,j),_point(v,i));
311 /* use the primary entry as the threshhold */
312 thismetric=firstmetric-v->metric_func(v,_now(v,j),_point(v,i));
315 if(k>=0 && thismetric>nearbiasptr[k]){
317 /* start at the end and search backward for where this entry
320 for(;k>0;k--) if(nearbiasptr[k-1]>=thismetric)break;
322 /* insert at k. Shift and inject. */
323 memmove(nearbiasptr+k+1,nearbiasptr+k,(desired-k-1)*sizeof(double));
324 nearbiasptr[k]=thismetric;
326 if(nearcount[j]<desired)nearcount[j]++;
329 if(nearcount[j]<desired){
330 /* we checked the thresh earlier. We know this is the
332 nearbiasptr[nearcount[j]++]=thismetric;
338 /* inflate/deflate */
339 for(i=0;i<v->entries;i++)
340 v->bias[i]=nearbias[(i+1)*desired-1];
342 /* assign midpoints */
344 for(j=0;j<v->entries;j++){
345 asserror+=fabs(v->assigned[j]-fdesired);
347 for(k=0;k<v->elements;k++)
348 _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
350 fprintf(assig,"%ld\n",v->assigned[j]);
351 fprintf(bias,"%g\n",v->bias[j]);
355 asserror/=(v->entries*fdesired);
356 fprintf(stderr,": dist %g(%g) metric error=%g \n",
357 asserror,fdesired,meterror/v->points/v->elements);