[xiph-cvs] cvs commit: vorbis/lib block.c mapping0.c vorbisfile.c window.c

Monty xiphmont at xiph.org
Sun Mar 2 03:45:18 PST 2003



xiphmont    03/03/02 06:45:17

  Modified:    lib      block.c mapping0.c vorbisfile.c window.c
  Log:
  Experimental addition to the vorbisfile API that required a few
  modifications elsewhere:
  
  added 'ov_crosslap()' such that decode of a second clip can be primed
  witht he MDCT overlap of a previous clip; this entirely eliminates any
  click on sample boundaries that should otherwise match, but have a
  small step error due to encoding being lossy.  It will also smooth
  transitions in general purpose loops.  More detailed docs to come
  after more testing.
  
  Monty

Revision  Changes    Path
1.69      +107 -9    vorbis/lib/block.c

Index: block.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis/lib/block.c,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -r1.68 -r1.69
--- block.c	11 Oct 2002 11:14:41 -0000	1.68
+++ block.c	2 Mar 2003 11:45:17 -0000	1.69
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: PCM data vector blocking, windowing and dis/reassembly
- last mod: $Id: block.c,v 1.68 2002/10/11 11:14:41 xiphmont Exp $
+ last mod: $Id: block.c,v 1.69 2003/03/02 11:45:17 xiphmont Exp $
 
  Handle windowing, overlap-add, etc of the PCM vectors.  This is made
  more amusing by Vorbis' current two allowed block sizes.
@@ -673,7 +673,7 @@
 
   v->sequence=vb->sequence;
   
-  if(vb->pcm){  /* not pcm to process if vorbis_synthesis_trackonly 
+  if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly 
                    was called on block */
     int n=ci->blocksizes[v->W]/2;
     int n0=ci->blocksizes[0]/2;
@@ -691,8 +691,8 @@
       thisCenter=n1;
       prevCenter=0;
     }else{
-	thisCenter=0;
-	prevCenter=n1;
+      thisCenter=0;
+      prevCenter=n1;
     }
     
     /* v->pcm is now used like a two-stage double buffer.  We don't want
@@ -706,32 +706,36 @@
       if(v->lW){
         if(v->W){
           /* large/large */
+	  float *w=b->window[1];
           float *pcm=v->pcm[j]+prevCenter;
           float *p=vb->pcm[j];
           for(i=0;i<n1;i++)
-	    pcm[i]+=p[i];
+	    pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
         }else{
           /* large/small */
+	  float *w=b->window[0];
           float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
           float *p=vb->pcm[j];
           for(i=0;i<n0;i++)
-	    pcm[i]+=p[i];
+	    pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
         }
       }else{
         if(v->W){
           /* small/large */
+	  float *w=b->window[0];
           float *pcm=v->pcm[j]+prevCenter;
           float *p=vb->pcm[j]+n1/2-n0/2;
           for(i=0;i<n0;i++)
-	    pcm[i]+=p[i];
+	    pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
           for(;i<n1/2+n0/2;i++)
             pcm[i]=p[i];
         }else{
           /* small/small */
+	  float *w=b->window[0];
           float *pcm=v->pcm[j]+prevCenter;
           float *p=vb->pcm[j];
           for(i=0;i<n0;i++)
-	    pcm[i]+=p[i];
+	    pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
         }
       }
       
@@ -796,7 +800,7 @@
           /* no preceeding granulepos; assume we started at zero (we'd
              have to in a short single-page stream) */
           /* granulepos could be -1 due to a seek, but that would result
-	     in a long coun`t, not short count */
+	     in a long count, not short count */
           
           v->pcm_current-=(b->sample_count-v->granulepos);
         }else{
@@ -856,3 +860,97 @@
   return(0);
 }
 
+/* intended for use with a specific vorbisfile feature; we want access
+   to the [usually synthetic/postextrapolated] buffer and lapping at
+   the end of a decode cycle, specifically, a half-short-block worth.
+   This funtion works like pcmout above, except it will also expose
+   this implicit buffer data not normally decoded. */
+int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){
+  vorbis_info *vi=v->vi;
+  codec_setup_info *ci=vi->codec_setup;
+  
+  int n=ci->blocksizes[v->W]/2;
+  int n0=ci->blocksizes[0]/2;
+  int n1=ci->blocksizes[1]/2;
+  int i,j;
+
+  if(v->pcm_returned<0)return 0;
+
+  /* our returned data ends at pcm_returned; because the synthesis pcm
+     buffer is a two-fragment ring, that means our data block may be
+     fragmented by buffering, wrapping or a short block not filling
+     out a buffer.  To simplify things, we unfragment if it's at all
+     possibly needed. Otherwise, we'd need to call lapout more than
+     once as well as hold additional dsp state.  Opt for
+     simplicity. */
+
+  /* centerW was advanced by blockin; it would be the center of the
+     *next* block */
+  if(v->centerW==n1){
+    /* the data buffer wraps; swap the halves */
+    /* slow, sure, small */
+    for(j=0;j<vi->channels;j++){
+      float *p=v->pcm[j];
+      for(i=0;i<n1;i++){
+	float temp=p[i];
+	p[i]=p[i+n1];
+	p[i+n1]=temp;
+      }
+    }
+
+    v->pcm_current-=n1;
+    v->pcm_returned-=n1;
+    v->centerW=0;
+  }
+  
+  if((v->lW^v->W)==1){
+    /* long/short or short/long */
+    for(j=0;j<vi->channels;j++){
+      float *s=v->pcm[j];
+      float *d=v->pcm[j]+(n1-n0)/2;
+      for(i=(n1+n0)/2-1;i>=0;--i)
+	d[i]=s[i];
+    }
+    v->pcm_returned+=(n1-n0)/2;
+    v->pcm_current+=(n1-n0)/2;
+  }else{
+    if(v->lW==0){
+      /* short/short */
+      for(j=0;j<vi->channels;j++){
+	float *s=v->pcm[j];
+	float *d=v->pcm[j]+n1-n0;
+	for(i=n0-1;i>=0;--i)
+	  d[i]=s[i];
+      }
+      v->pcm_returned+=n1-n0;
+      v->pcm_current+=n1-n0;
+    }
+  }
+    
+  if(pcm){
+    int i;
+    for(i=0;i<vi->channels;i++)
+      v->pcmret[i]=v->pcm[i]+v->pcm_returned;
+    *pcm=v->pcmret;
+  }
+
+  return(n1+n-v->pcm_returned);
+
+}
+
+void vorbis_splice(float *d,float *s,
+		   vorbis_dsp_state *v,int W){
+  
+  vorbis_info *vi=v->vi;
+  codec_setup_info *ci=vi->codec_setup;
+  private_state *b=v->backend_state;
+  int n=ci->blocksizes[W]/2;
+
+  float *wd=b->window[W];
+  float *ws=b->window[W]+n;
+  int i;
+
+  for(i=0;i<n;i++)
+    d[i]=d[i]*(*wd++) + s[i]*(*--ws);
+}
+	

<p><p>1.57      +1 -12     vorbis/lib/mapping0.c

Index: mapping0.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis/lib/mapping0.c,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -r1.56 -r1.57
--- mapping0.c	17 Oct 2002 06:06:59 -0000	1.56
+++ mapping0.c	2 Mar 2003 11:45:17 -0000	1.57
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: channel mapping 0 implementation
- last mod: $Id: mapping0.c,v 1.56 2002/10/17 06:06:59 xiphmont Exp $
+ last mod: $Id: mapping0.c,v 1.57 2003/03/02 11:45:17 xiphmont Exp $
 
  ********************************************************************/
 
@@ -745,17 +745,6 @@
   for(i=0;i<vi->channels;i++){
     float *pcm=vb->pcm[i];
     mdct_backward(b->transform[vb->W][0],pcm,pcm);
-  }
-
-  /* window the data */
-  for(i=0;i<vi->channels;i++){
-    float *pcm=vb->pcm[i];
-    if(nonzero[i])
-      _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW);
-    else
-      for(j=0;j<n;j++)
-	pcm[j]=0.f;
-
   }
 
   /* all done! */

<p><p>1.65      +136 -10   vorbis/lib/vorbisfile.c

Index: vorbisfile.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis/lib/vorbisfile.c,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -r1.64 -r1.65
--- vorbisfile.c	26 Oct 2002 13:37:03 -0000	1.64
+++ vorbisfile.c	2 Mar 2003 11:45:17 -0000	1.65
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id: vorbisfile.c,v 1.64 2002/10/26 13:37:03 msmith Exp $
+ last mod: $Id: vorbisfile.c,v 1.65 2003/03/02 11:45:17 xiphmont Exp $
 
  ********************************************************************/
 
@@ -457,7 +457,8 @@
 
 static int _fetch_and_process_packet(OggVorbis_File *vf,
                                      ogg_packet *op_in,
-				     int readp){
+				     int readp,
+				     int spanp){
   ogg_page og;
 
   /* handle one packet.  Try to fetch it from current stream state */
@@ -549,6 +550,8 @@
       /* has our decoding just traversed a bitstream boundary? */
       if(vf->ready_state==INITSET){
         if(vf->current_serialno!=ogg_page_serialno(&og)){
+	  if(!spanp)return(OV_EOF);
+
           _decode_clear(vf);
           
           if(!vf->seekable){
@@ -924,7 +927,7 @@
      decoding as immediately after the seek position as possible.
 
      So, a hack.  We use two stream states; a local scratch state and
-     a the shared vf->os stream state.  We use the local state to
+     the shared vf->os stream state.  We use the local state to
      scan, and the shared state as a buffer for later decode. 
 
      Unfortuantely, on the last page we still advance to last packet
@@ -1263,16 +1266,15 @@
   /* discard samples until we reach the desired position. Crossing a
      logical bitstream boundary with abandon is OK. */
   while(vf->pcm_offset<pos){
-    float **pcm;
     ogg_int64_t target=pos-vf->pcm_offset;
-    long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
+    long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
 
     if(samples>target)samples=target;
     vorbis_synthesis_read(&vf->vd,samples);
     vf->pcm_offset+=samples;
     
     if(samples<target)
-      if(_fetch_and_process_packet(vf,NULL,1)<=0)
+      if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
         vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
   }
   return 0;
@@ -1459,14 +1461,14 @@
   if(vf->ready_state<OPENED)return(OV_EINVAL);
 
   while(1){
-    if(vf->ready_state>=STREAMSET){
+    if(vf->ready_state==INITSET){
       samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
       if(samples)break;
     }
 
     /* suck in another packet */
     {
-      int ret=_fetch_and_process_packet(vf,NULL,1);
+      int ret=_fetch_and_process_packet(vf,NULL,1,1);
       if(ret==OV_EOF)return(0);
       if(ret<=0)return(ret);
     }
@@ -1597,7 +1599,7 @@
   if(vf->ready_state<OPENED)return(OV_EINVAL);
 
   while(1){
-    if(vf->ready_state>=STREAMSET){
+    if(vf->ready_state==INITSET){
       float **pcm;
       long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
       if(samples){
@@ -1613,11 +1615,135 @@
 
     /* suck in another packet */
     {
-      int ret=_fetch_and_process_packet(vf,NULL,1);
+      int ret=_fetch_and_process_packet(vf,NULL,1,1);
       if(ret==OV_EOF)return(0);
       if(ret<=0)return(ret);
     }
 
   }
 }
+
+extern void vorbis_splice(float *d,float *s,
+			  vorbis_dsp_state *v,int W);
+	
+/* this sets up crosslapping of a sample by using trailing data from
+   sample 1 and lapping it into the windowing buffer of the second */
+
+int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
+  vorbis_info *vi1,*vi2;
+  vorbis_dsp_state *vd1=&vf1->vd;
+  vorbis_dsp_state *vd2=&vf2->vd;
+  float **lappcm;
+  float **pcm;
+  vorbis_dsp_state *winstate;
+  int lapsize,lapcount=0,i,j;
+
+  /* first enforce some level of sanity... */
+  /* we need to know that sample rate & channels match.  To do that,
+     we need to verify the streams are actually initialized; the call
+     is not just to be used for end-to-beginning lapping */
+
+  if(vf1->ready_state<OPENED)return(OV_EINVAL);
+  if(vf2->ready_state<OPENED)return(OV_EINVAL);
+
+  /* make sure vf1 is INITSET */
+  while(1){
+    if(vf1->ready_state==INITSET)break;
+    /* suck in another packet */
+    {
+      int ret=_fetch_and_process_packet(vf1,NULL,1,0);
+      if(ret<0)return(ret);
+    }
+  }
+
+  /* make sure vf2 is INITSET and that we have a primed buffer; if
+     we're crosslapping at a stream section boundary, this also makes
+     sure we're sanity checking against the right stream information */
+
+  while(1){
+    if(vf2->ready_state==INITSET)
+      if(vorbis_synthesis_pcmout(vd2,NULL))break;
+
+    /* suck in another packet */
+    {
+      int ret=_fetch_and_process_packet(vf2,NULL,1,0);
+      if(ret<0)return(ret);
+    }
+  }
+
+  /* sanity-check settings */
+  vi1=ov_info(vf1,-1);
+  vi2=ov_info(vf2,-1);
+  if(vi1->channels != vi2->channels ||
+     vi1->rate     != vi2->rate) return OV_EINVAL;
+  
+  /* begin by grabbing enough data for lapping from vf1; this may be
+     in the form of unreturned, already-decoded pcm, remaining PCM we
+     will need to decode, or synthetic postextrapolation from last
+     packets. */
+
+  lappcm=alloca(sizeof(*lappcm)*vi1->channels);
+  lapsize=vorbis_info_blocksize(vi1,0);
+  if(vorbis_info_blocksize(vi2,0)<lapsize){
+    lapsize=vorbis_info_blocksize(vi2,0)/2;
+    winstate=vd2;
+  }else{
+    lapsize/=2;
+    winstate=vd1;
+  }
+
+  for(i=0;i<vi1->channels;i++)
+    lappcm[i]=alloca(sizeof(**lappcm)*lapsize);
+
+  /* try first to decode the lapping data */
+  while(lapcount<lapsize){
+    int samples=vorbis_synthesis_pcmout(vd1,&pcm);
+    if(samples){
+      if(samples>lapsize-lapcount)samples=lapsize-lapcount;
+      for(i=0;i<vi1->channels;i++)
+	memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
+      lapcount+=samples;
+      vorbis_synthesis_read(vd1,samples);
+    }else{
+    /* suck in another packet */
+      int ret=_fetch_and_process_packet(vf1,NULL,1,0); /* do *not* span */
+      if(ret==OV_EOF)break;
+    }
+  }
+  if(lapcount<lapsize){
+    /* failed to get lapping data from normal decode; pry it from the
+       postextrapolation buffering, or the second half of the MDCT
+       from the last packet */
+    int samples=vorbis_synthesis_lapout(&vf1->vd,&pcm);
+    if(samples>lapsize-lapcount)samples=lapsize-lapcount;
+    for(i=0;i<vi1->channels;i++)
+      memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
+    lapcount+=samples;
+
+    if(lapcount<lapsize){
+      fprintf(stderr,"GAR undersized lapping.\n");
+      exit(1);
+    }
+  }
+
+  /* have a lapping buffer from vf1; now to splice it into the lapping
+     buffer of vf2 */
+
+  /* consolidate and expose the buffer. */
+  if(vorbis_synthesis_lapout(vd2,&pcm)<lapsize){
+    fprintf(stderr,"vf2 undersized lapping.\n");
+    exit(1);
+  }
+
+  /* splice */
+  for(j=0;j<vi1->channels;j++){
+    float *s=lappcm[j];
+    float *d=pcm[j];
+    vorbis_splice(d,s,winstate,0);
+  }
+
+  /* done */
+  return(0);
+}
+
 

<p><p>1.19      +2 -1      vorbis/lib/window.c

Index: window.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis/lib/window.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- window.c	16 Oct 2002 02:43:48 -0000	1.18
+++ window.c	2 Mar 2003 11:45:17 -0000	1.19
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: window functions
- last mod: $Id: window.c,v 1.18 2002/10/16 02:43:48 xiphmont Exp $
+ last mod: $Id: window.c,v 1.19 2003/03/02 11:45:17 xiphmont Exp $
 
  ********************************************************************/
 
@@ -77,3 +77,4 @@
       d[i]=0.f;
   }
 }
+

<p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list