diff libtwamr/r_fft.c @ 412:810ac4b99025

libtwamr: integrate VAD2 r_fft.c
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 07 May 2024 01:22:02 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtwamr/r_fft.c	Tue May 07 01:22:02 2024 +0000
@@ -0,0 +1,233 @@
+/*
+*****************************************************************************
+*
+*      GSM AMR-NB speech codec   R98   Version 7.6.0   December 12, 2001
+*                                R99   Version 3.3.0                
+*                                REL-4 Version 4.1.0                
+*
+*****************************************************************************
+*
+*      File             : r_fft.c
+*      Purpose          : Fast Fourier Transform (FFT) algorithm
+*
+*****************************************************************************
+*/
+
+/*****************************************************************
+*
+* This is an implementation of decimation-in-time FFT algorithm for
+* real sequences.  The techniques used here can be found in several
+* books, e.g., i) Proakis and Manolakis, "Digital Signal Processing",
+* 2nd Edition, Chapter 9, and ii) W.H. Press et. al., "Numerical
+* Recipes in C", 2nd Ediiton, Chapter 12.
+*
+* Input -  There is one input to this function:
+*
+*	1) An integer pointer to the input data array 
+*
+* Output - There is no return value.
+*	The input data are replaced with transformed data.  If the
+*	input is a real time domain sequence, it is replaced with
+*	the complex FFT for positive frequencies.  The FFT value 
+*	for DC and the foldover frequency are combined to form the
+*	first complex number in the array.  The remaining complex
+*	numbers correspond to increasing frequencies.  If the input
+*	is a complex frequency domain sequence arranged	as above,
+*	it is replaced with the corresponding time domain sequence. 
+*
+* Notes:
+*
+*	1) This function is designed to be a part of a VAD
+*	   algorithm that requires 128-point FFT of real
+*	   sequences.  This is achieved here through a 64-point
+*	   complex FFT.  Consequently, the FFT size information is
+*	   not transmitted explicitly.  However, some flexibility
+*	   is provided in the function to change the size of the 
+*	   FFT by specifying the size information through "define"
+*	   statements.
+*
+*	2) The values of the complex sinusoids used in the FFT 
+*	   algorithm are stored in a ROM table.
+*
+*	3) In the c_fft function, the FFT values are divided by
+*	   2 after each stage of computation thus dividing the
+*	   final FFT values by 64.  This is somewhat different
+*          from the usual definition of FFT where the factor 1/N,
+*          i.e., 1/64, used for the IFFT and not the FFT.  No factor
+*          is used in the r_fft function.
+*
+*****************************************************************/
+
+#include "tw_amr.h"
+#include "namespace.h"
+#include "typedef.h"
+#include "cnst.h"
+#include "basic_op.h"
+#include "oper_32b.h"
+#include "no_count.h"
+#include "vad2.h"
+
+#define			SIZE			128
+#define			SIZE_BY_TWO		64
+#define			NUM_STAGE		6
+#define			TRUE			1
+#define			FALSE			0
+
+static const Word16 phs_tbl[] =
+{
+
+	32767, 0, 32729, -1608, 32610, -3212, 32413, -4808,
+	32138, -6393, 31786, -7962, 31357, -9512, 30853, -11039,
+	30274, -12540, 29622, -14010, 28899, -15447, 28106, -16846,
+	27246, -18205, 26320, -19520, 25330, -20788, 24279, -22006,
+	23170, -23170, 22006, -24279, 20788, -25330, 19520, -26320,
+	18205, -27246, 16846, -28106, 15447, -28899, 14010, -29622,
+	12540, -30274, 11039, -30853, 9512, -31357, 7962, -31786,
+	6393, -32138, 4808, -32413, 3212, -32610, 1608, -32729,
+	0, -32768, -1608, -32729, -3212, -32610, -4808, -32413,
+	-6393, -32138, -7962, -31786, -9512, -31357, -11039, -30853,
+	-12540, -30274, -14010, -29622, -15447, -28899, -16846, -28106,
+	-18205, -27246, -19520, -26320, -20788, -25330, -22006, -24279,
+	-23170, -23170, -24279, -22006, -25330, -20788, -26320, -19520,
+	-27246, -18205, -28106, -16846, -28899, -15447, -29622, -14010,
+	-30274, -12540, -30853, -11039, -31357, -9512, -31786, -7962,
+	-32138, -6393, -32413, -4808, -32610, -3212, -32729, -1608
+
+};
+
+static const Word16 ii_table[] =
+{SIZE / 2, SIZE / 4, SIZE / 8, SIZE / 16, SIZE / 32, SIZE / 64};
+
+/* FFT function for complex sequences */
+
+/*
+ * The decimation-in-time complex FFT is implemented below.
+ * The input complex numbers are presented as real part followed by
+ * imaginary part for each sample.  The counters are therefore
+ * incremented by two to access the complex valued samples.
+ */
+
+static void c_fft(Word16 * farray_ptr)
+{
+
+	Word16 i, j, k, ii, jj, kk, ji, kj, ii2;
+	Word32 ftmp, ftmp_real, ftmp_imag;
+	Word16 tmp, tmp1, tmp2;
+
+	/* Rearrange the input array in bit reversed order */
+	for (i = 0, j = 0; i < SIZE - 2; i = i + 2)
+	{										test();
+		if (sub(j, i) > 0)
+		{
+			ftmp = *(farray_ptr + i);					move16();
+			*(farray_ptr + i) = *(farray_ptr + j);				move16();
+			*(farray_ptr + j) = ftmp;					move16();
+
+			ftmp = *(farray_ptr + i + 1);					move16();
+			*(farray_ptr + i + 1) = *(farray_ptr + j + 1);			move16();
+			*(farray_ptr + j + 1) = ftmp;					move16();
+		}
+
+		k = SIZE_BY_TWO;							move16();
+											test();
+		while (sub(j, k) >= 0)
+		{
+			j = sub(j, k);
+			k = shr(k, 1);
+		}
+		j = add(j, k);
+	}
+
+	/* The FFT part */
+	for (i = 0; i < NUM_STAGE; i++)
+	{				/* i is stage counter */
+		jj = shl(2, i);		/* FFT size */
+		kk = shl(jj, 1);	/* 2 * FFT size */
+		ii = ii_table[i];	/* 2 * number of FFT's */			move16();
+		ii2 = shl(ii, 1);
+		ji = 0;			/* ji is phase table index */			move16();
+
+		for (j = 0; j < jj; j = j + 2)
+		{					/* j is sample counter */
+
+			for (k = j; k < SIZE; k = k + kk)
+			{				/* k is butterfly top */
+				kj = add(k, jj);	/* kj is butterfly bottom */
+
+				/* Butterfly computations */
+				ftmp_real = L_mult(*(farray_ptr + kj), phs_tbl[ji]);
+				ftmp_real = L_msu(ftmp_real, *(farray_ptr + kj + 1), phs_tbl[ji + 1]);
+
+				ftmp_imag = L_mult(*(farray_ptr + kj + 1), phs_tbl[ji]);
+				ftmp_imag = L_mac(ftmp_imag, *(farray_ptr + kj), phs_tbl[ji + 1]);
+
+				tmp1 = round(ftmp_real);
+				tmp2 = round(ftmp_imag);
+
+				tmp = sub(*(farray_ptr + k), tmp1);
+				*(farray_ptr + kj) = shr(tmp, 1);			move16();
+
+				tmp = sub(*(farray_ptr + k + 1), tmp2);
+				*(farray_ptr + kj + 1) = shr(tmp, 1);			move16();
+
+				tmp = add(*(farray_ptr + k), tmp1);
+				*(farray_ptr + k) = shr(tmp, 1);			move16();
+
+				tmp = add(*(farray_ptr + k + 1), tmp2);
+				*(farray_ptr + k + 1) = shr(tmp, 1);			move16();
+			}
+
+			ji =  add(ji, ii2);
+		}
+	}
+}								/* end of c_fft () */
+
+
+
+void r_fft(Word16 * farray_ptr)
+{
+
+	Word16 ftmp1_real, ftmp1_imag, ftmp2_real, ftmp2_imag;
+	Word32 Lftmp1_real, Lftmp1_imag;
+	Word16 i, j;
+	Word32 Ltmp1;
+
+	/* Perform the complex FFT */
+	c_fft(farray_ptr);
+
+	/* First, handle the DC and foldover frequencies */
+	ftmp1_real = *farray_ptr;							move16();
+	ftmp2_real = *(farray_ptr + 1);							move16();
+	*farray_ptr = add(ftmp1_real, ftmp2_real);					move16();
+	*(farray_ptr + 1) = sub(ftmp1_real, ftmp2_real);				move16();
+
+	/* Now, handle the remaining positive frequencies */
+	for (i = 2, j = SIZE - i; i <= SIZE_BY_TWO; i = i + 2, j = SIZE - i)
+	{
+		ftmp1_real = add(*(farray_ptr + i), *(farray_ptr + j));
+		ftmp1_imag = sub(*(farray_ptr + i + 1), *(farray_ptr + j + 1));
+		ftmp2_real = add(*(farray_ptr + i + 1), *(farray_ptr + j + 1));
+		ftmp2_imag = sub(*(farray_ptr + j), *(farray_ptr + i));
+
+		Lftmp1_real = L_deposit_h(ftmp1_real);
+		Lftmp1_imag = L_deposit_h(ftmp1_imag);
+
+		Ltmp1 = L_mac(Lftmp1_real, ftmp2_real, phs_tbl[i]);
+		Ltmp1 = L_msu(Ltmp1, ftmp2_imag, phs_tbl[i + 1]);
+		*(farray_ptr + i) = round(L_shr(Ltmp1, 1));				move16();
+
+		Ltmp1 = L_mac(Lftmp1_imag, ftmp2_imag, phs_tbl[i]);
+		Ltmp1 = L_mac(Ltmp1, ftmp2_real, phs_tbl[i + 1]);
+		*(farray_ptr + i + 1) = round(L_shr(Ltmp1, 1));				move16();
+
+		Ltmp1 = L_mac(Lftmp1_real, ftmp2_real, phs_tbl[j]);
+		Ltmp1 = L_mac(Ltmp1, ftmp2_imag, phs_tbl[j + 1]);
+		*(farray_ptr + j) = round(L_shr(Ltmp1, 1));				move16();
+
+		Ltmp1 = L_negate(Lftmp1_imag);
+		Ltmp1 = L_msu(Ltmp1, ftmp2_imag, phs_tbl[j]);
+		Ltmp1 = L_mac(Ltmp1, ftmp2_real, phs_tbl[j + 1]);
+		*(farray_ptr + j + 1) = round(L_shr(Ltmp1, 1));				move16();
+
+	}
+}								/* end r_fft () */