annotate src/libvorbis-1.3.3/vq/bookutil.c @ 83:ae30d91d2ffe

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