You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
6.4 KiB
C++
249 lines
6.4 KiB
C++
/*
|
|
* Project 25 IMBE Encoder/Decoder Fixed-Point implementation
|
|
* Developed by Pavel Yazev E-mail: pyazev@gmail.com
|
|
* Version 1.0 (c) Copyright 2009
|
|
*
|
|
* This is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* The software 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this; see the file COPYING. If not, write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
|
|
* 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
#include "typedef.h"
|
|
#include "basic_op.h"
|
|
#include "imbe.h"
|
|
#include "aux_sub.h"
|
|
#include "dsp_sub.h"
|
|
#include "math_sub.h"
|
|
#include "v_synt.h"
|
|
#include "rand_gen.h"
|
|
#include "tbls.h"
|
|
#include "encode.h"
|
|
#include "imbe_vocoder_impl.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CNST_0_1_Q1_15 0x0CCD
|
|
|
|
|
|
|
|
void imbe_vocoder_impl::v_synt_init(void)
|
|
{
|
|
Word16 i;
|
|
|
|
for(i = 0; i < NUM_HARMS_MAX; i++)
|
|
{
|
|
ph_mem[i] = L_deposit_h(rand_gen());
|
|
vu_dsn_prev[i] = 0;
|
|
}
|
|
|
|
num_harms_prev3 = 0;
|
|
fund_freq_prev = 0;
|
|
}
|
|
|
|
|
|
void imbe_vocoder_impl::v_synt(IMBE_PARAM *imbe_param, Word16 *snd)
|
|
{
|
|
Word32 L_tmp, L_tmp1, fund_freq, L_snd[FRAME], L_ph_acc, L_ph_step;
|
|
Word32 L_ph_acc_aux, L_ph_step_prev, L_amp_acc, L_amp_step, L_ph_step_aux;
|
|
Word16 num_harms, i, j, *vu_dsn, *sa, *s_ptr, *s_ptr_aux, num_harms_max, num_harms_max_4;
|
|
UWord32 ph_mem_prev[NUM_HARMS_MAX], dph[NUM_HARMS_MAX];
|
|
Word16 num_harms_inv, num_harms_sh, num_uv;
|
|
Word16 freq_flag;
|
|
|
|
|
|
fund_freq = imbe_param->fund_freq;
|
|
num_harms = imbe_param->num_harms;
|
|
vu_dsn = imbe_param->v_uv_dsn;
|
|
sa = imbe_param->sa;
|
|
num_harms_inv = imbe_param->div_one_by_num_harm;
|
|
num_harms_sh = imbe_param->div_one_by_num_harm_sh;
|
|
num_uv = imbe_param->l_uv;
|
|
|
|
for(i = 0; i < FRAME; i++)
|
|
L_snd[i] = 0;
|
|
|
|
// Update phases (calculated phase value correspond to bound of frame)
|
|
L_tmp = (((fund_freq_prev + fund_freq) >> 7) * FRAME/2) << 7; // It is performed integer multiplication by mod 1
|
|
|
|
L_ph_acc = 0;
|
|
for(i = 0; i < NUM_HARMS_MAX; i++)
|
|
{
|
|
ph_mem_prev[i] = ph_mem[i];
|
|
L_ph_acc += L_tmp;
|
|
ph_mem[i] += L_ph_acc;
|
|
dph[i] = 0;
|
|
}
|
|
|
|
num_harms_max = (num_harms >= num_harms_prev3)?num_harms:num_harms_prev3;
|
|
num_harms_max_4 = num_harms_max >> 2;
|
|
|
|
if(L_abs(L_sub(fund_freq, fund_freq_prev)) >= L_mpy_ls(fund_freq, CNST_0_1_Q1_15))
|
|
freq_flag = 1;
|
|
else
|
|
freq_flag = 0;
|
|
|
|
L_ph_step = L_ph_step_prev = 0;
|
|
for(i = 0; i < num_harms_max; i++)
|
|
{
|
|
L_ph_step += fund_freq;
|
|
L_ph_step_prev += fund_freq_prev;
|
|
|
|
|
|
if(i > num_harms_max_4)
|
|
{
|
|
if(num_uv == num_harms)
|
|
{
|
|
dph[i] = L_deposit_h(rand_gen());
|
|
}
|
|
else
|
|
{
|
|
L_tmp = L_mult(rand_gen(), num_harms_inv);
|
|
dph[i] = L_shr(L_tmp, 15 - num_harms_sh) * num_uv;
|
|
}
|
|
ph_mem[i] += dph[i];
|
|
}
|
|
|
|
if(vu_dsn[i] == 0 && vu_dsn_prev[i] == 0)
|
|
continue;
|
|
|
|
if(vu_dsn[i] == 1 && vu_dsn_prev[i] == 0) // unvoiced => voiced
|
|
{
|
|
s_ptr = (Word16 *)ws;
|
|
L_ph_acc = ph_mem[i] - (((L_ph_step >> 7) * 104) << 7);
|
|
for(j = 56; j <= 104; j++)
|
|
{
|
|
L_tmp = L_mult(*s_ptr++, sa[i]);
|
|
L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
L_ph_acc += L_ph_step;
|
|
}
|
|
|
|
for(j = 105; j <= 159; j++)
|
|
{
|
|
L_tmp = L_mult(sa[i], cos_fxp(extract_h(L_ph_acc)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
L_ph_acc += L_ph_step;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
|
|
if(vu_dsn[i] == 0 && vu_dsn_prev[i] == 1) // voiced => unvoiced
|
|
{
|
|
s_ptr = (Word16 *)&ws[48];
|
|
L_ph_acc = ph_mem_prev[i];
|
|
|
|
for(j = 0; j <= 55; j++)
|
|
{
|
|
L_tmp = L_mult(sa_prev3[i], cos_fxp(extract_h(L_ph_acc)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
L_ph_acc += L_ph_step_prev;
|
|
}
|
|
|
|
for(j = 56; j <= 104; j++)
|
|
{
|
|
L_tmp = L_mult(*s_ptr--, sa_prev3[i]);
|
|
L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
L_ph_acc += L_ph_step_prev;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if(i >=7 || freq_flag)
|
|
{
|
|
s_ptr_aux = (Word16 *)&ws[48];
|
|
L_ph_acc_aux = ph_mem_prev[i];
|
|
|
|
s_ptr = (Word16 *)ws;
|
|
L_ph_acc = ph_mem[i] - (((L_ph_step >> 7) * 104) << 7);
|
|
|
|
for(j = 0; j <= 55; j++)
|
|
{
|
|
L_tmp = L_mult(sa_prev3[i], cos_fxp(extract_h(L_ph_acc_aux)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
L_ph_acc_aux += L_ph_step_prev;
|
|
}
|
|
|
|
for(j = 56; j <= 104; j++)
|
|
{
|
|
L_tmp = L_mult(*s_ptr_aux--, sa_prev3[i]);
|
|
L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc_aux)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
|
|
L_tmp = L_mult(*s_ptr++, sa[i]);
|
|
L_tmp = L_mpy_ls(L_tmp, cos_fxp(extract_h(L_ph_acc)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
|
|
L_ph_acc_aux += L_ph_step_prev;
|
|
L_ph_acc += L_ph_step;
|
|
}
|
|
|
|
for(j = 105; j <= 159; j++)
|
|
{
|
|
L_tmp = L_mult(sa[i], cos_fxp(extract_h(L_ph_acc)));
|
|
L_tmp = L_shr(L_tmp, 1);
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
L_ph_acc += L_ph_step;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
L_amp_step = L_mpy_ls(L_shr(L_deposit_h(sub(sa[i], sa_prev3[i])), 4 + 1), CNST_0_1_Q1_15); // (sa[i] - sa_prev3[i]) / 160, 1/160 = 0.1/16
|
|
L_amp_acc = L_shr(L_deposit_h(sa_prev3[i]), 1);
|
|
|
|
|
|
L_ph_step_aux = L_mpy_ls(L_shr(fund_freq - fund_freq_prev, 4 + 1), CNST_0_1_Q1_15); // (fund_freq - fund_freq_prev)/(2*160)
|
|
L_ph_step_aux = ((L_ph_step_aux >> 7) * (i + 1)) << 7;
|
|
|
|
L_ph_acc = ph_mem_prev[i];
|
|
|
|
L_tmp1 = L_mpy_ls(L_shr(dph[i], 4), CNST_0_1_Q1_15); // dph[i] / 160
|
|
|
|
for(j = 0; j < 160; j++)
|
|
{
|
|
L_ph_acc_aux = ((L_ph_step_aux >> 9) * j) << 9;
|
|
L_ph_acc_aux = ((L_ph_acc_aux >> 9) * j) << 9;
|
|
|
|
L_tmp = L_mpy_ls(L_amp_acc, cos_fxp(extract_h(L_ph_acc + L_ph_acc_aux)));
|
|
L_snd[j] = L_add(L_snd[j], L_tmp);
|
|
|
|
L_amp_acc = L_add(L_amp_acc, L_amp_step);
|
|
L_ph_acc += L_ph_step_prev;
|
|
L_ph_acc += L_tmp1;
|
|
}
|
|
}
|
|
|
|
for(i = 0; i < FRAME; i++)
|
|
*snd++ = extract_h(L_snd[i]);
|
|
|
|
v_zap(vu_dsn_prev, NUM_HARMS_MAX);
|
|
v_equ(vu_dsn_prev, imbe_param->v_uv_dsn, num_harms);
|
|
v_equ(sa_prev3, imbe_param->sa, num_harms);
|
|
|
|
num_harms_prev3 = num_harms;
|
|
fund_freq_prev = fund_freq;
|
|
}
|