📄 vorbisfile.c
字号:
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 */
ogg_int32_t 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;
ogg_int32_t 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;
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 */
ogg_int32_t channels=ov_info(vf,-1)->channels;
ogg_int32_t bytespersample=word * channels;
vorbis_fpu_control fpu = 0;
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++)
{
#if R5900
val=vorbis_ftoipcm(src[j]*32768.f);
#else
val=vorbis_ftoi(src[j]*32768.f);
if(val>32767)val=32767;
else if(val<-32768)val=-32768;
#endif
*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 */
ogg_int32_t 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;
ogg_int32_t 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);
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.0f-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>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;
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);
lappcm=alloca(sizeof(*lappcm)*vi1->channels);
n1=vorbis_info_blocksize(vi1,0)/2;
n2=vorbis_info_blocksize(vi2,0)/2;
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);
/* 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;
int i,ret;
if(vf->ready_state<OPENED)return(OV_EINVAL);
ret=_ov_initset(vf);
if(ret)return(ret);
vi=ov_info(vf,-1);
ch1=vi->channels;
n1=vorbis_info_blocksize(vi,0)/2;
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)/2;
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,float pos,
int (*localseek)(OggVorbis_File *,float)){
vorbis_info *vi;
float **lappcm;
float **pcm;
float *w1,*w2;
int n1,n2,ch1,ch2;
int i,ret;
if(vf->ready_state<OPENED)return(OV_EINVAL);
ret=_ov_initset(vf);
if(ret)return(ret);
vi=ov_info(vf,-1);
ch1=vi->channels;
n1=vorbis_info_blocksize(vi,0)/2;
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)/2;
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,float pos){
return _ov_d_seek_lap(vf,pos,ov_time_seek);
}
int ov_time_seek_page_lap(OggVorbis_File *vf,float pos){
return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -