--- /dev/null
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *
+ * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: metrics and quantization code for LSP VQ codebooks
+ author: Monty <xiphmont@mit.edu>
+ modifications by: Monty
+ last modification date: Dec 15 1999
+
+ ********************************************************************/
+
+#include <math.h>
+#include <stdio.h>
+#include "vqgen.h"
+#include "vqext.h"
+
+char *vqext_booktype="LSPdata";
+
+/* LSP training metric. We weight error proportional to distance
+ *between* LSP vector values */
+
+ /* candidate,actual */
+double vqext_metric(vqgen *v,double *b, double *a){
+ int i;
+ int el=v->elements;
+ double acc=0.;
+ double lasta=0.;
+ /*double lastb=0.;*/
+ for(i=0;i<el;i++){
+ double actualdist=(a[i]-lasta);
+ /*double testdist=(b[i]-lastb);
+
+ double disterr=fabs(testdist-actualdist);*/
+ double poserr=fabs(a[i]-b[i]);
+ acc+=poserr/actualdist;
+
+ lasta=a[i];
+ /*lastb=b[i];*/
+ }
+ return acc;
+}
+
+/* LSP quantizes all absolute values, but the book encodes distance
+ between values (which has a smaller range). Thus the desired
+ quantibits apply to the encoded (delta) values, not abs
+ positions. This requires minor additional trickery. */
+
+quant_return vqext_quantize(vqgen *v,int quantbits){
+ quant_return q;
+ double maxval=0.;
+ double maxdel;
+ double mindel;
+ double delta;
+ double fullrangevals;
+ double maxquant=((1<<quantbits)-1);
+ int j,k;
+
+ mindel=maxdel=_now(v,0)[0];
+
+ for(j=0;j<v->entries;j++){
+ double last=0.;
+ for(k=0;k<v->elements;k++){
+ if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
+ if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
+ if(maxval<_now(v,j)[k])maxval=_now(v,j)[k];
+ last=_now(v,j)[k];
+ }
+ }
+
+ q.minval=0.;
+ delta=(maxdel-mindel)/((1<<quantbits)-2);
+ fullrangevals=floor(maxval/delta);
+ q.delt=delta=maxval/fullrangevals;
+ q.addtoquant=floor(mindel/delta);
+
+ for(j=0;j<v->entries;j++){
+ double last=0.;
+ for(k=0;k<v->elements;k++){
+ double val=_now(v,j)[k];
+ double now=rint(val/delta);
+ double test=_now(v,j)[k]=now-last-q.addtoquant;
+
+ if(test<0){
+ fprintf(stderr,"fault; quantized value<0\n");
+ exit(1);
+ }
+
+ if(test>maxquant){
+ fprintf(stderr,"fault; quantized value>max\n");
+ exit(1);
+ }
+ last=now;
+ }
+ }
+ return(q);
+}
+
+/* much easier :-) */
+void vqext_unquantize(vqgen *v,quant_return *q){
+ long j,k;
+ for(j=0;j<v->entries;j++){
+ double last=0.;
+ for(k=0;k<v->elements;k++){
+ last=(_now(v,j)[k]+q->addtoquant)*q->delt+q->minval+last;
+ _now(v,j)[k]=last;
+ }
+ }
+}
function: utility main for training codebooks
author: Monty <xiphmont@mit.edu>
modifications by: Monty
- last modification date: Dec 14 1999
+ last modification date: Dec 15 1999
********************************************************************/
#include <errno.h>
#include <signal.h>
#include "vqgen.h"
-
-/* A metric for LSP codes */
- /* candidate,actual */
-static double _dist_and_pos(vqgen *v,double *b, double *a){
- int i;
- int el=v->elements;
- double acc=0.;
- double lastb=0.;
- for(i=0;i<el;i++){
- double actualdist=(a[i]-lastb);
- double testdist=(b[i]-lastb);
- if(actualdist>0 && testdist>0){
- double val;
- if(actualdist>testdist)
- val=actualdist/testdist-1.;
- else
- val=testdist/actualdist-1.;
- acc+=val;
- }else{
- acc+=999999.;
- }
- lastb=b[i];
- }
- return acc;
-}
-
-static void *set_metric(int m){
- switch(m){
- case 0:
- return(NULL);
- case 1:
- return(_dist_and_pos);
- default:
- fprintf(stderr,"Invalid metric number\n");
- exit(0);
- }
-}
+#include "vqext.h"
static int rline(FILE *in,FILE *out,char *line,int max,int pass){
while(fgets(line,160,in)){
}
/* command line:
- trainvq [vq=file | [entries=n] [dim=n] [quant=n]] met=n in=file,firstcol
+ trainvq [vq=file | [entries=n] [dim=n] [quant=n]] in=file,firstcol
[in=file,firstcol]
*/
int main(int argc,char *argv[]){
vqgen v;
+ quant_return q;
+
int entries=-1,dim=-1,quant=-1;
FILE *out=NULL;
- int met=0;
- double (*metric)(vqgen *,double *, double *)=NULL;
char line[1024];
long i,j,k;
fprintf(stderr,"Unable to open %s for writing\n",filename);
exit(1);
}
- fprintf(out,"# OggVorbis VQ codebook trainer, intermediate file\n");
if(in){
/* we wish to suck in a preexisting book and continue to train it */
double a;
+
+ rline(in,out,line,160,1);
+ if(strlen(line)>0)line[strlen(line)-1]='\0';
+ if(strcmp(line,vqext_booktype)){
+ fprintf(stderr,"wrong book type; %s!=%s\n",line,vqext_booktype);
+ exit(1);
+ }
rline(in,out,line,160,1);
- if(sscanf(line,"%d %d %d %d",&entries,&dim,&met,&quant)!=3){
+ if(sscanf(line,"%d %d",&entries,&dim)!=2){
fprintf(stderr,"Syntax error reading book file\n");
exit(1);
}
+
- metric=set_metric(met);
- vqgen_init(&v,dim,entries,metric,quant);
+ vqgen_init(&v,dim,entries,vqext_metric);
init=1;
- /* entries, bias, points */
+ /* quant setup */
+ rline(in,out,line,160,1);
+ if(sscanf(line,"%lf %lf %d %d",&q.minval,&q.delt,
+ &q.addtoquant,&quant)!=4){
+ fprintf(stderr,"Syntax error reading book file\n");
+ exit(1);
+ }
+
+ /* entries */
i=0;
for(j=0;j<entries;j++){
for(k=0;k<dim;k++){
v.entrylist[i++]=a;
}
}
+
+ /* dequantize */
+ vqext_unquantize(&v,&q);
+ /* bias, points */
i=0;
for(j=0;j<entries;j++){
rline(in,out,line,160,0);
if(!strncmp(*argv,"entries=",8)){
sscanf(*argv,"entries=%d",&entries);
}
- if(!strncmp(*argv,"desired=",8)){
- sscanf(*argv,"desired=%lf",&desired);
- }
if(!strncmp(*argv,"dim=",4)){
sscanf(*argv,"dim=%d",&dim);
}
-
- /* which error metric (0==euclidian distance default) */
- if(!strncmp(*argv,"met=",4)){
- sscanf(*argv,"met=%d",&met);
- metric=set_metric(met);
+ if(!strncmp(*argv,"desired=",8)){
+ sscanf(*argv,"desired=%lf",&desired);
+ }
+ if(!strncmp(*argv,"iter=",5)){
+ sscanf(*argv,"iter=%d",&iter);
}
if(!strncmp(*argv,"in=",3)){
" first input file\n");
exit(1);
}
- vqgen_init(&v,dim,entries,metric,quant);
+ vqgen_init(&v,dim,entries,vqext_metric);
init=1;
}
signal(SIGINT,setexit);
for(i=0;i<iter && !exiting;i++){
- if(vqgen_iterate(&v)<desired)break;
+ double result;
+ if(i!=0)vqext_unquantize(&v,&q);
+ result=vqgen_iterate(&v);
+ q=vqext_quantize(&v,quant);
+ if(result<desired)break;
}
/* save the book */
- fprintf(out,"%d %d %d %d\n",entries,dim,met,quant);
+ fprintf(out,"# OggVorbis VQ codebook trainer, intermediate file\n");
+ fprintf(out,"%s\n",vqext_booktype);
+ fprintf(out,"%d %d\n",entries,dim);
+ fprintf(out,"%g %g %d %d\n",q.minval,q.delt,q.addtoquant,quant);
i=0;
for(j=0;j<entries;j++)
--- /dev/null
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *
+ * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: prototypes for extermal metrics specific to data type
+
+ ********************************************************************/
+
+#ifndef _V_VQEXT_
+#define _V_VQEXT_
+
+#include "vqgen.h"
+
+extern char *vqext_booktype;
+typedef struct {
+ double minval;
+ double delt;
+ int addtoquant;
+} quant_return;
+
+extern double vqext_metric(vqgen *v,double *b, double *a);
+extern quant_return vqext_quantize(vqgen *v,int quantbits);
+extern void vqext_unquantize(vqgen *v,quant_return *q);
+
+#endif
/* External calls *******************************************************/
void vqgen_init(vqgen *v,int elements,int entries,
- double (*metric)(vqgen *,double *, double *),
- int quant){
+ double (*metric)(vqgen *,double *, double *)){
memset(v,0,sizeof(vqgen));
v->elements=elements;
- v->quantbits=quant;
v->allocated=32768;
v->pointlist=malloc(v->allocated*v->elements*sizeof(double));
#endif
}
- {
- /* midpoints must be quantized. but we need to know the range in
- order to do so */
- double min,max;
-
- for(k=0;k<v->elements;k++){
- double delta;
- min=max=_now(v,0)[k];
-
- for(j=1;j<v->entries;j++){
- double val=_now(v,j)[k];
- if(val<min)min=val;
- if(val>max)max=val;
- }
-
- delta=(max-min)/((1<<v->quantbits)-1);
- for(j=0;j<v->entries;j++){
- double val=_now(v,j)[k];
- _now(v,j)[k]=min+delta*rint((val-min)/delta);
- }
- }
- }
-
asserror/=(v->entries*fdesired);
fprintf(stderr,": dist %g(%g) metric error=%g \n",
asserror,fdesired,meterror/v->points);
b->lengthlist=malloc(b->entries*sizeof(long));
/* first, generate the encoding decision heirarchy */
- fprintf(stderr,"Total leaves: %ld\n",
+ fprintf(stderr,"Total leaves: %d\n",
lp_split(v,b,entryindex,v->entries, pointindex,v->points,0,0));
/* run all training points through the decision tree to get a final
int it;
int elements;
- int quantbits;
/* point cache */
double *pointlist;
} vqbook;
extern void vqgen_init(vqgen *v,int elements,int entries,
- double (*metric)(vqgen *,double *, double *),
- int quant);
+ double (*metric)(vqgen *,double *, double *));
extern void vqgen_addpoint(vqgen *v, double *p);
extern double *vqgen_midpoint(vqgen *v);
extern double vqgen_iterate(vqgen *v);
extern int vqenc_entry(vqbook *b,double *val);
extern void vqgen_book(vqgen *v,vqbook *b);
+extern double *_now(vqgen *v,long ptr);
#endif