1 /*---------------------------------------------------------------------------*\
2 
3   FILE........: interp.c
4   AUTHOR......: David Rowe
5   DATE CREATED: 9/10/09
6 
7   Interpolation of 20ms frames to 10ms frames.
8 
9 \*---------------------------------------------------------------------------*/
10 
11 /*
12   Copyright (C) 2009 David Rowe
13 
14   All rights reserved.
15 
16   This program is free software; you can redistribute it and/or modify
17   it under the terms of the GNU Lesser General Public License version 2.1, as
18   published by the Free Software Foundation.  This program is
19   distributed in the hope that it will be useful, but WITHOUT ANY
20   WARRANTY; without even the implied warranty of MERCHANTABILITY or
21   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
22   License for more details.
23 
24   You should have received a copy of the GNU Lesser General Public License
25   along with this program; if not, see <http://www.gnu.org/licenses/>.
26 */
27 
28 #include <assert.h>
29 #include <math.h>
30 #include <string.h>
31 #include <stdio.h>
32 
33 #include "defines.h"
34 #include "interp.h"
35 #include "lsp.h"
36 #include "quantise.h"
37 
38 float sample_log_amp(MODEL *model, float w);
39 
40 #if 0
41 /*---------------------------------------------------------------------------*\
42 
43   FUNCTION....: interp()
44   AUTHOR......: David Rowe
45   DATE CREATED: 22/8/10
46 
47   Given two frames decribed by model parameters 20ms apart, determines
48   the model parameters of the 10ms frame between them.  Assumes
49   voicing is available for middle (interpolated) frame.  Outputs are
50   amplitudes and Wo for the interpolated frame.
51 
52   This version can interpolate the amplitudes between two frames of
53   different Wo and L.
54 
55   This version works by log linear interpolation, but listening tests
56   showed it creates problems in background noise, e.g. hts2a and mmt1.
57   When this function is used (--dec mode) bg noise appears to be
58   amplitude modulated, and gets louder.  The interp_lsp() function
59   below seems to do a better job.
60 
61 \*---------------------------------------------------------------------------*/
62 
63 void interpolate(
64   MODEL *interp,    /* interpolated model params                     */
65   MODEL *prev,      /* previous frames model params                  */
66   MODEL *next,      /* next frames model params                      */
67   float Wo_min
68 )
69 {
70     int   l;
71     float w,log_amp;
72 
73     /* Wo depends on voicing of this and adjacent frames */
74 
75     if (interp->voiced) {
76 	if (prev->voiced && next->voiced)
77 	    interp->Wo = (prev->Wo + next->Wo)/2.0;
78 	if (!prev->voiced && next->voiced)
79 	    interp->Wo = next->Wo;
80 	if (prev->voiced && !next->voiced)
81 	    interp->Wo = prev->Wo;
82     }
83     else {
84 	interp->Wo = Wo_min;
85     }
86     interp->L = PI/interp->Wo;
87 
88     /* Interpolate amplitudes using linear interpolation in log domain */
89 
90     for(l=1; l<=interp->L; l++) {
91 	w = l*interp->Wo;
92 	log_amp = (sample_log_amp(prev, w) + sample_log_amp(next, w))/2.0;
93 	interp->A[l] = powf(10.0, log_amp);
94     }
95 }
96 #endif
97 
98 /*---------------------------------------------------------------------------*\
99 
100   FUNCTION....: sample_log_amp()
101   AUTHOR......: David Rowe
102   DATE CREATED: 22/8/10
103 
104   Samples the amplitude envelope at an arbitrary frequency w.  Uses
105   linear interpolation in the log domain to sample between harmonic
106   amplitudes.
107 
108 \*---------------------------------------------------------------------------*/
109 
sample_log_amp(MODEL * model,float w)110 float sample_log_amp(MODEL *model, float w)
111 {
112     int   m;
113     float f, log_amp;
114 
115     assert(w > 0.0); assert (w <= PI);
116 
117     m = floorf(w/model->Wo + 0.5);
118     f = (w - m*model->Wo)/w;
119     assert(f <= 1.0);
120 
121     if (m < 1) {
122 	log_amp = f*log10f(model->A[1] + 1E-6);
123     }
124     else if ((m+1) > model->L) {
125 	log_amp = (1.0-f)*log10f(model->A[model->L] + 1E-6);
126     }
127     else {
128 	log_amp = (1.0-f)*log10f(model->A[m] + 1E-6) +
129                   f*log10f(model->A[m+1] + 1E-6);
130     }
131 
132     return log_amp;
133 }
134 
135 #ifdef NOT_NEEDED
136 
137 /*---------------------------------------------------------------------------*\
138 
139   FUNCTION....: interp_lsp()
140   AUTHOR......: David Rowe
141   DATE CREATED: 10 Nov 2010
142 
143   Given two frames decribed by model parameters 20ms apart, determines
144   the model parameters of the 10ms frame between them.  Assumes
145   voicing is available for middle (interpolated) frame.  Outputs are
146   amplitudes and Wo for the interpolated frame.
147 
148   This version uses interpolation of LSPs, seems to do a better job
149   with bg noise.
150 
151 \*---------------------------------------------------------------------------*/
152 
interpolate_lsp(codec2_fft_cfg fft_fwd_cfg,MODEL * interp,MODEL * prev,MODEL * next,float * prev_lsps,float prev_e,float * next_lsps,float next_e,float * ak_interp,float * lsps_interp,float Wo_min)153 void interpolate_lsp(
154   codec2_fft_cfg  fft_fwd_cfg,
155   MODEL *interp,      /* interpolated model params                     */
156   MODEL *prev,        /* previous frames model params                  */
157   MODEL *next,        /* next frames model params                      */
158   float *prev_lsps,   /* previous frames LSPs                          */
159   float  prev_e,      /* previous frames LPC energy                    */
160   float *next_lsps,   /* next frames LSPs                              */
161   float  next_e,      /* next frames LPC energy                        */
162   float *ak_interp,   /* interpolated aks for this frame               */
163   float *lsps_interp, /* interpolated lsps for this frame              */
164   float  Wo_min
165 )
166 {
167     int   i;
168     float e;
169     float snr;
170 
171     /* trap corner case where V est is probably wrong */
172 
173     if (interp->voiced && !prev->voiced && !next->voiced) {
174 	interp->voiced = 0;
175     }
176 
177     /* Wo depends on voicing of this and adjacent frames */
178 
179     if (interp->voiced) {
180 	if (prev->voiced && next->voiced)
181 	    interp->Wo = (prev->Wo + next->Wo)/2.0;
182 	if (!prev->voiced && next->voiced)
183 	    interp->Wo = next->Wo;
184 	if (prev->voiced && !next->voiced)
185 	    interp->Wo = prev->Wo;
186     }
187     else {
188 	interp->Wo = Wo_min;
189     }
190     interp->L = PI/interp->Wo;
191 
192     //printf("  interp: prev_v: %d next_v: %d prev_Wo: %f next_Wo: %f\n",
193     //	   prev->voiced, next->voiced, prev->Wo, next->Wo);
194     //printf("  interp: Wo: %1.5f  L: %d\n", interp->Wo, interp->L);
195 
196     /* interpolate LSPs */
197 
198     for(i=0; i<LPC_ORD; i++) {
199 	lsps_interp[i] = (prev_lsps[i] + next_lsps[i])/2.0;
200     }
201 
202     /* Interpolate LPC energy in log domain */
203 
204     e = powf(10.0, (log10f(prev_e) + log10f(next_e))/2.0);
205     //printf("  interp: e: %f\n", e);
206 
207     /* convert back to amplitudes */
208 
209     lsp_to_lpc(lsps_interp, ak_interp, LPC_ORD);
210     aks_to_M2(fft_fwd_cfg, ak_interp, LPC_ORD, interp, e, &snr, 0, 0, 1, 1, LPCPF_BETA, LPCPF_GAMMA);
211     //printf("  interp: ak[1]: %f A[1] %f\n", ak_interp[1], interp->A[1]);
212 }
213 #endif
214 
215 /*---------------------------------------------------------------------------*\
216 
217   FUNCTION....: interp_Wo()
218   AUTHOR......: David Rowe
219   DATE CREATED: 22 May 2012
220 
221   Interpolates centre 10ms sample of Wo and L samples given two
222   samples 20ms apart. Assumes voicing is available for centre
223   (interpolated) frame.
224 
225 \*---------------------------------------------------------------------------*/
226 
interp_Wo(MODEL * interp,MODEL * prev,MODEL * next,float Wo_min)227 void interp_Wo(
228   MODEL *interp,    /* interpolated model params                     */
229   MODEL *prev,      /* previous frames model params                  */
230   MODEL *next,      /* next frames model params                      */
231   float  Wo_min
232 	       )
233 {
234     interp_Wo2(interp, prev, next, 0.5, Wo_min);
235 }
236 
237 /*---------------------------------------------------------------------------*\
238 
239   FUNCTION....: interp_Wo2()
240   AUTHOR......: David Rowe
241   DATE CREATED: 22 May 2012
242 
243   Weighted interpolation of two Wo samples.
244 
245 \*---------------------------------------------------------------------------*/
246 
interp_Wo2(MODEL * interp,MODEL * prev,MODEL * next,float weight,float Wo_min)247 void interp_Wo2(
248   MODEL *interp,    /* interpolated model params                     */
249   MODEL *prev,      /* previous frames model params                  */
250   MODEL *next,      /* next frames model params                      */
251   float  weight,
252   float  Wo_min
253 )
254 {
255     /* trap corner case where voicing est is probably wrong */
256 
257     if (interp->voiced && !prev->voiced && !next->voiced) {
258 	interp->voiced = 0;
259     }
260 
261     /* Wo depends on voicing of this and adjacent frames */
262 
263     if (interp->voiced) {
264 	if (prev->voiced && next->voiced)
265 	    interp->Wo = (1.0 - weight)*prev->Wo + weight*next->Wo;
266 	if (!prev->voiced && next->voiced)
267 	    interp->Wo = next->Wo;
268 	if (prev->voiced && !next->voiced)
269 	    interp->Wo = prev->Wo;
270     }
271     else {
272 	interp->Wo = Wo_min;
273     }
274     interp->L = PI/interp->Wo;
275 }
276 
277 
278 /*---------------------------------------------------------------------------*\
279 
280   FUNCTION....: interp_energy()
281   AUTHOR......: David Rowe
282   DATE CREATED: 22 May 2012
283 
284   Interpolates centre 10ms sample of energy given two samples 20ms
285   apart.
286 
287 \*---------------------------------------------------------------------------*/
288 
interp_energy(float prev_e,float next_e)289 float interp_energy(float prev_e, float next_e)
290 {
291     //return powf(10.0, (log10f(prev_e) + log10f(next_e))/2.0);
292     return sqrtf(prev_e * next_e); //looks better is math. identical and faster math
293 }
294 
295 
296 /*---------------------------------------------------------------------------*\
297 
298   FUNCTION....: interp_energy2()
299   AUTHOR......: David Rowe
300   DATE CREATED: 22 May 2012
301 
302   Interpolates centre 10ms sample of energy given two samples 20ms
303   apart.
304 
305 \*---------------------------------------------------------------------------*/
306 
interp_energy2(float prev_e,float next_e,float weight)307 float interp_energy2(float prev_e, float next_e, float weight)
308 {
309     return POW10F((1.0 - weight)*log10f(prev_e) + weight*log10f(next_e));
310 
311 }
312 
313 
314 /*---------------------------------------------------------------------------*\
315 
316   FUNCTION....: interpolate_lsp_ver2()
317   AUTHOR......: David Rowe
318   DATE CREATED: 22 May 2012
319 
320   Weighted interpolation of LSPs.
321 
322 \*---------------------------------------------------------------------------*/
323 
interpolate_lsp_ver2(float interp[],float prev[],float next[],float weight,int order)324 void interpolate_lsp_ver2(float interp[], float prev[],  float next[], float weight, int order)
325 {
326     int i;
327 
328     for(i=0; i<order; i++)
329 	interp[i] = (1.0 - weight)*prev[i] + weight*next[i];
330 }
331 
332