Blame vq/bookutil.c

Packit 06404a
/********************************************************************
Packit 06404a
 *                                                                  *
Packit 06404a
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Packit 06404a
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
Packit 06404a
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Packit 06404a
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Packit 06404a
 *                                                                  *
Packit 06404a
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014             *
Packit 06404a
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
Packit 06404a
 *                                                                  *
Packit 06404a
 ********************************************************************
Packit 06404a
Packit 06404a
 function: utility functions for loading .vqh and .vqd files
Packit 06404a
 last mod: $Id: bookutil.c 19057 2014-01-22 12:32:31Z xiphmont $
Packit 06404a
Packit 06404a
 ********************************************************************/
Packit 06404a
Packit 06404a
#include <stdlib.h>
Packit 06404a
#include <stdio.h>
Packit 06404a
#include <math.h>
Packit 06404a
#include <string.h>
Packit 06404a
#include <errno.h>
Packit 06404a
#include "bookutil.h"
Packit 06404a
Packit 06404a
int _best(codebook *book, float *a, int step){
Packit 06404a
Packit 06404a
  int dim=book->dim;
Packit 06404a
  int i,j,o;
Packit 06404a
  int minval=book->minval;
Packit 06404a
  int del=book->delta;
Packit 06404a
  int qv=book->quantvals;
Packit 06404a
  int ze=(qv>>1);
Packit 06404a
  int index=0;
Packit 06404a
  /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
Packit 06404a
Packit 06404a
  if(del!=1){
Packit 06404a
    for(i=0,o=step*(dim-1);i
Packit 06404a
      int v = ((int)rint(a[o])-minval+(del>>1))/del;
Packit 06404a
      int m = (v
Packit 06404a
      index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
Packit 06404a
    }
Packit 06404a
  }else{
Packit 06404a
    for(i=0,o=step*(dim-1);i
Packit 06404a
      int v = (int)rint(a[o])-minval;
Packit 06404a
      int m = (v
Packit 06404a
      index = index*qv+ (m<0?0:(m>=qv?qv-1:m));
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  if(book->c->lengthlist[index]<=0){
Packit 06404a
    const static_codebook *c=book->c;
Packit 06404a
    int best=-1;
Packit 06404a
    /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */
Packit 06404a
    int e[8]={0,0,0,0,0,0,0,0};
Packit 06404a
    int maxval = book->minval + book->delta*(book->quantvals-1);
Packit 06404a
    for(i=0;i<book->entries;i++){
Packit 06404a
      if(c->lengthlist[i]>0){
Packit 06404a
        float this=0;
Packit 06404a
        for(j=0;j
Packit 06404a
          float val=(e[j]-a[j*step]);
Packit 06404a
          this+=val*val;
Packit 06404a
        }
Packit 06404a
        if(best==-1 || this
Packit 06404a
          best=this;
Packit 06404a
          index=i;
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
      /* assumes the value patterning created by the tools in vq/ */
Packit 06404a
      j=0;
Packit 06404a
      while(e[j]>=maxval)
Packit 06404a
        e[j++]=0;
Packit 06404a
      if(e[j]>=0)
Packit 06404a
        e[j]+=book->delta;
Packit 06404a
      e[j]= -e[j];
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return index;
Packit 06404a
}
Packit 06404a
Packit 06404a
/* A few little utils for reading files */
Packit 06404a
/* read a line.  Use global, persistent buffering */
Packit 06404a
static char *linebuffer=NULL;
Packit 06404a
static int  lbufsize=0;
Packit 06404a
char *get_line(FILE *in){
Packit 06404a
  long sofar=0;
Packit 06404a
  if(feof(in))return NULL;
Packit 06404a
Packit 06404a
  while(1){
Packit 06404a
    int gotline=0;
Packit 06404a
Packit 06404a
    while(!gotline){
Packit 06404a
      if(sofar+1>=lbufsize){
Packit 06404a
        if(!lbufsize){  
Packit 06404a
          lbufsize=1024;
Packit 06404a
          linebuffer=_ogg_malloc(lbufsize);
Packit 06404a
        }else{
Packit 06404a
          lbufsize*=2;
Packit 06404a
          linebuffer=_ogg_realloc(linebuffer,lbufsize);
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
      {
Packit 06404a
        long c=fgetc(in);
Packit 06404a
        switch(c){
Packit 06404a
        case EOF:
Packit 06404a
          if(sofar==0)return(NULL);
Packit 06404a
          /* fallthrough correct */
Packit 06404a
        case '\n':
Packit 06404a
          linebuffer[sofar]='\0';
Packit 06404a
          gotline=1;
Packit 06404a
          break;
Packit 06404a
        default:
Packit 06404a
          linebuffer[sofar++]=c;
Packit 06404a
          linebuffer[sofar]='\0';
Packit 06404a
          break;
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
    
Packit 06404a
    if(linebuffer[0]=='#'){
Packit 06404a
      sofar=0;
Packit 06404a
    }else{
Packit 06404a
      return(linebuffer);
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
/* read the next numerical value from the given file */
Packit 06404a
static char *value_line_buff=NULL;
Packit 06404a
Packit 06404a
int get_line_value(FILE *in,float *value){
Packit 06404a
  char *next;
Packit 06404a
Packit 06404a
  if(!value_line_buff)return(-1);
Packit 06404a
Packit 06404a
  *value=strtod(value_line_buff, &next;;
Packit 06404a
  if(next==value_line_buff){
Packit 06404a
    value_line_buff=NULL;
Packit 06404a
    return(-1);
Packit 06404a
  }else{
Packit 06404a
    value_line_buff=next;
Packit 06404a
    while(*value_line_buff>44)value_line_buff++;
Packit 06404a
    if(*value_line_buff==44)value_line_buff++;
Packit 06404a
    return(0);
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
int get_next_value(FILE *in,float *value){
Packit 06404a
  while(1){
Packit 06404a
    if(get_line_value(in,value)){
Packit 06404a
      value_line_buff=get_line(in);
Packit 06404a
      if(!value_line_buff)return(-1);
Packit 06404a
    }else{
Packit 06404a
      return(0);
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
int get_next_ivalue(FILE *in,long *ivalue){
Packit 06404a
  float value;
Packit 06404a
  int ret=get_next_value(in,&value);
Packit 06404a
  *ivalue=value;
Packit 06404a
  return(ret);
Packit 06404a
}
Packit 06404a
Packit 06404a
static float sequence_base=0.f;
Packit 06404a
static int v_sofar=0;
Packit 06404a
void reset_next_value(void){
Packit 06404a
  value_line_buff=NULL;
Packit 06404a
  sequence_base=0.f;
Packit 06404a
  v_sofar=0;
Packit 06404a
}
Packit 06404a
Packit 06404a
char *setup_line(FILE *in){
Packit 06404a
  reset_next_value();
Packit 06404a
  value_line_buff=get_line(in);
Packit 06404a
  return(value_line_buff);
Packit 06404a
}
Packit 06404a
Packit 06404a
Packit 06404a
int get_vector(codebook *b,FILE *in,int start, int n,float *a){
Packit 06404a
  int i;
Packit 06404a
  const static_codebook *c=b->c;
Packit 06404a
Packit 06404a
  while(1){
Packit 06404a
Packit 06404a
    if(v_sofar==n || get_line_value(in,a)){
Packit 06404a
      reset_next_value();
Packit 06404a
      if(get_next_value(in,a))
Packit 06404a
        break;
Packit 06404a
      for(i=0;i
Packit 06404a
        sequence_base=*a;
Packit 06404a
        get_line_value(in,a);
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
Packit 06404a
    for(i=1;i<c->dim;i++)
Packit 06404a
      if(get_line_value(in,a+i))
Packit 06404a
        break;
Packit 06404a
    
Packit 06404a
    if(i==c->dim){
Packit 06404a
      float temp=a[c->dim-1];
Packit 06404a
      for(i=0;i<c->dim;i++)a[i]-=sequence_base;
Packit 06404a
      if(c->q_sequencep)sequence_base=temp;
Packit 06404a
      v_sofar++;
Packit 06404a
      return(0);
Packit 06404a
    }
Packit 06404a
    sequence_base=0.f;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return(-1);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* read lines fromt he beginning until we find one containing the
Packit 06404a
   specified string */
Packit 06404a
char *find_seek_to(FILE *in,char *s){
Packit 06404a
  rewind(in);
Packit 06404a
  while(1){
Packit 06404a
    char *line=get_line(in);
Packit 06404a
    if(line){
Packit 06404a
      if(strstr(line,s))
Packit 06404a
        return(line);
Packit 06404a
    }else
Packit 06404a
      return(NULL);
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
Packit 06404a
/* this reads the format as written by vqbuild/latticebuild; innocent
Packit 06404a
   (legal) tweaking of the file that would not affect its valid
Packit 06404a
   header-ness will break this routine */
Packit 06404a
Packit 06404a
codebook *codebook_load(char *filename){
Packit 06404a
  codebook *b=_ogg_calloc(1,sizeof(codebook));
Packit 06404a
  static_codebook *c=(static_codebook *)(b->c=_ogg_calloc(1,sizeof(static_codebook)));
Packit 06404a
  int quant_to_read=0;
Packit 06404a
  FILE *in=fopen(filename,"r");
Packit 06404a
  char *line;
Packit 06404a
  long i;
Packit 06404a
Packit 06404a
  if(in==NULL){
Packit 06404a
    fprintf(stderr,"Couldn't open codebook %s\n",filename);
Packit 06404a
    exit(1);
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* find the codebook struct */
Packit 06404a
  find_seek_to(in,"static const static_codebook ");
Packit 06404a
Packit 06404a
  /* get the major important values */
Packit 06404a
  line=get_line(in);
Packit 06404a
  if(sscanf(line,"%ld, %ld,",
Packit 06404a
            &(c->dim),&(c->entries))!=2){
Packit 06404a
    fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
Packit 06404a
    exit(1);
Packit 06404a
  }
Packit 06404a
  line=get_line(in);
Packit 06404a
  line=get_line(in);
Packit 06404a
  if(sscanf(line,"%d, %ld, %ld, %d, %d,",
Packit 06404a
            &(c->maptype),&(c->q_min),&(c->q_delta),&(c->q_quant),
Packit 06404a
            &(c->q_sequencep))!=5){
Packit 06404a
    fprintf(stderr,"1: syntax in %s in line:\t %s",filename,line);
Packit 06404a
    exit(1);
Packit 06404a
  }
Packit 06404a
  
Packit 06404a
  switch(c->maptype){
Packit 06404a
  case 0:
Packit 06404a
    quant_to_read=0;
Packit 06404a
    break;
Packit 06404a
  case 1:
Packit 06404a
    quant_to_read=_book_maptype1_quantvals(c);
Packit 06404a
    break;
Packit 06404a
  case 2:
Packit 06404a
    quant_to_read=c->entries*c->dim;
Packit 06404a
    break;
Packit 06404a
  }
Packit 06404a
    
Packit 06404a
  /* load the quantized entries */
Packit 06404a
  find_seek_to(in,"static const long _vq_quantlist_");
Packit 06404a
  reset_next_value();
Packit 06404a
  c->quantlist=_ogg_malloc(sizeof(long)*quant_to_read);
Packit 06404a
  for(i=0;i
Packit 06404a
    if(get_next_ivalue(in,c->quantlist+i)){
Packit 06404a
      fprintf(stderr,"out of data while reading codebook %s\n",filename);
Packit 06404a
      exit(1);
Packit 06404a
    }
Packit 06404a
  
Packit 06404a
  /* load the lengthlist */
Packit 06404a
  find_seek_to(in,"_lengthlist");
Packit 06404a
  reset_next_value();
Packit 06404a
  c->lengthlist=_ogg_malloc(sizeof(long)*c->entries);
Packit 06404a
  for(i=0;i<c->entries;i++)
Packit 06404a
    if(get_next_ivalue(in,c->lengthlist+i)){
Packit 06404a
      fprintf(stderr,"out of data while reading codebook %s\n",filename);
Packit 06404a
      exit(1);
Packit 06404a
    }
Packit 06404a
Packit 06404a
  /* got it all */
Packit 06404a
  fclose(in);
Packit 06404a
  
Packit 06404a
  vorbis_book_init_encode(b,c);
Packit 06404a
  b->valuelist=_book_unquantize(c,c->entries,NULL);
Packit 06404a
Packit 06404a
  return(b);
Packit 06404a
}
Packit 06404a
Packit 06404a
void spinnit(char *s,int n){
Packit 06404a
  static int p=0;
Packit 06404a
  static long lasttime=0;
Packit 06404a
  long test;
Packit 06404a
  struct timeval thistime;
Packit 06404a
Packit 06404a
  gettimeofday(&thistime,NULL);
Packit 06404a
  test=thistime.tv_sec*10+thistime.tv_usec/100000;
Packit 06404a
  if(lasttime!=test){
Packit 06404a
    lasttime=test;
Packit 06404a
Packit 06404a
    fprintf(stderr,"%s%d ",s,n);
Packit 06404a
Packit 06404a
    p++;if(p>3)p=0;
Packit 06404a
    switch(p){
Packit 06404a
    case 0:
Packit 06404a
      fprintf(stderr,"|    \r");
Packit 06404a
      break;
Packit 06404a
    case 1:
Packit 06404a
      fprintf(stderr,"/    \r");
Packit 06404a
      break;
Packit 06404a
    case 2:
Packit 06404a
      fprintf(stderr,"-    \r");
Packit 06404a
      break;
Packit 06404a
    case 3:
Packit 06404a
      fprintf(stderr,"\\    \r");
Packit 06404a
      break;
Packit 06404a
    }
Packit 06404a
    fflush(stderr);
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
void build_tree_from_lengths(int vals, long *hist, long *lengths){
Packit 06404a
  int i,j;
Packit 06404a
  long *membership=_ogg_malloc(vals*sizeof(long));
Packit 06404a
  long *histsave=alloca(vals*sizeof(long));
Packit 06404a
  memcpy(histsave,hist,vals*sizeof(long));
Packit 06404a
Packit 06404a
  for(i=0;i
Packit 06404a
Packit 06404a
  /* find codeword lengths */
Packit 06404a
  /* much more elegant means exist.  Brute force n^2, minimum thought */
Packit 06404a
  for(i=vals;i>1;i--){
Packit 06404a
    int first=-1,second=-1;
Packit 06404a
    long least=-1;
Packit 06404a
        
Packit 06404a
    spinnit("building... ",i);
Packit 06404a
    
Packit 06404a
    /* find the two nodes to join */
Packit 06404a
    for(j=0;j
Packit 06404a
      if(least==-1 || hist[j]<=least){
Packit 06404a
        least=hist[j];
Packit 06404a
        first=membership[j];
Packit 06404a
      }
Packit 06404a
    least=-1;
Packit 06404a
    for(j=0;j
Packit 06404a
      if((least==-1 || hist[j]<=least) && membership[j]!=first){
Packit 06404a
        least=hist[j];
Packit 06404a
        second=membership[j];
Packit 06404a
      }
Packit 06404a
    if(first==-1 || second==-1){
Packit 06404a
      fprintf(stderr,"huffman fault; no free branch\n");
Packit 06404a
      exit(1);
Packit 06404a
    }
Packit 06404a
    
Packit 06404a
    /* join them */
Packit 06404a
    least=hist[first]+hist[second];
Packit 06404a
    for(j=0;j
Packit 06404a
      if(membership[j]==first || membership[j]==second){
Packit 06404a
        membership[j]=first;
Packit 06404a
        hist[j]=least;
Packit 06404a
        lengths[j]++;
Packit 06404a
      }
Packit 06404a
  }
Packit 06404a
  for(i=0;i
Packit 06404a
    if(membership[i]!=membership[i+1]){
Packit 06404a
      fprintf(stderr,"huffman fault; failed to build single tree\n");
Packit 06404a
      exit(1);
Packit 06404a
    }
Packit 06404a
Packit 06404a
  /* for sanity check purposes: how many bits would it have taken to
Packit 06404a
     encode the training set? */
Packit 06404a
  {
Packit 06404a
    long bitsum=0;
Packit 06404a
    long samples=0;
Packit 06404a
    for(i=0;i
Packit 06404a
      bitsum+=(histsave[i]-1)*lengths[i];
Packit 06404a
      samples+=histsave[i]-1;
Packit 06404a
    }
Packit 06404a
Packit 06404a
    if(samples){
Packit 06404a
      fprintf(stderr,"\rTotal samples in training set: %ld      \n",samples);
Packit 06404a
      fprintf(stderr,"\rTotal bits used to represent training set: %ld\n",
Packit 06404a
              bitsum);
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  free(membership);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* wrap build_tree_from_lengths to allow zero entries in the histogram */
Packit 06404a
void build_tree_from_lengths0(int vals, long *hist, long *lengths){
Packit 06404a
Packit 06404a
  /* pack the 'sparse' hit list into a dense list, then unpack
Packit 06404a
     the lengths after the build */
Packit 06404a
Packit 06404a
  int upper=0,i;
Packit 06404a
  long *lengthlist=_ogg_calloc(vals,sizeof(long));
Packit 06404a
  long *newhist=alloca(vals*sizeof(long));
Packit 06404a
Packit 06404a
  for(i=0;i
Packit 06404a
    if(hist[i]>0)
Packit 06404a
      newhist[upper++]=hist[i];
Packit 06404a
Packit 06404a
  if(upper != vals){
Packit 06404a
    fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n",
Packit 06404a
            vals-upper,upper);
Packit 06404a
  }
Packit 06404a
    
Packit 06404a
  build_tree_from_lengths(upper,newhist,lengthlist);
Packit 06404a
      
Packit 06404a
  upper=0;
Packit 06404a
  for(i=0;i
Packit 06404a
    if(hist[i]>0)
Packit 06404a
      lengths[i]=lengthlist[upper++];
Packit 06404a
    else
Packit 06404a
      lengths[i]=0;
Packit 06404a
Packit 06404a
  free(lengthlist);
Packit 06404a
}
Packit 06404a
Packit 06404a
void write_codebook(FILE *out,char *name,const static_codebook *c){
Packit 06404a
  int i,j,k;
Packit 06404a
Packit 06404a
  /* save the book in C header form */
Packit 06404a
Packit 06404a
  /* first, the static vectors, then the book structure to tie it together. */
Packit 06404a
  /* quantlist */
Packit 06404a
  if(c->quantlist){
Packit 06404a
    long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim);
Packit 06404a
    fprintf(out,"static const long _vq_quantlist_%s[] = {\n",name);
Packit 06404a
    for(j=0;j
Packit 06404a
      fprintf(out,"\t%ld,\n",c->quantlist[j]);
Packit 06404a
    }
Packit 06404a
    fprintf(out,"};\n\n");
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* lengthlist */
Packit 06404a
  fprintf(out,"static const char _vq_lengthlist_%s[] = {\n",name);
Packit 06404a
  for(j=0;j<c->entries;){
Packit 06404a
    fprintf(out,"\t");
Packit 06404a
    for(k=0;k<16 && j<c->entries;k++,j++)
Packit 06404a
      fprintf(out,"%2ld,",c->lengthlist[j]);
Packit 06404a
    fprintf(out,"\n");
Packit 06404a
  }
Packit 06404a
  fprintf(out,"};\n\n");
Packit 06404a
Packit 06404a
  /* tie it all together */
Packit 06404a
  
Packit 06404a
  fprintf(out,"static const static_codebook %s = {\n",name);
Packit 06404a
  
Packit 06404a
  fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries);
Packit 06404a
  fprintf(out,"\t(char *)_vq_lengthlist_%s,\n",name);
Packit 06404a
  fprintf(out,"\t%d, %ld, %ld, %d, %d,\n",
Packit 06404a
          c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep);
Packit 06404a
  if(c->quantlist)
Packit 06404a
    fprintf(out,"\t(long *)_vq_quantlist_%s,\n",name);
Packit 06404a
  else
Packit 06404a
    fprintf(out,"\tNULL,\n");
Packit 06404a
Packit 06404a
  fprintf(out,"\t0\n};\n\n");
Packit 06404a
}