Coverage Report

Created: 2026-08-13 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opus/celt/mdct.c
Line
Count
Source
1
/* Copyright (c) 2007-2008 CSIRO
2
   Copyright (c) 2007-2008 Xiph.Org Foundation
3
   Written by Jean-Marc Valin */
4
/*
5
   Redistribution and use in source and binary forms, with or without
6
   modification, are permitted provided that the following conditions
7
   are met:
8
9
   - Redistributions of source code must retain the above copyright
10
   notice, this list of conditions and the following disclaimer.
11
12
   - Redistributions in binary form must reproduce the above copyright
13
   notice, this list of conditions and the following disclaimer in the
14
   documentation and/or other materials provided with the distribution.
15
16
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20
   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
/* This is a simple MDCT implementation that uses a N/4 complex FFT
30
   to do most of the work. It should be relatively straightforward to
31
   plug in pretty much and FFT here.
32
33
   This replaces the Vorbis FFT (and uses the exact same API), which
34
   was a bit too messy and that was ending up duplicating code
35
   (might as well use the same FFT everywhere).
36
37
   The algorithm is similar to (and inspired from) Fabrice Bellard's
38
   MDCT implementation in FFMPEG, but has differences in signs, ordering
39
   and scaling in many places.
40
*/
41
42
#ifndef SKIP_CONFIG_H
43
#ifdef HAVE_CONFIG_H
44
#include "config.h"
45
#endif
46
#endif
47
48
#include "mdct.h"
49
#include "kiss_fft.h"
50
#include "_kiss_fft_guts.h"
51
#include <math.h>
52
#include "os_support.h"
53
#include "mathops.h"
54
#include "stack_alloc.h"
55
56
#if defined(FIXED_POINT) && defined(__mips) && __mips == 32
57
#include "mips/mdct_mipsr1.h"
58
#endif
59
60
#ifndef M_PI
61
#define M_PI 3.141592653
62
#endif
63
64
#ifdef CUSTOM_MODES
65
66
int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch)
67
{
68
   int i;
69
   kiss_twiddle_scalar *trig;
70
   int shift;
71
   int N2=N>>1;
72
   l->n = N;
73
   l->maxshift = maxshift;
74
   for (i=0;i<=maxshift;i++)
75
   {
76
      if (i==0)
77
         l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch);
78
      else
79
         l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch);
80
#ifndef ENABLE_TI_DSPLIB55
81
      if (l->kfft[i]==NULL)
82
         return 0;
83
#endif
84
   }
85
   l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar));
86
   if (l->trig==NULL)
87
     return 0;
88
   for (shift=0;shift<=maxshift;shift++)
89
   {
90
      /* We have enough points that sine isn't necessary */
91
#if defined(FIXED_POINT)
92
#ifndef ENABLE_QEXT
93
      for (i=0;i<N2;i++)
94
         trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2+16384),N));
95
#else
96
      for (i=0;i<N2;i++)
97
         trig[i] = (kiss_twiddle_scalar)MAX32(-2147483647,MIN32(2147483647,floor(.5+2147483648*cos(2*M_PI*(i+.125)/N))));
98
#endif
99
#else
100
      for (i=0;i<N2;i++)
101
         trig[i] = (kiss_twiddle_scalar)cos(2*PI*(i+.125)/N);
102
#endif
103
      trig += N2;
104
      N2 >>= 1;
105
      N >>= 1;
106
   }
107
   return 1;
108
}
109
110
void clt_mdct_clear(mdct_lookup *l, int arch)
111
{
112
   int i;
113
   for (i=0;i<=l->maxshift;i++)
114
      opus_fft_free(l->kfft[i], arch);
115
   opus_free((kiss_twiddle_scalar*)l->trig);
116
}
117
118
#endif /* CUSTOM_MODES */
119
120
/* Forward MDCT trashes the input array */
121
#ifndef OVERRIDE_clt_mdct_forward
122
void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
123
      const celt_coef *window, int overlap, int shift, int stride, int arch)
124
81.2M
{
125
81.2M
   int i;
126
81.2M
   int N, N2, N4;
127
81.2M
   VARDECL(kiss_fft_scalar, f);
128
81.2M
   VARDECL(kiss_fft_cpx, f2);
129
81.2M
   const kiss_fft_state *st = l->kfft[shift];
130
81.2M
   const kiss_twiddle_scalar *trig;
131
81.2M
   celt_coef scale;
132
81.2M
#ifdef FIXED_POINT
133
   /* Allows us to scale with MULT16_32_Q16(), which is faster than
134
      MULT16_32_Q15() on ARM. */
135
81.2M
   int scale_shift = st->scale_shift-1;
136
81.2M
   int headroom;
137
81.2M
#endif
138
81.2M
   SAVE_STACK;
139
81.2M
   (void)arch;
140
81.2M
   scale = st->scale;
141
142
81.2M
   N = l->n;
143
81.2M
   trig = l->trig;
144
270M
   for (i=0;i<shift;i++)
145
189M
   {
146
189M
      N >>= 1;
147
189M
      trig += N;
148
189M
   }
149
81.2M
   N2 = N>>1;
150
81.2M
   N4 = N>>2;
151
152
81.2M
   ALLOC(f, N2, kiss_fft_scalar);
153
81.2M
   ALLOC(f2, N4, kiss_fft_cpx);
154
155
   /* Consider the input to be composed of four blocks: [a, b, c, d] */
156
   /* Window, shuffle, fold */
157
81.2M
   {
158
      /* Temp pointers to make it really clear to the compiler what we're doing */
159
81.2M
      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
160
81.2M
      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
161
81.2M
      kiss_fft_scalar * OPUS_RESTRICT yp = f;
162
81.2M
      const celt_coef * OPUS_RESTRICT wp1 = window+(overlap>>1);
163
81.2M
      const celt_coef * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
164
2.52G
      for(i=0;i<((overlap+3)>>2);i++)
165
2.43G
      {
166
         /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
167
2.43G
         *yp++ = S_MUL(xp1[N2], *wp2) + S_MUL(*xp2, *wp1);
168
2.43G
         *yp++ = S_MUL(*xp1, *wp1)    - S_MUL(xp2[-N2], *wp2);
169
2.43G
         xp1+=2;
170
2.43G
         xp2-=2;
171
2.43G
         wp1+=2;
172
2.43G
         wp2-=2;
173
2.43G
      }
174
81.2M
      wp1 = window;
175
81.2M
      wp2 = window+overlap-1;
176
6.12G
      for(;i<N4-((overlap+3)>>2);i++)
177
6.04G
      {
178
         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
179
6.04G
         *yp++ = *xp2;
180
6.04G
         *yp++ = *xp1;
181
6.04G
         xp1+=2;
182
6.04G
         xp2-=2;
183
6.04G
      }
184
2.52G
      for(;i<N4;i++)
185
2.43G
      {
186
         /* Real part arranged as a-bR, Imag part arranged as -c-dR */
187
2.43G
         *yp++ =  -S_MUL(xp1[-N2], *wp1) + S_MUL(*xp2, *wp2);
188
2.43G
         *yp++ = S_MUL(*xp1, *wp2)     + S_MUL(xp2[N2], *wp1);
189
2.43G
         xp1+=2;
190
2.43G
         xp2-=2;
191
2.43G
         wp1+=2;
192
2.43G
         wp2-=2;
193
2.43G
      }
194
81.2M
   }
195
   /* Pre-rotation */
196
81.2M
   {
197
81.2M
      kiss_fft_scalar * OPUS_RESTRICT yp = f;
198
81.2M
      const kiss_twiddle_scalar *t = &trig[0];
199
81.2M
#ifdef FIXED_POINT
200
81.2M
      opus_val32 maxval=1;
201
81.2M
#endif
202
11.0G
      for(i=0;i<N4;i++)
203
10.9G
      {
204
10.9G
         kiss_fft_cpx yc;
205
10.9G
         kiss_twiddle_scalar t0, t1;
206
10.9G
         kiss_fft_scalar re, im, yr, yi;
207
10.9G
         t0 = t[i];
208
10.9G
         t1 = t[N4+i];
209
10.9G
         re = *yp++;
210
10.9G
         im = *yp++;
211
10.9G
         yr = S_MUL(re,t0)  -  S_MUL(im,t1);
212
10.9G
         yi = S_MUL(im,t0)  +  S_MUL(re,t1);
213
         /* For QEXT, it's best to scale before the FFT, but otherwise it's best to scale after.
214
            For floating-point it doesn't matter. */
215
#ifdef ENABLE_QEXT
216
         yc.r = yr;
217
         yc.i = yi;
218
#else
219
10.9G
         yc.r = S_MUL2(yr, scale);
220
10.9G
         yc.i = S_MUL2(yi, scale);
221
10.9G
#endif
222
10.9G
#ifdef FIXED_POINT
223
10.9G
         maxval = MAX32(maxval, MAX32(ABS32(yc.r), ABS32(yc.i)));
224
10.9G
#endif
225
10.9G
         f2[st->bitrev[i]] = yc;
226
10.9G
      }
227
81.2M
#ifdef FIXED_POINT
228
81.2M
      headroom = IMAX(0, IMIN(scale_shift, 28-celt_ilog2(maxval)));
229
81.2M
#endif
230
81.2M
   }
231
232
   /* N/4 complex FFT, does not downscale anymore */
233
81.2M
   opus_fft_impl(st, f2 ARG_FIXED(scale_shift-headroom));
234
235
   /* Post-rotate */
236
81.2M
   {
237
      /* Temp pointers to make it really clear to the compiler what we're doing */
238
81.2M
      const kiss_fft_cpx * OPUS_RESTRICT fp = f2;
239
81.2M
      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
240
81.2M
      kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
241
81.2M
      const kiss_twiddle_scalar *t = &trig[0];
242
      /* Temp pointers to make it really clear to the compiler what we're doing */
243
11.0G
      for(i=0;i<N4;i++)
244
10.9G
      {
245
10.9G
         kiss_fft_scalar yr, yi;
246
10.9G
         kiss_fft_scalar t0, t1;
247
#ifdef ENABLE_QEXT
248
         t0 = S_MUL2(t[i], scale);
249
         t1 = S_MUL2(t[N4+i], scale);
250
#else
251
10.9G
         t0 = t[i];
252
10.9G
         t1 = t[N4+i];
253
10.9G
#endif
254
10.9G
         yr = PSHR32(S_MUL(fp->i,t1) - S_MUL(fp->r,t0), headroom);
255
10.9G
         yi = PSHR32(S_MUL(fp->r,t1) + S_MUL(fp->i,t0), headroom);
256
10.9G
         *yp1 = yr;
257
10.9G
         *yp2 = yi;
258
10.9G
         fp++;
259
10.9G
         yp1 += 2*stride;
260
10.9G
         yp2 -= 2*stride;
261
10.9G
      }
262
81.2M
   }
263
81.2M
   RESTORE_STACK;
264
81.2M
}
265
#endif /* OVERRIDE_clt_mdct_forward */
266
267
#ifndef OVERRIDE_clt_mdct_backward
268
void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
269
      const celt_coef * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch)
270
0
{
271
0
   int i;
272
0
   int N, N2, N4;
273
0
   const kiss_twiddle_scalar *trig;
274
0
#ifdef FIXED_POINT
275
0
   int pre_shift, post_shift, fft_shift;
276
0
#endif
277
0
   (void) arch;
278
279
0
   N = l->n;
280
0
   trig = l->trig;
281
0
   for (i=0;i<shift;i++)
282
0
   {
283
0
      N >>= 1;
284
0
      trig += N;
285
0
   }
286
0
   N2 = N>>1;
287
0
   N4 = N>>2;
288
289
0
#ifdef FIXED_POINT
290
0
   {
291
0
      opus_val32 sumval=N2;
292
0
      opus_val32 maxval=0;
293
0
      for (i=0;i<N2;i++) {
294
0
         maxval = MAX32(maxval, ABS32(in[i*stride]));
295
0
         sumval = ADD32_ovflw(sumval, ABS32(SHR32(in[i*stride],11)));
296
0
      }
297
0
      pre_shift = IMAX(0, 29-celt_zlog2(1+maxval));
298
      /* Worst-case where all the energy goes to a single sample. */
299
0
      post_shift = IMAX(0, 19-celt_ilog2(ABS32(sumval)));
300
0
      post_shift = IMIN(post_shift, pre_shift);
301
0
      fft_shift = pre_shift - post_shift;
302
0
   }
303
0
#endif
304
   /* Pre-rotate */
305
0
   {
306
      /* Temp pointers to make it really clear to the compiler what we're doing */
307
0
      const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
308
0
      const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
309
0
      kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1);
310
0
      const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0];
311
0
      const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev;
312
0
      for(i=0;i<N4;i++)
313
0
      {
314
0
         int rev;
315
0
         kiss_fft_scalar yr, yi;
316
0
         opus_val32 x1, x2;
317
0
         rev = *bitrev++;
318
0
         x1 = SHL32_ovflw(*xp1, pre_shift);
319
0
         x2 = SHL32_ovflw(*xp2, pre_shift);
320
0
         yr = ADD32_ovflw(S_MUL(x2, t[i]), S_MUL(x1, t[N4+i]));
321
0
         yi = SUB32_ovflw(S_MUL(x1, t[i]), S_MUL(x2, t[N4+i]));
322
         /* We swap real and imag because we use an FFT instead of an IFFT. */
323
0
         yp[2*rev+1] = yr;
324
0
         yp[2*rev] = yi;
325
         /* Storing the pre-rotation directly in the bitrev order. */
326
0
         xp1+=2*stride;
327
0
         xp2-=2*stride;
328
0
      }
329
0
   }
330
331
0
   opus_fft_impl(l->kfft[shift], (kiss_fft_cpx*)(out+(overlap>>1)) ARG_FIXED(fft_shift));
332
333
   /* Post-rotate and de-shuffle from both ends of the buffer at once to make
334
      it in-place. */
335
0
   {
336
0
      kiss_fft_scalar * yp0 = out+(overlap>>1);
337
0
      kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2;
338
0
      const kiss_twiddle_scalar *t = &trig[0];
339
      /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
340
         middle pair will be computed twice. */
341
0
      for(i=0;i<(N4+1)>>1;i++)
342
0
      {
343
0
         kiss_fft_scalar re, im, yr, yi;
344
0
         kiss_twiddle_scalar t0, t1;
345
         /* We swap real and imag because we're using an FFT instead of an IFFT. */
346
0
         re = yp0[1];
347
0
         im = yp0[0];
348
0
         t0 = t[i];
349
0
         t1 = t[N4+i];
350
         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
351
0
         yr = PSHR32_ovflw(ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)), post_shift);
352
0
         yi = PSHR32_ovflw(SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)), post_shift);
353
         /* We swap real and imag because we're using an FFT instead of an IFFT. */
354
0
         re = yp1[1];
355
0
         im = yp1[0];
356
0
         yp0[0] = yr;
357
0
         yp1[1] = yi;
358
359
0
         t0 = t[(N4-i-1)];
360
0
         t1 = t[(N2-i-1)];
361
         /* We'd scale up by 2 here, but instead it's done when mixing the windows */
362
0
         yr = PSHR32_ovflw(ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)), post_shift);
363
0
         yi = PSHR32_ovflw(SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)), post_shift);
364
0
         yp1[0] = yr;
365
0
         yp0[1] = yi;
366
0
         yp0 += 2;
367
0
         yp1 -= 2;
368
0
      }
369
0
   }
370
371
   /* Mirror on both sides for TDAC */
372
0
   {
373
0
      kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
374
0
      kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
375
0
      const celt_coef * OPUS_RESTRICT wp1 = window;
376
0
      const celt_coef * OPUS_RESTRICT wp2 = window+overlap-1;
377
378
0
      for(i = 0; i < overlap/2; i++)
379
0
      {
380
0
         kiss_fft_scalar x1, x2;
381
0
         x1 = *xp1;
382
0
         x2 = *yp1;
383
0
         *yp1++ = SUB32_ovflw(S_MUL(x2, *wp2), S_MUL(x1, *wp1));
384
0
         *xp1-- = ADD32_ovflw(S_MUL(x2, *wp1), S_MUL(x1, *wp2));
385
0
         wp1++;
386
0
         wp2--;
387
0
      }
388
0
   }
389
0
}
390
#endif /* OVERRIDE_clt_mdct_backward */