[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