diff src/libvorbis-1.3.3/vq/bookutil.c @ 1:05aa0afa9217

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