Minor optimization to align p and q indexes in .vqh files.
[platform/upstream/libvorbis.git] / vq / bookutil.c
1 /********************************************************************
2  *                                                                  *
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.                            *
7  *                                                                  *
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/                                             *
11  *                                                                  *
12  ********************************************************************
13
14  function: utility functions for loading .vqh and .vqd files
15  last mod: $Id: bookutil.c,v 1.8 2000/02/07 19:39:44 xiphmont Exp $
16
17  ********************************************************************/
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <math.h>
22 #include <string.h>
23 #include <errno.h>
24 #include "vorbis/codebook.h"
25 #include "bookutil.h"
26
27 void codebook_unquantize(codebook *b){
28   long j,k;
29   const static_codebook *c=b->c;
30   double mindel=float24_unpack(c->q_min);
31   double delta=float24_unpack(c->q_delta);
32   if(!b->valuelist)b->valuelist=malloc(sizeof(double)*c->entries*c->dim);
33   
34   for(j=0;j<c->entries;j++){
35     double last=0.;
36     for(k=0;k<c->dim;k++){
37       double val=c->quantlist[j*c->dim+k]*delta+last+mindel;
38       b->valuelist[j*c->dim+k]=val;
39       if(c->q_sequencep)last=val;
40
41     }
42   }
43 }
44
45 /* A few little utils for reading files */
46 /* read a line.  Use global, persistent buffering */
47 static char *linebuffer=NULL;
48 static int  lbufsize=0;
49 char *get_line(FILE *in){
50   long sofar=0;
51   if(feof(in))return NULL;
52
53   while(1){
54     int gotline=0;
55
56     while(!gotline){
57       if(sofar+1>=lbufsize){
58         if(!lbufsize){  
59           lbufsize=1024;
60           linebuffer=malloc(lbufsize);
61         }else{
62           lbufsize*=2;
63           linebuffer=realloc(linebuffer,lbufsize);
64         }
65       }
66       {
67         long c=fgetc(in);
68         switch(c){
69         case EOF:
70           if(sofar==0)return(NULL);
71           /* fallthrough correct */
72         case '\n':
73           linebuffer[sofar]='\0';
74           gotline=1;
75           break;
76         default:
77           linebuffer[sofar++]=c;
78           linebuffer[sofar]='\0';
79           break;
80         }
81       }
82     }
83     
84     if(linebuffer[0]=='#'){
85       sofar=0;
86     }else{
87       return(linebuffer);
88     }
89   }
90 }
91
92 /* read the next numerical value from the given file */
93 static char *value_line_buff=NULL;
94
95 int get_line_value(FILE *in,double *value){
96   char *next;
97
98   if(!value_line_buff)return(-1);
99
100   *value=strtod(value_line_buff, &next);
101   if(next==value_line_buff){
102     value_line_buff=NULL;
103     return(-1);
104   }else{
105     value_line_buff=next;
106     while(*value_line_buff>32)value_line_buff++;
107     return(0);
108   }
109 }
110
111 int get_next_value(FILE *in,double *value){
112   while(1){
113     if(get_line_value(in,value)){
114       value_line_buff=get_line(in);
115       if(!value_line_buff)return(-1);
116     }else{
117       return(0);
118     }
119   }
120 }
121
122 int get_next_ivalue(FILE *in,long *ivalue){
123   double value;
124   int ret=get_next_value(in,&value);
125   *ivalue=value;
126   return(ret);
127 }
128
129 static double sequence_base=0.;
130 static int v_sofar=0;
131 void reset_next_value(void){
132   value_line_buff=NULL;
133   sequence_base=0.;
134   v_sofar=0;
135 }
136
137 int get_vector(codebook *b,FILE *in,int start, int n,double *a){
138   int i;
139   const static_codebook *c=b->c;
140
141   while(1){
142
143     if(v_sofar==n || get_line_value(in,a)){
144       reset_next_value();
145       if(get_next_value(in,a))
146         break;
147       for(i=0;i<start;i++){
148         sequence_base=*a;
149         get_line_value(in,a);
150       }
151     }
152
153     for(i=1;i<c->dim;i++)
154       if(get_line_value(in,a+i))
155         break;
156     
157     if(i==c->dim){
158       double temp=a[c->dim-1];
159       for(i=0;i<c->dim;i++)a[i]-=sequence_base;
160       if(c->q_sequencep)sequence_base=temp;
161       v_sofar++;
162       return(0);
163     }
164     sequence_base=0.;
165   }
166
167   return(-1);
168 }
169
170 /* read lines fromt he beginning until we find one containing the
171    specified string */
172 char *find_seek_to(FILE *in,char *s){
173   rewind(in);
174   while(1){
175     char *line=get_line(in);
176     if(line){
177       if(strstr(line,s))
178         return(line);
179     }else
180       return(NULL);
181   }
182 }
183
184
185 /* this reads the format as written by vqbuild; innocent (legal)
186    tweaking of the file that would not affect its valid header-ness
187    will break this routine */
188
189 codebook *codebook_load(char *filename){
190   codebook *b=calloc(1,sizeof(codebook));
191   static_codebook *c=(static_codebook *)(b->c=calloc(1,sizeof(static_codebook)));
192   encode_aux *a=calloc(1,sizeof(encode_aux));
193   FILE *in=fopen(filename,"r");
194   char *line;
195   long i;
196
197   c->encode_tree=a;
198
199   if(in==NULL){
200     fprintf(stderr,"Couldn't open codebook %s\n",filename);
201     exit(1);
202   }
203
204   /* find the codebook struct */
205   find_seek_to(in,"static static_codebook _vq_book_");
206
207   /* get the major important values */
208   line=get_line(in);
209   if(sscanf(line,"%ld, %ld, %ld, %ld, %d, %d",
210             &(c->dim),&(c->entries),&(c->q_min),&(c->q_delta),&(c->q_quant),
211             &(c->q_sequencep))!=6){
212     fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
213     exit(1);
214   }
215
216   /* find the auxiliary encode struct (if any) */
217   find_seek_to(in,"static encode_aux _vq_aux_");
218   /* how big? */
219   line=get_line(in);
220   line=get_line(in);
221   line=get_line(in);
222   line=get_line(in);
223   line=get_line(in);
224   if(sscanf(line,"%ld, %ld",&(a->aux),&(a->alloc))!=2){
225     fprintf(stderr,"2: syntax in %s in line:\t %s",filename,line);
226     exit(1);
227   }
228     
229   /* load the quantized entries */
230   find_seek_to(in,"static long _vq_quantlist_");
231   reset_next_value();
232   c->quantlist=malloc(sizeof(long)*c->entries*c->dim);
233   for(i=0;i<c->entries*c->dim;i++)
234     if(get_next_ivalue(in,c->quantlist+i)){
235       fprintf(stderr,"out of data while reading codebook %s\n",filename);
236       exit(1);
237     }
238
239   /* load the lengthlist */
240   find_seek_to(in,"static long _vq_lengthlist");
241   reset_next_value();
242   c->lengthlist=malloc(sizeof(long)*c->entries);
243   for(i=0;i<c->entries;i++)
244     if(get_next_ivalue(in,c->lengthlist+i)){
245       fprintf(stderr,"out of data while reading codebook %s\n",filename);
246       exit(1);
247     }
248
249   /* load ptr0 */
250   find_seek_to(in,"static long _vq_ptr0");
251   reset_next_value();
252   a->ptr0=malloc(sizeof(long)*a->aux);
253   for(i=0;i<a->aux;i++)
254     if(get_next_ivalue(in,a->ptr0+i)){
255       fprintf(stderr,"out of data while reading codebook %s\n",filename);
256       exit(1);
257     }
258
259   /* load ptr1 */
260   find_seek_to(in,"static long _vq_ptr1");
261   reset_next_value();
262   a->ptr1=malloc(sizeof(long)*a->aux);
263   for(i=0;i<a->aux;i++)
264     if(get_next_ivalue(in,a->ptr1+i)){
265       fprintf(stderr,"out of data while reading codebook %s\n",filename);
266       exit(1);
267     }
268
269
270   /* load p */
271   find_seek_to(in,"static long _vq_p_");
272   reset_next_value();
273   a->p=malloc(sizeof(long)*a->aux);
274   for(i=0;i<a->aux;i++)
275     if(get_next_ivalue(in,a->p+i)){
276       fprintf(stderr,"out of data while reading codebook %s\n",filename);
277       exit(1);
278     }
279
280   /* load q */
281   find_seek_to(in,"static long _vq_q_");
282   reset_next_value();
283   a->q=malloc(sizeof(long)*a->aux);
284   for(i=0;i<a->aux;i++)
285     if(get_next_ivalue(in,a->q+i)){
286       fprintf(stderr,"out of data while reading codebook %s\n",filename);
287       exit(1);
288     }
289
290   /* got it all */
291   fclose(in);
292
293   /* might as well unquantize the entries while we're at it */
294   codebook_unquantize(b);
295
296   /* don't need n and c */
297   return(b);
298 }
299
300 int codebook_entry(codebook *b,double *val){
301   const static_codebook *c=b->c;
302   encode_aux *t=c->encode_tree;
303   int ptr=0,k;
304   double *n=alloca(c->dim*sizeof(double));
305
306   while(1){
307     double C=0.;
308     double *p=b->valuelist+t->p[ptr];
309     double *q=b->valuelist+t->q[ptr];
310     
311     for(k=0;k<c->dim;k++){
312       n[k]=p[k]-q[k];
313       C-=(p[k]+q[k])*n[k];
314     }
315     C/=2.;
316
317     for(k=0;k<c->dim;k++)
318       C+=n[k]*val[k];
319
320     if(C>0.) /* in A */
321       ptr= -t->ptr0[ptr];
322     else     /* in B */
323       ptr= -t->ptr1[ptr];
324     if(ptr<=0)break;
325   }
326   return(-ptr);
327 }
328
329 /* 24 bit float (not IEEE; nonnormalized mantissa +
330    biased exponent ): neeeeemm mmmmmmmm mmmmmmmm */
331
332 long float24_pack(double val){
333   int sign=0;
334   long exp;
335   long mant;
336   if(val<0){
337     sign=0x800000;
338     val= -val;
339   }
340   exp= floor(log(val)/log(2));
341   mant=rint(ldexp(val,17-exp));
342   exp=(exp+VQ_FEXP_BIAS)<<18;
343
344   return(sign|exp|mant);
345 }
346
347 double float24_unpack(long val){
348   double mant=val&0x3ffff;
349   double sign=val&0x800000;
350   double exp =(val&0x7c0000)>>18;
351   if(sign)mant= -mant;
352   return(ldexp(mant,exp-17-VQ_FEXP_BIAS));
353 }
354
355 void spinnit(char *s,int n){
356   static int p=0;
357   static long lasttime=0;
358   long test;
359   struct timeval thistime;
360
361   gettimeofday(&thistime,NULL);
362   test=thistime.tv_sec*10+thistime.tv_usec/100000;
363   if(lasttime!=test){
364     lasttime=test;
365
366     fprintf(stderr,"%s%d ",s,n);
367
368     p++;if(p>3)p=0;
369     switch(p){
370     case 0:
371       fprintf(stderr,"|    \r");
372       break;
373     case 1:
374       fprintf(stderr,"/    \r");
375       break;
376     case 2:
377       fprintf(stderr,"-    \r");
378       break;
379     case 3:
380       fprintf(stderr,"\\    \r");
381       break;
382     }
383     fflush(stderr);
384   }
385 }
386