📄 vorbisfile.c
字号:
static int host_is_big_endian() { ogg_int32_t pattern = 0xfeedface; /* deadbeef */ unsigned char *bytewise = (unsigned char *)&pattern; if (bytewise[0] == 0xfe) return 1; return 0;}/* up to this point, everything could more or less hide the multiple logical bitstream nature of chaining from the toplevel application if the toplevel application didn't particularly care. However, at the point that we actually read audio back, the multiple-section nature must surface: Multiple bitstream sections do not necessarily have to have the same number of channels or sampling rate. ov_read returns the sequential logical bitstream number currently being decoded along with the PCM data in order that the toplevel application can take action on channel/sample rate changes. This number will be incremented even for streamed (non-seekable) streams (for seekable streams, it represents the actual logical bitstream index within the physical bitstream. Note that the accessor functions above are aware of this dichotomy). input values: buffer) a buffer to hold packed PCM data for return length) the byte length requested to be placed into buffer bigendianp) should the data be packed LSB first (0) or MSB first (1) word) word size for output. currently 1 (byte) or 2 (16 bit short) return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) 0) EOF n) number of bytes of PCM actually returned. The below works on a packet-by-packet basis, so the return length is not related to the 'length' passed in, just guaranteed to fit. *section) set to the logical bitstream number */long ov_read(OggVorbis_File *vf,char *buffer,int length, int bigendianp,int word,int sgned,int *bitstream){ int i,j; int host_endian = host_is_big_endian(); float **pcm; long samples; if(vf->ready_state<OPENED)return(OV_EINVAL); while(1){ 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,1); if(ret==OV_EOF) return(0); if(ret<=0) return(ret); } } if(samples>0){ /* yay! proceed to pack data into the byte buffer */ long channels=ov_info(vf,-1)->channels; long bytespersample=word * channels; vorbis_fpu_control fpu; if(samples>length/bytespersample)samples=length/bytespersample; if(samples <= 0) return OV_EINVAL; /* a tight loop to pack each size */ { int val; if(word==1){ int off=(sgned?0:128); vorbis_fpu_setround(&fpu); for(j=0;j<samples;j++) for(i=0;i<channels;i++){ val=vorbis_ftoi(pcm[i][j]*128.f); if(val>127)val=127; else if(val<-128)val=-128; *buffer++=val+off; } vorbis_fpu_restore(fpu); }else{ int off=(sgned?0:32768); if(host_endian==bigendianp){ if(sgned){ vorbis_fpu_setround(&fpu); for(i=0;i<channels;i++) { /* It's faster in this order */ float *src=pcm[i]; short *dest=((short *)buffer)+i; for(j=0;j<samples;j++) { val=vorbis_ftoi(src[j]*32768.f); if(val>32767)val=32767; else if(val<-32768)val=-32768; *dest=val; dest+=channels; } } vorbis_fpu_restore(fpu); }else{ vorbis_fpu_setround(&fpu); for(i=0;i<channels;i++) { float *src=pcm[i]; short *dest=((short *)buffer)+i; for(j=0;j<samples;j++) { val=vorbis_ftoi(src[j]*32768.f); if(val>32767)val=32767; else if(val<-32768)val=-32768; *dest=val+off; dest+=channels; } } vorbis_fpu_restore(fpu); } }else if(bigendianp){ vorbis_fpu_setround(&fpu); for(j=0;j<samples;j++) for(i=0;i<channels;i++){ val=vorbis_ftoi(pcm[i][j]*32768.f); if(val>32767)val=32767; else if(val<-32768)val=-32768; val+=off; *buffer++=(val>>8); *buffer++=(val&0xff); } vorbis_fpu_restore(fpu); }else{ int val; vorbis_fpu_setround(&fpu); for(j=0;j<samples;j++) for(i=0;i<channels;i++){ val=vorbis_ftoi(pcm[i][j]*32768.f); if(val>32767)val=32767; else if(val<-32768)val=-32768; val+=off; *buffer++=(val&0xff); *buffer++=(val>>8); } vorbis_fpu_restore(fpu); } } } vorbis_synthesis_read(&vf->vd,samples); vf->pcm_offset+=samples; if(bitstream)*bitstream=vf->current_link; return(samples*bytespersample); }else{ return(samples); }}/* input values: pcm_channels) a float vector per channel of output length) the sample length being read by the app return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) 0) EOF n) number of samples of PCM actually returned. The below works on a packet-by-packet basis, so the return length is not related to the 'length' passed in, just guaranteed to fit. *section) set to the logical bitstream number */long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length, int *bitstream){ if(vf->ready_state<OPENED)return(OV_EINVAL); while(1){ if(vf->ready_state==INITSET){ float **pcm; long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); if(samples){ if(pcm_channels)*pcm_channels=pcm; if(samples>length)samples=length; vorbis_synthesis_read(&vf->vd,samples); vf->pcm_offset+=samples; if(bitstream)*bitstream=vf->current_link; return samples; } } /* suck in another packet */ { int ret=_fetch_and_process_packet(vf,NULL,1,1); if(ret==OV_EOF)return(0); if(ret<=0)return(ret); } }}extern float *vorbis_window(vorbis_dsp_state *v,int W);extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB, ogg_int64_t off);static void _ov_splice(float **pcm,float **lappcm, int n1, int n2, int ch1, int ch2, float *w1, float *w2){ int i,j; float *w=w1; int n=n1; if(n1>n2){ n=n2; w=w2; } /* 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; 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); _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0); _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0); /* 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; 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; 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -