5
|
1 /*
|
|
2 * SpanDSP - a series of DSP components for telephony
|
|
3 *
|
|
4 * lpc10_placev.c - LPC10 low bit rate speech codec.
|
|
5 *
|
|
6 * Written by Steve Underwood <steveu@coppice.org>
|
|
7 *
|
|
8 * Copyright (C) 2006 Steve Underwood
|
|
9 *
|
|
10 * All rights reserved.
|
|
11 *
|
|
12 * This program is free software; you can redistribute it and/or modify
|
|
13 * it under the terms of the GNU General Public License version 2, as
|
|
14 * published by the Free Software Foundation.
|
|
15 *
|
|
16 * This program is distributed in the hope that it will be useful,
|
|
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19 * GNU General Public License for more details.
|
|
20 *
|
|
21 * You should have received a copy of the GNU General Public License
|
|
22 * along with this program; if not, write to the Free Software
|
|
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
24 *
|
|
25 * This code is based on the U.S. Department of Defense reference
|
|
26 * implementation of the LPC-10 2400 bps Voice Coder. They do not
|
|
27 * exert copyright claims on their code, and it may be freely used.
|
|
28 *
|
|
29 * $Id: lpc10_placev.c,v 1.11 2006/11/21 13:32:27 steveu Exp $
|
|
30 */
|
|
31
|
|
32 #ifdef HAVE_CONFIG_H
|
|
33 #include <config.h>
|
|
34 #endif
|
|
35
|
|
36 #include <stdlib.h>
|
|
37 #include <stdio.h>
|
|
38 #include <inttypes.h>
|
|
39 #include <memory.h>
|
|
40 #if defined(HAVE_TGMATH_H)
|
|
41 #include <tgmath.h>
|
|
42 #endif
|
|
43 #if defined(HAVE_MATH_H)
|
|
44 #include <math.h>
|
|
45 #endif
|
|
46
|
|
47 #include "spandsp/telephony.h"
|
|
48 #include "spandsp/dc_restore.h"
|
|
49 #include "spandsp/lpc10.h"
|
|
50
|
|
51 #include "lpc10_encdecs.h"
|
|
52
|
|
53 #define subsc(x,y) (((x) << 1) + (y))
|
|
54
|
|
55 void lpc10_placea(int32_t *ipitch,
|
|
56 int32_t voibuf[3][2],
|
|
57 int32_t *obound,
|
|
58 int32_t af,
|
|
59 int32_t vwin[3][2],
|
|
60 int32_t awin[3][2],
|
|
61 int32_t ewin[3][2],
|
|
62 int32_t lframe,
|
|
63 int32_t maxwin)
|
|
64 {
|
|
65 int allv;
|
|
66 int winv;
|
|
67 int32_t i;
|
|
68 int32_t j;
|
|
69 int32_t k;
|
|
70 int32_t l;
|
|
71 int32_t hrange;
|
|
72 int ephase;
|
|
73 int32_t lrange;
|
|
74
|
|
75 lrange = (af - 2)*lframe + 1;
|
|
76 hrange = af*lframe;
|
|
77
|
|
78 /* Place the analysis window based on the voicing window placement,
|
|
79 onsets, tentative voicing decision, and pitch. */
|
|
80
|
|
81 /* Case 1: Sustained voiced speech
|
|
82 If the five most recent voicing decisions are
|
|
83 voiced, then the window is placed phase-synchronously with the
|
|
84 previous window, as close to the present voicing window if possible.
|
|
85 If onsets bound the voicing window, then preference is given to
|
|
86 a phase-synchronous placement which does not overlap these onsets. */
|
|
87
|
|
88 /* Case 2: Voiced transition
|
|
89 If at least one voicing decision in AF is voicied, and there are no
|
|
90 onsets, then the window is placed as in case 1. */
|
|
91
|
|
92 /* Case 3: Unvoiced speech or onsets
|
|
93 If both voicing decisions in AF are unvoiced, or there are onsets
|
|
94 then the window is placed coincident with the voicing window. */
|
|
95
|
|
96 /* Note: During phase-synchronous placement of windows, the length
|
|
97 is not altered from MAXWIN, since this would defeat the purpose
|
|
98 of phase-synchronous placement. */
|
|
99
|
|
100 /* Check for case 1 and case 2 */
|
|
101 allv = voibuf[af - 2][1] == 1
|
|
102 &&
|
|
103 voibuf[af - 1][0] == 1
|
|
104 &&
|
|
105 voibuf[af - 1][1] == 1
|
|
106 &&
|
|
107 voibuf[af][0] == 1
|
|
108 &&
|
|
109 voibuf[af][1] == 1;
|
|
110 winv = voibuf[af][0] == 1 || voibuf[af][1] == 1;
|
|
111 if (allv || (winv && *obound == 0))
|
|
112 {
|
|
113 /* APHASE: Phase synchronous window placement. */
|
|
114 /* Get minimum lower index of the window. */
|
|
115 i = (lrange + *ipitch - 1 - awin[af - 2][0]) / *ipitch;
|
|
116 i *= *ipitch;
|
|
117 i += awin[af - 2][0];
|
|
118 /* l = the actual length of this frame's analysis window. */
|
|
119 l = maxwin;
|
|
120 /* Calculate the location where a perfectly centered window would start. */
|
|
121 k = (vwin[af - 1][0] + vwin[af - 1][1] + 1 - l)/2;
|
|
122 /* Choose the actual location to be the pitch multiple closest to this */
|
|
123 awin[af - 1][0] = i + lroundf((float) (k - i) / (float) *ipitch) * *ipitch;
|
|
124 awin[af - 1][1] = awin[af - 1][0] + l - 1;
|
|
125 /* If there is an onset bounding the right of the voicing window and the
|
|
126 analysis window overlaps that, then move the analysis window backward
|
|
127 to avoid this onset. */
|
|
128 if (*obound >= 2 && awin[af - 1][1] > vwin[af - 1][1])
|
|
129 {
|
|
130 awin[af - 1][0] -= *ipitch;
|
|
131 awin[af - 1][1] -= *ipitch;
|
|
132 }
|
|
133 /* Similarly for the left of the voicing window. */
|
|
134 if ((*obound == 1 || *obound == 3) && awin[af - 1][0] < vwin[af - 1][0])
|
|
135 {
|
|
136 awin[af - 1][0] += *ipitch;
|
|
137 awin[af - 1][1] += *ipitch;
|
|
138 }
|
|
139 /* If this placement puts the analysis window above HRANGE, then
|
|
140 move it backward an integer number of pitch periods. */
|
|
141 while (awin[af - 1][1] > hrange)
|
|
142 {
|
|
143 awin[af - 1][0] -= *ipitch;
|
|
144 awin[af - 1][1] -= *ipitch;
|
|
145 }
|
|
146 /* Similarly if the placement puts the analysis window below LRANGE. */
|
|
147 while (awin[af - 1][0] < lrange)
|
|
148 {
|
|
149 awin[af - 1][0] += *ipitch;
|
|
150 awin[af - 1][1] += *ipitch;
|
|
151 }
|
|
152 /* Make energy window be phase-synchronous. */
|
|
153 ephase = TRUE;
|
|
154 }
|
|
155 else
|
|
156 {
|
|
157 /* Case 3 */
|
|
158 awin[af - 1][0] = vwin[af - 1][0];
|
|
159 awin[af - 1][1] = vwin[af - 1][1];
|
|
160 ephase = FALSE;
|
|
161 }
|
|
162 /* RMS is computed over an integer number of pitch periods in the analysis
|
|
163 window. When it is not placed phase-synchronously, it is placed as close
|
|
164 as possible to onsets. */
|
|
165 j = (awin[af - 1][1] - awin[af - 1][0] + 1) / *ipitch * *ipitch;
|
|
166 if (j == 0 || !winv)
|
|
167 {
|
|
168 ewin[af - 1][0] = vwin[af - 1][0];
|
|
169 ewin[af - 1][1] = vwin[af - 1][1];
|
|
170 }
|
|
171 else if (!ephase && *obound == 2)
|
|
172 {
|
|
173 ewin[af - 1][0] = awin[af - 1][1] - j + 1;
|
|
174 ewin[af - 1][1] = awin[af - 1][1];
|
|
175 }
|
|
176 else
|
|
177 {
|
|
178 ewin[af - 1][0] = awin[af - 1][0];
|
|
179 ewin[af - 1][1] = awin[af - 1][0] + j - 1;
|
|
180 }
|
|
181 }
|
|
182 /*- End of function --------------------------------------------------------*/
|
|
183
|
|
184 void lpc10_placev(int32_t *osbuf,
|
|
185 int32_t *osptr,
|
|
186 int32_t oslen,
|
|
187 int32_t *obound,
|
|
188 int32_t vwin[3][2],
|
|
189 int32_t af,
|
|
190 int32_t lframe,
|
|
191 int32_t minwin,
|
|
192 int32_t maxwin,
|
|
193 int32_t dvwinl,
|
|
194 int32_t dvwinh)
|
|
195 {
|
|
196 int32_t i1;
|
|
197 int32_t i2;
|
|
198 int crit;
|
|
199 int32_t q;
|
|
200 int32_t osptr1;
|
|
201 int32_t hrange;
|
|
202 int32_t lrange;
|
|
203 int i;
|
|
204
|
|
205 /* Voicing window placement */
|
|
206
|
|
207 /* __________________ __________________ ______________ */
|
|
208 /* | | | */
|
|
209 /* | 1F | 2F | 3F ... */
|
|
210 /* |__________________|__________________|______________ */
|
|
211
|
|
212 /* Previous | */
|
|
213 /* Window | */
|
|
214 /* ...________| */
|
|
215
|
|
216 /* | | */
|
|
217 /* ------>| This window's placement range |<------ */
|
|
218 /* | | */
|
|
219
|
|
220 /* There are three cases. Note these are different from those
|
|
221 given in the LPC-10e phase 1 report. */
|
|
222
|
|
223 /* 1. If there are no onsets in this range, then the voicing window
|
|
224 is centered in the pitch window. If such a placement is not within
|
|
225 the window's placement range, then the window is placed in the left-most
|
|
226 portion of the placement range. Its length is always MAXWIN. */
|
|
227
|
|
228 /* 2. If the first onset is in 2F and there is sufficient room to place
|
|
229 the window immediately before this onset, then the window is placed
|
|
230 there, and its length is set to the maximum possible under these
|
|
231 constraints. */
|
|
232
|
|
233 /* "Critical Region Exception": If there is another onset in 2F
|
|
234 such that a window can be placed between the two onsets, the
|
|
235 window is placed there (ie, as in case 3). */
|
|
236
|
|
237 /* 3. Otherwise, the window is placed immediately after the onset. The
|
|
238 window's length is the longest length that can fit in the range under these
|
|
239 constraints, except that the window may be shortened even further to avoid
|
|
240 overlapping other onsets in the placement range. In any case, the window's
|
|
241 length is at least MINWIN. */
|
|
242
|
|
243 /* Note that the values of MINWIN and LFRAME must be chosen such
|
|
244 that case 2 = false implies case 3 = true. This means that
|
|
245 MINWIN <= LFRAME/2. If this were not the case, then a fourth case
|
|
246 would have to be added for when the window cannot fit either before
|
|
247 or after the onset. */
|
|
248
|
|
249 /* Note also that onsets which weren't in 2F last time may be in 1F this
|
|
250 time, due to the filter delays in computing onsets. The result is that
|
|
251 occasionally a voicing window will overlap that onset. The only way
|
|
252 to circumvent this problem is to add more delay in processing input
|
|
253 speech. In the trade-off between delay and window-placement, window
|
|
254 placement lost. */
|
|
255
|
|
256 /* Compute the placement range */
|
|
257
|
|
258 /* Computing MAX */
|
|
259 i1 = vwin[af - 2][1] + 1;
|
|
260 i2 = (af - 2)*lframe + 1;
|
|
261 lrange = max(i1, i2);
|
|
262 hrange = af*lframe;
|
|
263 /* Compute OSPTR1, so the following code only looks at relevant onsets. */
|
|
264 for (osptr1 = *osptr - 1; osptr1 >= 1; osptr1--)
|
|
265 {
|
|
266 if (osbuf[osptr1 - 1] <= hrange)
|
|
267 break;
|
|
268 }
|
|
269 osptr1++;
|
|
270 /* Check for case 1 first (fast case) */
|
|
271 if (osptr1 <= 1 || osbuf[osptr1 - 2] < lrange)
|
|
272 {
|
|
273 /* Compute max */
|
|
274 i1 = vwin[af - 2][1] + 1;
|
|
275 vwin[af - 1][0] = max(i1, dvwinl);
|
|
276 vwin[af - 1][1] = vwin[af - 1][0] + maxwin - 1;
|
|
277 *obound = 0;
|
|
278 }
|
|
279 else
|
|
280 {
|
|
281 /* Search backward in OSBUF for first onset in range. */
|
|
282 /* This code relies on the above check being performed first. */
|
|
283 for (q = osptr1 - 1; q >= 1; q--)
|
|
284 {
|
|
285 if (osbuf[q - 1] < lrange)
|
|
286 break;
|
|
287 }
|
|
288 q++;
|
|
289 /* Check for case 2 (placement before onset): */
|
|
290 /* Check for critical region exception: */
|
|
291 crit = FALSE;
|
|
292 for (i = q + 1; i < osptr1; i++)
|
|
293 {
|
|
294 if (osbuf[i - 1] - osbuf[q - 1] >= minwin)
|
|
295 {
|
|
296 crit = TRUE;
|
|
297 break;
|
|
298 }
|
|
299 }
|
|
300 /* Compute max */
|
|
301 i1 = (af - 1)*lframe;
|
|
302 i2 = lrange + minwin - 1;
|
|
303 if (!crit && osbuf[q - 1] > max(i1, i2))
|
|
304 {
|
|
305 vwin[af - 1][1] = osbuf[q - 1] - 1;
|
|
306 /* Compute max */
|
|
307 i2 = vwin[af - 1][1] - maxwin + 1;
|
|
308 vwin[af - 1][0] = max(lrange, i2);
|
|
309 *obound = 2;
|
|
310 }
|
|
311 else
|
|
312 {
|
|
313 /* Case 3 (placement after onset) */
|
|
314 vwin[af - 1][0] = osbuf[q - 1];
|
|
315 do
|
|
316 {
|
|
317 if (++q >= osptr1
|
|
318 ||
|
|
319 osbuf[q - 1] > vwin[af - 1][0] + maxwin)
|
|
320 {
|
|
321 /* Compute min */
|
|
322 i1 = vwin[af - 1][0] + maxwin - 1;
|
|
323 vwin[af - 1][1] = min(i1, hrange);
|
|
324 *obound = 1;
|
|
325 return;
|
|
326 }
|
|
327 }
|
|
328 while (osbuf[q - 1] < vwin[af - 1][0] + minwin);
|
|
329 vwin[af - 1][1] = osbuf[q - 1] - 1;
|
|
330 *obound = 3;
|
|
331 }
|
|
332 }
|
|
333 }
|
|
334 /*- End of function --------------------------------------------------------*/
|
|
335 /*- End of file ------------------------------------------------------------*/
|