From 117b96ee4431075adc24c09afd0b6251c8ababd6 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 31 Aug 1999 03:53:25 +0000 Subject: [PATCH] First shot at the continuous balance code. Analysis is not correct yet. Monty svn path=/trunk/vorbis/; revision=80 --- lib/analysis.c | 222 ++++++++++++----- lib/block.c | 29 ++- lib/codec.h | 40 +++- lib/dsptest.c | 11 +- lib/lpc.c | 92 +++----- lib/lpc.h | 8 +- lib/lsp.c | 1 - lib/lsp.h | 2 +- lib/mdct.h | 9 +- lib/psy.c | 134 ++++++++++- lib/psy.h | 4 + lib/smallft.c | 721 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/smallft.h | 6 +- lib/synthesis.c | 15 +- 14 files changed, 1116 insertions(+), 178 deletions(-) diff --git a/lib/analysis.c b/lib/analysis.c index a99d662..6004e43 100644 --- a/lib/analysis.c +++ b/lib/analysis.c @@ -14,122 +14,220 @@ function: single-block PCM analysis author: Monty modifications by: Monty - last modification date: Aug 09 1999 + last modification date: Aug 22 1999 ********************************************************************/ #include +#include #include #include "lpc.h" +#include "lsp.h" #include "codec.h" #include "envelope.h" #include "mdct.h" #include "psy.h" +extern void compute_balance(double *A, double *B, double *phi,int n); + int vorbis_analysis(vorbis_block *vb){ int i; double *window=vb->vd->window[vb->W][vb->lW][vb->nW]; + lpc_lookup *vl=&vb->vd->vl[vb->W]; + lpc_lookup *vbal=&vb->vd->vbal[vb->W]; int n=vb->pcmend; static int frameno=0; + double balance_v[vbal->m]; + double balance_amp; + _ve_envelope_sparsify(vb); _ve_envelope_apply(vb,0); for(i=0;ipcm_channels;i++) mdct_forward(&vb->vd->vm[vb->W],vb->pcm[i],vb->pcm[i],window); - /* handle vectors to be encoded one at a time. The PCM storage now - has twice the space we need in the MDCT domain, so mix down into - the second half of storage */ - /* XXXX Mix down to C+D stereo now */ + /* hardwired to stereo for now */ { - double *C=vb->pcm[0]+n/2; - double *D=vb->pcm[1]+n/2; - double *L=vb->pcm[0]; - double *R=vb->pcm[1]; - for(i=0;ipcm[0]; + double *D=vb->pcm[1]; + + /* Balance */ + + balance_amp=_vp_balance_compute(D,C,balance_v,vbal); + + /*{ + FILE *out; + char buffer[80]; + + sprintf(buffer,"com%d.m",frameno); + out=fopen(buffer,"w+"); + for(i=0;ivf[0],vi->smallblock); /* only used in analysis */ - drft_init(&v->vf[1],vi->largeblock); /* only used in analysis */ + + /* Yes, wasteful to have four lookups. This will get collapsed once + things crystallize */ + lpc_init(&v->vl[0],vi->smallblock/2,vi->smallblock/2, + vi->floororder,vi->flooroctaves,1); + lpc_init(&v->vl[1],vi->largeblock/2,vi->largeblock/2, + vi->floororder,vi->flooroctaves,1); + + lpc_init(&v->vbal[0],vi->smallblock/2,256, + vi->balanceorder,vi->balanceoctaves,1); + lpc_init(&v->vbal[1],vi->largeblock/2,256, + vi->balanceorder,vi->balanceoctaves,1); return(0); } @@ -168,8 +178,6 @@ void vorbis_analysis_clear(vorbis_dsp_state *v){ free(v->multipliers); } _ve_envelope_clear(&v->ve); - drft_clear(&v->vf[0]); - drft_clear(&v->vf[1]); mdct_clear(&v->vm[0]); mdct_clear(&v->vm[1]); memset(v,0,sizeof(vorbis_dsp_state)); @@ -336,6 +344,7 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){ } }else v->nW=1; + v->nW=1; /* Do we actually have enough data *now* for the next block? The reason to check is that if we had no multipliers, that could @@ -435,6 +444,18 @@ int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ _vds_shared_init(v,vi); vi->envelopech=temp; + /* Yes, wasteful to have four lookups. This will get collapsed once + things crystallize */ + lpc_init(&v->vl[0],vi->smallblock/2,vi->smallblock/2, + vi->floororder,vi->flooroctaves,0); + lpc_init(&v->vl[1],vi->largeblock/2,vi->largeblock/2, + vi->floororder,vi->flooroctaves,0); + lpc_init(&v->vbal[0],vi->smallblock/2,256, + vi->balanceorder,vi->balanceoctaves,0); + lpc_init(&v->vbal[1],vi->largeblock/2,256, + vi->balanceorder,vi->balanceoctaves,0); + + /* Adjust centerW to allow an easier mechanism for determining output */ v->pcm_returned=v->centerW; v->centerW-= v->block_size[v->W]/4+v->block_size[v->lW]/4; diff --git a/lib/codec.h b/lib/codec.h index c9c07df..7247fed 100644 --- a/lib/codec.h +++ b/lib/codec.h @@ -14,21 +14,48 @@ function: codec headers author: Monty modifications by: Monty - last modification date: Jul 28 1999 + last modification date: Aug 21 1999 ********************************************************************/ #ifndef _vorbis_codec_h_ #define _vorbis_codec_h_ -#include "mdct.h" -#include "smallft.h" +typedef struct { + int n; + int log2n; + + double *trig; + int *bitrev; + +} mdct_lookup; + +typedef struct { + int n; + double *trigcache; + int *splitcache; +} drft_lookup; typedef struct { int winlen; double *window; } envelope_lookup; +typedef struct lpclook{ + /* encode lookups */ + int *bscale; + double *escale; + drft_lookup fft; + + /* en/decode lookups */ + double *dscale; + double *norm; + int n; + int ln; + int m; + +} lpc_lookup; + typedef struct { long endbyte; @@ -56,9 +83,13 @@ typedef struct vorbis_info{ int **Echannelmap; /* which encoding channels produce what pcm (decode) */ int **channelmap; /* which pcm channels produce what floors (encode) */ int floororder; + int flooroctaves; int floorch; int *floormap; + int balanceorder; + int balanceoctaves; + double preecho_thresh; double preecho_clamp; } vorbis_info; @@ -126,8 +157,9 @@ typedef struct vorbis_dsp_state{ double *window[2][2][2]; /* windowsize, leadin, leadout */ envelope_lookup ve; - drft_lookup vf[2]; mdct_lookup vm[2]; + lpc_lookup vl[2]; + lpc_lookup vbal[2]; vorbis_info vi; diff --git a/lib/dsptest.c b/lib/dsptest.c index a46e7e5..67d0b2a 100644 --- a/lib/dsptest.c +++ b/lib/dsptest.c @@ -15,6 +15,7 @@ int main(){ int mtemp[]={0,1}; int mtemp2[]={0,1}; int frame=0; + int i; signed char buffer[READ*4+44]; @@ -30,8 +31,13 @@ int main(){ vi.envelopech=2; vi.envelopemap=mtemp; vi.floormap=mtemp2; - vi.floororder=20; + vi.floororder=30; + vi.flooroctaves=5; vi.floorch=2; + + vi.balanceorder=4; + vi.balanceoctaves=5; + vi.channelmap=NULL; vi.preecho_thresh=10.; vi.preecho_clamp=.5; @@ -43,11 +49,12 @@ int main(){ fread(buffer,1,44,stdin); fwrite(buffer,1,44,stdout); + for(i=0;i<0;i++) + fread(buffer,1,READ*4,stdin); while(!done){ long bread=fread(buffer,1,READ*4,stdin); double **buf=vorbis_analysis_buffer(&encode,READ); - long i; /* uninterleave samples */ diff --git a/lib/lpc.c b/lib/lpc.c index e8c6cc1..b9af103 100644 --- a/lib/lpc.c +++ b/lib/lpc.c @@ -60,60 +60,15 @@ Carsten Bormann coefficients. Autocorrelation LPC coeff generation algorithm invented by N. Levinson in 1947, modified by J. Durbin in 1959. */ -/* Input : n element envelope curve - Output: m lpc coefficients, excitation energy */ +/* Input : n element envelope curve + Output: m lpc coefficients, excitation energy */ -double memcof(double *data, int n, int m, double *d){ - int k,j,i; - double p=0.,wk1[n],wk2[n],wkm[m],xms; - - memset(wk1,0,sizeof(wk1)); - memset(wk2,0,sizeof(wk2)); - memset(wkm,0,sizeof(wkm)); - - for (j=0;jln; + int m=l->m; double aut[m+1],work[n+n],error; - drft_lookup dl; int i,j; - + /* input is a real curve. make it complex-real */ for(i=0;ifft,work); /* The autocorrelation will not be circular. Shift, else we lose most of the power in the edges. */ @@ -133,7 +86,7 @@ static double vorbis_gen_lpc(double *curve,int n,double *lpc,int m){ work[i++]=work[j]; work[j++]=temp; } - + /* autocorrelation, p+1 lag coefficients */ j=m+1; @@ -177,7 +130,7 @@ static double vorbis_gen_lpc(double *curve,int n,double *lpc,int m){ /* we need the error value to know how big an impulse to hit the filter with later */ - + return error; } @@ -187,7 +140,7 @@ static double vorbis_gen_lpc(double *curve,int n,double *lpc,int m){ looks at the below in the context of the calling function, there's lots of redundant trig, but at least it's clear */ -static double vorbis_lpc_magnitude(double w,double *lpc, int m){ +double vorbis_lpc_magnitude(double w,double *lpc, int m){ int k; double real=1,imag=0; double wn=w; @@ -228,14 +181,16 @@ static double vorbis_lpc_magnitude(double w,double *lpc, int m){ oct == octaves in normalized scale, encode_p == encode (1) or decode (0) */ -double lpc_init(lpc_lookup *l,int n, int m, int oct, int encode_p){ +void lpc_init(lpc_lookup *l,int n, int mapped, int m, int oct, int encode_p){ double bias=LOG_BIAS(n,oct); - double scale=(float)n/(float)oct; /* where n==mapped */ + double scale=(float)mapped/(float)oct; /* where n==mapped */ int i; + memset(l,0,sizeof(lpc_lookup)); + l->n=n; + l->ln=mapped; l->m=m; - l->escale=malloc(n*sizeof(double)); l->dscale=malloc(n*sizeof(double)); l->norm=malloc(n*sizeof(double)); @@ -251,10 +206,15 @@ double lpc_init(lpc_lookup *l,int n, int m, int oct, int encode_p){ if(encode_p){ /* encode */ + l->bscale=malloc(n*sizeof(int)); + l->escale=malloc(n*sizeof(double)); - for(i=0;iescale[i]=LINEAR_X(i/scale,bias); - + l->bscale[i]=rint(LOG_X(i,bias)*scale); + } + + drft_init(&l->fft,mapped*2); } /* decode; encode may use this too */ @@ -267,7 +227,9 @@ double lpc_init(lpc_lookup *l,int n, int m, int oct, int encode_p){ void lpc_clear(lpc_lookup *l){ if(l){ + if(l->bscale)free(l->bscale); if(l->escale)free(l->escale); + drft_clear(&l->fft); free(l->dscale); free(l->norm); } @@ -281,10 +243,10 @@ double vorbis_curve_to_lpc(double *curve,double *lpc,lpc_lookup *l){ /* map the input curve to a log curve for encoding */ /* for clarity, mapped and n are both represented although setting - 'em equal is a decent rule of thumb. */ + 'em equal is a decent rule of thumb. The below must be reworked + slightly if mapped != n */ int n=l->n; - int m=l->m; int mapped=n; double work[mapped]; int i; @@ -305,7 +267,7 @@ double vorbis_curve_to_lpc(double *curve,double *lpc,lpc_lookup *l){ memcpy(curve,work,sizeof(work)); - return vorbis_gen_lpc(work,mapped,lpc,l->m); + return vorbis_gen_lpc(work,lpc,l); } /* generate the whole freq response curve on an LPC IIR filter */ diff --git a/lib/lpc.h b/lib/lpc.h index e21f73b..4b72874 100644 --- a/lib/lpc.h +++ b/lib/lpc.h @@ -20,9 +20,15 @@ #include "codec.h" -extern double lpc_init(lpc_lookup *l,int n, int m, int oct, int encode_p); +extern void lpc_init(lpc_lookup *l,int n, int mapped, + int m, int oct, int encode_p); extern void lpc_clear(lpc_lookup *l); +/* simple linear scale LPC code */ +extern double vorbis_gen_lpc(double *curve,double *lpc,lpc_lookup *l); +extern double vorbis_lpc_magnitude(double w,double *lpc, int m); + +/* log scale layer */ extern double vorbis_curve_to_lpc(double *curve,double *lpc,lpc_lookup *l); extern void vorbis_lpc_to_curve(double *curve,double *lpc, double amp, lpc_lookup *l); diff --git a/lib/lsp.c b/lib/lsp.c index 2d5b9bc..0448de7 100644 --- a/lib/lsp.c +++ b/lib/lsp.c @@ -163,4 +163,3 @@ void vorbis_lpc_to_lsp(double *lpc,double *lsp,int m){ lsp[i+1] = acos(g2r[i/2]*.5); } } - diff --git a/lib/lsp.h b/lib/lsp.h index 48f31d5..02e3c76 100644 --- a/lib/lsp.h +++ b/lib/lsp.h @@ -16,5 +16,5 @@ extern void vorbis_lsp_to_lpc(double *lsp,double *lpc,int m); extern void vorbis_lpc_to_lsp(double *lpc,double *lsp,int m); - + #endif diff --git a/lib/mdct.h b/lib/mdct.h index 771527e..4337ca3 100644 --- a/lib/mdct.h +++ b/lib/mdct.h @@ -18,14 +18,7 @@ #ifndef _OGG_mdct_H_ #define _OGG_mdct_H_ -typedef struct { - int n; - int log2n; - - double *trig; - int *bitrev; - -} mdct_lookup; +#include "codec.h" extern void mdct_init(mdct_lookup *lookup,int n); extern void mdct_clear(mdct_lookup *l); diff --git a/lib/psy.c b/lib/psy.c index f50c623..188f138 100644 --- a/lib/psy.c +++ b/lib/psy.c @@ -14,22 +14,27 @@ function: random psychoacoustics (not including preecho) author: Monty modifications by: Monty - last modification date: Aug 08 1999 + last modification date: Aug 26 1999 ********************************************************************/ #include +#include +#include "stdio.h" #include "codec.h" #include "psy.h" +#include "lpc.h" +#include "smallft.h" +#include "xlogmap.h" -#define NOISEdB 6 +#define NOISEdB 10 -#define MASKdB 12 +#define MASKdB 18 #define HROLL 60 #define LROLL 90 -#define MASKBIAS 40 +#define MASKBIAS 10 -#define LNOISE .8 +#define LNOISE .95 #define HNOISE 1.01 #define NOISEBIAS 20 @@ -47,7 +52,7 @@ void _vp_noise_floor(double *f, double *m,int n){ double acc=0,div=0; int i,j; - for(i=0;i16)val=16; if(val<-16)val=-16; - f[i]=val*m[i]; + if(val==0 || val==2){ + if(f[i]<0){ + f[i]=-1; + }else{ + f[i]=1; + } + } + + f[i]=val; } } +void _vp_psy_unquantize(double *f, double *m,int n){ + int i; + for(i=0;in; + int mapped=vb->ln; + + /* 256/15 are arbitrary but unimportant to decoding */ + int resp=15; + int i; + /* This is encode side. Don't think too hard about it */ + + double workA[mapped+resp]; + double workB[mapped+resp]; + double p[mapped]; + double workC[resp]; + memset(workA,0,sizeof(workA)); + memset(workB,0,sizeof(workB)); + memset(workC,0,sizeof(workC)); + + for(i=0;ibscale[i]+(resp>>1); + double mag_sq=A[i]*A[i]+B[i]*B[i]; + double phi; + + if(B[i]==0) + phi=M_PI/2.; + else{ + phi=atan(A[i]/B[i]); + if((A[i]<0 && B[i]>0)|| + (A[i]>0 && B[i]<0)){ + /* rotate II and IV into the first quadrant. III is already there */ + phi+=M_PI/2; + } + } + + workA[j]+=mag_sq*sin(phi); + workB[j]+=mag_sq*cos(phi); + } + + /* prepare convolution vector. Play with a few different shapes */ + + for(i=0;in;i++){ + double mag=sqrt(A[i]*A[i]+B[i]*B[i]); + double del=vorbis_lpc_magnitude(vb->dscale[i],lpc,vb->m)*amp; + double phi=atan2(A[i],B[i]); + + if(divp) + phi-=del; + else + phi+=del; + + A[i]=mag*sin(phi); + B[i]=mag*cos(phi); + } +} diff --git a/lib/psy.h b/lib/psy.h index db96725..1281085 100644 --- a/lib/psy.h +++ b/lib/psy.h @@ -18,6 +18,10 @@ #ifndef _V_PSY_H_ #define _V_PSY_H_ +extern double _vp_balance_compute(double *A, double *B, double *lpc, + lpc_lookup *vb); +extern void _vp_balance_apply(double *A, double *B, double *lpc, double amp, + lpc_lookup *vb,int divp); #endif diff --git a/lib/smallft.c b/lib/smallft.c index 3da64ef..0d3a69c 100644 --- a/lib/smallft.c +++ b/lib/smallft.c @@ -249,6 +249,308 @@ static void dradf4(int ido,int l1,double *cc,double *ch,double *wa1, } } +static void dradfg(int ido,int ip,int l1,int idl1,double *cc,double *c1, + double *c2,double *ch,double *ch2,double *wa){ + + static double tpi=6.28318530717958647692528676655900577; + int idij,ipph,i,j,k,l,ic,ik,is; + int t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10; + double dc2,ai1,ai2,ar1,ar2,ds2; + int nbd; + double dcp,arg,dsp,ar1h,ar2h; + int idp2,ipp2; + + arg=tpi/(double)ip; + dcp=cos(arg); + dsp=sin(arg); + ipph=(ip+1)>>1; + ipp2=ip; + idp2=ido; + nbd=(ido-1)>>1; + t0=l1*ido; + t10=ip*ido; + + if(ido==1)goto L119; + for(ik=0;ikl1){ + for(j=1;j>1; + ipp2=ip; + ipph=(ip+1)>>1; + if(idol1)goto L139; + + is= -ido-1; + t1=0; + for(j=1;jvd->vi; double *window=vb->vd->window[vb->W][vb->lW][vb->nW]; + lpc_lookup *vl=&vb->vd->vl[vb->W]; /* get the LSP params back to LPC params. This will be for each spectral floor curve */ @@ -41,20 +42,6 @@ int vorbis_synthesis(vorbis_block *vb){ vorbis_lpc_apply(vb->pcm[i],vb->pcmend,vb->lpc[vi->floormap[i]], vb->amp[vi->floormap[i]],vi->floororder);*/ - /* XXXX Mix back from C+D stereo now */ - { - int i; - int n=vb->pcmend; - double *C=vb->pcm[0]+n/2; - double *D=vb->pcm[1]+n/2; - double *L=vb->pcm[0]; - double *R=vb->pcm[1]; - for(i=0;ipcm_channels;i++) mdct_backward(&vb->vd->vm[vb->W],vb->pcm[i],vb->pcm[i],window); _ve_envelope_apply(vb,1); -- 2.7.4