michael@0: /******************************************************************** michael@0: * * michael@0: * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * michael@0: * * michael@0: * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * michael@0: * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * michael@0: * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * michael@0: * * michael@0: * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * michael@0: * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * michael@0: * * michael@0: ******************************************************************** michael@0: michael@0: function: floor backend 0 implementation michael@0: michael@0: ********************************************************************/ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include "ivorbiscodec.h" michael@0: #include "codec_internal.h" michael@0: #include "registry.h" michael@0: #include "codebook.h" michael@0: #include "misc.h" michael@0: #include "block.h" michael@0: michael@0: #define LSP_FRACBITS 14 michael@0: michael@0: typedef struct { michael@0: long n; michael@0: int ln; michael@0: int m; michael@0: int *linearmap; michael@0: michael@0: vorbis_info_floor0 *vi; michael@0: ogg_int32_t *lsp_look; michael@0: michael@0: } vorbis_look_floor0; michael@0: michael@0: /*************** LSP decode ********************/ michael@0: michael@0: #include "lsp_lookup.h" michael@0: michael@0: /* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in michael@0: 16.16 format michael@0: returns in m.8 format */ michael@0: michael@0: static long ADJUST_SQRT2[2]={8192,5792}; michael@0: STIN ogg_int32_t vorbis_invsqlook_i(long a,long e){ michael@0: long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); michael@0: long d=a&INVSQ_LOOKUP_I_MASK; /* 0.10 */ michael@0: long val=INVSQ_LOOKUP_I[i]- /* 1.16 */ michael@0: ((INVSQ_LOOKUP_IDel[i]*d)>>INVSQ_LOOKUP_I_SHIFT); /* result 1.16 */ michael@0: val*=ADJUST_SQRT2[e&1]; michael@0: e=(e>>1)+21; michael@0: return(val>>e); michael@0: } michael@0: michael@0: /* interpolated lookup based fromdB function, domain -140dB to 0dB only */ michael@0: /* a is in n.12 format */ michael@0: STIN ogg_int32_t vorbis_fromdBlook_i(long a){ michael@0: int i=(-a)>>(12-FROMdB2_SHIFT); michael@0: if(i<0) return 0x7fffffff; michael@0: if(i>=(FROMdB_LOOKUP_SZ<>FROMdB_SHIFT] * FROMdB2_LOOKUP[i&FROMdB2_MASK]; michael@0: } michael@0: michael@0: /* interpolated lookup based cos function, domain 0 to PI only */ michael@0: /* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ michael@0: STIN ogg_int32_t vorbis_coslook_i(long a){ michael@0: int i=a>>COS_LOOKUP_I_SHIFT; michael@0: int d=a&COS_LOOKUP_I_MASK; michael@0: return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> michael@0: COS_LOOKUP_I_SHIFT); michael@0: } michael@0: michael@0: /* interpolated lookup based cos function */ michael@0: /* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */ michael@0: STIN ogg_int32_t vorbis_coslook2_i(long a){ michael@0: a=a&0x1ffff; michael@0: michael@0: if(a>0x10000)a=0x20000-a; michael@0: { michael@0: int i=a>>COS_LOOKUP_I_SHIFT; michael@0: int d=a&COS_LOOKUP_I_MASK; michael@0: a=((COS_LOOKUP_I[i]<> michael@0: (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14); michael@0: } michael@0: michael@0: return(a); michael@0: } michael@0: michael@0: static const int barklook[28]={ michael@0: 0,100,200,301, 405,516,635,766, michael@0: 912,1077,1263,1476, 1720,2003,2333,2721, michael@0: 3184,3742,4428,5285, 6376,7791,9662,12181, michael@0: 15624,20397,27087,36554 michael@0: }; michael@0: michael@0: /* used in init only; interpolate the long way */ michael@0: STIN ogg_int32_t toBARK(int n){ michael@0: int i; michael@0: for(i=0;i<27;i++) michael@0: if(n>=barklook[i] && n>10)*0x517d)>>14; michael@0: #endif michael@0: michael@0: /* safeguard against a malicious stream */ michael@0: if(val<0 || (val>>COS_LOOKUP_I_SHIFT)>=COS_LOOKUP_I_SZ){ michael@0: memset(curve,0,sizeof(*curve)*n); michael@0: return; michael@0: } michael@0: michael@0: ilsp[i]=vorbis_coslook_i(val); michael@0: } michael@0: michael@0: i=0; michael@0: while(i>16); michael@0: qi=((qi*qi)>>16); michael@0: michael@0: if(m&1){ michael@0: qexp= qexp*2-28*((m+1)>>1)+m; michael@0: pi*=(1<<14)-((wi*wi)>>14); michael@0: qi+=pi>>14; michael@0: }else{ michael@0: qexp= qexp*2-13*m; michael@0: michael@0: pi*=(1<<14)-wi; michael@0: qi*=(1<<14)+wi; michael@0: michael@0: qi=(qi+pi)>>14; michael@0: } michael@0: michael@0: if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ michael@0: qi>>=1; qexp++; michael@0: }else michael@0: lsp_norm_asm(&qi,&qexp); michael@0: michael@0: #else michael@0: michael@0: j=1; michael@0: if(m>1){ michael@0: qi*=labs(ilsp[0]-wi); michael@0: pi*=labs(ilsp[1]-wi); michael@0: michael@0: for(j+=2;j>25])) michael@0: if(!(shift=MLOOP_2[(pi|qi)>>19])) michael@0: shift=MLOOP_3[(pi|qi)>>16]; michael@0: qi=(qi>>shift)*labs(ilsp[j-1]-wi); michael@0: pi=(pi>>shift)*labs(ilsp[j]-wi); michael@0: qexp+=shift; michael@0: } michael@0: } michael@0: if(!(shift=MLOOP_1[(pi|qi)>>25])) michael@0: if(!(shift=MLOOP_2[(pi|qi)>>19])) michael@0: shift=MLOOP_3[(pi|qi)>>16]; michael@0: michael@0: /* pi,qi normalized collectively, both tracked using qexp */ michael@0: michael@0: if(m&1){ michael@0: /* odd order filter; slightly assymetric */ michael@0: /* the last coefficient */ michael@0: qi=(qi>>shift)*labs(ilsp[j-1]-wi); michael@0: pi=(pi>>shift)<<14; michael@0: qexp+=shift; michael@0: michael@0: if(!(shift=MLOOP_1[(pi|qi)>>25])) michael@0: if(!(shift=MLOOP_2[(pi|qi)>>19])) michael@0: shift=MLOOP_3[(pi|qi)>>16]; michael@0: michael@0: pi>>=shift; michael@0: qi>>=shift; michael@0: qexp+=shift-14*((m+1)>>1); michael@0: michael@0: pi=((pi*pi)>>16); michael@0: qi=((qi*qi)>>16); michael@0: qexp=qexp*2+m; michael@0: michael@0: pi*=(1<<14)-((wi*wi)>>14); michael@0: qi+=pi>>14; michael@0: michael@0: }else{ michael@0: /* even order filter; still symmetric */ michael@0: michael@0: /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't michael@0: worth tracking step by step */ michael@0: michael@0: pi>>=shift; michael@0: qi>>=shift; michael@0: qexp+=shift-7*m; michael@0: michael@0: pi=((pi*pi)>>16); michael@0: qi=((qi*qi)>>16); michael@0: qexp=qexp*2+m; michael@0: michael@0: pi*=(1<<14)-wi; michael@0: qi*=(1<<14)+wi; michael@0: qi=(qi+pi)>>14; michael@0: michael@0: } michael@0: michael@0: michael@0: /* we've let the normalization drift because it wasn't important; michael@0: however, for the lookup, things must be normalized again. We michael@0: need at most one right shift or a number of left shifts */ michael@0: michael@0: if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ michael@0: qi>>=1; qexp++; michael@0: }else michael@0: while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/ michael@0: qi<<=1; qexp--; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: amp=vorbis_fromdBlook_i(ampi* /* n.4 */ michael@0: vorbis_invsqlook_i(qi,qexp)- michael@0: /* m.8, m+n<=8 */ michael@0: ampoffseti); /* 8.12[0] */ michael@0: michael@0: #ifdef _LOW_ACCURACY_ michael@0: amp>>=9; michael@0: #endif michael@0: curve[i]= MULT31_SHIFT15(curve[i],amp); michael@0: while(map[++i]==k) curve[i]= MULT31_SHIFT15(curve[i],amp); michael@0: } michael@0: } michael@0: michael@0: /*************** vorbis decode glue ************/ michael@0: michael@0: static void floor0_free_info(vorbis_info_floor *i){ michael@0: vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; michael@0: if(info){ michael@0: memset(info,0,sizeof(*info)); michael@0: _ogg_free(info); michael@0: } michael@0: } michael@0: michael@0: static void floor0_free_look(vorbis_look_floor *i){ michael@0: vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; michael@0: if(look){ michael@0: michael@0: if(look->linearmap)_ogg_free(look->linearmap); michael@0: if(look->lsp_look)_ogg_free(look->lsp_look); michael@0: memset(look,0,sizeof(*look)); michael@0: _ogg_free(look); michael@0: } michael@0: } michael@0: michael@0: static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){ michael@0: codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; michael@0: int j; michael@0: michael@0: vorbis_info_floor0 *info=(vorbis_info_floor0 *)_ogg_malloc(sizeof(*info)); michael@0: info->order=oggpack_read(opb,8); michael@0: info->rate=oggpack_read(opb,16); michael@0: info->barkmap=oggpack_read(opb,16); michael@0: info->ampbits=oggpack_read(opb,6); michael@0: info->ampdB=oggpack_read(opb,8); michael@0: info->numbooks=oggpack_read(opb,4)+1; michael@0: michael@0: if(info->order<1)goto err_out; michael@0: if(info->rate<1)goto err_out; michael@0: if(info->barkmap<1)goto err_out; michael@0: if(info->numbooks<1)goto err_out; michael@0: michael@0: for(j=0;jnumbooks;j++){ michael@0: info->books[j]=oggpack_read(opb,8); michael@0: if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out; michael@0: if(ci->book_param[info->books[j]]->maptype==0)goto err_out; michael@0: } michael@0: return(info); michael@0: michael@0: err_out: michael@0: floor0_free_info(info); michael@0: return(NULL); michael@0: } michael@0: michael@0: /* initialize Bark scale and normalization lookups. We could do this michael@0: with static tables, but Vorbis allows a number of possible michael@0: combinations, so it's best to do it computationally. michael@0: michael@0: The below is authoritative in terms of defining scale mapping. michael@0: Note that the scale depends on the sampling rate as well as the michael@0: linear block and mapping sizes */ michael@0: michael@0: static vorbis_look_floor *floor0_look (vorbis_dsp_state *vd,vorbis_info_mode *mi, michael@0: vorbis_info_floor *i){ michael@0: int j; michael@0: vorbis_info *vi=vd->vi; michael@0: codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; michael@0: vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; michael@0: vorbis_look_floor0 *look=(vorbis_look_floor0 *)_ogg_calloc(1,sizeof(*look)); michael@0: look->m=info->order; michael@0: look->n=ci->blocksizes[mi->blockflag]/2; michael@0: look->ln=info->barkmap; michael@0: look->vi=info; michael@0: michael@0: /* the mapping from a linear scale to a smaller bark scale is michael@0: straightforward. We do *not* make sure that the linear mapping michael@0: does not skip bark-scale bins; the decoder simply skips them and michael@0: the encoder may do what it wishes in filling them. They're michael@0: necessary in some mapping combinations to keep the scale spacing michael@0: accurate */ michael@0: look->linearmap=(int *)_ogg_malloc((look->n+1)*sizeof(*look->linearmap)); michael@0: for(j=0;jn;j++){ michael@0: michael@0: int val=(look->ln* michael@0: ((toBARK(info->rate/2*j/look->n)<<11)/toBARK(info->rate/2)))>>11; michael@0: michael@0: if(val>=look->ln)val=look->ln-1; /* guard against the approximation */ michael@0: look->linearmap[j]=val; michael@0: } michael@0: look->linearmap[j]=-1; michael@0: michael@0: look->lsp_look=(ogg_int32_t *)_ogg_malloc(look->ln*sizeof(*look->lsp_look)); michael@0: for(j=0;jln;j++) michael@0: look->lsp_look[j]=vorbis_coslook2_i(0x10000*j/look->ln); michael@0: michael@0: return look; michael@0: } michael@0: michael@0: static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){ michael@0: vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; michael@0: vorbis_info_floor0 *info=look->vi; michael@0: int j,k; michael@0: michael@0: int ampraw=oggpack_read(&vb->opb,info->ampbits); michael@0: if(ampraw>0){ /* also handles the -1 out of data case */ michael@0: long maxval=(1<ampbits)-1; michael@0: int amp=((ampraw*info->ampdB)<<4)/maxval; michael@0: int booknum=oggpack_read(&vb->opb,_ilog(info->numbooks)); michael@0: michael@0: if(booknum!=-1 && booknumnumbooks){ /* be paranoid */ michael@0: codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup; michael@0: codebook *b=ci->fullbooks+info->books[booknum]; michael@0: ogg_int32_t last=0; michael@0: ogg_int32_t *lsp=(ogg_int32_t *)_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+1)); michael@0: michael@0: if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m,-24)==-1)goto eop; michael@0: for(j=0;jm;){ michael@0: for(k=0;jm && kdim;k++,j++)lsp[j]+=last; michael@0: last=lsp[j-1]; michael@0: } michael@0: michael@0: lsp[look->m]=amp; michael@0: return(lsp); michael@0: } michael@0: } michael@0: eop: michael@0: return(NULL); michael@0: } michael@0: michael@0: static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i, michael@0: void *memo,ogg_int32_t *out){ michael@0: vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; michael@0: vorbis_info_floor0 *info=look->vi; michael@0: michael@0: if(memo){ michael@0: ogg_int32_t *lsp=(ogg_int32_t *)memo; michael@0: ogg_int32_t amp=lsp[look->m]; michael@0: michael@0: /* take the coefficients back to a spectral envelope curve */ michael@0: vorbis_lsp_to_curve(out,look->linearmap,look->n,look->ln, michael@0: lsp,look->m,amp,info->ampdB,look->lsp_look); michael@0: return(1); michael@0: } michael@0: memset(out,0,sizeof(*out)*look->n); michael@0: return(0); michael@0: } michael@0: michael@0: /* export hooks */ michael@0: vorbis_func_floor floor0_exportbundle={ michael@0: &floor0_unpack,&floor0_look,&floor0_free_info, michael@0: &floor0_free_look,&floor0_inverse1,&floor0_inverse2 michael@0: }; michael@0: michael@0: