Commit 32ab2651 authored by Monty's avatar Monty
Browse files

Some significant encoder-side codebook cleanup toward new surround code

landing.

This is primarily elimination of dead code and useless float vectors 
that are of no use given the current encoder codebook strategy.


svn path=/trunk/vorbis/; revision=16939
parent 82c3a0d0
......@@ -96,7 +96,7 @@ typedef struct{
float **,int *,int);
int (*forward) (oggpack_buffer *,struct vorbis_block *,
vorbis_look_residue *,
float **,float **,int *,int,long **);
int **,int *,int,long **);
int (*inverse) (struct vorbis_block *,vorbis_look_residue *,
float **,int *,int);
} vorbis_func_residue;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -264,37 +264,6 @@ int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){
return(book->c->lengthlist[a]);
}
/* One the encode side, our vector writers are each designed for a
specific purpose, and the encoder is not flexible without modification:
The LSP vector coder uses a single stage nearest-match with no
interleave, so no step and no error return. This is specced by floor0
and doesn't change.
Residue0 encoding interleaves, uses multiple stages, and each stage
peels of a specific amount of resolution from a lattice (thus we want
to match by threshold, not nearest match). Residue doesn't *have* to
be encoded that way, but to change it, one will need to add more
infrastructure on the encode side (decode side is specced and simpler) */
/* floor0 LSP (single stage, non interleaved, nearest match) */
/* returns entry number and *modifies a* to the quantization value *****/
int vorbis_book_errorv(codebook *book,float *a){
int dim=book->dim,k;
int best=_best(book,a,1);
for(k=0;k<dim;k++)
a[k]=(book->valuelist+best*dim)[k];
return(best);
}
/* returns the number of bits and *modifies a* to the quantization value *****/
int vorbis_book_encodev(codebook *book,int best,float *a,oggpack_buffer *b){
int k,dim=book->dim;
for(k=0;k<dim;k++)
a[k]=(book->valuelist+best*dim)[k];
return(vorbis_book_encode(book,best,b));
}
/* the 'eliminate the decode tree' optimization actually requires the
codewords to be MSb first, not LSb. This is an annoying inelegancy
(and one of the first places where carefully thought out design
......@@ -495,144 +464,3 @@ long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch,
}
return(0);
}
#ifdef _V_SELFTEST
/* Simple enough; pack a few candidate codebooks, unpack them. Code a
number of vectors through (keeping track of the quantized values),
and decode using the unpacked book. quantized version of in should
exactly equal out */
#include <stdio.h>
#include "vorbis/book/lsp20_0.vqh"
#include "vorbis/book/res0a_13.vqh"
#define TESTSIZE 40
float test1[TESTSIZE]={
0.105939f,
0.215373f,
0.429117f,
0.587974f,
0.181173f,
0.296583f,
0.515707f,
0.715261f,
0.162327f,
0.263834f,
0.342876f,
0.406025f,
0.103571f,
0.223561f,
0.368513f,
0.540313f,
0.136672f,
0.395882f,
0.587183f,
0.652476f,
0.114338f,
0.417300f,
0.525486f,
0.698679f,
0.147492f,
0.324481f,
0.643089f,
0.757582f,
0.139556f,
0.215795f,
0.324559f,
0.399387f,
0.120236f,
0.267420f,
0.446940f,
0.608760f,
0.115587f,
0.287234f,
0.571081f,
0.708603f,
};
float test3[TESTSIZE]={
0,1,-2,3,4,-5,6,7,8,9,
8,-2,7,-1,4,6,8,3,1,-9,
10,11,12,13,14,15,26,17,18,19,
30,-25,-30,-1,-5,-32,4,3,-2,0};
static_codebook *testlist[]={&_vq_book_lsp20_0,
&_vq_book_res0a_13,NULL};
float *testvec[]={test1,test3};
int main(){
oggpack_buffer write;
oggpack_buffer read;
long ptr=0,i;
oggpack_writeinit(&write);
fprintf(stderr,"Testing codebook abstraction...:\n");
while(testlist[ptr]){
codebook c;
static_codebook s;
float *qv=alloca(sizeof(*qv)*TESTSIZE);
float *iv=alloca(sizeof(*iv)*TESTSIZE);
memcpy(qv,testvec[ptr],sizeof(*qv)*TESTSIZE);
memset(iv,0,sizeof(*iv)*TESTSIZE);
fprintf(stderr,"\tpacking/coding %ld... ",ptr);
/* pack the codebook, write the testvector */
oggpack_reset(&write);
vorbis_book_init_encode(&c,testlist[ptr]); /* get it into memory
we can write */
vorbis_staticbook_pack(testlist[ptr],&write);
fprintf(stderr,"Codebook size %ld bytes... ",oggpack_bytes(&write));
for(i=0;i<TESTSIZE;i+=c.dim){
int best=_best(&c,qv+i,1);
vorbis_book_encodev(&c,best,qv+i,&write);
}
vorbis_book_clear(&c);
fprintf(stderr,"OK.\n");
fprintf(stderr,"\tunpacking/decoding %ld... ",ptr);
/* transfer the write data to a read buffer and unpack/read */
oggpack_readinit(&read,oggpack_get_buffer(&write),oggpack_bytes(&write));
if(vorbis_staticbook_unpack(&read,&s)){
fprintf(stderr,"Error unpacking codebook.\n");
exit(1);
}
if(vorbis_book_init_decode(&c,&s)){
fprintf(stderr,"Error initializing codebook.\n");
exit(1);
}
for(i=0;i<TESTSIZE;i+=c.dim)
if(vorbis_book_decodev_set(&c,iv+i,&read,c.dim)==-1){
fprintf(stderr,"Error reading codebook test data (EOP).\n");
exit(1);
}
for(i=0;i<TESTSIZE;i++)
if(fabs(qv[i]-iv[i])>.000001){
fprintf(stderr,"read (%g) != written (%g) at position (%ld)\n",
iv[i],qv[i],i);
exit(1);
}
fprintf(stderr,"OK\n");
ptr++;
}
/* The above is the trivial stuff; now try unquantizing a log scale codebook */
exit(0);
}
#endif
......@@ -52,50 +52,9 @@ typedef struct static_codebook{
long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map
map == 2: list of dim*entries quantized entry vals
*/
/* encode helpers ********************************************************/
struct encode_aux_nearestmatch *nearest_tree;
struct encode_aux_threshmatch *thresh_tree;
struct encode_aux_pigeonhole *pigeon_tree;
int allocedp;
} static_codebook;
/* this structures an arbitrary trained book to quickly find the
nearest cell match */
typedef struct encode_aux_nearestmatch{
/* pre-calculated partitioning tree */
long *ptr0;
long *ptr1;
long *p; /* decision points (each is an entry) */
long *q; /* decision points (each is an entry) */
long aux; /* number of tree entries */
long alloc;
} encode_aux_nearestmatch;
/* assumes a maptype of 1; encode side only, so that's OK */
typedef struct encode_aux_threshmatch{
float *quantthresh;
long *quantmap;
int quantvals;
int threshvals;
} encode_aux_threshmatch;
typedef struct encode_aux_pigeonhole{
float min;
float del;
int mapentries;
int quantvals;
long *pigeonmap;
long fittotal;
long *fitlist;
long *fitmap;
long *fitlength;
} encode_aux_pigeonhole;
typedef struct codebook{
long dim; /* codebook dimensions (elements per vector) */
long entries; /* codebook entries */
......@@ -114,6 +73,10 @@ typedef struct codebook{
int dec_firsttablen;
int dec_maxlength;
/* The current encoder uses only centered, integer-only lattice books. */
int quantvals;
int minval;
int delta;
} codebook;
extern void vorbis_staticbook_clear(static_codebook *b);
......@@ -140,9 +103,6 @@ extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b);
extern int vorbis_staticbook_unpack(oggpack_buffer *b,static_codebook *c);
extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b);
extern int vorbis_book_errorv(codebook *book, float *a);
extern int vorbis_book_encodev(codebook *book, int best,float *a,
oggpack_buffer *b);
extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
extern long vorbis_book_decodevs_add(codebook *book, float *a,
......
......@@ -246,7 +246,7 @@ static int mapping0_forward(vorbis_block *vb){
int *nonzero = alloca(sizeof(*nonzero)*vi->channels);
float **gmdct = _vorbis_block_alloc(vb,vi->channels*sizeof(*gmdct));
int **ilogmaskch= _vorbis_block_alloc(vb,vi->channels*sizeof(*ilogmaskch));
int **iwork = _vorbis_block_alloc(vb,vi->channels*sizeof(*iwork));
int ***floor_posts = _vorbis_block_alloc(vb,vi->channels*sizeof(*floor_posts));
float global_ampmax=vbi->ampmax;
......@@ -628,6 +628,7 @@ static int mapping0_forward(vorbis_block *vb){
for(i=0;i<vi->channels;i++){
float *mdct =gmdct[i];
sortindex[i]=alloca(sizeof(**sortindex)*n/2);
iwork[i]=_vorbis_block_alloc(vb,n/2*sizeof(**iwork));
_vp_noise_normalize_sort(psy_look,mdct,sortindex[i]);
}
}
......@@ -653,8 +654,7 @@ static int mapping0_forward(vorbis_block *vb){
int submap=info->chmuxlist[i];
float *mdct =gmdct[i];
float *res =vb->pcm[i];
int *ilogmask=ilogmaskch[i]=
_vorbis_block_alloc(vb,n/2*sizeof(**gmdct));
int *ilogmask=iwork[i];
nonzero[i]=floor1_encode(opb,vb,b->flr[info->floorsubmap[submap]],
floor_posts[i][k],
......@@ -665,7 +665,7 @@ static int mapping0_forward(vorbis_block *vb){
sprintf(buf,"maskI%c%d",i?'R':'L',k);
float work[n/2];
for(j=0;j<n/2;j++)
work[j]=FLOOR1_fromdB_LOOKUP[ilogmask[j]];
work[j]=FLOOR1_fromdB_LOOKUP[iwork[j]];
_analysis_output(buf,seq,work,n/2,1,1,0);
}
#endif
......@@ -683,7 +683,7 @@ static int mapping0_forward(vorbis_block *vb){
char buf[80];
float work[n/2];
for(j=0;j<n/2;j++)
work[j]=FLOOR1_fromdB_LOOKUP[ilogmask[j]]*(res+n/2)[j];
work[j]=FLOOR1_fromdB_LOOKUP[iwork[j]]*(res+n/2)[j];
sprintf(buf,"resI%c%d",i?'R':'L',k);
_analysis_output(buf,seq,work,n/2,1,1,0);
......@@ -705,7 +705,7 @@ static int mapping0_forward(vorbis_block *vb){
vb->pcm,
mag_memo,
mag_sort,
ilogmaskch,
iwork,
nonzero,
ci->psy_g_param.sliding_lowpass[vb->W][k]);
}
......@@ -728,17 +728,20 @@ static int mapping0_forward(vorbis_block *vb){
classifications=_residue_P[ci->residue_type[resnum]]->
class(vb,b->residue[resnum],couple_bundle,zerobundle,ch_in_bundle);
/* couple_bundle is destructively overwritten by
the class function if some but not all of the channels are
marked as silence; build a fresh copy */
ch_in_bundle=0;
for(j=0;j<vi->channels;j++)
if(info->chmuxlist[j]==i)
couple_bundle[ch_in_bundle++]=vb->pcm[j]+n/2;
if(info->chmuxlist[j]==i){
/* move from float to int vector; temporary until new coupling lands */
float *res=vb->pcm[j]+n/2;
int *ires=iwork[ch_in_bundle++];
int k;
for(k=0;k<n/2;k++)
ires[k]=(int)rint(res[k]);
}
_residue_P[ci->residue_type[resnum]]->
forward(opb,vb,b->residue[resnum],
couple_bundle,NULL,zerobundle,ch_in_bundle,classifications);
iwork,zerobundle,ch_in_bundle,classifications);
}
/* ok, done encoding. Next protopacket. */
......
......@@ -321,65 +321,71 @@ vorbis_look_residue *res0_look(vorbis_dsp_state *vd,
}
/* break an abstraction and copy some code for performance purposes */
static int local_book_besterror(codebook *book,float *a){
int dim=book->dim,i,k,o;
int best=0;
encode_aux_threshmatch *tt=book->c->thresh_tree;
/* find the quant val of each scalar */
for(k=0,o=dim;k<dim;++k){
float val=a[--o];
i=tt->threshvals>>1;
if(val<tt->quantthresh[i]){
if(val<tt->quantthresh[i-1]){
for(--i;i>0;--i)
if(val>=tt->quantthresh[i-1])
break;
}
}else{
for(++i;i<tt->threshvals-1;++i)
if(val<tt->quantthresh[i])break;
static int local_book_besterror(codebook *book,int *a){
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 */
int p[8]={0,0,0,0,0,0,0,0};
if(del!=1){
for(i=0,o=dim;i<dim;i++){
int v = (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));
p[o]=v*del+minval;
}
}else{
for(i=0,o=dim;i<dim;i++){
int v = 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));
p[o]=v*del+minval;
}
best=(best*tt->quantvals)+tt->quantmap[i];
}
/* regular lattices are easy :-) */
if(book->c->lengthlist[best]<=0){
if(book->c->lengthlist[index]<=0){
const static_codebook *c=book->c;
int i,j;
float bestf=0.f;
float *e=book->valuelist;
best=-1;
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.f;
int this=0;
for(j=0;j<dim;j++){
float val=(e[j]-a[j]);
this+=val*val;
}
if(best==-1 || this<bestf){
bestf=this;
best=i;
if(best==-1 || this<best){
memcpy(p,e,sizeof(p));
best=this;
index=i;
}
}
e+=dim;
/* 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];
}
}
if(best>-1){
float *ptr=book->valuelist+best*dim;
if(index>-1){
for(i=0;i<dim;i++)
*a++ -= *ptr++;
*a++ -= p[i];
}
return(best);
return(index);
}
static int _encodepart(oggpack_buffer *opb,float *vec, int n,
static int _encodepart(oggpack_buffer *opb,int *vec, int n,
codebook *book,long *acc){
int i,bits=0;
int dim=book->dim;
......@@ -524,9 +530,9 @@ static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,float **in,
static int _01forward(oggpack_buffer *opb,
vorbis_block *vb,vorbis_look_residue *vl,
float **in,int ch,
int **in,int ch,
long **partword,
int (*encode)(oggpack_buffer *,float *,int,
int (*encode)(oggpack_buffer *,int *,int,
codebook *,long *)){
long i,j,k,s;
vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
......@@ -698,54 +704,6 @@ static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
return(0);
}
#if 0
/* residue 0 and 1 are just slight variants of one another. 0 is
interleaved, 1 is not */
long **res0_class(vorbis_block *vb,vorbis_look_residue *vl,
float **in,int *nonzero,int ch){
/* we encode only the nonzero parts of a bundle */
int i,used=0;
for(i=0;i<ch;i++)
if(nonzero[i])
in[used++]=in[i];
if(used)
/*return(_01class(vb,vl,in,used,_interleaved_testhack));*/
return(_01class(vb,vl,in,used));
else
return(0);
}
int res0_forward(vorbis_block *vb,vorbis_look_residue *vl,
float **in,float **out,int *nonzero,int ch,
long **partword){
/* we encode only the nonzero parts of a bundle */
int i,j,used=0,n=vb->pcmend/2;
for(i=0;i<ch;i++)
if(nonzero[i]){
if(out)
for(j=0;j<n;j++)
out[i][j]+=in[i][j];
in[used++]=in[i];
}
if(used){
int ret=_01forward(vb,vl,in,used,partword,
_interleaved_encodepart);
if(out){
used=0;
for(i=0;i<ch;i++)
if(nonzero[i]){
for(j=0;j<n;j++)
out[i][j]-=in[used][j];
used++;
}
}
return(ret);
}else{
return(0);
}
}
#endif
int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
float **in,int *nonzero,int ch){
int i,used=0;
......@@ -759,29 +717,14 @@ int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
}
int res1_forward(oggpack_buffer *opb,vorbis_block *vb,vorbis_look_residue *vl,
float **in,float **out,int *nonzero,int ch,
long **partword){
int **in,int *nonzero,int ch, long **partword){
int i,j,used=0,n=vb->pcmend/2;
for(i=0;i<ch;i++)
if(nonzero[i]){
if(out)
for(j=0;j<n;j++)
out[i][j]+=in[i][j];
if(nonzero[i])
in[used++]=in[i];
}
if(used){
int ret=_01forward(opb,vb,vl,in,used,partword,_encodepart);
if(out){
used=0;
for(i=0;i<ch;i++)
if(nonzero[i]){
for(j=0;j<n;j++)
out[i][j]-=in[used][j];
used++;
}
}
return(ret);
return _01forward(opb,vb,vl,in,used,partword,_encodepart);
}else{
return(0);
}
......@@ -827,34 +770,22 @@ long **res2_class(vorbis_block *vb,vorbis_look_residue *vl,
int res2_forward(oggpack_buffer *opb,
vorbis_block *vb,vorbis_look_residue *vl,
float **in,float **out,int *nonzero,int ch,
long **partword){
int **in,int *nonzero,int ch, long **partword){
long i,j,k,n=vb->pcmend/2,used=0;
/* don't duplicate the code; use a working vector hack for now and
reshape ourselves into a single channel res1 */
/* ugly; reallocs for each coupling pass :-( */
float *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work));
int *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work));
for(i=0;i<ch;i++){
float *pcm=in[i];
int *pcm=in[i];
if(nonzero[i])used++;
for(j=0,k=i;j<n;j++,k+=ch)
work[k]=pcm[j];
}
if(used){
int ret=_01forward(opb,vb,vl,&work,1,partword,_encodepart);
/* update the sofar vector */
if(out){
for(i=0;i<ch;i++){
float *pcm=in[i];
float *sofar=out[i];
for(j=0,k=i;j<n;j++,k+=ch)
sofar[j]+=pcm[j]-work[k];
}
}
return(ret);
return _01forward(opb,vb,vl,&work,1,partword,_encodepart);
}else{
return(0);
}
......
......@@ -262,21 +262,6 @@ void vorbis_staticbook_clear(static_codebook *b){
if(b->allocedp){
if(b->quantlist)_ogg_free(b->quantlist);
if(b->lengthlist)_ogg_free(b->lengthlist);
if(b->nearest_tree){
_ogg_free(b->nearest_tree->ptr0);
_ogg_free(b->nearest_tree->ptr1);
_ogg_free(b->nearest_tree->p);
_ogg_free(b->nearest_tree->q);
memset(b->nearest_tree,0,sizeof(*b->nearest_tree));
_ogg_free(b->nearest_tree);
}
if(b->thresh_tree){