178 lines
4.4 KiB
C
178 lines
4.4 KiB
C
/* GMR-1 AMBE vocoder - Math functions */
|
|
|
|
/* (C) 2011-2019 by Sylvain Munaut <tnt@246tNt.com>
|
|
* All Rights Reserved
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*! \addtogroup codec_private
|
|
* @{
|
|
*/
|
|
|
|
/*! \file codec/math.c
|
|
* \brief Osmocom GMR-1 AMBE vocoder math functions
|
|
*/
|
|
|
|
#include <math.h>
|
|
|
|
#include "private.h"
|
|
|
|
|
|
/*! \brief Table for \ref cosf_fast and \ref sinf_fast */
|
|
static float cos_tbl[1024];
|
|
|
|
/*! \brief Initializes \ref cos_tbl for \ref cosf_fast */
|
|
static void __attribute__ ((constructor))
|
|
cos_tbl_init(void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<1024; i++)
|
|
cos_tbl[i] = cosf((M_PIf * i) / 512.0f);
|
|
}
|
|
|
|
/*! \brief Fast Cosinus approximation using a simple table
|
|
* \param[in] angle The angle value
|
|
* \returns The cosinus of the angle
|
|
*/
|
|
float
|
|
cosf_fast(float angle)
|
|
{
|
|
const float f = 512.0f / M_PIf;
|
|
return cos_tbl[(int)(angle*f) & 1023];
|
|
}
|
|
|
|
/*! \brief Fast Sinus approximation using a simple table
|
|
* \param[in] angle The angle value
|
|
* \returns The sinus of the angle
|
|
*/
|
|
float
|
|
sinf_fast(float angle)
|
|
{
|
|
const float f = 512.0f / M_PIf;
|
|
return cos_tbl[((int)(angle*f) + 768) & 1023];
|
|
}
|
|
|
|
/*! \brief Forward Discrete Cosine Transform (fDCT)
|
|
* \param[out] out fDCT result buffer (freq domain, M elements)
|
|
* \param[in] in fDCT input buffer (time domain, N elements)
|
|
* \param[in] N Number of points of the DCT
|
|
* \param[in] M Limit to the number of frequency components (M <= N)
|
|
*/
|
|
void
|
|
ambe_fdct(float *out, float *in, int N, int M)
|
|
{
|
|
int i, j;
|
|
|
|
for (i=0; i<M; i++)
|
|
{
|
|
float v = 0.0f;
|
|
|
|
for (j=0; j<N; j++)
|
|
{
|
|
v += in[j] * cosf_fast( (M_PIf / N) * (j + .5f) * i );
|
|
}
|
|
|
|
out[i] = v / (float)N;
|
|
}
|
|
}
|
|
|
|
/*! \brief Inverse Discrete Cosine Transform (iDCT)
|
|
* \param[out] out iDCT result buffer (time domain, N elements)
|
|
* \param[in] in iDCT input buffer (freq domain, M elements)
|
|
* \param[in] N Number of points of the DCT
|
|
* \param[in] M Limit to the number of frequency components (M <= N)
|
|
*/
|
|
void
|
|
ambe_idct(float *out, float *in, int N, int M)
|
|
{
|
|
int i, j;
|
|
|
|
for (i=0; i<N; i++)
|
|
{
|
|
float v = in[0];
|
|
|
|
for (j=1; j<M; j++)
|
|
{
|
|
v += 2.0f * in[j] * cosf_fast( (M_PIf / N) * j * (i + .5f) );
|
|
}
|
|
|
|
out[i] = v;
|
|
}
|
|
}
|
|
|
|
/*! \brief Forward Discrete Fourrier Transform (float->complex)
|
|
* \param[out] out_i Real component result buffer (freq domain, N/2+1 elements)
|
|
* \param[out] out_q Imag component result buffer (freq domain, N/2+1 elements)
|
|
* \param[in] in Input buffer (time domain, M elements)
|
|
* \param[in] N Number of points of the DFT
|
|
* \param[in] M Limit to to the number of available time domain elements
|
|
*
|
|
* Since the input is float, the result is symmetric and so only one side
|
|
* is computed. The output index 0 is DC.
|
|
*/
|
|
void
|
|
ambe_fdft_fc(float *out_i, float *out_q, float *in, int N, int M)
|
|
{
|
|
int fb, ts;
|
|
|
|
for (fb=0; fb<=(N/2); fb++)
|
|
{
|
|
float i=0.0f, q=0.0f;
|
|
|
|
for (ts=0; ts<M; ts++)
|
|
{
|
|
float angle = (- 2.0f * M_PIf / N) * fb * ts;
|
|
i += in[ts] * cosf_fast(angle);
|
|
q += in[ts] * sinf_fast(angle);
|
|
}
|
|
|
|
out_i[fb] = i;
|
|
out_q[fb] = q;
|
|
}
|
|
}
|
|
|
|
/*! \brief Inverse Discret Fourrier Transform (complex->float)
|
|
* \param[out] out Result buffer (time domain, M
|
|
* \param[in] in_i Real component input buffer (freq domain, N/2+1 elements)
|
|
* \param[in] in_q Imag component input buffer (freq domain, N/2+1 elements)
|
|
* \param[in] N Number of points of the DFT
|
|
* \param[in] M Limit to the number of time domain elements to generate
|
|
*
|
|
* The input is assumed to be symmetric and so only N/2+1 inputs are
|
|
* needed. DC component must be input index 0.
|
|
*/
|
|
void
|
|
ambe_idft_cf(float *out, float *in_i, float *in_q, int N, int M)
|
|
{
|
|
int fb, ts;
|
|
|
|
for (ts=0; ts<M; ts++)
|
|
{
|
|
float r=0.0f;
|
|
|
|
for (fb=0; fb<=(N/2); fb++)
|
|
{
|
|
float angle = (- 2.0f * M_PIf / N) * fb * ts;
|
|
float m = (fb == 0 || fb == (N/2)) ? 1.0f : 2.0f;
|
|
r += m * (in_i[fb] * cosf_fast(angle) + in_q[fb] * sinf_fast(angle));
|
|
}
|
|
|
|
out[ts] = r / N;
|
|
}
|
|
}
|
|
|
|
/*! @} */
|