+ /* splice */
+ for(j=0;j<ch1 && j<ch2;j++){
+ float *s=lappcm[j];
+ float *d=pcm[j];
+
+ for(i=0;i<n;i++){
+ float wd=w[i]*w[i];
+ float ws=1.-wd;
+ d[i]=d[i]*wd + s[i]*ws;
+ }
+ }
+ /* window from zero */
+ for(;j<ch2;j++){
+ float *d=pcm[j];
+ for(i=0;i<n;i++){
+ float wd=w[i]*w[i];
+ d[i]=d[i]*wd;
+ }
+ }
+
+}
+
+/* make sure vf is INITSET */
+static int _ov_initset(OggVorbis_File *vf){
+ while(1){
+ if(vf->ready_state==INITSET)break;
+ /* suck in another packet */
+ {
+ int ret=_fetch_and_process_packet(vf,NULL,1,0);
+ if(ret<0 && ret!=OV_HOLE)return(ret);
+ }
+ }
+ return 0;
+}
+
+/* make sure vf 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 */
+static int _ov_initprime(OggVorbis_File *vf){
+ vorbis_dsp_state *vd=&vf->vd;
+ while(1){
+ if(vf->ready_state==INITSET)
+ if(vorbis_synthesis_pcmout(vd,NULL))break;
+
+ /* suck in another packet */
+ {
+ int ret=_fetch_and_process_packet(vf,NULL,1,0);
+ if(ret<0 && ret!=OV_HOLE)return(ret);
+ }
+ }
+ return 0;
+}
+
+/* grab enough data for lapping from vf; this may be in the form of
+ unreturned, already-decoded pcm, remaining PCM we will need to
+ decode, or synthetic postextrapolation from last packets. */
+static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
+ float **lappcm,int lapsize){
+ int lapcount=0,i;
+ float **pcm;
+
+ /* try first to decode the lapping data */
+ while(lapcount<lapsize){
+ int samples=vorbis_synthesis_pcmout(vd,&pcm);
+ if(samples){
+ if(samples>lapsize-lapcount)samples=lapsize-lapcount;
+ for(i=0;i<vi->channels;i++)
+ memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
+ lapcount+=samples;
+ vorbis_synthesis_read(vd,samples);
+ }else{
+ /* suck in another packet */
+ int ret=_fetch_and_process_packet(vf,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(&vf->vd,&pcm);
+ if(samples==0){
+ for(i=0;i<vi->channels;i++)
+ memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
+ lapcount=lapsize;
+ }else{
+ if(samples>lapsize-lapcount)samples=lapsize-lapcount;
+ for(i=0;i<vi->channels;i++)
+ memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
+ lapcount+=samples;
+ }
+ }
+}
+
+/* this sets up crosslapping of a sample by using trailing data from
+ sample 1 and lapping it into the windowing buffer of sample 2 */
+int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
+ vorbis_info *vi1,*vi2;
+ float **lappcm;
+ float **pcm;
+ const float *w1,*w2;
+ int n1,n2,i,ret,hs1,hs2;
+
+ if(vf1==vf2)return(0); /* degenerate case */
+ if(vf1->ready_state<OPENED)return(OV_EINVAL);
+ if(vf2->ready_state<OPENED)return(OV_EINVAL);
+
+ /* the relevant overlap buffers must be pre-checked and pre-primed
+ before looking at settings in the event that priming would cross
+ a bitstream boundary. So, do it now */
+
+ ret=_ov_initset(vf1);
+ if(ret)return(ret);
+ ret=_ov_initprime(vf2);
+ if(ret)return(ret);
+
+ vi1=ov_info(vf1,-1);
+ vi2=ov_info(vf2,-1);
+ hs1=ov_halfrate_p(vf1);
+ hs2=ov_halfrate_p(vf2);
+
+ lappcm=alloca(sizeof(*lappcm)*vi1->channels);
+ n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
+ n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
+ w1=vorbis_window(&vf1->vd,0);
+ w2=vorbis_window(&vf2->vd,0);
+
+ for(i=0;i<vi1->channels;i++)
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
+
+ _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
+
+ /* have a lapping buffer from vf1; now to splice it into the lapping
+ buffer of vf2 */
+ /* consolidate and expose the buffer. */
+ vorbis_synthesis_lapout(&vf2->vd,&pcm);
+
+#if 0
+ _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
+ _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
+#endif
+
+ /* splice */
+ _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
+
+ /* done */
+ return(0);
+}
+
+static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
+ int (*localseek)(OggVorbis_File *,ogg_int64_t)){
+ vorbis_info *vi;
+ float **lappcm;
+ float **pcm;
+ const float *w1,*w2;
+ int n1,n2,ch1,ch2,hs;
+ int i,ret;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ ret=_ov_initset(vf);
+ if(ret)return(ret);
+ vi=ov_info(vf,-1);
+ hs=ov_halfrate_p(vf);
+
+ ch1=vi->channels;
+ n1=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are
+ persistent; even if the decode state
+ from this link gets dumped, this
+ window array continues to exist */
+
+ lappcm=alloca(sizeof(*lappcm)*ch1);
+ for(i=0;i<ch1;i++)
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
+ _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
+
+ /* have lapping data; seek and prime the buffer */
+ ret=localseek(vf,pos);
+ if(ret)return ret;
+ ret=_ov_initprime(vf);
+ if(ret)return(ret);
+
+ /* Guard against cross-link changes; they're perfectly legal */
+ vi=ov_info(vf,-1);
+ ch2=vi->channels;
+ n2=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w2=vorbis_window(&vf->vd,0);
+
+ /* consolidate and expose the buffer. */
+ vorbis_synthesis_lapout(&vf->vd,&pcm);
+
+ /* splice */
+ _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
+
+ /* done */
+ return(0);
+}
+
+int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
+ return _ov_64_seek_lap(vf,pos,ov_raw_seek);
+}
+
+int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
+ return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
+}
+
+int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
+ return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
+}
+
+static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
+ int (*localseek)(OggVorbis_File *,double)){
+ vorbis_info *vi;
+ float **lappcm;
+ float **pcm;
+ const float *w1,*w2;
+ int n1,n2,ch1,ch2,hs;
+ int i,ret;
+
+ if(vf->ready_state<OPENED)return(OV_EINVAL);
+ ret=_ov_initset(vf);
+ if(ret)return(ret);
+ vi=ov_info(vf,-1);
+ hs=ov_halfrate_p(vf);
+
+ ch1=vi->channels;
+ n1=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are
+ persistent; even if the decode state
+ from this link gets dumped, this
+ window array continues to exist */
+
+ lappcm=alloca(sizeof(*lappcm)*ch1);
+ for(i=0;i<ch1;i++)
+ lappcm[i]=alloca(sizeof(**lappcm)*n1);
+ _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
+
+ /* have lapping data; seek and prime the buffer */
+ ret=localseek(vf,pos);
+ if(ret)return ret;
+ ret=_ov_initprime(vf);
+ if(ret)return(ret);
+
+ /* Guard against cross-link changes; they're perfectly legal */
+ vi=ov_info(vf,-1);
+ ch2=vi->channels;
+ n2=vorbis_info_blocksize(vi,0)>>(1+hs);
+ w2=vorbis_window(&vf->vd,0);
+
+ /* consolidate and expose the buffer. */
+ vorbis_synthesis_lapout(&vf->vd,&pcm);
+
+ /* splice */
+ _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
+
+ /* done */
+ return(0);
+}
+
+int ov_time_seek_lap(OggVorbis_File *vf,double pos){
+ return _ov_d_seek_lap(vf,pos,ov_time_seek);
+}
+
+int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
+ return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
+}