Synthesis blocking and extraction completed/tested. Envelope
authorMonty <xiphmont@xiph.org>
Thu, 29 Jul 1999 10:09:30 +0000 (10:09 +0000)
committerMonty <xiphmont@xiph.org>
Thu, 29 Jul 1999 10:09:30 +0000 (10:09 +0000)
manipulation not yet written.  MDCT scaling modification.

Monty 19990729

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

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

index b7c41d9..e44c5b5 100644 (file)
@@ -1,6 +1,6 @@
 # vorbis makefile configured for use with gcc on any platform
 
-# $Id: Makefile.in,v 1.3 1999/07/28 09:07:45 xiphmont Exp $
+# $Id: Makefile.in,v 1.4 1999/07/29 10:09:25 xiphmont Exp $
 
 ###############################################################################
 #                                                                             #
@@ -42,8 +42,8 @@ profile:
 selftest:
        $(MAKE) clean
        $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST framing.c -o test_framing 
-       $(CC) $(DEBUG) -c window.c
-       $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST analysis.c window.o\
+       $(CC) $(DEBUG) -c window.c mdct.c
+       $(CC) $(DEBUG) $(LDFLAGS) -D_V_SELFTEST block.c window.o mdct.o\
                -o test_blocking -lm
        @echo
        @./test_framing
index 4bb6bc6..b74bd92 100644 (file)
@@ -1,3 +1,23 @@
+/********************************************************************
+ *                                                                  *
+ * 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: single-block PCM analysis
+ author: Monty <xiphmont@mit.edu>
+ modifications by: Monty
+ last modification date: Jul 28 1999
+
+ ********************************************************************/
+
 analysis_packetout(vorbis_dsp_state *v, vorbis_block *vb,
                              ogg_packet *op){
 
index c843081..b752e15 100644 (file)
@@ -14,7 +14,7 @@
  function: PCM data vector blocking, windowing and dis/reassembly
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jul 27 1999
+ last modification date: Jul 28 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
@@ -31,6 +31,7 @@
 #include "codec.h"
 #include "window.h"
 #include "envelope.h"
+#include "mdct.h"
 
 /* pcm accumulator and multipliers 
    examples (not exhaustive):
                                  mult[n]
 */
 
-/* arbitrary settings and spec-mandated numbers get filled in here */
-int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
+static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi){
   memset(v,0,sizeof(vorbis_dsp_state));
-  v->samples_per_envelope_step=64;
-  v->block_size[0]=512; 
-  v->block_size[1]=2048;
+  v->samples_per_envelope_step=vi->envelopesa;
+  v->block_size[0]=vi->smallblock;
+  v->block_size[1]=vi->largeblock;
   
   v->window[0][0][0]=_vorbis_window(v->block_size[0],
                                   v->block_size[0]/2,v->block_size[0]/2);
@@ -112,16 +112,16 @@ int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
   }
 
   /* Initialize the envelope multiplier storage */
-  
-  v->envelope_storage=v->pcm_storage/v->samples_per_envelope_step;
-  v->envelope_channels=vi->channels;
-  v->deltas=calloc(v->envelope_channels,sizeof(double *));
-  v->multipliers=calloc(v->envelope_channels,sizeof(int *));
-  {
-    int i;
-    for(i=0;i<v->envelope_channels;i++){
-      v->deltas[i]=calloc(v->envelope_storage,sizeof(double));
-      v->multipliers[i]=calloc(v->envelope_storage,sizeof(int));
+
+  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 *));
+    {
+      int i;
+      for(i=0;i<v->envelope_channels;i++){
+       v->multipliers[i]=calloc(v->envelope_storage,sizeof(int));
+      }
     }
   }
 
@@ -138,6 +138,18 @@ int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
   return(0);
 }
 
+/* arbitrary settings and spec-mandated numbers get filled in here */
+int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
+  vi->smallblock=512;
+  vi->largeblock=2048;
+  vi->envelopesa=64;
+  vi->envelopech=vi->channels;
+
+  _vds_shared_init(v,vi);
+
+  return(0);
+}
+
 void vorbis_analysis_clear(vorbis_dsp_state *v){
   int i,j,k;
   if(v){
@@ -152,11 +164,6 @@ void vorbis_analysis_clear(vorbis_dsp_state *v){
       free(v->pcm);
       free(v->pcmret);
     }
-    if(v->deltas){
-      for(i=0;i<v->envelope_channels;i++)
-       if(v->deltas[i])free(v->deltas[i]);
-      free(v->deltas);
-    }
     if(v->multipliers){
       for(i=0;i<v->envelope_channels;i++)
        if(v->multipliers[i])free(v->multipliers[i]);
@@ -178,10 +185,10 @@ double **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
    
     for(i=0;i<v->pcm_channels;i++){
       v->pcm[i]=realloc(v->pcm[i],v->pcm_storage*sizeof(double));
-      v->deltas[i]=realloc(v->deltas[i],v->envelope_storage*sizeof(double));
+    }
+    for(i=0;i<v->envelope_channels;i++){
       v->multipliers[i]=realloc(v->multipliers[i],
                                v->envelope_storage*sizeof(double));
-
     }
   }
 
@@ -250,7 +257,7 @@ int vorbis_block_clear(vorbis_block *vb){
 
 /* do the deltas, envelope shaping, pre-echo and determine the size of
    the next block on which to continue analysis */
-int vorbis_analysis_block(vorbis_dsp_state *v,vorbis_block *vb){
+int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
   int i,j;
   long beginW=v->centerW-v->block_size[v->W]/2,centerNext;
   long beginM=beginW/v->samples_per_envelope_step;
@@ -262,8 +269,7 @@ int vorbis_analysis_block(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){
-    _va_envelope_deltas(v);
-    _va_envelope_multipliers(v);
+    _ve_envelope_multipliers(v);
   }
 
   /* By our invariant, we have lW, W and centerW set.  Search for
@@ -373,8 +379,6 @@ int vorbis_analysis_block(vorbis_dsp_state *v,vorbis_block *vb){
              (v->pcm_current-movementW)*sizeof(double));
     
     for(i=0;i<v->envelope_channels;i++){
-      memmove(v->deltas[i],v->deltas[i]+movementM,
-             (v->envelope_current-movementM)*sizeof(double));
       memmove(v->multipliers[i],v->multipliers[i]+movementM,
              (v->envelope_current-movementM)*sizeof(int));
     }
@@ -397,45 +401,159 @@ int vorbis_analysis_block(vorbis_dsp_state *v,vorbis_block *vb){
   return(1);
 }
 
+int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+  _vds_shared_init(v,vi);
+  /* 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. */
 
+int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
 
+  /* Shift out any PCM that we returned previously */
 
+  if(v->pcm_returned  && v->centerW>v->block_size[1]/2){
 
+    /* don't shift too much; we need to have a minimum PCM buffer of
+       1/2 long block */
 
+    int shift=v->centerW-v->block_size[1]/2;
+    shift=(v->pcm_returned<shift?v->pcm_returned:shift);
 
+    v->pcm_current-=shift;
+    v->centerW-=shift;
+    v->pcm_returned-=shift;
+    
+    if(shift){
+      int i;
+      for(i=0;i<v->pcm_channels;i++)
+       memmove(v->pcm[i],v->pcm[i]+shift,
+               v->pcm_current*sizeof(double));
+    }
+  }
 
+  {
+    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;
+    double *window;
+
+    /* Do we have enough PCM storage for the block? */
+    if(endW>v->pcm_storage){
+      /* expand the PCM storage */
+
+      v->pcm_storage=endW+v->block_size[1];
+   
+      for(i=0;i<v->pcm_channels;i++)
+       v->pcm[i]=realloc(v->pcm[i],v->pcm_storage*sizeof(double)); 
+    }
 
-int vorbis_analysis_packetout(vorbis_dsp_state *v, vorbis_block *vb,
-                             ogg_packet *op){
+    /* 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;
+    }
 
-  /* find block's envelope vector and apply it */
+    /* 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 */
 
-  /* the real analysis begins; forward MDCT with window */
+    _ve_envelope_apply(vb);
+    
+    /* Overlap/add */
+    switch(vb->W){
+    case 0:
+      beginSl=0;
+      endSl=v->block_size[0]/2;
+      break;
+    case 1:
+      beginSl=v->block_size[1]/4-v->block_size[vb->lW]/4;
+      endSl=beginSl+v->block_size[vb->lW]/2;
+      break;
+    }
 
-  
-  /* Noise floor, resolution floor */
+    window=v->window[vb->W][0][vb->lW]+v->block_size[vb->W]/2;
 
-  /* encode the floor into LSP; get the actual floor back for quant */
+    for(j=0;j<v->pcm_channels;j++){
+      double *pcm=v->pcm[j]+beginW;
 
-  /* use noise floor, res floor for culling, actual floor for quant */
+      /* the add section */
+      for(i=beginSl;i<endSl;i++)
+       pcm[i]=pcm[i]*window[i]+vb->pcm[j][i];
+      /* the remaining section */
+      for(;i<sizeW;i++)
+       pcm[i]=vb->pcm[j][i];
+    }
+
+    /* Update, cleanup */
 
-  /* encode residue */
+    v->centerW=centerW;
+    v->pcm_current=endW;
 
+    if(vb->eofflag)v->eofflag=1;
+  }
+  return(0);
 }
 
+int vorbis_synthesis_pcmout(vorbis_dsp_state *v,double ***pcm){
+  if(v->pcm_returned<v->centerW){
+    int i;
+    for(i=0;i<v->pcm_channels;i++)
+      v->pcmret[i]=v->pcm[i]+v->pcm_returned;
+    *pcm=v->pcmret;
+    return(v->centerW-v->pcm_returned);
+  }
+  return(0);
+}
 
+int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
+  if(bytes && v->pcm_returned+bytes>v->centerW)return(-1);
+  v->pcm_returned+=bytes;
+  return(0);
+}
 
 #ifdef _V_SELFTEST
 #include <stdio.h>
 #include <math.h>
 
-void _va_envelope_deltas(vorbis_dsp_state *v){
-  /* do nothing... */
-}
-
-void _va_envelope_multipliers(vorbis_dsp_state *v){
+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;
@@ -451,6 +569,9 @@ void _va_envelope_multipliers(vorbis_dsp_state *v){
   v->envelope_current=i;
 }
 
+void _ve_envelope_apply(vorbis_block *vb){
+
+}
 
 /* basic test of PCM blocking:
 
@@ -460,14 +581,18 @@ void _va_envelope_multipliers(vorbis_dsp_state *v){
 
 int main(){
   int blocksize=1024;
-  int fini=5000*1024;
+  int fini=100*1024;
   vorbis_dsp_state encode,decode;
   vorbis_info vi;
   vorbis_block vb;
   long counterin=0;
+  long countermid=0;
   long counterout=0;
   int done=0;
   char *temp[]={ "Test" ,"the Test band", "test records",NULL };
+  int frame=0;
+
+  MDCT_lookup *ml[2];
 
   vi.channels=2;
   vi.rate=44100;
@@ -478,17 +603,21 @@ int main(){
   vi.vendor="Xiphophorus";
 
   vorbis_analysis_init(&encode,&vi);
+  vorbis_synthesis_init(&decode,&vi);
 
   memset(&vb,0,sizeof(vorbis_block));
   vorbis_block_init(&encode,&vb);
 
+  ml[0]=MDCT_init(encode.block_size[0]);
+  ml[1]=MDCT_init(encode.block_size[1]);
+
   /* Submit 100K samples of data reading out blocks... */
   
   while(!done){
     int i;
     double **buf=vorbis_analysis_buffer(&encode,blocksize);
     for(i=0;i<blocksize;i++){
-      buf[0][i]=1;
+      buf[0][i]=sin((counterin+i)%500/500.*M_PI*2)+2;
       buf[1][i]=-1;
 
       if((counterin+i)%15000>13000)buf[0][i]+=10;
@@ -498,20 +627,73 @@ int main(){
     vorbis_analysis_wrote(&encode,i);
     counterin+=i;
 
-    while(vorbis_analysis_block(&encode,&vb)){
+    while(vorbis_analysis_blockout(&encode,&vb)){
+      double **pcm;
+      int avail;
+
+      /* temp fixup */
+
       double *window=encode.window[vb.W][vb.lW][vb.nW];
-      FILE *out;
-      char path[80];
-      int begin=counterout-encode.block_size[vb.W]/2;
+
+      for(i=0;i<vb.pcm_channels;i++)
+       MDCT(vb.pcm[i],vb.pcm[i],ml[vb.W],window);
+
+      for(i=0;i<vb.pcm_channels;i++)
+       iMDCT(vb.pcm[i],vb.pcm[i],ml[vb.W],window);
+
+
+      {
+       FILE *out;
+       char path[80];
+       int i;
+
+       int avail=encode.block_size[vb.W];
+       int beginW=countermid-avail/2;
+       
+       sprintf(path,"ana%d",vb.frameno);
+       out=fopen(path,"w");
+
+       for(i=0;i<avail;i++)
+         fprintf(out,"%ld %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]);
+
+       fclose(out);
+       countermid+=encode.block_size[vb.W]/4+encode.block_size[vb.nW]/4;
+      }
+
+
+      vorbis_synthesis_blockin(&decode,&vb);
+      
+
+      while((avail=vorbis_synthesis_pcmout(&decode,&pcm))){
+       FILE *out;
+       char path[80];
+       int i;
+       
+       sprintf(path,"syn%d",frame);
+       out=fopen(path,"w");
+
+       for(i=0;i<avail;i++)
+         fprintf(out,"%ld %g\n",i+counterout,pcm[0][i]);
+       fprintf(out,"\n");
+       for(i=0;i<avail;i++)
+         fprintf(out,"%ld %g\n",i+counterout,pcm[1][i]);
+
+       fclose(out);
+
+       vorbis_synthesis_read(&decode,avail);
+
+       counterout+=avail;
+       frame++;
+      }
+      
 
       if(vb.eofflag){
        done=1;
        break;
       }
-
-      counterout=counterout+encode.block_size[vb.W]/4+
-       encode.block_size[vb.nW]/4;
-
     }
   }
   return 0;
index f7a5c31..2304ff6 100644 (file)
@@ -14,7 +14,7 @@
  function: codec headers
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jul 25 1999
+ last modification date: Jul 28 1999
 
  ********************************************************************/
 
@@ -29,6 +29,10 @@ typedef struct vorbis_info{
   char **user_comments;
   char *vendor;
 
+  int smallblock;
+  int largeblock;
+  int envelopesa;
+  int envelopech;
 } vorbis_info;
  
 typedef struct {
@@ -107,8 +111,8 @@ typedef struct vorbis_dsp_state{
   int      pcm_storage;
   int      pcm_channels;
   int      pcm_current;
+  int      pcm_returned;
 
-  double **deltas;
   int    **multipliers;
   int      envelope_storage;
   int      envelope_channels;
@@ -198,7 +202,8 @@ extern int      vorbis_analysis_reset(vorbis_dsp_state *vd);
 extern void     vorbis_analysis_free(vorbis_dsp_state *vd);
 extern double **vorbis_analysis_buffer(vorbis_dsp_state *vd,int vals);
 extern int      vorbis_analysis_wrote(vorbis_dsp_state *vd,int vals);
-extern int      vorbis_analysis_block(vorbis_dsp_state *vd,vorbis_block *vb);
+extern int      vorbis_analysis_blockout(vorbis_dsp_state *vd,
+                                        vorbis_block *vb);
 extern int      vorbis_analysis_packetout(vorbis_dsp_state *vd,
                                          vorbis_block *vb,
                                          ogg_packet *op);
@@ -206,12 +211,13 @@ extern int      vorbis_analysis_packetout(vorbis_dsp_state *vd,
 /* Vorbis PRIMITIVES: synthesis layer *******************************/
 
 extern void vorbis_synthesis_free(vorbis_dsp_state *vd);
-extern int  vorbis_synthesis_init(vorbis_dsp_state *vd);
-extern int  vorbis_synthesis_info(vorbis_dsp_state *vd,vorbis_info *vi);
-extern int  vorbis_synthesis_packetin(vorbis_dsp_state *vd,vorbis_block *vb,
-                                     ogg_packet *op);
-extern int  vorbis_synthesis_pcmout(vorbis_dsp_state *vd,vorbis_block *vb,
-                                     double **pcm);
+extern int  vorbis_synthesis_init(vorbis_dsp_state *vd,vorbis_info *vi);
+
+extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
+extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,double ***pcm);
+extern int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes);
+
+
 
 #endif
 
index c9b0283..0b10b5e 100644 (file)
@@ -21,8 +21,8 @@
 #ifndef _V_ENVELOPE_
 #define _V_ENVELOPE_
 
-extern void _va_envelope_deltas(vorbis_dsp_state *v);
-extern void _va_envelope_multipliers(vorbis_dsp_state *v);
+extern void _ve_envelope_multipliers(vorbis_dsp_state *v);
+extern void _ve_envelope_apply(vorbis_block *vb);
 
 #endif
 
index f28fb4e..85379c7 100644 (file)
@@ -16,7 +16,7 @@
 
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jun 04 1999
+ last modification date: Jul 29 1999
 
  Algorithm adapted from _The use of multirate filter banks for coding
  of high quality digital audio_, by T. Sporer, K. Brandenburg and
@@ -36,6 +36,9 @@
 
  ********************************************************************/
 
+/* Undef the following if you want a normal MDCT */
+#define VORBIS_SPECIFIC_MODIFICATIONS
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
@@ -319,6 +322,14 @@ void iMDCT(double *in, double *out, MDCT_lookup *init, double *window){
     double scale=n/4.;
     
     for(i=0;i<n4;i++){
+#ifdef VORBIS_SPECIFIC_MODIFICATIONS
+      double temp1= (*x * *BO - *(x+2) * *BE)/ scale;
+      double temp2= (*x * *BE + *(x+2) * *BO)/ -scale;
+    
+      out[o1]=-temp1*window[o1];
+      out[o2]=temp1*window[o2];
+      out[o3]=out[o4]=temp2;
+#else
       double temp1= (*x * *BO - *(x+2) * *BE)* scale;
       double temp2= (*x * *BE + *(x+2) * *BO)* -scale;
     
@@ -326,6 +337,7 @@ void iMDCT(double *in, double *out, MDCT_lookup *init, double *window){
       out[o2]=temp1*window[o2];
       out[o3]=temp2*window[o3];
       out[o4]=temp2*window[o4];
+#endif
 
       o1++;
       o2--;