Gloria Wang | 37fe158 | 2010-03-12 14:53:20 -0800 | [diff] [blame^] | 1 | /************************************************************************ |
| 2 | * Copyright (C) 2010, The Android Open Source Project |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions are |
| 7 | * met: |
| 8 | * |
| 9 | * * Redistributions of source code must retain the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer. |
| 11 | * * Redistributions in binary form must reproduce the above |
| 12 | * copyright notice, this list of conditions and the following disclaimer |
| 13 | * in the documentation and/or other materials provided with the |
| 14 | * distribution. |
| 15 | * * Neither the name of the Android Open Source Project nor the |
| 16 | * names of its contributors may be used to endorse or promote products |
| 17 | * derived from this software without specific prior written permission. |
| 18 | * |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | ************************************************************************ |
Gloria Wang | 7913073 | 2010-02-08 14:41:04 -0800 | [diff] [blame] | 31 | |
| 32 | function: floor backend 0 implementation |
| 33 | |
Gloria Wang | 37fe158 | 2010-03-12 14:53:20 -0800 | [diff] [blame^] | 34 | ************************************************************************/ |
Gloria Wang | 7913073 | 2010-02-08 14:41:04 -0800 | [diff] [blame] | 35 | |
| 36 | #include <stdlib.h> |
| 37 | #include <string.h> |
| 38 | #include <math.h> |
| 39 | #include "ogg.h" |
| 40 | #include "ivorbiscodec.h" |
| 41 | #include "codec_internal.h" |
| 42 | #include "codebook.h" |
| 43 | #include "misc.h" |
| 44 | #include "os.h" |
| 45 | |
| 46 | #define LSP_FRACBITS 14 |
| 47 | extern const ogg_int32_t FLOOR_fromdB_LOOKUP[]; |
| 48 | |
| 49 | /*************** LSP decode ********************/ |
| 50 | |
| 51 | #include "lsp_lookup.h" |
| 52 | |
| 53 | /* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in |
| 54 | 16.16 format |
| 55 | returns in m.8 format */ |
| 56 | |
| 57 | static long ADJUST_SQRT2[2]={8192,5792}; |
| 58 | static inline ogg_int32_t vorbis_invsqlook_i(long a,long e){ |
| 59 | long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); |
| 60 | long d=a&INVSQ_LOOKUP_I_MASK; /* 0.10 */ |
| 61 | long val=INVSQ_LOOKUP_I[i]- /* 1.16 */ |
| 62 | ((INVSQ_LOOKUP_IDel[i]*d)>>INVSQ_LOOKUP_I_SHIFT); /* result 1.16 */ |
| 63 | val*=ADJUST_SQRT2[e&1]; |
| 64 | e=(e>>1)+21; |
| 65 | return(val>>e); |
| 66 | } |
| 67 | |
| 68 | /* interpolated lookup based fromdB function, domain -140dB to 0dB only */ |
| 69 | /* a is in n.12 format */ |
| 70 | #ifdef _LOW_ACCURACY_ |
| 71 | static inline ogg_int32_t vorbis_fromdBlook_i(long a){ |
| 72 | if(a>0) return 0x7fffffff; |
| 73 | if(a<(-140<<12)) return 0; |
| 74 | return FLOOR_fromdB_LOOKUP[((a+140)*467)>>20]<<9; |
| 75 | } |
| 76 | #else |
| 77 | static inline ogg_int32_t vorbis_fromdBlook_i(long a){ |
| 78 | if(a>0) return 0x7fffffff; |
| 79 | if(a<(-140<<12)) return 0; |
| 80 | return FLOOR_fromdB_LOOKUP[((a+(140<<12))*467)>>20]; |
| 81 | } |
| 82 | #endif |
| 83 | |
| 84 | /* interpolated lookup based cos function, domain 0 to PI only */ |
| 85 | /* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ |
| 86 | static inline ogg_int32_t vorbis_coslook_i(long a){ |
| 87 | int i=a>>COS_LOOKUP_I_SHIFT; |
| 88 | int d=a&COS_LOOKUP_I_MASK; |
| 89 | return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> |
| 90 | COS_LOOKUP_I_SHIFT); |
| 91 | } |
| 92 | |
| 93 | /* interpolated half-wave lookup based cos function */ |
| 94 | /* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */ |
| 95 | static inline ogg_int32_t vorbis_coslook2_i(long a){ |
| 96 | int i=a>>COS_LOOKUP_I_SHIFT; |
| 97 | int d=a&COS_LOOKUP_I_MASK; |
| 98 | return ((COS_LOOKUP_I[i]<<COS_LOOKUP_I_SHIFT)- |
| 99 | d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> |
| 100 | (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14); |
| 101 | } |
| 102 | |
| 103 | static const ogg_uint16_t barklook[54]={ |
| 104 | 0,51,102,154, 206,258,311,365, |
| 105 | 420,477,535,594, 656,719,785,854, |
| 106 | 926,1002,1082,1166, 1256,1352,1454,1564, |
| 107 | 1683,1812,1953,2107, 2276,2463,2670,2900, |
| 108 | 3155,3440,3756,4106, 4493,4919,5387,5901, |
| 109 | 6466,7094,7798,8599, 9528,10623,11935,13524, |
| 110 | 15453,17775,20517,23667, 27183,31004 |
| 111 | }; |
| 112 | |
| 113 | /* used in init only; interpolate the long way */ |
| 114 | static inline ogg_int32_t toBARK(int n){ |
| 115 | int i; |
| 116 | for(i=0;i<54;i++) |
| 117 | if(n>=barklook[i] && n<barklook[i+1])break; |
| 118 | |
| 119 | if(i==54){ |
| 120 | return 54<<14; |
| 121 | }else{ |
| 122 | return (i<<14)+(((n-barklook[i])* |
| 123 | ((1UL<<31)/(barklook[i+1]-barklook[i])))>>17); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | static const unsigned char MLOOP_1[64]={ |
| 128 | 0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13, |
| 129 | 14,14,14,14, 14,14,14,14, 14,14,14,14, 14,14,14,14, |
| 130 | 15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15, |
| 131 | 15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15, |
| 132 | }; |
| 133 | |
| 134 | static const unsigned char MLOOP_2[64]={ |
| 135 | 0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7, |
| 136 | 8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8, |
| 137 | 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9, |
| 138 | 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9, |
| 139 | }; |
| 140 | |
| 141 | static const unsigned char MLOOP_3[8]={0,1,2,2,3,3,3,3}; |
| 142 | |
| 143 | void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln, |
| 144 | ogg_int32_t *lsp,int m, |
| 145 | ogg_int32_t amp, |
| 146 | ogg_int32_t ampoffset, |
| 147 | ogg_int32_t nyq){ |
| 148 | |
| 149 | /* 0 <= m < 256 */ |
| 150 | |
| 151 | /* set up for using all int later */ |
| 152 | int i; |
| 153 | int ampoffseti=ampoffset*4096; |
| 154 | int ampi=amp; |
| 155 | ogg_int32_t *ilsp=(ogg_int32_t *)alloca(m*sizeof(*ilsp)); |
| 156 | |
| 157 | ogg_uint32_t inyq= (1UL<<31) / toBARK(nyq); |
| 158 | ogg_uint32_t imap= (1UL<<31) / ln; |
| 159 | ogg_uint32_t tBnyq1 = toBARK(nyq)<<1; |
| 160 | |
| 161 | /* Besenham for frequency scale to avoid a division */ |
| 162 | int f=0; |
| 163 | int fdx=n; |
| 164 | int fbase=nyq/fdx; |
| 165 | int ferr=0; |
| 166 | int fdy=nyq-fbase*fdx; |
| 167 | int map=0; |
| 168 | |
| 169 | #ifdef _LOW_ACCURACY_ |
| 170 | ogg_uint32_t nextbark=((tBnyq1<<11)/ln)>>12; |
| 171 | #else |
| 172 | ogg_uint32_t nextbark=MULT31(imap>>1,tBnyq1); |
| 173 | #endif |
| 174 | int nextf=barklook[nextbark>>14]+(((nextbark&0x3fff)* |
| 175 | (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14); |
| 176 | |
| 177 | /* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/ |
| 178 | for(i=0;i<m;i++){ |
| 179 | #ifndef _LOW_ACCURACY_ |
| 180 | ogg_int32_t val=MULT32(lsp[i],0x517cc2); |
| 181 | #else |
| 182 | ogg_int32_t val=((lsp[i]>>10)*0x517d)>>14; |
| 183 | #endif |
| 184 | |
| 185 | /* safeguard against a malicious stream */ |
| 186 | if(val<0 || (val>>COS_LOOKUP_I_SHIFT)>=COS_LOOKUP_I_SZ){ |
| 187 | memset(curve,0,sizeof(*curve)*n); |
| 188 | return; |
| 189 | } |
| 190 | |
| 191 | ilsp[i]=vorbis_coslook_i(val); |
| 192 | } |
| 193 | |
| 194 | i=0; |
| 195 | while(i<n){ |
| 196 | int j; |
| 197 | ogg_uint32_t pi=46341; /* 2**-.5 in 0.16 */ |
| 198 | ogg_uint32_t qi=46341; |
| 199 | ogg_int32_t qexp=0,shift; |
| 200 | ogg_int32_t wi; |
| 201 | |
| 202 | wi=vorbis_coslook2_i((map*imap)>>15); |
| 203 | |
| 204 | |
| 205 | #ifdef _V_LSP_MATH_ASM |
| 206 | lsp_loop_asm(&qi,&pi,&qexp,ilsp,wi,m); |
| 207 | |
| 208 | pi=((pi*pi)>>16); |
| 209 | qi=((qi*qi)>>16); |
| 210 | |
| 211 | if(m&1){ |
| 212 | qexp= qexp*2-28*((m+1)>>1)+m; |
| 213 | pi*=(1<<14)-((wi*wi)>>14); |
| 214 | qi+=pi>>14; |
| 215 | }else{ |
| 216 | qexp= qexp*2-13*m; |
| 217 | |
| 218 | pi*=(1<<14)-wi; |
| 219 | qi*=(1<<14)+wi; |
| 220 | |
| 221 | qi=(qi+pi)>>14; |
| 222 | } |
| 223 | |
| 224 | if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ |
| 225 | qi>>=1; qexp++; |
| 226 | }else |
| 227 | lsp_norm_asm(&qi,&qexp); |
| 228 | |
| 229 | #else |
| 230 | |
| 231 | qi*=labs(ilsp[0]-wi); |
| 232 | pi*=labs(ilsp[1]-wi); |
| 233 | |
| 234 | for(j=3;j<m;j+=2){ |
| 235 | if(!(shift=MLOOP_1[(pi|qi)>>25])) |
| 236 | if(!(shift=MLOOP_2[(pi|qi)>>19])) |
| 237 | shift=MLOOP_3[(pi|qi)>>16]; |
| 238 | |
| 239 | qi=(qi>>shift)*labs(ilsp[j-1]-wi); |
| 240 | pi=(pi>>shift)*labs(ilsp[j]-wi); |
| 241 | qexp+=shift; |
| 242 | } |
| 243 | if(!(shift=MLOOP_1[(pi|qi)>>25])) |
| 244 | if(!(shift=MLOOP_2[(pi|qi)>>19])) |
| 245 | shift=MLOOP_3[(pi|qi)>>16]; |
| 246 | |
| 247 | /* pi,qi normalized collectively, both tracked using qexp */ |
| 248 | |
| 249 | if(m&1){ |
| 250 | /* odd order filter; slightly assymetric */ |
| 251 | /* the last coefficient */ |
| 252 | qi=(qi>>shift)*labs(ilsp[j-1]-wi); |
| 253 | pi=(pi>>shift)<<14; |
| 254 | qexp+=shift; |
| 255 | |
| 256 | if(!(shift=MLOOP_1[(pi|qi)>>25])) |
| 257 | if(!(shift=MLOOP_2[(pi|qi)>>19])) |
| 258 | shift=MLOOP_3[(pi|qi)>>16]; |
| 259 | |
| 260 | pi>>=shift; |
| 261 | qi>>=shift; |
| 262 | qexp+=shift-14*((m+1)>>1); |
| 263 | |
| 264 | pi=((pi*pi)>>16); |
| 265 | qi=((qi*qi)>>16); |
| 266 | qexp=qexp*2+m; |
| 267 | |
| 268 | pi*=(1<<14)-((wi*wi)>>14); |
| 269 | qi+=pi>>14; |
| 270 | |
| 271 | }else{ |
| 272 | /* even order filter; still symmetric */ |
| 273 | |
| 274 | /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't |
| 275 | worth tracking step by step */ |
| 276 | |
| 277 | pi>>=shift; |
| 278 | qi>>=shift; |
| 279 | qexp+=shift-7*m; |
| 280 | |
| 281 | pi=((pi*pi)>>16); |
| 282 | qi=((qi*qi)>>16); |
| 283 | qexp=qexp*2+m; |
| 284 | |
| 285 | pi*=(1<<14)-wi; |
| 286 | qi*=(1<<14)+wi; |
| 287 | qi=(qi+pi)>>14; |
| 288 | |
| 289 | } |
| 290 | |
| 291 | |
| 292 | /* we've let the normalization drift because it wasn't important; |
| 293 | however, for the lookup, things must be normalized again. We |
| 294 | need at most one right shift or a number of left shifts */ |
| 295 | |
| 296 | if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ |
| 297 | qi>>=1; qexp++; |
| 298 | }else |
| 299 | while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/ |
| 300 | qi<<=1; qexp--; |
| 301 | } |
| 302 | |
| 303 | #endif |
| 304 | |
| 305 | amp=vorbis_fromdBlook_i(ampi* /* n.4 */ |
| 306 | vorbis_invsqlook_i(qi,qexp)- |
| 307 | /* m.8, m+n<=8 */ |
| 308 | ampoffseti); /* 8.12[0] */ |
| 309 | |
| 310 | #ifdef _LOW_ACCURACY_ |
| 311 | amp>>=9; |
| 312 | #endif |
| 313 | curve[i]= MULT31_SHIFT15(curve[i],amp); |
| 314 | |
| 315 | while(++i<n){ |
| 316 | |
| 317 | /* line plot to get new f */ |
| 318 | ferr+=fdy; |
| 319 | if(ferr>=fdx){ |
| 320 | ferr-=fdx; |
| 321 | f++; |
| 322 | } |
| 323 | f+=fbase; |
| 324 | |
| 325 | if(f>=nextf)break; |
| 326 | |
| 327 | curve[i]= MULT31_SHIFT15(curve[i],amp); |
| 328 | } |
| 329 | |
| 330 | while(1){ |
| 331 | map++; |
| 332 | |
| 333 | if(map+1<ln){ |
| 334 | |
| 335 | #ifdef _LOW_ACCURACY_ |
| 336 | nextbark=((tBnyq1<<11)/ln*(map+1))>>12; |
| 337 | #else |
| 338 | nextbark=MULT31((map+1)*(imap>>1),tBnyq1); |
| 339 | #endif |
| 340 | nextf=barklook[nextbark>>14]+ |
| 341 | (((nextbark&0x3fff)* |
| 342 | (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14); |
| 343 | if(f<=nextf)break; |
| 344 | |
| 345 | }else{ |
| 346 | nextf=9999999; |
| 347 | break; |
| 348 | } |
| 349 | } |
| 350 | if(map>=ln){ |
| 351 | map=ln-1; /* guard against the approximation */ |
| 352 | nextf=9999999; |
| 353 | } |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | /*************** vorbis decode glue ************/ |
| 358 | |
| 359 | void floor0_free_info(vorbis_info_floor *i){ |
| 360 | vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; |
| 361 | if(info)_ogg_free(info); |
| 362 | } |
| 363 | |
| 364 | vorbis_info_floor *floor0_info_unpack (vorbis_info *vi,oggpack_buffer *opb){ |
| 365 | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
| 366 | int j; |
| 367 | |
| 368 | vorbis_info_floor0 *info=(vorbis_info_floor0 *)_ogg_malloc(sizeof(*info)); |
| 369 | info->order=oggpack_read(opb,8); |
| 370 | info->rate=oggpack_read(opb,16); |
| 371 | info->barkmap=oggpack_read(opb,16); |
| 372 | info->ampbits=oggpack_read(opb,6); |
| 373 | info->ampdB=oggpack_read(opb,8); |
| 374 | info->numbooks=oggpack_read(opb,4)+1; |
| 375 | |
| 376 | if(info->order<1)goto err_out; |
| 377 | if(info->rate<1)goto err_out; |
| 378 | if(info->barkmap<1)goto err_out; |
| 379 | |
| 380 | for(j=0;j<info->numbooks;j++){ |
| 381 | info->books[j]=(char)oggpack_read(opb,8); |
| 382 | if(info->books[j]>=ci->books)goto err_out; |
| 383 | } |
| 384 | |
| 385 | if(oggpack_eop(opb))goto err_out; |
| 386 | return(info); |
| 387 | |
| 388 | err_out: |
| 389 | floor0_free_info(info); |
| 390 | return(NULL); |
| 391 | } |
| 392 | |
| 393 | int floor0_memosize(vorbis_info_floor *i){ |
| 394 | vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; |
| 395 | return info->order+1; |
| 396 | } |
| 397 | |
| 398 | ogg_int32_t *floor0_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *i, |
| 399 | ogg_int32_t *lsp){ |
| 400 | vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; |
| 401 | int j,k; |
| 402 | |
| 403 | int ampraw=oggpack_read(&vd->opb,info->ampbits); |
| 404 | if(ampraw>0){ /* also handles the -1 out of data case */ |
| 405 | long maxval=(1<<info->ampbits)-1; |
| 406 | int amp=((ampraw*info->ampdB)<<4)/maxval; |
| 407 | int booknum=oggpack_read(&vd->opb,_ilog(info->numbooks)); |
| 408 | |
| 409 | if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */ |
| 410 | codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; |
| 411 | codebook *b=ci->book_param+info->books[booknum]; |
| 412 | ogg_int32_t last=0; |
| 413 | |
| 414 | for(j=0;j<info->order;j+=b->dim) |
| 415 | if(vorbis_book_decodev_set(b,lsp+j,&vd->opb,b->dim,-24)==-1)goto eop; |
| 416 | for(j=0;j<info->order;){ |
| 417 | for(k=0;k<b->dim;k++,j++)lsp[j]+=last; |
| 418 | last=lsp[j-1]; |
| 419 | } |
| 420 | |
| 421 | lsp[info->order]=amp; |
| 422 | return(lsp); |
| 423 | } |
| 424 | } |
| 425 | eop: |
| 426 | return(NULL); |
| 427 | } |
| 428 | |
| 429 | int floor0_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *i, |
| 430 | ogg_int32_t *lsp,ogg_int32_t *out){ |
| 431 | vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; |
| 432 | codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; |
| 433 | |
| 434 | if(lsp){ |
| 435 | ogg_int32_t amp=lsp[info->order]; |
| 436 | |
| 437 | /* take the coefficients back to a spectral envelope curve */ |
| 438 | vorbis_lsp_to_curve(out,ci->blocksizes[vd->W]/2,info->barkmap, |
| 439 | lsp,info->order,amp,info->ampdB, |
| 440 | info->rate>>1); |
| 441 | return(1); |
| 442 | } |
| 443 | memset(out,0,sizeof(*out)*ci->blocksizes[vd->W]/2); |
| 444 | return(0); |
| 445 | } |
| 446 | |