annotate src/libvorbis-1.3.3/vq/bookutil.c @ 127:7867fa7e1b6b

Current fftw source
author Chris Cannam <cannam@all-day-breakfast.com>
date Tue, 18 Oct 2016 13:40:26 +0100
parents 98c1576536ae
children
rev   line source
cannam@86 1 /********************************************************************
cannam@86 2 * *
cannam@86 3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
cannam@86 4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
cannam@86 5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
cannam@86 6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
cannam@86 7 * *
cannam@86 8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
cannam@86 9 * by the Xiph.Org Foundation http://www.xiph.org/ *
cannam@86 10 * *
cannam@86 11 ********************************************************************
cannam@86 12
cannam@86 13 function: utility functions for loading .vqh and .vqd files
cannam@86 14 last mod: $Id: bookutil.c 16959 2010-03-10 16:03:11Z xiphmont $
cannam@86 15
cannam@86 16 ********************************************************************/
cannam@86 17
cannam@86 18 #include <stdlib.h>
cannam@86 19 #include <stdio.h>
cannam@86 20 #include <math.h>
cannam@86 21 #include <string.h>
cannam@86 22 #include <errno.h>
cannam@86 23 #include "bookutil.h"
cannam@86 24
cannam@86 25 int _best(codebook *book, float *a, int step){
cannam@86 26
cannam@86 27 int dim=book->dim;
cannam@86 28 int i,j,o;
cannam@86 29 int minval=book->minval;
cannam@86 30 int del=book->delta;
cannam@86 31 int qv=book->quantvals;
cannam@86 32 int ze=(qv>>1);
cannam@86 33 int index=0;
cannam@86 34 /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
cannam@86 35
cannam@86 36 if(del!=1){
cannam@86 37 for(i=0,o=step*(dim-1);i<dim;i++,o-=step){
cannam@86 38 int v = ((int)rint(a[o])-minval+(del>>1))/del;
cannam@86 39 int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1));
cannam@86 40 index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
cannam@86 41 }
cannam@86 42 }else{
cannam@86 43 for(i=0,o=step*(dim-1);i<dim;i++,o-=step){
cannam@86 44 int v = (int)rint(a[o])-minval;
cannam@86 45 int m = (v<ze ? ((ze-v)<<1)-1 : ((v-ze)<<1));
cannam@86 46 index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
cannam@86 47 }
cannam@86 48 }
cannam@86 49
cannam@86 50 if(book->c->lengthlist[index]<=0){
cannam@86 51 const static_codebook *c=book->c;
cannam@86 52 int best=-1;
cannam@86 53 /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
cannam@86 54 int e[8]={0,0,0,0,0,0,0,0};
cannam@86 55 int maxval = book->minval + book->delta*(book->quantvals-1);
cannam@86 56 for(i=0;i<book->entries;i++){
cannam@86 57 if(c->lengthlist[i]>0){
cannam@86 58 float this=0;
cannam@86 59 for(j=0;j<dim;j++){
cannam@86 60 float val=(e[j]-a[j*step]);
cannam@86 61 this+=val*val;
cannam@86 62 }
cannam@86 63 if(best==-1 || this<best){
cannam@86 64 best=this;
cannam@86 65 index=i;
cannam@86 66 }
cannam@86 67 }
cannam@86 68 /* assumes the value patterning created by the tools in vq/ */
cannam@86 69 j=0;
cannam@86 70 while(e[j]>=maxval)
cannam@86 71 e[j++]=0;
cannam@86 72 if(e[j]>=0)
cannam@86 73 e[j]+=book->delta;
cannam@86 74 e[j]= -e[j];
cannam@86 75 }
cannam@86 76 }
cannam@86 77
cannam@86 78 return index;
cannam@86 79 }
cannam@86 80
cannam@86 81 /* A few little utils for reading files */
cannam@86 82 /* read a line. Use global, persistent buffering */
cannam@86 83 static char *linebuffer=NULL;
cannam@86 84 static int lbufsize=0;
cannam@86 85 char *get_line(FILE *in){
cannam@86 86 long sofar=0;
cannam@86 87 if(feof(in))return NULL;
cannam@86 88
cannam@86 89 while(1){
cannam@86 90 int gotline=0;
cannam@86 91
cannam@86 92 while(!gotline){
cannam@86 93 if(sofar+1>=lbufsize){
cannam@86 94 if(!lbufsize){
cannam@86 95 lbufsize=1024;
cannam@86 96 linebuffer=_ogg_malloc(lbufsize);
cannam@86 97 }else{
cannam@86 98 lbufsize*=2;
cannam@86 99 linebuffer=_ogg_realloc(linebuffer,lbufsize);
cannam@86 100 }
cannam@86 101 }
cannam@86 102 {
cannam@86 103 long c=fgetc(in);
cannam@86 104 switch(c){
cannam@86 105 case EOF:
cannam@86 106 if(sofar==0)return(NULL);
cannam@86 107 /* fallthrough correct */
cannam@86 108 case '\n':
cannam@86 109 linebuffer[sofar]='\0';
cannam@86 110 gotline=1;
cannam@86 111 break;
cannam@86 112 default:
cannam@86 113 linebuffer[sofar++]=c;
cannam@86 114 linebuffer[sofar]='\0';
cannam@86 115 break;
cannam@86 116 }
cannam@86 117 }
cannam@86 118 }
cannam@86 119
cannam@86 120 if(linebuffer[0]=='#'){
cannam@86 121 sofar=0;
cannam@86 122 }else{
cannam@86 123 return(linebuffer);
cannam@86 124 }
cannam@86 125 }
cannam@86 126 }
cannam@86 127
cannam@86 128 /* read the next numerical value from the given file */
cannam@86 129 static char *value_line_buff=NULL;
cannam@86 130
cannam@86 131 int get_line_value(FILE *in,float *value){
cannam@86 132 char *next;
cannam@86 133
cannam@86 134 if(!value_line_buff)return(-1);
cannam@86 135
cannam@86 136 *value=strtod(value_line_buff, &next);
cannam@86 137 if(next==value_line_buff){
cannam@86 138 value_line_buff=NULL;
cannam@86 139 return(-1);
cannam@86 140 }else{
cannam@86 141 value_line_buff=next;
cannam@86 142 while(*value_line_buff>44)value_line_buff++;
cannam@86 143 if(*value_line_buff==44)value_line_buff++;
cannam@86 144 return(0);
cannam@86 145 }
cannam@86 146 }
cannam@86 147
cannam@86 148 int get_next_value(FILE *in,float *value){
cannam@86 149 while(1){
cannam@86 150 if(get_line_value(in,value)){
cannam@86 151 value_line_buff=get_line(in);
cannam@86 152 if(!value_line_buff)return(-1);
cannam@86 153 }else{
cannam@86 154 return(0);
cannam@86 155 }
cannam@86 156 }
cannam@86 157 }
cannam@86 158
cannam@86 159 int get_next_ivalue(FILE *in,long *ivalue){
cannam@86 160 float value;
cannam@86 161 int ret=get_next_value(in,&value);
cannam@86 162 *ivalue=value;
cannam@86 163 return(ret);
cannam@86 164 }
cannam@86 165
cannam@86 166 static float sequence_base=0.f;
cannam@86 167 static int v_sofar=0;
cannam@86 168 void reset_next_value(void){
cannam@86 169 value_line_buff=NULL;
cannam@86 170 sequence_base=0.f;
cannam@86 171 v_sofar=0;
cannam@86 172 }
cannam@86 173
cannam@86 174 char *setup_line(FILE *in){
cannam@86 175 reset_next_value();
cannam@86 176 value_line_buff=get_line(in);
cannam@86 177 return(value_line_buff);
cannam@86 178 }
cannam@86 179
cannam@86 180
cannam@86 181 int get_vector(codebook *b,FILE *in,int start, int n,float *a){
cannam@86 182 int i;
cannam@86 183 const static_codebook *c=b->c;
cannam@86 184
cannam@86 185 while(1){
cannam@86 186
cannam@86 187 if(v_sofar==n || get_line_value(in,a)){
cannam@86 188 reset_next_value();
cannam@86 189 if(get_next_value(in,a))
cannam@86 190 break;
cannam@86 191 for(i=0;i<start;i++){
cannam@86 192 sequence_base=*a;
cannam@86 193 get_line_value(in,a);
cannam@86 194 }
cannam@86 195 }
cannam@86 196
cannam@86 197 for(i=1;i<c->dim;i++)
cannam@86 198 if(get_line_value(in,a+i))
cannam@86 199 break;
cannam@86 200
cannam@86 201 if(i==c->dim){
cannam@86 202 float temp=a[c->dim-1];
cannam@86 203 for(i=0;i<c->dim;i++)a[i]-=sequence_base;
cannam@86 204 if(c->q_sequencep)sequence_base=temp;
cannam@86 205 v_sofar++;
cannam@86 206 return(0);
cannam@86 207 }
cannam@86 208 sequence_base=0.f;
cannam@86 209 }
cannam@86 210
cannam@86 211 return(-1);
cannam@86 212 }
cannam@86 213
cannam@86 214 /* read lines fromt he beginning until we find one containing the
cannam@86 215 specified string */
cannam@86 216 char *find_seek_to(FILE *in,char *s){
cannam@86 217 rewind(in);
cannam@86 218 while(1){
cannam@86 219 char *line=get_line(in);
cannam@86 220 if(line){
cannam@86 221 if(strstr(line,s))
cannam@86 222 return(line);
cannam@86 223 }else
cannam@86 224 return(NULL);
cannam@86 225 }
cannam@86 226 }
cannam@86 227
cannam@86 228
cannam@86 229 /* this reads the format as written by vqbuild/latticebuild; innocent
cannam@86 230 (legal) tweaking of the file that would not affect its valid
cannam@86 231 header-ness will break this routine */
cannam@86 232
cannam@86 233 codebook *codebook_load(char *filename){
cannam@86 234 codebook *b=_ogg_calloc(1,sizeof(codebook));
cannam@86 235 static_codebook *c=(static_codebook *)(b->c=_ogg_calloc(1,sizeof(static_codebook)));
cannam@86 236 int quant_to_read=0;
cannam@86 237 FILE *in=fopen(filename,"r");
cannam@86 238 char *line;
cannam@86 239 long i;
cannam@86 240
cannam@86 241 if(in==NULL){
cannam@86 242 fprintf(stderr,"Couldn't open codebook %s\n",filename);
cannam@86 243 exit(1);
cannam@86 244 }
cannam@86 245
cannam@86 246 /* find the codebook struct */
cannam@86 247 find_seek_to(in,"static const static_codebook ");
cannam@86 248
cannam@86 249 /* get the major important values */
cannam@86 250 line=get_line(in);
cannam@86 251 if(sscanf(line,"%ld, %ld,",
cannam@86 252 &(c->dim),&(c->entries))!=2){
cannam@86 253 fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
cannam@86 254 exit(1);
cannam@86 255 }
cannam@86 256 line=get_line(in);
cannam@86 257 line=get_line(in);
cannam@86 258 if(sscanf(line,"%d, %ld, %ld, %d, %d,",
cannam@86 259 &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant),
cannam@86 260 &(c->q_sequencep))!=5){
cannam@86 261 fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
cannam@86 262 exit(1);
cannam@86 263 }
cannam@86 264
cannam@86 265 switch(c->maptype){
cannam@86 266 case 0:
cannam@86 267 quant_to_read=0;
cannam@86 268 break;
cannam@86 269 case 1:
cannam@86 270 quant_to_read=_book_maptype1_quantvals(c);
cannam@86 271 break;
cannam@86 272 case 2:
cannam@86 273 quant_to_read=c->entries*c->dim;
cannam@86 274 break;
cannam@86 275 }
cannam@86 276
cannam@86 277 /* load the quantized entries */
cannam@86 278 find_seek_to(in,"static const long _vq_quantlist_");
cannam@86 279 reset_next_value();
cannam@86 280 c->quantlist=_ogg_malloc(sizeof(long)*quant_to_read);
cannam@86 281 for(i=0;i<quant_to_read;i++)
cannam@86 282 if(get_next_ivalue(in,c->quantlist+i)){
cannam@86 283 fprintf(stderr,"out of data while reading codebook %s\n",filename);
cannam@86 284 exit(1);
cannam@86 285 }
cannam@86 286
cannam@86 287 /* load the lengthlist */
cannam@86 288 find_seek_to(in,"_lengthlist");
cannam@86 289 reset_next_value();
cannam@86 290 c->lengthlist=_ogg_malloc(sizeof(long)*c->entries);
cannam@86 291 for(i=0;i<c->entries;i++)
cannam@86 292 if(get_next_ivalue(in,c->lengthlist+i)){
cannam@86 293 fprintf(stderr,"out of data while reading codebook %s\n",filename);
cannam@86 294 exit(1);
cannam@86 295 }
cannam@86 296
cannam@86 297 /* got it all */
cannam@86 298 fclose(in);
cannam@86 299
cannam@86 300 vorbis_book_init_encode(b,c);
cannam@86 301 b->valuelist=_book_unquantize(c,c->entries,NULL);
cannam@86 302
cannam@86 303 return(b);
cannam@86 304 }
cannam@86 305
cannam@86 306 void spinnit(char *s,int n){
cannam@86 307 static int p=0;
cannam@86 308 static long lasttime=0;
cannam@86 309 long test;
cannam@86 310 struct timeval thistime;
cannam@86 311
cannam@86 312 gettimeofday(&thistime,NULL);
cannam@86 313 test=thistime.tv_sec*10+thistime.tv_usec/100000;
cannam@86 314 if(lasttime!=test){
cannam@86 315 lasttime=test;
cannam@86 316
cannam@86 317 fprintf(stderr,"%s%d ",s,n);
cannam@86 318
cannam@86 319 p++;if(p>3)p=0;
cannam@86 320 switch(p){
cannam@86 321 case 0:
cannam@86 322 fprintf(stderr,"| \r");
cannam@86 323 break;
cannam@86 324 case 1:
cannam@86 325 fprintf(stderr,"/ \r");
cannam@86 326 break;
cannam@86 327 case 2:
cannam@86 328 fprintf(stderr,"- \r");
cannam@86 329 break;
cannam@86 330 case 3:
cannam@86 331 fprintf(stderr,"\\ \r");
cannam@86 332 break;
cannam@86 333 }
cannam@86 334 fflush(stderr);
cannam@86 335 }
cannam@86 336 }
cannam@86 337
cannam@86 338 void build_tree_from_lengths(int vals, long *hist, long *lengths){
cannam@86 339 int i,j;
cannam@86 340 long *membership=_ogg_malloc(vals*sizeof(long));
cannam@86 341 long *histsave=alloca(vals*sizeof(long));
cannam@86 342 memcpy(histsave,hist,vals*sizeof(long));
cannam@86 343
cannam@86 344 for(i=0;i<vals;i++)membership[i]=i;
cannam@86 345
cannam@86 346 /* find codeword lengths */
cannam@86 347 /* much more elegant means exist. Brute force n^2, minimum thought */
cannam@86 348 for(i=vals;i>1;i--){
cannam@86 349 int first=-1,second=-1;
cannam@86 350 long least=-1;
cannam@86 351
cannam@86 352 spinnit("building... ",i);
cannam@86 353
cannam@86 354 /* find the two nodes to join */
cannam@86 355 for(j=0;j<vals;j++)
cannam@86 356 if(least==-1 || hist[j]<=least){
cannam@86 357 least=hist[j];
cannam@86 358 first=membership[j];
cannam@86 359 }
cannam@86 360 least=-1;
cannam@86 361 for(j=0;j<vals;j++)
cannam@86 362 if((least==-1 || hist[j]<=least) && membership[j]!=first){
cannam@86 363 least=hist[j];
cannam@86 364 second=membership[j];
cannam@86 365 }
cannam@86 366 if(first==-1 || second==-1){
cannam@86 367 fprintf(stderr,"huffman fault; no free branch\n");
cannam@86 368 exit(1);
cannam@86 369 }
cannam@86 370
cannam@86 371 /* join them */
cannam@86 372 least=hist[first]+hist[second];
cannam@86 373 for(j=0;j<vals;j++)
cannam@86 374 if(membership[j]==first || membership[j]==second){
cannam@86 375 membership[j]=first;
cannam@86 376 hist[j]=least;
cannam@86 377 lengths[j]++;
cannam@86 378 }
cannam@86 379 }
cannam@86 380 for(i=0;i<vals-1;i++)
cannam@86 381 if(membership[i]!=membership[i+1]){
cannam@86 382 fprintf(stderr,"huffman fault; failed to build single tree\n");
cannam@86 383 exit(1);
cannam@86 384 }
cannam@86 385
cannam@86 386 /* for sanity check purposes: how many bits would it have taken to
cannam@86 387 encode the training set? */
cannam@86 388 {
cannam@86 389 long bitsum=0;
cannam@86 390 long samples=0;
cannam@86 391 for(i=0;i<vals;i++){
cannam@86 392 bitsum+=(histsave[i]-1)*lengths[i];
cannam@86 393 samples+=histsave[i]-1;
cannam@86 394 }
cannam@86 395
cannam@86 396 if(samples){
cannam@86 397 fprintf(stderr,"\rTotal samples in training set: %ld \n",samples);
cannam@86 398 fprintf(stderr,"\rTotal bits used to represent training set: %ld\n",
cannam@86 399 bitsum);
cannam@86 400 }
cannam@86 401 }
cannam@86 402
cannam@86 403 free(membership);
cannam@86 404 }
cannam@86 405
cannam@86 406 /* wrap build_tree_from_lengths to allow zero entries in the histogram */
cannam@86 407 void build_tree_from_lengths0(int vals, long *hist, long *lengths){
cannam@86 408
cannam@86 409 /* pack the 'sparse' hit list into a dense list, then unpack
cannam@86 410 the lengths after the build */
cannam@86 411
cannam@86 412 int upper=0,i;
cannam@86 413 long *lengthlist=_ogg_calloc(vals,sizeof(long));
cannam@86 414 long *newhist=alloca(vals*sizeof(long));
cannam@86 415
cannam@86 416 for(i=0;i<vals;i++)
cannam@86 417 if(hist[i]>0)
cannam@86 418 newhist[upper++]=hist[i];
cannam@86 419
cannam@86 420 if(upper != vals){
cannam@86 421 fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n",
cannam@86 422 vals-upper,upper);
cannam@86 423 }
cannam@86 424
cannam@86 425 build_tree_from_lengths(upper,newhist,lengthlist);
cannam@86 426
cannam@86 427 upper=0;
cannam@86 428 for(i=0;i<vals;i++)
cannam@86 429 if(hist[i]>0)
cannam@86 430 lengths[i]=lengthlist[upper++];
cannam@86 431 else
cannam@86 432 lengths[i]=0;
cannam@86 433
cannam@86 434 free(lengthlist);
cannam@86 435 }
cannam@86 436
cannam@86 437 void write_codebook(FILE *out,char *name,const static_codebook *c){
cannam@86 438 int i,j,k;
cannam@86 439
cannam@86 440 /* save the book in C header form */
cannam@86 441
cannam@86 442 /* first, the static vectors, then the book structure to tie it together. */
cannam@86 443 /* quantlist */
cannam@86 444 if(c->quantlist){
cannam@86 445 long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim);
cannam@86 446 fprintf(out,"static const long _vq_quantlist_%s[] = {\n",name);
cannam@86 447 for(j=0;j<vals;j++){
cannam@86 448 fprintf(out,"\t%ld,\n",c->quantlist[j]);
cannam@86 449 }
cannam@86 450 fprintf(out,"};\n\n");
cannam@86 451 }
cannam@86 452
cannam@86 453 /* lengthlist */
cannam@86 454 fprintf(out,"static const long _vq_lengthlist_%s[] = {\n",name);
cannam@86 455 for(j=0;j<c->entries;){
cannam@86 456 fprintf(out,"\t");
cannam@86 457 for(k=0;k<16 && j<c->entries;k++,j++)
cannam@86 458 fprintf(out,"%2ld,",c->lengthlist[j]);
cannam@86 459 fprintf(out,"\n");
cannam@86 460 }
cannam@86 461 fprintf(out,"};\n\n");
cannam@86 462
cannam@86 463 /* tie it all together */
cannam@86 464
cannam@86 465 fprintf(out,"static const static_codebook %s = {\n",name);
cannam@86 466
cannam@86 467 fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries);
cannam@86 468 fprintf(out,"\t(long *)_vq_lengthlist_%s,\n",name);
cannam@86 469 fprintf(out,"\t%d, %ld, %ld, %d, %d,\n",
cannam@86 470 c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep);
cannam@86 471 if(c->quantlist)
cannam@86 472 fprintf(out,"\t(long *)_vq_quantlist_%s,\n",name);
cannam@86 473 else
cannam@86 474 fprintf(out,"\tNULL,\n");
cannam@86 475
cannam@86 476 fprintf(out,"\t0\n};\n\n");
cannam@86 477 }