********************************************************************
function: libvorbis codec headers
- last mod: $Id: codec.h,v 1.43 2003/03/04 21:23:37 xiphmont Exp $
+ last mod: $Id: codec.h,v 1.44 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
+extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag);
+extern int vorbis_synthesis_halfrate_p(vorbis_info *v);
+
/* Vorbis ERRORS and return codes ***********************************/
#define OV_FALSE -1
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id: vorbisfile.h,v 1.19 2003/03/06 22:03:42 xiphmont Exp $
+ last mod: $Id: vorbisfile.h,v 1.20 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
int bigendianp,int word,int sgned,int *bitstream);
extern int ov_crosslap(OggVorbis_File *vf1,OggVorbis_File *vf2);
+extern int ov_halfrate(OggVorbis_File *vf,int flag);
+extern int ov_halfrate_p(OggVorbis_File *vf);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
* by the XIPHOPHORUS Company http://www.xiph.org/ *
* *
********************************************************************
function: PCM data vector blocking, windowing and dis/reassembly
- last mod: $Id: block.c,v 1.72 2003/03/06 22:05:26 xiphmont Exp $
+ last mod: $Id: block.c,v 1.73 2003/08/18 05:34:01 xiphmont Exp $
Handle windowing, overlap-add, etc of the PCM vectors. This is made
more amusing by Vorbis' current two allowed block sizes.
int i;
codec_setup_info *ci=vi->codec_setup;
private_state *b=NULL;
+ int hs=ci->halfrate_flag;
memset(v,0,sizeof(*v));
b=v->backend_state=_ogg_calloc(1,sizeof(*b));
b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup));
b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup));
- mdct_init(b->transform[0][0],ci->blocksizes[0]);
- mdct_init(b->transform[1][0],ci->blocksizes[1]);
+ mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs);
+ mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs);
/* Vorbis I uses only window type 0 */
- b->window[0]=_vorbis_window_get(0,ci->blocksizes[0]/2);
- b->window[1]=_vorbis_window_get(0,ci->blocksizes[1]/2);
+ b->window[0]=ilog2(ci->blocksizes[0])-6;
+ b->window[1]=ilog2(ci->blocksizes[1])-6;
if(encp){ /* encode/decode differ here */
int vorbis_synthesis_restart(vorbis_dsp_state *v){
vorbis_info *vi=v->vi;
codec_setup_info *ci;
+ int hs;
if(!v->backend_state)return -1;
if(!vi)return -1;
ci=vi->codec_setup;
if(!ci)return -1;
+ hs=ci->halfrate_flag;
- v->centerW=ci->blocksizes[1]/2;
- v->pcm_current=v->centerW;
+ v->centerW=ci->blocksizes[1]>>(hs+1);
+ v->pcm_current=v->centerW>>hs;
v->pcm_returned=-1;
v->granulepos=-1;
vorbis_info *vi=v->vi;
codec_setup_info *ci=vi->codec_setup;
private_state *b=v->backend_state;
+ int hs=ci->halfrate_flag;
int i,j;
if(!vb)return(OV_EINVAL);
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;
- int n1=ci->blocksizes[1]/2;
-
+ int n=ci->blocksizes[v->W]>>(hs+1);
+ int n0=ci->blocksizes[0]>>(hs+1);
+ int n1=ci->blocksizes[1]>>(hs+1);
+
int thisCenter;
int prevCenter;
to have to constantly shift *or* adjust memory usage. Don't
accept a new block until the old is shifted out */
- /* overlap/add PCM */
-
for(j=0;j<vi->channels;j++){
/* the overlap/add section */
if(v->lW){
if(v->W){
/* large/large */
- float *w=b->window[1];
+ float *w=_vorbis_window_get(b->window[1]-hs);
float *pcm=v->pcm[j]+prevCenter;
float *p=vb->pcm[j];
for(i=0;i<n1;i++)
pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
}else{
/* large/small */
- float *w=b->window[0];
+ float *w=_vorbis_window_get(b->window[0]-hs);
float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
float *p=vb->pcm[j];
for(i=0;i<n0;i++)
}else{
if(v->W){
/* small/large */
- float *w=b->window[0];
+ float *w=_vorbis_window_get(b->window[0]-hs);
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];
}else{
/* small/small */
- float *w=b->window[0];
+ float *w=_vorbis_window_get(b->window[0]-hs);
float *pcm=v->pcm[j]+prevCenter;
float *p=vb->pcm[j];
for(i=0;i<n0;i++)
}else{
v->pcm_returned=prevCenter;
v->pcm_current=prevCenter+
- ci->blocksizes[v->lW]/4+
- ci->blocksizes[v->W]/4;
+ ((ci->blocksizes[v->lW]/4+
+ ci->blocksizes[v->W]/4)>>hs);
}
}
/* granulepos could be -1 due to a seek, but that would result
in a long count, not short count */
- v->pcm_current-=(b->sample_count-v->granulepos);
+ v->pcm_current-=(b->sample_count-v->granulepos)>>hs;
}else{
/* trim the beginning */
- v->pcm_returned+=(b->sample_count-v->granulepos);
+ v->pcm_returned+=(b->sample_count-v->granulepos)>>hs;
if(v->pcm_returned>v->pcm_current)
v->pcm_returned=v->pcm_current;
}
if(extra)
if(vb->eofflag){
/* partial last frame. Strip the extra samples off */
- v->pcm_current-=extra;
+ v->pcm_current-=extra>>hs;
} /* else {Shouldn't happen *unless* the bitstream is out of
spec. Either way, believe the bitstream } */
} /* else {Shouldn't happen *unless* the bitstream is out of
/* pcm==NULL indicates we just want the pending samples, no more */
int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){
vorbis_info *vi=v->vi;
+
if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
if(pcm){
int i;
int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){
vorbis_info *vi=v->vi;
codec_setup_info *ci=vi->codec_setup;
+ int hs=ci->halfrate_flag;
- int n=ci->blocksizes[v->W]/2;
- int n0=ci->blocksizes[0]/2;
- int n1=ci->blocksizes[1]/2;
+ int n=ci->blocksizes[v->W]>>(hs+1);
+ int n0=ci->blocksizes[0]>>(hs+1);
+ int n1=ci->blocksizes[1]>>(hs+1);
int i,j;
if(v->pcm_returned<0)return 0;
v->centerW=0;
}
+ /* solidify buffer into contiguous space */
if((v->lW^v->W)==1){
/* long/short or short/long */
for(j=0;j<vi->channels;j++){
float *vorbis_window(vorbis_dsp_state *v,int W){
private_state *b=v->backend_state;
- return b->window[W];
+ return _vorbis_window_get(b->window[W]);
}
********************************************************************
function: libvorbis codec headers
- last mod: $Id: codec_internal.h,v 1.16 2002/10/11 11:14:41 xiphmont Exp $
+ last mod: $Id: codec_internal.h,v 1.17 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
typedef struct private_state {
/* local lookup storage */
envelope_lookup *ve; /* envelope lookup */
- float *window[2];
+ int window[2];
vorbis_look_transform **transform[2]; /* block, type */
drft_lookup fft_look[2];
bitrate_manager_state bms;
ogg_int64_t sample_count;
-
} private_state;
/* codec_setup_info contains all the setup information specific to the
highlevel_encode_setup hi; /* used only by vorbisenc.c. It's a
highly redundant structure, but
improves clarity of program flow. */
-
+ int halfrate_flag; /* painless downsample for decode */
} codec_setup_info;
extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi);
********************************************************************
function: channel mapping 0 implementation
- last mod: $Id: mapping0.c,v 1.57 2003/03/02 11:45:17 xiphmont Exp $
+ last mod: $Id: mapping0.c,v 1.58 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
codec_setup_info *ci=vi->codec_setup;
private_state *b=vd->backend_state;
vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)l;
+ int hs=ci->halfrate_flag;
int i,j;
long n=vb->pcmend=ci->blocksizes[vb->W];
********************************************************************
function: single-block PCM synthesis
- last mod: $Id: synthesis.c,v 1.29 2002/10/11 11:14:41 xiphmont Exp $
+ last mod: $Id: synthesis.c,v 1.30 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
return(ci->blocksizes[ci->mode_param[mode]->blockflag]);
}
+int vorbis_synthesis_halfrate(vorbis_info *vi,int flag){
+ /* set / clear half-sample-rate mode */
+ codec_setup_info *ci=vi->codec_setup;
+
+ /* right now, our MDCT can't handle < 64 sample windows. */
+ if(ci->blocksizes[0]<=64 && flag)return -1;
+ ci->halfrate_flag=(flag?1:0);
+ return 0;
+}
+
+int vorbis_synthesis_halfrate_p(vorbis_info *vi){
+ codec_setup_info *ci=vi->codec_setup;
+ return ci->halfrate_flag;
+}
+
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id: vorbisfile.c,v 1.69 2003/03/11 23:52:02 xiphmont Exp $
+ last mod: $Id: vorbisfile.c,v 1.70 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
}
+
+/* cheap hack for game usage where downsampling is desirable; there's
+ no need for SRC as we can just do it cheaply in libvorbis. */
+
+int ov_halfrate(OggVorbis_File *vf,int flag){
+ int i;
+ if(vf->vi==NULL)return OV_EINVAL;
+ if(!vf->seekable)return OV_EINVAL;
+ if(vf->ready_state>=STREAMSET)
+ _decode_clear(vf); /* clear out stream state; later on libvorbis
+ will be able to swap this on the fly, but
+ for now dumping the decode machine is needed
+ to reinit the MDCT lookups. 1.1 libvorbis
+ is planned to be able to switch on the fly */
+ for(i=0;i<vf->links;i++){
+ if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
+ ov_halfrate(vf,0);
+ return OV_EINVAL;
+ }
+ }
+ return 0;
+}
+
+int ov_halfrate_p(OggVorbis_File *vf){
+ if(vf->vi==NULL)return OV_EINVAL;
+ return vorbis_synthesis_halfrate_p(vf->vi);
+}
+
/* Only partially open the vorbis file; test for Vorbisness, and load
the headers for the first chain. Do not seek (although test for
seekability). Use ov_test_open to finish opening the file, else
********************************************************************
function: window functions
- last mod: $Id: window.c,v 1.21 2003/03/06 22:05:26 xiphmont Exp $
+ last mod: $Id: window.c,v 1.22 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
1.0000000000F, 1.0000000000F, 1.0000000000F, 1.0000000000F,
};
-float *_vorbis_window_get(int type, int left){
- switch(type){
- case 0:
- /* The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*pi*.5) */
- switch(left){
- case 32:
- return(vwin64);
- case 64:
- return(vwin128);
- case 128:
- return(vwin256);
- case 256:
- return(vwin512);
- case 512:
- return(vwin1024);
- case 1024:
- return(vwin2048);
- case 2048:
- return(vwin4096);
- case 4096:
- return(vwin8192);
- }
- default:
- return(NULL);
- }
+static float *vwin[8] = {
+ vwin64,
+ vwin128,
+ vwin256,
+ vwin512,
+ vwin1024,
+ vwin2048,
+ vwin4096,
+ vwin8192,
+};
+
+float *_vorbis_window_get(int n){
+ return vwin[n];
}
-void _vorbis_apply_window(float *d,float *window[2],long *blocksizes,
+void _vorbis_apply_window(float *d,int *winno,long *blocksizes,
int lW,int W,int nW){
+ float *windowLW=vwin[winno[lW]];
+ float *windowNW=vwin[winno[nW]];
+
lW=(W?lW:0);
nW=(W?nW:0);
d[i]=0.f;
for(p=0;i<leftend;i++,p++)
- d[i]*=window[lW][p];
+ d[i]*=windowLW[p];
for(i=rightbegin,p=rn/2-1;i<rightend;i++,p--)
- d[i]*=window[nW][p];
+ d[i]*=windowNW[p];
for(;i<n;i++)
d[i]=0.f;
********************************************************************
function: window functions
- last mod: $Id: window.h,v 1.12 2003/03/06 22:05:26 xiphmont Exp $
+ last mod: $Id: window.h,v 1.13 2003/08/18 05:34:01 xiphmont Exp $
********************************************************************/
#ifndef _V_WINDOW_
#define _V_WINDOW_
-extern float *_vorbis_window_get(int type,int left);
+extern float *_vorbis_window_get(int n);
extern void _vorbis_apply_window(float *d,float *window[2],long *blocksizes,
int lW,int W,int nW);