misc/libtremor/tremor/floor0.c
changeset 7849 a12155461b34
parent 7697 767d3c4153a1
--- a/misc/libtremor/tremor/floor0.c	Sun Oct 28 03:48:37 2012 +0100
+++ b/misc/libtremor/tremor/floor0.c	Sun Oct 28 04:00:07 2012 +0100
@@ -6,7 +6,7 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
@@ -21,12 +21,23 @@
 #include "ogg.h"
 #include "ivorbiscodec.h"
 #include "codec_internal.h"
+#include "registry.h"
 #include "codebook.h"
 #include "misc.h"
-#include "os.h"
+#include "block.h"
 
 #define LSP_FRACBITS 14
-extern const ogg_int32_t FLOOR_fromdB_LOOKUP[];
+
+typedef struct {
+  long n;
+  int ln;
+  int  m;
+  int *linearmap;
+
+  vorbis_info_floor0 *vi;
+  ogg_int32_t *lsp_look;
+
+} vorbis_look_floor0;
 
 /*************** LSP decode ********************/
 
@@ -37,7 +48,7 @@
    returns in m.8 format */
 
 static long ADJUST_SQRT2[2]={8192,5792};
-static inline ogg_int32_t vorbis_invsqlook_i(long a,long e){
+STIN ogg_int32_t vorbis_invsqlook_i(long a,long e){
   long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); 
   long d=a&INVSQ_LOOKUP_I_MASK;                              /*  0.10 */
   long val=INVSQ_LOOKUP_I[i]-                                /*  1.16 */
@@ -49,60 +60,60 @@
 
 /* interpolated lookup based fromdB function, domain -140dB to 0dB only */
 /* a is in n.12 format */
-#ifdef _LOW_ACCURACY_
-static inline ogg_int32_t vorbis_fromdBlook_i(long a){
-  if(a>0) return 0x7fffffff;
-  if(a<(-140<<12)) return 0;
-  return FLOOR_fromdB_LOOKUP[((a+140)*467)>>20]<<9;
+STIN ogg_int32_t vorbis_fromdBlook_i(long a){
+  int i=(-a)>>(12-FROMdB2_SHIFT);
+  if(i<0) return 0x7fffffff;
+  if(i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))return 0;
+  
+  return FROMdB_LOOKUP[i>>FROMdB_SHIFT] * FROMdB2_LOOKUP[i&FROMdB2_MASK];
 }
-#else
-static inline ogg_int32_t vorbis_fromdBlook_i(long a){
-  if(a>0) return 0x7fffffff;
-  if(a<(-140<<12)) return 0;
-  return FLOOR_fromdB_LOOKUP[((a+(140<<12))*467)>>20];
-}
-#endif
 
 /* interpolated lookup based cos function, domain 0 to PI only */
 /* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */
-static inline ogg_int32_t vorbis_coslook_i(long a){
+STIN ogg_int32_t vorbis_coslook_i(long a){
   int i=a>>COS_LOOKUP_I_SHIFT;
   int d=a&COS_LOOKUP_I_MASK;
   return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
 			   COS_LOOKUP_I_SHIFT);
 }
 
-/* interpolated half-wave lookup based cos function */
+/* interpolated lookup based cos function */
 /* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */
-static inline ogg_int32_t vorbis_coslook2_i(long a){
-  int i=a>>COS_LOOKUP_I_SHIFT;
-  int d=a&COS_LOOKUP_I_MASK;
-  return ((COS_LOOKUP_I[i]<<COS_LOOKUP_I_SHIFT)-
-	  d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
-    (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14);
+STIN ogg_int32_t vorbis_coslook2_i(long a){
+  a=a&0x1ffff;
+
+  if(a>0x10000)a=0x20000-a;
+  {               
+    int i=a>>COS_LOOKUP_I_SHIFT;
+    int d=a&COS_LOOKUP_I_MASK;
+    a=((COS_LOOKUP_I[i]<<COS_LOOKUP_I_SHIFT)-
+       d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
+      (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14);
+  }
+  
+  return(a);
 }
 
-static const ogg_uint16_t barklook[54]={
-  0,51,102,154,            206,258,311,365,
-  420,477,535,594,         656,719,785,854,
-  926,1002,1082,1166,      1256,1352,1454,1564,
-  1683,1812,1953,2107,     2276,2463,2670,2900,
-  3155,3440,3756,4106,     4493,4919,5387,5901,
-  6466,7094,7798,8599,     9528,10623,11935,13524,
-  15453,17775,20517,23667, 27183,31004
+static const int barklook[28]={
+  0,100,200,301,          405,516,635,766,
+  912,1077,1263,1476,     1720,2003,2333,2721,
+  3184,3742,4428,5285,    6376,7791,9662,12181,
+  15624,20397,27087,36554
 };
 
 /* used in init only; interpolate the long way */
-static inline ogg_int32_t toBARK(int n){
+STIN ogg_int32_t toBARK(int n){
   int i;
-  for(i=0;i<54;i++) 
+  for(i=0;i<27;i++) 
     if(n>=barklook[i] && n<barklook[i+1])break;
   
-  if(i==54){
-    return 54<<14;
+  if(i==27){
+    return 27<<15;
   }else{
-    return (i<<14)+(((n-barklook[i])*  
-		     ((1UL<<31)/(barklook[i+1]-barklook[i])))>>17);
+    int gap=barklook[i+1]-barklook[i];
+    int del=n-barklook[i];
+
+    return((i<<15)+((del<<15)/gap));
   }
 }
 
@@ -122,11 +133,11 @@
 
 static const unsigned char MLOOP_3[8]={0,1,2,2,3,3,3,3};
 
-void vorbis_lsp_to_curve(ogg_int32_t *curve,int n,int ln,
+void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln,
 			 ogg_int32_t *lsp,int m,
 			 ogg_int32_t amp,
 			 ogg_int32_t ampoffset,
-			 ogg_int32_t nyq){
+			 ogg_int32_t *icos){
 
   /* 0 <= m < 256 */
 
@@ -135,27 +146,6 @@
   int ampoffseti=ampoffset*4096;
   int ampi=amp;
   ogg_int32_t *ilsp=(ogg_int32_t *)alloca(m*sizeof(*ilsp));
-
-  ogg_uint32_t inyq= (1UL<<31) / toBARK(nyq);
-  ogg_uint32_t imap= (1UL<<31) / ln;
-  ogg_uint32_t tBnyq1 = toBARK(nyq)<<1;
-
-  /* Besenham for frequency scale to avoid a division */
-  int f=0;
-  int fdx=n;
-  int fbase=nyq/fdx;
-  int ferr=0;
-  int fdy=nyq-fbase*fdx;
-  int map=0;
-
-#ifdef _LOW_ACCURACY_
-  ogg_uint32_t nextbark=((tBnyq1<<11)/ln)>>12;
-#else
-  ogg_uint32_t nextbark=MULT31(imap>>1,tBnyq1);
-#endif
-  int nextf=barklook[nextbark>>14]+(((nextbark&0x3fff)*
-	    (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14);
-
   /* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/
   for(i=0;i<m;i++){
 #ifndef _LOW_ACCURACY_
@@ -175,14 +165,11 @@
 
   i=0;
   while(i<n){
-    int j;
+    int j,k=map[i];
     ogg_uint32_t pi=46341; /* 2**-.5 in 0.16 */
     ogg_uint32_t qi=46341;
     ogg_int32_t qexp=0,shift;
-    ogg_int32_t wi;
-
-    wi=vorbis_coslook2_i((map*imap)>>15);
-
+    ogg_int32_t wi=icos[k];
 
 #ifdef _V_LSP_MATH_ASM
     lsp_loop_asm(&qi,&pi,&qexp,ilsp,wi,m);
@@ -215,9 +202,8 @@
 
     for(j=3;j<m;j+=2){
       if(!(shift=MLOOP_1[(pi|qi)>>25]))
-      	if(!(shift=MLOOP_2[(pi|qi)>>19]))
-      	  shift=MLOOP_3[(pi|qi)>>16];
-      
+	if(!(shift=MLOOP_2[(pi|qi)>>19]))
+	  shift=MLOOP_3[(pi|qi)>>16];
       qi=(qi>>shift)*labs(ilsp[j-1]-wi);
       pi=(pi>>shift)*labs(ilsp[j]-wi);
       qexp+=shift;
@@ -225,7 +211,7 @@
     if(!(shift=MLOOP_1[(pi|qi)>>25]))
       if(!(shift=MLOOP_2[(pi|qi)>>19]))
 	shift=MLOOP_3[(pi|qi)>>16];
-    
+
     /* pi,qi normalized collectively, both tracked using qexp */
 
     if(m&1){
@@ -293,57 +279,32 @@
     amp>>=9;
 #endif
     curve[i]= MULT31_SHIFT15(curve[i],amp);
-
-    while(++i<n){
-	
-      /* line plot to get new f */
-      ferr+=fdy;
-      if(ferr>=fdx){
-	ferr-=fdx;
-	f++;
-      }
-      f+=fbase;
-      
-      if(f>=nextf)break;
-
-      curve[i]= MULT31_SHIFT15(curve[i],amp);
-    }
-
-    while(1){
-      map++;
-
-      if(map+1<ln){
-	
-#ifdef _LOW_ACCURACY_
-	nextbark=((tBnyq1<<11)/ln*(map+1))>>12;
-#else
-	nextbark=MULT31((map+1)*(imap>>1),tBnyq1);
-#endif
-	nextf=barklook[nextbark>>14]+
-	  (((nextbark&0x3fff)*
-	    (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14);
-	if(f<=nextf)break;
-	
-      }else{
-	nextf=9999999;
-	break;
-      }
-    }
-    if(map>=ln){
-      map=ln-1; /* guard against the approximation */      
-      nextf=9999999;
-    }
+    while(map[++i]==k) curve[i]= MULT31_SHIFT15(curve[i],amp);
   }
 }
 
 /*************** vorbis decode glue ************/
 
-void floor0_free_info(vorbis_info_floor *i){
+static void floor0_free_info(vorbis_info_floor *i){
   vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
-  if(info)_ogg_free(info);
+  if(info){
+    memset(info,0,sizeof(*info));
+    _ogg_free(info);
+  }
 }
 
-vorbis_info_floor *floor0_info_unpack (vorbis_info *vi,oggpack_buffer *opb){
+static void floor0_free_look(vorbis_look_floor *i){
+  vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
+  if(look){
+
+    if(look->linearmap)_ogg_free(look->linearmap);
+    if(look->lsp_look)_ogg_free(look->lsp_look);
+    memset(look,0,sizeof(*look));
+    _ogg_free(look);
+  }
+}
+
+static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){
   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
   int j;
 
@@ -358,13 +319,12 @@
   if(info->order<1)goto err_out;
   if(info->rate<1)goto err_out;
   if(info->barkmap<1)goto err_out;
+  if(info->numbooks<1)goto err_out;
     
   for(j=0;j<info->numbooks;j++){
     info->books[j]=oggpack_read(opb,8);
-    if(info->books[j]>=ci->books)goto err_out;
+    if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out;
   }
-
-  if(oggpack_eop(opb))goto err_out;
   return(info);
 
  err_out:
@@ -372,35 +332,75 @@
   return(NULL);
 }
 
-int floor0_memosize(vorbis_info_floor *i){
+/* initialize Bark scale and normalization lookups.  We could do this
+   with static tables, but Vorbis allows a number of possible
+   combinations, so it's best to do it computationally.
+
+   The below is authoritative in terms of defining scale mapping.
+   Note that the scale depends on the sampling rate as well as the
+   linear block and mapping sizes */
+
+static vorbis_look_floor *floor0_look (vorbis_dsp_state *vd,vorbis_info_mode *mi,
+                              vorbis_info_floor *i){
+  int j;
+  vorbis_info        *vi=vd->vi;
+  codec_setup_info   *ci=(codec_setup_info *)vi->codec_setup;
   vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
-  return info->order+1;
+  vorbis_look_floor0 *look=(vorbis_look_floor0 *)_ogg_calloc(1,sizeof(*look));
+  look->m=info->order;
+  look->n=ci->blocksizes[mi->blockflag]/2;
+  look->ln=info->barkmap;
+  look->vi=info;
+
+  /* the mapping from a linear scale to a smaller bark scale is
+     straightforward.  We do *not* make sure that the linear mapping
+     does not skip bark-scale bins; the decoder simply skips them and
+     the encoder may do what it wishes in filling them.  They're
+     necessary in some mapping combinations to keep the scale spacing
+     accurate */
+  look->linearmap=(int *)_ogg_malloc((look->n+1)*sizeof(*look->linearmap));
+  for(j=0;j<look->n;j++){
+
+    int val=(look->ln*
+	     ((toBARK(info->rate/2*j/look->n)<<11)/toBARK(info->rate/2)))>>11;
+
+    if(val>=look->ln)val=look->ln-1; /* guard against the approximation */
+    look->linearmap[j]=val;
+  }
+  look->linearmap[j]=-1;
+
+  look->lsp_look=(ogg_int32_t *)_ogg_malloc(look->ln*sizeof(*look->lsp_look));
+  for(j=0;j<look->ln;j++)
+    look->lsp_look[j]=vorbis_coslook2_i(0x10000*j/look->ln);
+
+  return look;
 }
 
-ogg_int32_t *floor0_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *i,
-			     ogg_int32_t *lsp){
-  vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
+static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){
+  vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
+  vorbis_info_floor0 *info=look->vi;
   int j,k;
   
-  int ampraw=oggpack_read(&vd->opb,info->ampbits);
+  int ampraw=oggpack_read(&vb->opb,info->ampbits);
   if(ampraw>0){ /* also handles the -1 out of data case */
     long maxval=(1<<info->ampbits)-1;
     int amp=((ampraw*info->ampdB)<<4)/maxval;
-    int booknum=oggpack_read(&vd->opb,_ilog(info->numbooks));
+    int booknum=oggpack_read(&vb->opb,_ilog(info->numbooks));
     
     if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */
-      codec_setup_info  *ci=(codec_setup_info *)vd->vi->codec_setup;
-      codebook *b=ci->book_param+info->books[booknum];
+      codec_setup_info  *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
+      codebook *b=ci->fullbooks+info->books[booknum];
       ogg_int32_t last=0;
+      ogg_int32_t *lsp=(ogg_int32_t *)_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+1));
             
-      for(j=0;j<info->order;j+=b->dim)
-	if(vorbis_book_decodev_set(b,lsp+j,&vd->opb,b->dim,-24)==-1)goto eop;
-      for(j=0;j<info->order;){
+      for(j=0;j<look->m;j+=b->dim)
+	if(vorbis_book_decodev_set(b,lsp+j,&vb->opb,b->dim,-24)==-1)goto eop;
+      for(j=0;j<look->m;){
 	for(k=0;k<b->dim;k++,j++)lsp[j]+=last;
 	last=lsp[j-1];
       }
       
-      lsp[info->order]=amp;
+      lsp[look->m]=amp;
       return(lsp);
     }
   }
@@ -408,21 +408,28 @@
   return(NULL);
 }
 
-int floor0_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *i,
-			   ogg_int32_t *lsp,ogg_int32_t *out){
-  vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
-  codec_setup_info  *ci=(codec_setup_info *)vd->vi->codec_setup;
+static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i,
+			   void *memo,ogg_int32_t *out){
+  vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
+  vorbis_info_floor0 *info=look->vi;
   
-  if(lsp){
-    ogg_int32_t amp=lsp[info->order];
+  if(memo){
+    ogg_int32_t *lsp=(ogg_int32_t *)memo;
+    ogg_int32_t amp=lsp[look->m];
 
     /* take the coefficients back to a spectral envelope curve */
-    vorbis_lsp_to_curve(out,ci->blocksizes[vd->W]/2,info->barkmap,
-			lsp,info->order,amp,info->ampdB,
-			info->rate>>1);
+    vorbis_lsp_to_curve(out,look->linearmap,look->n,look->ln,
+			lsp,look->m,amp,info->ampdB,look->lsp_look);
     return(1);
   }
-  memset(out,0,sizeof(*out)*ci->blocksizes[vd->W]/2);
+  memset(out,0,sizeof(*out)*look->n);
   return(0);
 }
 
+/* export hooks */
+vorbis_func_floor floor0_exportbundle={
+  &floor0_unpack,&floor0_look,&floor0_free_info,
+  &floor0_free_look,&floor0_inverse1,&floor0_inverse2
+};
+
+