Skip to content

Commit ec1e887

Browse files
yunhohuhgjmvalin
authored andcommitted
Add the fixed-point cos(PI*0.5*x) function (cos_norm2).
Change-Id: I08be579a4224b7b09057e2f6b2771d0a4c3567ca Signed-off-by: Jean-Marc Valin <[email protected]>
1 parent 57a17aa commit ec1e887

File tree

4 files changed

+63
-7
lines changed

4 files changed

+63
-7
lines changed

celt/bands.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,8 +1051,8 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
10511051
# ifdef ENABLE_QEXT
10521052
(void)imid;
10531053
(void)iside;
1054-
mid = (int)MIN32(2147483647, floor(.5+2147483648*celt_cos_norm2(sctx.itheta_q30*(1.f/(1<<30)))));
1055-
side = (int)MIN32(2147483647, floor(.5+2147483648*celt_cos_norm2(1.f-sctx.itheta_q30*(1.f/(1<<30)))));
1054+
mid = celt_cos_norm32(sctx.itheta_q30);
1055+
side = celt_cos_norm32((1<<30)-sctx.itheta_q30);
10561056
# else
10571057
mid = SHL32(EXTEND32(imid), 16);
10581058
side = SHL32(EXTEND32(iside), 16);
@@ -1261,8 +1261,8 @@ static unsigned cubic_quant_partition(struct band_ctx *ctx, celt_norm *X, int N,
12611261
delta = (N0-1) * 23 * ((itheta_q30>>16)-8192) >> (17-BITRES);
12621262

12631263
#ifdef FIXED_POINT
1264-
g1 = (int)MIN32(2147483647, floor(.5+2147483648*celt_cos_norm2(itheta_q30*(1.f/(1<<30)))));
1265-
g2 = (int)MIN32(2147483647, floor(.5+2147483648*celt_cos_norm2(1.f-itheta_q30*(1.f/(1<<30)))));
1264+
g1 = celt_cos_norm32(itheta_q30);
1265+
g2 = celt_cos_norm32((1<<30)-itheta_q30);
12661266
#else
12671267
g1 = celt_cos_norm2(itheta_q30*(1.f/(1<<30)));
12681268
g2 = celt_cos_norm2(1.f-itheta_q30*(1.f/(1<<30)));
@@ -1459,8 +1459,8 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm
14591459
# ifdef ENABLE_QEXT
14601460
(void)imid;
14611461
(void)iside;
1462-
mid = (int)MIN32(2147483647, floor(.5+2147483648*cos(.5*M_PI*sctx.itheta_q30*(1.f/(1<<30)))));
1463-
side = (int)MIN32(2147483647, floor(.5+2147483648*sin(.5*M_PI*sctx.itheta_q30*(1.f/(1<<30)))));
1462+
mid = celt_cos_norm32(sctx.itheta_q30);
1463+
side = celt_cos_norm32((1<<30)-sctx.itheta_q30);
14641464
# else
14651465
mid = SHL32(EXTEND32(imid), 16);
14661466
side = SHL32(EXTEND32(iside), 16);

celt/mathops.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,26 @@ opus_val16 celt_cos_norm(opus_val32 x)
199199
}
200200
}
201201

202+
/* Calculates the cosine of (PI*0.5*x) where the input x ranges from -1 to 1 and
203+
* is in Q30 format. The output will also be in Q31 format. */
204+
opus_val32 celt_cos_norm32(opus_val32 x)
205+
{
206+
static const opus_val32 COS_NORM_COEFF_A0 = 134217720; /* Q27 */
207+
static const opus_val32 COS_NORM_COEFF_A1 = -662336704; /* Q29 */
208+
static const opus_val32 COS_NORM_COEFF_A2 = 544710848; /* Q31 */
209+
static const opus_val32 COS_NORM_COEFF_A3 = -178761936; /* Q33 */
210+
static const opus_val32 COS_NORM_COEFF_A4 = 29487206; /* Q35 */
211+
opus_int32 x_sq_q29, tmp;
212+
/* The expected x is in the range of [-1.0f, 1.0f] */
213+
celt_sig_assert((x >= -1073741824) && (x <= 1073741824));
214+
x_sq_q29 = MULT32_32_Q31(x, x);
215+
/* Split evaluation in steps to avoid exploding macro expansion. */
216+
tmp = ADD32(COS_NORM_COEFF_A3, MULT32_32_Q31(x_sq_q29, COS_NORM_COEFF_A4));
217+
tmp = ADD32(COS_NORM_COEFF_A2, MULT32_32_Q31(x_sq_q29, tmp));
218+
tmp = ADD32(COS_NORM_COEFF_A1, MULT32_32_Q31(x_sq_q29, tmp));
219+
return SHL32(ADD32(COS_NORM_COEFF_A0, MULT32_32_Q31(x_sq_q29, tmp)), 4);
220+
}
221+
202222
/** Reciprocal approximation (Q15 input, Q16 output) */
203223
opus_val32 celt_rcp(opus_val32 x)
204224
{

celt/mathops.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ opus_val32 celt_sqrt(opus_val32 x);
371371

372372
opus_val16 celt_cos_norm(opus_val32 x);
373373

374+
opus_val32 celt_cos_norm32(opus_val32 x);
375+
374376
/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */
375377
static OPUS_INLINE opus_val16 celt_log2(opus_val32 x)
376378
{

celt/tests/test_unit_mathops.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,40 @@ void testatan(void)
519519
testatan_norm();
520520
testatan2p_norm();
521521
}
522+
523+
void test_cos_norm32(void)
524+
{
525+
float error = -1;
526+
float max_error = -2;
527+
float error_threshold = 1e-07;
528+
float fx = 0;
529+
opus_int32 x = 0;
530+
int q_input = 30;
531+
int q_output = 31;
532+
for (fx = -1.0f; fx <= 1.0f; fx += 0.007f)
533+
{
534+
x = DOUBLE_TO_FIX_INT(fx, q_input);
535+
error = fabs(cos(1.5707963267948966 * FIX_INT_TO_DOUBLE(x, q_input)) -
536+
FIX_INT_TO_DOUBLE(celt_cos_norm32(x), q_output));
537+
if (error > max_error)
538+
{
539+
max_error = error;
540+
}
541+
if (error > error_threshold)
542+
{
543+
fprintf(stderr,
544+
"celt_cos_norm32 failed: error: [%.5e > %.5e] (x = %f)\n",
545+
error, error_threshold, FIX_INT_TO_DOUBLE(x, DB_SHIFT));
546+
ret = 1;
547+
}
548+
}
549+
fprintf(stdout, "celt_cos_norm32 max_error: %.7e\n", max_error);
550+
}
551+
552+
void test_cos(void)
553+
{
554+
test_cos_norm32();
555+
}
522556
#endif
523557

524558
int main(void)
@@ -530,14 +564,14 @@ int main(void)
530564
testlog2();
531565
testexp2();
532566
testexp2log2();
567+
test_cos();
533568
#ifdef FIXED_POINT
534569
testilog2();
535570
testlog2_db();
536571
testexp2_db();
537572
testrsqrt();
538573
testatan();
539574
#else
540-
test_cos();
541575
test_atan2();
542576
#endif
543577
return ret;

0 commit comments

Comments
 (0)