Envelope infrastructure now in place. Basic preecho running (but
authorMonty <xiphmont@xiph.org>
Sat, 7 Aug 1999 00:09:17 +0000 (00:09 +0000)
committerMonty <xiphmont@xiph.org>
Sat, 7 Aug 1999 00:09:17 +0000 (00:09 +0000)
woefully naieve)

Monty 19990806

svn path=/trunk/vorbis/; revision=20

lib/Makefile.in
lib/block.c
lib/codec.h
lib/envelope.c
lib/envelope.h

index 9b5246c..70ae7fd 100644 (file)
@@ -1,6 +1,6 @@
 # vorbis makefile configured for use with gcc on any platform
 
-# $Id: Makefile.in,v 1.5 1999/08/04 09:18:28 xiphmont Exp $
+# $Id: Makefile.in,v 1.6 1999/08/07 00:09:13 xiphmont Exp $
 
 ###############################################################################
 #                                                                             #
@@ -27,7 +27,7 @@ AR=@AR@
 RANLIB=@RANLIB@
 LIBS=@LIBS@ -lm
 
-OFILES =       framing.o
+OFILES =       framing.o mdct.o smallft.o block.o envelope.o window.o
 TARGETFILES =  libvorbis.a
 
 all:
@@ -39,14 +39,19 @@ debug:
 profile: 
        $(MAKE) target CFLAGS="$(PROFILE)"
 
-selftest:
+selftest:      
        $(MAKE) clean
        $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST framing.c -o test_framing 
        $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST bitwise.c\
                -o test_bitwise -lm
+       $(CC) $(DEBUG) -c envelope.c mdct.c window.c
+       $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST envelope.o mdct.o window.c\
+                       block.c -o test_blocking -lm
+
        @echo
        @./test_framing
        @./test_bitwise
+       @./test_blocking
 
 target:        $(TARGETFILES)
 
index dde6938..8ae8861 100644 (file)
  function: PCM data vector blocking, windowing and dis/reassembly
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jul 29 1999
+ last modification date: Aug 05 1999
 
  Handle windowing, overlap-add, etc of the PCM vectors.  This is made
- more amusing by Vorbis' current two allowed block sizes (512 and 2048
- elements/channel).
+ more amusing by Vorbis' current two allowed block sizes.
  
  Vorbis manipulates the dynamic range of the incoming PCM data
  envelope to minimise time-domain energy leakage from percussive and
 
 static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
   memset(v,0,sizeof(vorbis_dsp_state));
+
+  memcpy(&v->vi,vi,sizeof(vorbis_info));
+  _ve_envelope_init(&v->ve,vi->envelopesa);
+
   v->samples_per_envelope_step=vi->envelopesa;
   v->block_size[0]=vi->smallblock;
   v->block_size[1]=vi->largeblock;
@@ -112,11 +115,11 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
   if(vi->envelopech){
     v->envelope_storage=v->pcm_storage/v->samples_per_envelope_step;
     v->envelope_channels=vi->envelopech;
-    v->multipliers=calloc(v->envelope_channels,sizeof(int *));
+    v->multipliers=calloc(v->envelope_channels,sizeof(double *));
     {
       int i;
       for(i=0;i<v->envelope_channels;i++){
-       v->multipliers[i]=calloc(v->envelope_storage,sizeof(int));
+       v->multipliers[i]=calloc(v->envelope_storage,sizeof(double));
       }
     }
   }
@@ -140,6 +143,11 @@ int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
   vi->largeblock=2048;
   vi->envelopesa=64;
   vi->envelopech=vi->channels;
+  vi->preecho_thresh=10.;
+  vi->preecho_thresh=4.;
+  vi->envelopemap=calloc(2,sizeof(int));
+  vi->envelopemap[0]=0;
+  vi->envelopemap[1]=1;
 
   _vds_shared_init(v,vi);
 
@@ -229,9 +237,9 @@ int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
   for(i=0;i<vb->pcm_channels;i++)
     vb->pcm[i]=malloc(vb->pcm_storage*sizeof(double));
   
-  vb->mult=malloc(vb->mult_channels*sizeof(int *));
+  vb->mult=malloc(vb->mult_channels*sizeof(double *));
   for(i=0;i<vb->mult_channels;i++)
-    vb->mult[i]=malloc(vb->mult_storage*sizeof(int));
+    vb->mult[i]=malloc(vb->mult_storage*sizeof(double));
   return(0);
 }
 
@@ -265,6 +273,8 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
      data, fill them up in before proceeding. */
 
   if(v->pcm_current/v->samples_per_envelope_step>v->envelope_current){
+    /* This generates the multipliers, but does not sparsify the vector.
+       That's done by block before coding */
     _ve_envelope_multipliers(v);
   }
 
@@ -286,7 +296,8 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
 
   for(;i<v->envelope_current;i++){
     for(j=0;j<v->envelope_channels;j++)
-      if(v->multipliers[j][i])break;
+      if(v->multipliers[j][i-1]*v->vi.preecho_thresh<  
+        v->multipliers[j][i])break;
     if(j<v->envelope_channels)break;
   }
   
@@ -349,7 +360,7 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
     memcpy(vb->pcm[i],v->pcm[i]+beginW,v->block_size[v->W]*sizeof(double));
   for(i=0;i<v->envelope_channels;i++)
     memcpy(vb->mult[i],v->multipliers[i]+beginM,v->block_size[v->W]/
-          v->samples_per_envelope_step*sizeof(int));
+          v->samples_per_envelope_step*sizeof(double));
 
   vb->frameno=v->frame;
 
@@ -370,13 +381,17 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
     int movementW=centerNext-new_centerNext;
     int movementM=movementW/v->samples_per_envelope_step;
 
+    /* the multipliers and pcm stay synced up because the blocksizes
+       must be multiples of samples_per_envelope_step (minimum
+       multiple is 2) */
+
     for(i=0;i<v->pcm_channels;i++)
       memmove(v->pcm[i],v->pcm[i]+movementW,
              (v->pcm_current-movementW)*sizeof(double));
     
     for(i=0;i<v->envelope_channels;i++){
       memmove(v->multipliers[i],v->multipliers[i]+movementM,
-             (v->envelope_current-movementM)*sizeof(int));
+             (v->envelope_current-movementM)*sizeof(double));
     }
 
     v->pcm_current-=movementW;
@@ -398,15 +413,20 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
 }
 
 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+  int temp=vi->envelopech;
+  vi->envelopech=0; /* we don't need multiplier buffering in syn */
   _vds_shared_init(v,vi);
+  vi->envelopech=temp;
+
   /* 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;
   return(0);
 }
 
-/* Unike in analysis, the window is only partially applied, and
-   envelope *not* applied. */
+/* Unike in analysis, the window is only partially applied.  Envelope
+   is previously applied (the whole envelope, if any, is shipped in
+   each block) */
 
 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
 
@@ -433,15 +453,13 @@ int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
   }
 
   {
-    int envperlong=v->block_size[1]/v->samples_per_envelope_step;
-    int envperW=v->block_size[v->W]/v->samples_per_envelope_step;
     int sizeW=v->block_size[vb->W];
     int centerW=v->centerW+v->block_size[vb->lW]/4+sizeW/4;
     int beginW=centerW-sizeW/2;
     int endW=beginW+sizeW;
     int beginSl;
     int endSl;
-    int i,j,k;
+    int i,j;
     double *window;
 
     /* Do we have enough PCM storage for the block? */
@@ -454,45 +472,6 @@ int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
        v->pcm[i]=realloc(v->pcm[i],v->pcm_storage*sizeof(double)); 
     }
 
-    /* multiplier storage works differently in decode than it does in
-       encode; we only need to buffer the last 'half largeblock' and
-       we don't need to keep it aligned with the PCM. */
-
-    /* fill in the first half of the block's multipliers */
-    i=v->envelope_current-1;
-    j=envperW/2-1;
-    for(;j>=0;j--)
-      for(k=0;k<v->envelope_channels;k++)
-       vb->mult[k][j]=v->multipliers[k][i];
-      
-    /* shift out unneeded buffered multipliers */
-    {
-      int needed=(envperlong-envperW)/2;
-      if(needed){
-       /* We need to keep some of the buffered ones */
-       for(k=0;k<v->envelope_channels;k++)
-         memmove(v->multipliers[k],
-                 v->multipliers[k]+v->envelope_current-needed,
-                 needed*sizeof(int));
-      }
-      v->envelope_current=needed;
-    }
-
-    /* add block's second half to the multiplier buffer */
-    /* init makes certain we have enough storage; we only buffer a
-       half longblock */
-    
-    for(i=envperW/2;i<envperW;i++){
-      j=v->envelope_current;
-      for(k=0;k<v->envelope_channels;k++)
-       v->multipliers[k][j++]=vb->mult[k][i];
-    }
-    v->envelope_current+=envperW/2;
-
-    /* manufacture/apply multiplier vector */
-
-    _ve_envelope_apply(vb);
-    
     /* Overlap/add */
     switch(vb->W){
     case 0:
@@ -549,26 +528,6 @@ int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
 #include <stdio.h>
 #include <math.h>
 
-void _ve_envelope_multipliers(vorbis_dsp_state *v){
-  /* set 'random' deltas... */
-  int new_current=v->pcm_current/v->samples_per_envelope_step;
-  int i,j;
-
-  for(i=v->envelope_current;i<new_current;i++){
-    int flag=0;
-    for(j=0;j<v->samples_per_envelope_step;j++)
-      if(v->pcm[0][j+i*v->samples_per_envelope_step]>5)flag=1;
-    
-    for(j=0;j<v->envelope_channels;j++)
-      v->multipliers[j][i]=flag;
-  }
-  v->envelope_current=i;
-}
-
-void _ve_envelope_apply(vorbis_block *vb){
-
-}
-
 /* basic test of PCM blocking:
 
    construct a PCM vector and block it using preset sizing in our fake
@@ -594,7 +553,6 @@ int main(){
   vi.rate=44100;
   vi.version=0;
   vi.mode=0;
-
   vi.user_comments=temp;
   vi.vendor="Xiphophorus";
 
@@ -631,6 +589,10 @@ int main(){
 
       double *window=encode.window[vb.W][vb.lW][vb.nW];
 
+      /* apply envelope */
+      _ve_envelope_sparsify(&vb);
+      _ve_envelope_apply(&vb,0);
+
       for(i=0;i<vb.pcm_channels;i++)
        MDCT(vb.pcm[i],vb.pcm[i],ml[vb.W],window);
 
@@ -650,16 +612,17 @@ int main(){
        out=fopen(path,"w");
 
        for(i=0;i<avail;i++)
-         fprintf(out,"%ld %g\n",i+beginW,vb.pcm[0][i]);
+         fprintf(out,"%d %g\n",i+beginW,vb.pcm[0][i]);
        fprintf(out,"\n");
        for(i=0;i<avail;i++)
-         fprintf(out,"%ld %g\n",i+beginW,window[i]);
+         fprintf(out,"%d %g\n",i+beginW,window[i]);
 
        fclose(out);
        countermid+=encode.block_size[vb.W]/4+encode.block_size[vb.nW]/4;
       }
 
 
+      _ve_envelope_apply(&vb,1);
       vorbis_synthesis_blockin(&decode,&vb);
       
 
index d2141ab..afe304e 100644 (file)
@@ -43,6 +43,11 @@ typedef struct vorbis_info{
   int largeblock;
   int envelopesa;
   int envelopech;
+  int *envelopemap; /* which envelope applies to what pcm channel */
+  int **channelmap; /* which encoding channels produce what pcm */
+
+  double preecho_thresh;
+  double preecho_clamp;
 } vorbis_info;
  
 typedef struct {
@@ -103,17 +108,16 @@ typedef struct {
 } ogg_sync_state;
 
 typedef struct {
-    int divisor;
+  int winlen;
   double *window;
-} _ve_lookup;
-
+} envelope_lookup;
 
 typedef struct vorbis_dsp_state{
   int samples_per_envelope_step;
   int block_size[2];
   double *window[2][2][2]; /* windowsize, leadin, leadout */
 
-  _ve_lookup ve;
+  envelope_lookup ve;
   vorbis_info vi;
 
   double **pcm;
@@ -123,7 +127,7 @@ typedef struct vorbis_dsp_state{
   int      pcm_current;
   int      pcm_returned;
 
-  int    **multipliers;
+  double **multipliers;
   int      envelope_storage;
   int      envelope_channels;
   int      envelope_current;
@@ -142,7 +146,7 @@ typedef struct vorbis_dsp_state{
 
 typedef struct vorbis_block{
   double **pcm;
-  int    **mult;
+  double **mult;
   int    pcm_channels; /* allocated, not used */
   int    pcm_storage;  /* allocated, not used */
   int    mult_channels; /* allocated, not used */
index 71efd4b..5909d0f 100644 (file)
@@ -14,7 +14,7 @@
  function: PCM data envelope analysis and manipulation
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jun 17 1999
+ last modification date: Aug 05 1999
 
  Vorbis manipulates the dynamic range of the incoming PCM data
  envelope to minimise time-domain energy leakage from percussive and
  ********************************************************************/
 
 #include <stdlib.h>
+#include <string.h>
 #include <stdio.h>
 #include <math.h>
 
-static typedef struct {
-  int divisor;
-  double *window;
-} envelope_lookup;
+#include "codec.h"
+#include "envelope.h"
 
-static double oPI  = 3.14159265358979323846;
-
-envelope_lookup *init_envelope(int length,int divleng){
-  envelope_lookup *ret=malloc(sizeof(envelope_lookup));
+void _ve_envelope_init(envelope_lookup *e,int samples_per){
   int i;
 
-  ret->length=divleng;
-  ret->window=malloc(divleng*sizeof(double)*2);
+  e->winlen=samples_per*2;
+  e->window=malloc(e->winlen*sizeof(double));
 
   /* We just use a straight sin^2(x) window for this */
-  for(i=0;i<divleng*2;i++){
-    double temp=sin((i+.5)/divleng*oPI);
-    ret->window[i]=temp*temp;
+  for(i=0;i<e->winlen;i++){
+    double temp=sin((i+.5)/e->winlen*M_PI);
+    e->window[i]=temp*temp;
   }
 }
 
-/* right now, we do things simple and dirty.  Should this prove
-   inadequate, then we'll think of something different.  The details
-   of the encoding format do not depend on the exact behavior, only
-   the format of the bits that come out.
-
-   Using residual from an LPC whitening filter to judge envelope
-   energy would probably yield cleaner results, but that's slow.
-   Let's see if simple delta analysis gives us acceptible results.  */
+/* initial and final blocks are special cases. Eg:
+   ______
+         `--_            
+   |_______|_`-.___|_______|_______|
 
-int analyze_envelope0(double *vector, envelope_lookup *init, int n,
-                      double *deltas){
+              ___                     
+          _--'   `--_     
+   |___.-'_|_______|_`-.___|_______|
 
-  int divisor=init->length;
-  int divs=n/divisor-1;
-  double *win=init->window;
-  int i,j,count=0;
+                      ___                     
+                  _--'   `--_     
+   |_______|___.-'_|_______|_`-.___|
 
-  double max,spanlo,spanhi;
-  
-  /* initial and final blocks are special cases. Eg:
-     ______________                  
-                   \        
-     |_______|______\|_______|_______|
-
-                ___________             
-               /           \
-     |_______|/______|______\|_______|
-
-                        _____________
-                       /    
-     |_______|_______|/______|_______|
+                               _____
+                           _--'
+   |_______|_______|____.-'|_______|
  
-     as we go block by block, we watch the collective metrics span. If we 
-     span the threshhold (assuming the threshhold is active), we use an 
-     abbreviated vector */
+   as we go block by block, we watch the collective metrics span. If we 
+   span the threshhold (assuming the threshhold is active), we use an 
+   abbreviated vector */
+
+static void _ve_envelope_generate(double *mult,double *env,double *look,
+                                 int n,int step){
+  int i,j,p;
+  double m;
+  n*=step;
+
+  /* first multiplier special case */
+  m=ldexp(2,mult[0]-1);
+  for(i=0;i<step/2;i++)env[i]=m;
+  p=i;
+  for(i=step;i<step*2;i++,p++)env[p]=m*look[i];
   
-  /* initial frame */
-  max=0;
-  for(i=1;i<divisor;i++){
-    double temp=abs(vector[i-1]-vector[i]);
-    if(max<temp)max=temp;
+  /* mid multipliers normal case */
+  for(j=1;p<n-step/2;j++){
+    p-=step;
+    m=ldexp(2,mult[j]-1);
+    for(i=0;i<step;i++,p++)env[p]+=m*look[i];
+    for(;i<step*2;i++,p++)env[p]=m*look[i];
   }
-  for(;i<divisor*2;i++){
-    double temp=abs(win[i-1]*vector[i-1]-win[i]*vector[i]);
-    if(max<temp)max=temp;
+
+  /* last multiplier special case */
+  p-=step;
+  m=ldexp(2,mult[j]-1);
+  for(i=0;i<step;i++,p++)env[p]+=m*look[i];
+  for(;p<n;p++)env[p]=m;
+  
+  {
+    static int frameno=0;
+    FILE *out;
+    char path[80];
+    int i;
+    
+    sprintf(path,"env%d",frameno);
+    out=fopen(path,"w");
+    for(i=0;i<n;i++)
+      fprintf(out,"%g\n",env[i]);
+    fclose(out);
+
+    frameno++;
   }
-  spanlo=spanhi=deltas[count++]=max;
-
-  /* mid frames */
-  for(j=divisor;j<n-divisor*2;j+=divisor){
-    max=0;
-    for(i=1;i<divisor*2;i++){
-      double temp=abs(win[i-1]*vector[j+i-1]-win[i]*vector[j+i]);
-      if(max<temp)max=temp;
+}
+
+/* right now, we do things simple and dirty (read: our current preecho
+   is a joke).  Should this prove inadequate, then we'll think of
+   something different.  The details of the encoding format do not
+   depend on the exact behavior, only the format of the bits that come
+   out.
+
+   Mark Taylor probably has much witter ways of doing this...  Let's
+   see if simple delta analysis gives us acceptible results for now.  */
+
+static void _ve_deltas(double *deltas,double *pcm,int n,double *win,
+                      int winsize){
+  int i,j,p=winsize/2;
+  for(j=0;j<n;j++){
+    p-=winsize/2;
+    for(i=0;i<winsize-1;i++,p++){
+      double temp=fabs(win[i]*pcm[p]-win[i+1]*pcm[p+1]);
+      if(deltas[j]<temp)deltas[j]=temp;
     }
-    deltas[count++]=max;
-    if(max<spanlo)spanlo=max;
-    if(max>spanhi)spanhi=max;
-    if(threshhold>1 && spanlo*threshhold<spanhi)
-      abbrevflag=1;
-    if(abbrevflag && j>n0-divisor/2)break;
+    p++;
   }
+}
 
-  /* last frame */
-  if(!abbrevflag){
-    max=0;
-    for(i=1;i<divisor;i++){
-      double temp=abs(win[i-1]*vector[j+i-1]-win[i]*vector[j+i]);
-      if(max<temp)max=temp;
-    }
-    for(;i<divisor*2;i++){
-      double temp=abs(vector[j+i-1]-vector[j+i]);
-      if(max<temp)max=temp;
+void _ve_envelope_multipliers(vorbis_dsp_state *v){
+  int step=v->samples_per_envelope_step;
+  static int frame=0;
+
+  /* we need a 1-1/4 envelope window overlap begin and 1/4 end */
+  int dtotal=(v->pcm_current-step/2)/v->samples_per_envelope_step;
+  int dcurr=v->envelope_current;
+  double *window=v->ve.window;
+  int winlen=v->ve.winlen;
+  int pch,ech;
+  vorbis_info *vi=&v->vi;
+
+  if(dtotal>dcurr){
+    for(ech=0;ech<vi->envelopech;ech++){
+      double *mult=v->multipliers[ech]+dcurr;
+      memset(mult,0,sizeof(double)*(dtotal-dcurr));
+      
+      for(pch=0;pch<vi->channels;pch++){
+       
+       /* does this channel contribute to the envelope analysis */
+       if(vi->envelopemap[pch]==ech){
+
+         /* we need a 1/4 envelope window overlap front and back */
+         double *pcm=v->pcm[pch]+dcurr*step-step/2;
+         _ve_deltas(mult,pcm,dtotal-dcurr,window,winlen);
+
+       }
+      }
     }
-    deltas[count++]=max;
-    if(max<spanlo)spanlo=max;
-    if(max>spanhi)spanhi=max;
-    if(threshhold>1 && spanlo*threshhold<spanhi)
-      abbrevflag=1;
+    v->envelope_current=dtotal;
+    frame++;
   }
+}
 
-  if(abbrevflag)return(n0);
-  return(n);
-}  
-
-/* also decide if we're going with a full sized or abbreviated
-   vector. Some encoding tactics might want to use envelope massaging
-   fully and discard abbreviated vectors entriely.  We make that
-   decision here */
-
-int analyze_envelope1(envelope_lookup *init,int n,
-                     double triggerthresh,double spanthresh,
-                     double *deltas){
-
-  /* Look at the delta values; decide if we need to do any envelope
-     manipulation at all on this vector; if so, choose the
-     multipliers and placeholders.
-
-     '0' is a placeholder.  Other values specify a
-     multiplier/divisor. Multipliers are used by the decoder, divisors
-     in the encoder.  The mapped m/d value for each segment is
-     2^(n-1).  Placeholders (zeros) take on the value of the last
-     non-zero multiplier/divisor.  When the placeholder is not
-     preceeded by a non-placeholder value in the current vector, it
-     assumes the value of the *next* non-zero value.  In this way, the
-     vector manipulation is local to the current vector and does not
-     rely on preceeding vectors.
-
-  */
-  
-  /* scan forward with sliding windows; we start manipulating envelopes
-     when the collective deltas span over a threshhold. If in fact we
-     begin manipulating, we can manage on a finer scale than the
-     original threshhold. first look for the larger threshhold and if
-     we span it, manipulate the vector to hold within the smaller span
-     threshhold. */
-
-  /* scan for the trigger */
-
-  int divisor=init->length;
-  int divs=n/divisor-1;
-  int i,triggerflag=0;
-  double spanlo,spanhi;
-  
-  spanlo=spanhi=deltas[0];
-
-  for(i=1;i<divs;i++){
-    double max=deltas[i];
-    if(max<spanlo)spanlo=max;
-    if(max>spanhi)spanhi=max;
-    if(spanlo*triggerthresh<spanhi){
-      triggerflag=1;
-      break;
+/* This readies the multiplier vector for use/coding.  Clamp/adjust
+   the multipliers to the allowed range and eliminate unneeded
+   coefficients */
+
+void _ve_envelope_sparsify(vorbis_block *vb){
+  int ch;
+  for(ch=0;ch<vb->vd->vi.envelopech;ch++){
+    int flag=0;
+    double *mult=vb->mult[ch];
+    int n=vb->multend;
+    double first=mult[0];
+    double last=first;
+    double clamp;
+    int i;
+
+    /* are we going to multiply anything? */
+    
+    for(i=1;i<n;i++){
+      if(mult[i]>=last*vb->vd->vi.preecho_thresh){
+       flag=1;
+       break;
+      }
+      if(i<n-1 && mult[i+1]>=last*vb->vd->vi.preecho_thresh){
+       flag=1;
+       break;
+      }
+      last=mult[i];
     }
+    
+    if(flag){
+      /* we need to adjust, so we might as well go nuts */
+      
+      int begin=i;
+      clamp=last?last:1;
+      
+      for(i=0;i<begin;i++)mult[i]=0;
+      
+      last=1;
+      for(;i<n;i++){
+       if(mult[i]/last>clamp*vb->vd->vi.preecho_thresh){
+         last=mult[i]/vb->vd->vi.preecho_clamp;
+         
+         mult[i]=floor(log(mult[i]/clamp/vb->vd->vi.preecho_clamp)/log(2))-1;
+         if(mult[i]>15)mult[i]=15;
+       }else{
+         mult[i]=0;
+       }
+      }  
+    }else
+      memset(mult,0,sizeof(double)*n);
   }
+}
 
-  if(triggerflag){
-    /* choose divisors/multipliers to fit the vector into the
-       specified span.  In the decoder, these values are *multipliers*, so  */
-
-
-
-
-
-
-
-
-
+void _ve_envelope_apply(vorbis_block *vb,int multp){
+  vorbis_info *vi=&vb->vd->vi;
+  double env[vb->multend*vi->envelopesa];
+  envelope_lookup *look=&vb->vd->ve;
+  int i,j,k;
+  
+  for(i=0;i<vi->envelopech;i++){
+    double *mult=vb->mult[i];
+    double last=1.;
+    
+    /* fill in the multiplier placeholders */
+
+    for(j=0;j<vb->multend;j++){
+      if(mult[j]){
+       last=mult[j];
+      }else
+       mult[j]=last;
+    }
 
+    /* compute the envelope curve */
+    _ve_envelope_generate(mult,env,look->window,vb->multend,vi->envelopesa);
 
+    /* apply the envelope curve */
+    for(j=0;j<vi->channels;j++){
 
+      /* check to see if the generated envelope applies to this channel */
+      if(vi->envelopemap[j]==i){
+       
+       if(multp)
+         for(k=0;k<vb->multend*vi->envelopesa;k++)
+           vb->pcm[j][k]*=env[k];
+       else
+         for(k=0;k<vb->multend*vi->envelopesa;k++)
+           vb->pcm[j][k]/=env[k];
 
+      }
+    }
   }
-  return(triggerflag);
 }
 
index 0b10b5e..8f25966 100644 (file)
@@ -14,7 +14,7 @@
  function: PCM data envelope analysis and manipulation
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jul 27 1999
+ last modification date: Aug 06 1999
 
  ********************************************************************/
 
@@ -22,7 +22,9 @@
 #define _V_ENVELOPE_
 
 extern void _ve_envelope_multipliers(vorbis_dsp_state *v);
-extern void _ve_envelope_apply(vorbis_block *vb);
+extern void _ve_envelope_apply(vorbis_block *vb,int multp);
+extern void _ve_envelope_sparsify(vorbis_block *vb);
+extern void _ve_envelope_init(envelope_lookup *e,int samples_per);
 
 #endif