Mercurial > hg > audiostuff
diff spandsp-0.0.6pre17/src/lpc10_placev.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spandsp-0.0.6pre17/src/lpc10_placev.c Fri Jun 25 15:50:58 2010 +0200 @@ -0,0 +1,336 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * lpc10_placev.c - LPC10 low bit rate speech codec. + * + * Written by Steve Underwood <steveu@coppice.org> + * + * Copyright (C) 2006 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This code is based on the U.S. Department of Defense reference + * implementation of the LPC-10 2400 bps Voice Coder. They do not + * exert copyright claims on their code, and it may be freely used. + * + * $Id: lpc10_placev.c,v 1.19 2009/01/28 03:41:27 steveu Exp $ + */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <memory.h> +#if defined(HAVE_TGMATH_H) +#include <tgmath.h> +#endif +#if defined(HAVE_MATH_H) +#include <math.h> +#endif +#include "floating_fudge.h" + +#include "spandsp/telephony.h" +#include "spandsp/dc_restore.h" +#include "spandsp/lpc10.h" + +#include "lpc10_encdecs.h" + +#define subsc(x,y) (((x) << 1) + (y)) + +void lpc10_placea(int32_t *ipitch, + int32_t voibuf[3][2], + int32_t *obound, + int32_t af, + int32_t vwin[3][2], + int32_t awin[3][2], + int32_t ewin[3][2], + int32_t lframe, + int32_t maxwin) +{ + int allv; + int winv; + int32_t i; + int32_t j; + int32_t k; + int32_t l; + int32_t hrange; + int ephase; + int32_t lrange; + + lrange = (af - 2)*lframe + 1; + hrange = af*lframe; + + /* Place the analysis window based on the voicing window placement, + onsets, tentative voicing decision, and pitch. */ + + /* Case 1: Sustained voiced speech + If the five most recent voicing decisions are + voiced, then the window is placed phase-synchronously with the + previous window, as close to the present voicing window if possible. + If onsets bound the voicing window, then preference is given to + a phase-synchronous placement which does not overlap these onsets. */ + + /* Case 2: Voiced transition + If at least one voicing decision in AF is voicied, and there are no + onsets, then the window is placed as in case 1. */ + + /* Case 3: Unvoiced speech or onsets + If both voicing decisions in AF are unvoiced, or there are onsets + then the window is placed coincident with the voicing window. */ + + /* Note: During phase-synchronous placement of windows, the length + is not altered from MAXWIN, since this would defeat the purpose + of phase-synchronous placement. */ + + /* Check for case 1 and case 2 */ + allv = voibuf[af - 2][1] == 1 + && + voibuf[af - 1][0] == 1 + && + voibuf[af - 1][1] == 1 + && + voibuf[af][0] == 1 + && + voibuf[af][1] == 1; + winv = voibuf[af][0] == 1 || voibuf[af][1] == 1; + if (allv || (winv && *obound == 0)) + { + /* APHASE: Phase synchronous window placement. */ + /* Get minimum lower index of the window. */ + i = (lrange + *ipitch - 1 - awin[af - 2][0]) / *ipitch; + i *= *ipitch; + i += awin[af - 2][0]; + /* l = the actual length of this frame's analysis window. */ + l = maxwin; + /* Calculate the location where a perfectly centered window would start. */ + k = (vwin[af - 1][0] + vwin[af - 1][1] + 1 - l)/2; + /* Choose the actual location to be the pitch multiple closest to this */ + awin[af - 1][0] = i + ((int) floorf((float) (k - i)/(float) *ipitch + 0.5f))*(*ipitch); + awin[af - 1][1] = awin[af - 1][0] + l - 1; + /* If there is an onset bounding the right of the voicing window and the + analysis window overlaps that, then move the analysis window backward + to avoid this onset. */ + if (*obound >= 2 && awin[af - 1][1] > vwin[af - 1][1]) + { + awin[af - 1][0] -= *ipitch; + awin[af - 1][1] -= *ipitch; + } + /* Similarly for the left of the voicing window. */ + if ((*obound == 1 || *obound == 3) && awin[af - 1][0] < vwin[af - 1][0]) + { + awin[af - 1][0] += *ipitch; + awin[af - 1][1] += *ipitch; + } + /* If this placement puts the analysis window above HRANGE, then + move it backward an integer number of pitch periods. */ + while (awin[af - 1][1] > hrange) + { + awin[af - 1][0] -= *ipitch; + awin[af - 1][1] -= *ipitch; + } + /* Similarly if the placement puts the analysis window below LRANGE. */ + while (awin[af - 1][0] < lrange) + { + awin[af - 1][0] += *ipitch; + awin[af - 1][1] += *ipitch; + } + /* Make energy window be phase-synchronous. */ + ephase = TRUE; + } + else + { + /* Case 3 */ + awin[af - 1][0] = vwin[af - 1][0]; + awin[af - 1][1] = vwin[af - 1][1]; + ephase = FALSE; + } + /* RMS is computed over an integer number of pitch periods in the analysis + window. When it is not placed phase-synchronously, it is placed as close + as possible to onsets. */ + j = (awin[af - 1][1] - awin[af - 1][0] + 1) / *ipitch * *ipitch; + if (j == 0 || !winv) + { + ewin[af - 1][0] = vwin[af - 1][0]; + ewin[af - 1][1] = vwin[af - 1][1]; + } + else if (!ephase && *obound == 2) + { + ewin[af - 1][0] = awin[af - 1][1] - j + 1; + ewin[af - 1][1] = awin[af - 1][1]; + } + else + { + ewin[af - 1][0] = awin[af - 1][0]; + ewin[af - 1][1] = awin[af - 1][0] + j - 1; + } +} +/*- End of function --------------------------------------------------------*/ + +void lpc10_placev(int32_t *osbuf, + int32_t *osptr, + int32_t oslen, + int32_t *obound, + int32_t vwin[3][2], + int32_t af, + int32_t lframe, + int32_t minwin, + int32_t maxwin, + int32_t dvwinl, + int32_t dvwinh) +{ + int32_t i1; + int32_t i2; + int crit; + int32_t q; + int32_t osptr1; + int32_t hrange; + int32_t lrange; + int i; + + /* Voicing window placement */ + + /* __________________ __________________ ______________ */ + /* | | | */ + /* | 1F | 2F | 3F ... */ + /* |__________________|__________________|______________ */ + + /* Previous | */ + /* Window | */ + /* ...________| */ + + /* | | */ + /* ------>| This window's placement range |<------ */ + /* | | */ + + /* There are three cases. Note these are different from those + given in the LPC-10e phase 1 report. */ + + /* 1. If there are no onsets in this range, then the voicing window + is centered in the pitch window. If such a placement is not within + the window's placement range, then the window is placed in the left-most + portion of the placement range. Its length is always MAXWIN. */ + + /* 2. If the first onset is in 2F and there is sufficient room to place + the window immediately before this onset, then the window is placed + there, and its length is set to the maximum possible under these + constraints. */ + + /* "Critical Region Exception": If there is another onset in 2F + such that a window can be placed between the two onsets, the + window is placed there (ie, as in case 3). */ + + /* 3. Otherwise, the window is placed immediately after the onset. The + window's length is the longest length that can fit in the range under these + constraints, except that the window may be shortened even further to avoid + overlapping other onsets in the placement range. In any case, the window's + length is at least MINWIN. */ + + /* Note that the values of MINWIN and LFRAME must be chosen such + that case 2 = false implies case 3 = true. This means that + MINWIN <= LFRAME/2. If this were not the case, then a fourth case + would have to be added for when the window cannot fit either before + or after the onset. */ + + /* Note also that onsets which weren't in 2F last time may be in 1F this + time, due to the filter delays in computing onsets. The result is that + occasionally a voicing window will overlap that onset. The only way + to circumvent this problem is to add more delay in processing input + speech. In the trade-off between delay and window-placement, window + placement lost. */ + + /* Compute the placement range */ + + /* Computing MAX */ + i1 = vwin[af - 2][1] + 1; + i2 = (af - 2)*lframe + 1; + lrange = max(i1, i2); + hrange = af*lframe; + /* Compute OSPTR1, so the following code only looks at relevant onsets. */ + for (osptr1 = *osptr - 1; osptr1 >= 1; osptr1--) + { + if (osbuf[osptr1 - 1] <= hrange) + break; + } + osptr1++; + /* Check for case 1 first (fast case) */ + if (osptr1 <= 1 || osbuf[osptr1 - 2] < lrange) + { + /* Compute max */ + i1 = vwin[af - 2][1] + 1; + vwin[af - 1][0] = max(i1, dvwinl); + vwin[af - 1][1] = vwin[af - 1][0] + maxwin - 1; + *obound = 0; + } + else + { + /* Search backward in OSBUF for first onset in range. */ + /* This code relies on the above check being performed first. */ + for (q = osptr1 - 1; q >= 1; q--) + { + if (osbuf[q - 1] < lrange) + break; + } + q++; + /* Check for case 2 (placement before onset): */ + /* Check for critical region exception: */ + crit = FALSE; + for (i = q + 1; i < osptr1; i++) + { + if (osbuf[i - 1] - osbuf[q - 1] >= minwin) + { + crit = TRUE; + break; + } + } + /* Compute max */ + i1 = (af - 1)*lframe; + i2 = lrange + minwin - 1; + if (!crit && osbuf[q - 1] > max(i1, i2)) + { + vwin[af - 1][1] = osbuf[q - 1] - 1; + /* Compute max */ + i2 = vwin[af - 1][1] - maxwin + 1; + vwin[af - 1][0] = max(lrange, i2); + *obound = 2; + } + else + { + /* Case 3 (placement after onset) */ + vwin[af - 1][0] = osbuf[q - 1]; + do + { + if (++q >= osptr1 + || + osbuf[q - 1] > vwin[af - 1][0] + maxwin) + { + /* Compute min */ + i1 = vwin[af - 1][0] + maxwin - 1; + vwin[af - 1][1] = min(i1, hrange); + *obound = 1; + return; + } + } + while (osbuf[q - 1] < vwin[af - 1][0] + minwin); + vwin[af - 1][1] = osbuf[q - 1] - 1; + *obound = 3; + } + } +} +/*- End of function --------------------------------------------------------*/ +/*- End of file ------------------------------------------------------------*/