shithub: opus

Download patch

ref: 7fa23b4ed0101fa4cf1afc8657fab581d8fd6fe0
parent: e75503be9419dcc6e4dc3c998948dc2374ae6d07
author: Yunho Huh <yunho@google.com>
date: Mon Dec 9 03:25:38 EST 2024

Update celt_log2_db fixed point to match new celt_log2 floating point.

Change-Id: Ibd0d16918272cb568923d384475e139dc312c61b
Signed-off-by: Jean-Marc Valin <jeanmarcv@google.com>

--- a/celt/mathops.h
+++ b/celt/mathops.h
@@ -325,8 +325,49 @@
 
 #ifdef ENABLE_QEXT
 
+/* Calculates the base-2 logarithm of a Q14 input value. The result is returned
+ * in Q(DB_SHIFT). If the input value is 0, the function will output -32.0f. */
 static OPUS_INLINE opus_val32 celt_log2_db(opus_val32 x) {
-   return (int)floor(.5 + (1<<DB_SHIFT) * 1.4426950409f*log(x/(float)(1<<14)));
+   /* Q30 */
+   static const opus_val32 log2_x_norm_coeff[8] = {
+      1073741824, 954437184, 858993472, 780903168,
+      715827904,  660764224, 613566784, 572662336};
+   /* Q24 */
+   static const opus_val32 log2_y_norm_coeff[8] = {
+      0,       2850868,  5401057,  7707983,
+      9814042, 11751428, 13545168, 15215099};
+   static const opus_val32 LOG2_COEFF_A0 = 1467383;     /* Q24 */
+   static const opus_val32 LOG2_COEFF_A1 = 182244800;   /* Q27 */
+   static const opus_val32 LOG2_COEFF_A2 = -21440512;   /* Q25 */
+   static const opus_val32 LOG2_COEFF_A3 = 107903336;   /* Q28 */
+   static const opus_val32 LOG2_COEFF_A4 = -610217024;  /* Q31 */
+
+   opus_int32 integer, norm_coeff_idx, tmp;
+   opus_val32 mantissa;
+   if (x==0) {
+      return -536870912; /* -32.0f */
+   }
+   integer =  SUB32(celt_ilog2(x), 14);  /* Q0 */
+   mantissa = VSHR32(x, integer + 14 - 29);  /* Q29 */
+   norm_coeff_idx = SHR32(mantissa, 29 - 3) & 0x7;
+   /* mantissa is in Q28 (29 + Q_NORM_CONST - 31 where Q_NORM_CONST is Q30)
+    * 285212672 (Q28) is 1.0625f. */
+   mantissa = SUB32(MULT32_32_Q31(mantissa, log2_x_norm_coeff[norm_coeff_idx]),
+                    285212672);
+
+   /* q_a3(Q28): q_mantissa + q_a4 - 31
+    * q_a2(Q25): q_mantissa + q_a3 - 31
+    * q_a1(Q27): q_mantissa + q_a2 - 31 + 5
+    * q_a0(Q24): q_mantissa + q_a1 - 31
+    * where  q_mantissa is Q28 */
+   /* Split evaluation in steps to avoid exploding macro expansion. */
+   tmp = MULT32_32_Q31(mantissa, LOG2_COEFF_A4);
+   tmp = MULT32_32_Q31(mantissa, ADD32(LOG2_COEFF_A3, tmp));
+   tmp = SHL32(MULT32_32_Q31(mantissa, ADD32(LOG2_COEFF_A2, tmp)), 5 /* SHL32 for LOG2_COEFF_A1 */);
+   tmp = MULT32_32_Q31(mantissa, ADD32(LOG2_COEFF_A1, tmp));
+   return ADD32(log2_y_norm_coeff[norm_coeff_idx],
+          ADD32(SHL32(integer, DB_SHIFT),
+          ADD32(LOG2_COEFF_A0, tmp)));
 }
 
 static OPUS_INLINE opus_val32 celt_exp2_db_frac(opus_val32 x)
--- a/celt/tests/test_unit_mathops.c
+++ b/celt/tests/test_unit_mathops.c
@@ -41,6 +41,8 @@
 
 #ifdef FIXED_POINT
 #define WORD "%d"
+#define FIX_INT_TO_DOUBLE(x,q) ((double)(x) / (double)(1L << q))
+#define DOUBLE_TO_FIX_INT(x,q) (((double)x * (double)(1L << q)))
 #else
 #define WORD "%f"
 #endif
@@ -204,6 +206,35 @@
    fprintf (stdout, "celt_exp2, celt_log2 max_error: %15.25e\n", max_error);
 }
 #else
+
+void testlog2_db(void)
+{
+#if defined(ENABLE_QEXT)
+   /* celt_log2_db test */
+   float error = -1;
+   float max_error = -2;
+   float error_threshold = 2.e-07;
+   opus_int32 x = 0;
+   int q_input = 14;
+   for (x = 8; x < 1073741824; x += (x >> 3))
+   {
+      error = fabs((1.442695040888963387*log(FIX_INT_TO_DOUBLE(x, q_input))) -
+                   FIX_INT_TO_DOUBLE(celt_log2_db(x), DB_SHIFT));
+      if (error > max_error)
+      {
+         max_error = error;
+      }
+      if (error > error_threshold)
+      {
+         fprintf(stderr, "celt_log2_db failed: error: [%.5e > %.5e] (x = %f)\n",
+                 error, error_threshold, FIX_INT_TO_DOUBLE(x, DB_SHIFT));
+         ret = 1;
+      }
+   }
+   fprintf(stdout, "celt_log2_db max_error: %.7e\n", max_error);
+#endif  /* defined(ENABLE_QEXT) */
+}
+
 void testlog2(void)
 {
    opus_val32 x;
@@ -283,6 +314,7 @@
    testexp2log2();
 #ifdef FIXED_POINT
    testilog2();
+   testlog2_db();
 #endif
    return ret;
 }
--