?? openlpc.fixed.c
字號:
/*
Fixed point OpenLPC codec
Copyright (C) 2003-2005 Phil Frisbie, Jr. (phil@hawksoft.com)
This is a major rewrite of the orginal floating point OpenLPC
code from Future Dynamics. As such, a copywrite notice is not
required to credit Future Dynamics.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Or go to http://www.gnu.org/copyleft/lgpl.html
*/
/************************************************************************\
Low bitrate LPC CODEC derived from the public domain implementation
of Ron Frederick.
The basic design is preserved, except for several bug fixes and
the following modifications:
1. The pitch detector operates on the (downsampled) signal, not on
the residue. This appears to yield better performances, and it
lowers the processing load.
2. Each frame is elongated by 50% prefixing it with the last half
of the previous frame. This design, inherited from the original
code for windowing purposes, is exploited in order to provide
two independent pitch analyses: on the first 2/3, and on the
second 2/3 of the elongated frame (of course, they overlap by
half):
last half old frame new frame
--------------------========================================
<--------- first pitch region --------->
<--------- second pitch region ------->
Two voiced/unvoiced flags define the voicing status of each
region; only one value for the period is retained (if both
halves are voiced, the average is used).
The two flags are used by the synthesizer for the halves of
each frame to play back. Of course, this is non optimal but
is good enough (a half-frame would be too short for measuring
low pitches)
3. The parameters (one float for the period (pitch), one for the
gain, and ten for the LPC-10 filter) are quantized according
this procedure:
- the period is logarithmically compressed, then quantized
as 8-bit unsigned int (6 would actually suffice)
- the gain is logarithmically compressed (using a different
formula), then quantized at 6-bit unsigned int. The two
remaining bits are used for the voicing flags.
- the first two LPC parameters (k[1] and k[2]) are multiplied
by PI/2, and the arcsine of the result is quantized as
6 and 5 bit signed integers. This has proved more effective
than the log-area compression used by LPC-10.
- the remaining eight LPC parameters (k[3]...k[10]) are
quantized as, respectively, 5,4,4,3,3,3,3 and 2 bit signed
integers.
Finally, period and gain plus voicing flags are stored in the
first two bytes of the 7-byte parameters block, and the quantized
LPC parameters are packed into the remaining 5 bytes. Two bits
remain unassigned, and can be used for error detection or other
purposes.
The frame lenght is actually variable, and is simply passed as
initialization parameter to lpc_init(): this allows to experiment
with various frame lengths. Long frames reduce the bitrate, but
exceeding 320 samples (i.e. 40 ms, at 8000 samples/s) tend to
deteriorate the speech, that sounds like spoken by a person
affected by a stroke: the LPC parameters (modeling the vocal
tract) can't change fast enough for a natural-sounding synthesis.
25 ms per frame already yields a quite tight compression, corresponding
to 1000/40 * 7 * 8 = 1400 bps. The quality improves little with
frames shorter than 250 samples (32 frames/s), so this is a recommended
compromise. The bitrate is 32 * 7 * 8 = 1792 bps.
The synthesizer has been modified as well. For voiced subframes it
now uses a sawtooth excitation, instead of the original pulse train.
This idea, copied from MELP, reduces the buzzing-noise artifacts.
In order to compensate the non-white spectrum of the sawtooth, a
pre-emphasis is applied to the signal before the Durbin calculation.
The filter has (in s-space) two zeroes at (640, 0) Hz and two poles
at (3200, 0) Hz. These filters have been handoded, and may not be
and pre-downsampling lowpass with corner at 300 Hz) are Butterworth
designs produced by the MkFilter package by A.J. Fisher
(http://www.cs.york.ac.uk/~fisher/mkfilter/).
\************************************************************************/
#ifdef _MSC_VER
#pragma warning (disable:4711) /* to disable automatic inline warning */
#define M_PI (3.1415926535897932384626433832795)
#endif
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <math.h>
#include "openlpc.h"
#define fixed32 long
#if defined WIN32 || defined WIN64 || defined (_WIN32_WCE)
#define fixed64 __int64
#else
#define fixed64 long long
#endif
/* These are for development and debugging and should not be changed unless
you REALLY know what you are doing ;) */
#define IGNORE_OVERFLOW
#define FAST_FILTERS
#define PRECISION 20
#define ftofix32(x) ((fixed32)((x) * (float)(1 << PRECISION) + ((x) < 0 ? -0.5 : 0.5)))
#define itofix32(x) ((x) << PRECISION)
#define fixtoi32(x) ((x) >> PRECISION)
#define fixtof32(x) (float)((float)(x) / (float)(1 << PRECISION))
static fixed32 fixmul32(fixed32 x, fixed32 y)
{
fixed64 temp;
temp = x;
temp *= y;
temp >>= PRECISION;
#ifndef IGNORE_OVERFLOW
if(temp > 0x7fffffff)
{
return 0x7fffffff;
}
else if(temp < -0x7ffffffe)
{
return -0x7ffffffe;
}
#endif
return (fixed32)temp;
}
static fixed32 fixdiv32(fixed32 x, fixed32 y)
{
fixed64 temp;
if(x == 0)
return 0;
if(y == 0)
return 0x7fffffff;
temp = x;
temp <<= PRECISION;
return (fixed32)(temp / y);
}
static fixed32 fixsqrt32(fixed32 x)
{
unsigned long r = 0, s, v = (unsigned long)x;
#define STEP(k) s = r + (1 << k * 2); r >>= 1; \
if (s <= v) { v -= s; r |= (1 << k * 2); }
STEP(15);
STEP(14);
STEP(13);
STEP(12);
STEP(11);
STEP(10);
STEP(9);
STEP(8);
STEP(7);
STEP(6);
STEP(5);
STEP(4);
STEP(3);
STEP(2);
STEP(1);
STEP(0);
return (fixed32)(r << (PRECISION / 2));
}
__inline static fixed32 fixexp32(fixed32 x)
{
fixed64 result = ftofix32(1.f);
fixed64 temp;
int sign = 1;
/* reduce range to 0.0 to 1.0 */
if(x < 0)
{
x = (fixed32)-x;
sign = -1;
}
while(x > itofix32(1))
{
x -= itofix32(1);
result *= ftofix32(2.718282f);
result >>= PRECISION;
}
/* reduce range to 0.0 to 0.5 */
if(x > ftofix32(0.5f))
{
x -= ftofix32(0.5f);
result *= ftofix32(1.648721f);
result >>= PRECISION;
}
if(result > 0x7fffffff)
{
return 0x7fffffff;
}
temp = ftofix32(0.00138888f) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(0.00833333f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(0.04166666f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(0.16666666f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(0.5f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(1.0f)) * x;
temp >>= PRECISION;
result *= (temp + ftofix32(1.f));
result >>= PRECISION;
if(sign == -1)
{
temp = 1;
result = (temp << (PRECISION * 2)) / result;
}
if(result > 0x7fffffff)
{
return 0x7fffffff;
}
return (fixed32)result;
}
__inline static fixed32 fixlog32(fixed32 x)
{
fixed64 result = 0;
fixed64 temp;
if(x == 0)
{
return -0x7ffffffe;
}
else if(x < 0)
{
return 0;
}
while(x > itofix32(2))
{
result += ftofix32(0.693147f);
x /= 2;
}
while(x < itofix32(1))
{
result -= ftofix32(0.693147f);
x *= 2;
}
x -= itofix32(1);
temp = ftofix32(-.0064535442f) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(.0360884937f)) * x;
temp >>= PRECISION;
temp = (temp - ftofix32(.0953293897f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(.1676540711f)) * x;
temp >>= PRECISION;
temp = (temp - ftofix32(.2407338084f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(.3317990258f)) * x;
temp >>= PRECISION;
temp = (temp - ftofix32(.4998741238f)) * x;
temp >>= PRECISION;
temp = (temp + ftofix32(.9999964239f)) * x;
temp >>= PRECISION;
result += temp;
return (fixed32)result;
}
__inline fixed32 fixsin32(fixed32 x)
{
fixed64 x2, temp;
int sign = 1;
if(x < 0)
{
sign = -1;
x = -x;
}
while(x > ftofix32(M_PI))
{
x -= ftofix32(M_PI);
sign = -sign;
}
if(x > ftofix32(M_PI/2))
{
x = ftofix32(M_PI) - x;
}
x2 = (fixed64)x * x;
x2 >>= PRECISION;
if(sign != 1)
{
x = -x;
}
temp = ftofix32(-.0000000239f) * x2;
temp >>= PRECISION;
temp = (temp + ftofix32(.0000027526f)) * x2;
temp >>= PRECISION;
temp = (temp - ftofix32(.0001984090f)) * x2;
temp >>= PRECISION;
temp = (temp + ftofix32(.0083333315f)) * x2;
temp >>= PRECISION;
temp = (temp - ftofix32(.1666666664f)) * x2;
temp >>= PRECISION;
temp += itofix32(1);
temp = temp * x;
temp >>= PRECISION;
return (fixed32)(temp);
}
__inline fixed32 fixasin32(fixed32 x)
{
fixed64 temp;
int sign = 1;
if(x > itofix32(1) || x < itofix32(-1))
{
return 0;
}
if(x < 0)
{
sign = -1;
x = -x;
}
temp = 0;
temp = ftofix32(-.0012624911f) * (fixed64)x;
temp >>= PRECISION;
temp = (temp + ftofix32(.0066700901f)) * x;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -