mirror of https://github.com/n7tae/tcd.git
parent
9f8518b6d3
commit
3533472690
@ -0,0 +1,964 @@
|
||||
/*
|
||||
* This intermediary file and the files that used to create it are under
|
||||
* The LGPL. See the file COPYING.
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
/* codebook/lsp1.txt */
|
||||
static float codes00[] =
|
||||
{
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600
|
||||
};
|
||||
/* codebook/lsp2.txt */
|
||||
static float codes01[] =
|
||||
{
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700
|
||||
};
|
||||
/* codebook/lsp3.txt */
|
||||
static float codes02[] =
|
||||
{
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250
|
||||
};
|
||||
/* codebook/lsp4.txt */
|
||||
static float codes03[] =
|
||||
{
|
||||
700,
|
||||
800,
|
||||
900,
|
||||
1000,
|
||||
1100,
|
||||
1200,
|
||||
1300,
|
||||
1400,
|
||||
1500,
|
||||
1600,
|
||||
1700,
|
||||
1800,
|
||||
1900,
|
||||
2000,
|
||||
2100,
|
||||
2200
|
||||
};
|
||||
/* codebook/lsp5.txt */
|
||||
static float codes04[] =
|
||||
{
|
||||
950,
|
||||
1050,
|
||||
1150,
|
||||
1250,
|
||||
1350,
|
||||
1450,
|
||||
1550,
|
||||
1650,
|
||||
1750,
|
||||
1850,
|
||||
1950,
|
||||
2050,
|
||||
2150,
|
||||
2250,
|
||||
2350,
|
||||
2450
|
||||
};
|
||||
/* codebook/lsp6.txt */
|
||||
static float codes05[] =
|
||||
{
|
||||
1100,
|
||||
1200,
|
||||
1300,
|
||||
1400,
|
||||
1500,
|
||||
1600,
|
||||
1700,
|
||||
1800,
|
||||
1900,
|
||||
2000,
|
||||
2100,
|
||||
2200,
|
||||
2300,
|
||||
2400,
|
||||
2500,
|
||||
2600
|
||||
};
|
||||
/* codebook/lsp7.txt */
|
||||
static float codes06[] =
|
||||
{
|
||||
1500,
|
||||
1600,
|
||||
1700,
|
||||
1800,
|
||||
1900,
|
||||
2000,
|
||||
2100,
|
||||
2200,
|
||||
2300,
|
||||
2400,
|
||||
2500,
|
||||
2600,
|
||||
2700,
|
||||
2800,
|
||||
2900,
|
||||
3000
|
||||
};
|
||||
/* codebook/lsp8.txt */
|
||||
static float codes07[] =
|
||||
{
|
||||
2300,
|
||||
2400,
|
||||
2500,
|
||||
2600,
|
||||
2700,
|
||||
2800,
|
||||
2900,
|
||||
3000
|
||||
};
|
||||
/* codebook/lsp9.txt */
|
||||
static float codes08[] =
|
||||
{
|
||||
2500,
|
||||
2600,
|
||||
2700,
|
||||
2800,
|
||||
2900,
|
||||
3000,
|
||||
3100,
|
||||
3200
|
||||
};
|
||||
/* codebook/lsp10.txt */
|
||||
static float codes09[] =
|
||||
{
|
||||
2900,
|
||||
3100,
|
||||
3300,
|
||||
3500
|
||||
};
|
||||
|
||||
const struct lsp_codebook lsp_cb[] =
|
||||
{
|
||||
/* codebook/lsp1.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes00
|
||||
},
|
||||
/* codebook/lsp2.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes01
|
||||
},
|
||||
/* codebook/lsp3.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes02
|
||||
},
|
||||
/* codebook/lsp4.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes03
|
||||
},
|
||||
/* codebook/lsp5.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes04
|
||||
},
|
||||
/* codebook/lsp6.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes05
|
||||
},
|
||||
/* codebook/lsp7.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes06
|
||||
},
|
||||
/* codebook/lsp8.txt */
|
||||
{
|
||||
1,
|
||||
3,
|
||||
8,
|
||||
codes07
|
||||
},
|
||||
/* codebook/lsp9.txt */
|
||||
{
|
||||
1,
|
||||
3,
|
||||
8,
|
||||
codes08
|
||||
},
|
||||
/* codebook/lsp10.txt */
|
||||
{
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
codes09
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* codebook/dlsp1.txt */
|
||||
static float codes10[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp2.txt */
|
||||
static float codes11[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp3.txt */
|
||||
static float codes12[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp4.txt */
|
||||
static float codes13[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250,
|
||||
1300,
|
||||
1350,
|
||||
1400
|
||||
};
|
||||
/* codebook/dlsp5.txt */
|
||||
static float codes14[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250,
|
||||
1300,
|
||||
1350,
|
||||
1400
|
||||
};
|
||||
/* codebook/dlsp6.txt */
|
||||
static float codes15[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250,
|
||||
1300,
|
||||
1350,
|
||||
1400
|
||||
};
|
||||
/* codebook/dlsp7.txt */
|
||||
static float codes16[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp8.txt */
|
||||
static float codes17[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp9.txt */
|
||||
static float codes18[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp10.txt */
|
||||
static float codes19[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
|
||||
const struct lsp_codebook lsp_cbd[] =
|
||||
{
|
||||
/* codebook/dlsp1.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes10
|
||||
},
|
||||
/* codebook/dlsp2.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes11
|
||||
},
|
||||
/* codebook/dlsp3.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes12
|
||||
},
|
||||
/* codebook/dlsp4.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes13
|
||||
},
|
||||
/* codebook/dlsp5.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes14
|
||||
},
|
||||
/* codebook/dlsp6.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes15
|
||||
},
|
||||
/* codebook/dlsp7.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes16
|
||||
},
|
||||
/* codebook/dlsp8.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes17
|
||||
},
|
||||
/* codebook/dlsp9.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes18
|
||||
},
|
||||
/* codebook/dlsp10.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes19
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
/* codebook/gecb.txt */
|
||||
static float codes30[] =
|
||||
{
|
||||
2.71, 12.0184,
|
||||
0.04675, -2.73881,
|
||||
0.120993, 8.38895,
|
||||
-1.58028, -0.892307,
|
||||
1.19307, -1.91561,
|
||||
0.187101, -3.27679,
|
||||
0.332251, -7.66455,
|
||||
-1.47944, 31.2461,
|
||||
1.52761, 27.7095,
|
||||
-0.524379, 5.25012,
|
||||
0.55333, 7.4388,
|
||||
-0.843451, -1.95299,
|
||||
2.26389, 8.61029,
|
||||
0.143143, 2.36549,
|
||||
0.616506, 1.28427,
|
||||
-1.71133, 22.0967,
|
||||
1.00813, 17.3965,
|
||||
-0.106718, 1.41891,
|
||||
-0.136246, 14.2736,
|
||||
-1.70909, -20.5319,
|
||||
1.65787, -3.39107,
|
||||
0.138049, -4.95785,
|
||||
0.536729, -1.94375,
|
||||
0.196307, 36.8519,
|
||||
1.27248, 22.5565,
|
||||
-0.670219, -1.90604,
|
||||
0.382092, 6.40113,
|
||||
-0.756911, -4.90102,
|
||||
1.82931, 4.6138,
|
||||
0.318794, 0.73683,
|
||||
0.612815, -2.07505,
|
||||
-0.410151, 24.7871,
|
||||
1.77602, 13.1909,
|
||||
0.106457, -0.104492,
|
||||
0.192206, 10.1838,
|
||||
-1.82442, -7.71565,
|
||||
0.931346, 4.34835,
|
||||
0.308813, -4.086,
|
||||
0.397143, -11.8089,
|
||||
-0.048715, 41.2273,
|
||||
0.877342, 35.8503,
|
||||
-0.759794, 0.476634,
|
||||
0.978593, 7.67467,
|
||||
-1.19506, 3.03883,
|
||||
2.63989, -3.41106,
|
||||
0.191127, 3.60351,
|
||||
0.402932, 1.0843,
|
||||
-2.15202, 18.1076,
|
||||
1.5468, 8.32271,
|
||||
-0.143089, -4.07592,
|
||||
-0.150142, 5.86674,
|
||||
-1.40844, -3.2507,
|
||||
1.56615, -10.4132,
|
||||
0.178171, -10.2267,
|
||||
0.362164, -0.028556,
|
||||
-0.070125, 24.3907,
|
||||
0.594752, 17.4828,
|
||||
-0.28698, -6.90407,
|
||||
0.464818, 10.2055,
|
||||
-1.00684, -14.3572,
|
||||
2.32957, -3.69161,
|
||||
0.335745, 2.40714,
|
||||
1.01966, -3.15565,
|
||||
-1.25945, 7.9919,
|
||||
2.38369, 19.6806,
|
||||
-0.094947, -2.41374,
|
||||
0.20933, 6.66477,
|
||||
-2.22103, 1.37986,
|
||||
1.29239, 2.04633,
|
||||
0.243626, -0.890741,
|
||||
0.428773, -7.19366,
|
||||
-1.11374, 41.3414,
|
||||
2.6098, 31.1405,
|
||||
-0.446468, 2.53419,
|
||||
0.490104, 4.62757,
|
||||
-1.11723, -3.24174,
|
||||
1.79156, 8.41493,
|
||||
0.156012, 0.183336,
|
||||
0.532447, 3.15455,
|
||||
-0.764484, 18.514,
|
||||
0.952395, 11.7713,
|
||||
-0.332567, 0.346987,
|
||||
0.202165, 14.7168,
|
||||
-2.12924, -15.559,
|
||||
1.35358, -1.92679,
|
||||
-0.010963, -16.3364,
|
||||
0.399053, -2.79057,
|
||||
0.750657, 31.1483,
|
||||
0.655743, 24.4819,
|
||||
-0.45321, -0.735879,
|
||||
0.2869, 6.5467,
|
||||
-0.715673, -12.3578,
|
||||
1.54849, 3.87217,
|
||||
0.271874, 0.802339,
|
||||
0.502073, -4.85485,
|
||||
-0.497037, 17.7619,
|
||||
1.19116, 13.9544,
|
||||
0.01563, 1.33157,
|
||||
0.341867, 8.93537,
|
||||
-2.31601, -5.39506,
|
||||
0.75861, 1.9645,
|
||||
0.24132, -3.23769,
|
||||
0.267151, -11.2344,
|
||||
-0.273126, 32.6248,
|
||||
1.75352, 40.432,
|
||||
-0.784011, 3.04576,
|
||||
0.705987, 5.66118,
|
||||
-1.3864, 1.35356,
|
||||
2.37646, 1.67485,
|
||||
0.242973, 4.73218,
|
||||
0.491227, 0.354061,
|
||||
-1.60676, 8.65895,
|
||||
1.16711, 5.9871,
|
||||
-0.137601, -12.0417,
|
||||
-0.251375, 10.3972,
|
||||
-1.43151, -8.90411,
|
||||
0.98828, -13.209,
|
||||
0.261484, -6.35497,
|
||||
0.395932, -0.702529,
|
||||
0.283704, 26.8996,
|
||||
0.420959, 15.4418,
|
||||
-0.355804, -13.7278,
|
||||
0.527372, 12.3985,
|
||||
-1.16956, -15.9985,
|
||||
1.90669, -5.81605,
|
||||
0.354492, 3.85157,
|
||||
0.82576, -4.16264,
|
||||
-0.49019, 13.0572,
|
||||
2.25577, 13.5264,
|
||||
-0.004956, -3.23713,
|
||||
0.026709, 7.86645,
|
||||
-1.81037, -0.451183,
|
||||
1.08383, -0.18362,
|
||||
0.135836, -2.26658,
|
||||
0.375812, -5.51225,
|
||||
-1.96644, 38.6829,
|
||||
1.97799, 24.5655,
|
||||
-0.704656, 6.35881,
|
||||
0.480786, 7.05175,
|
||||
-0.976417, -2.42273,
|
||||
2.50215, 6.75935,
|
||||
0.083588, 3.2588,
|
||||
0.543629, 0.910013,
|
||||
-1.23196, 23.0915,
|
||||
0.785492, 14.807,
|
||||
-0.213554, 1.688,
|
||||
0.004748, 18.1718,
|
||||
-1.54719, -16.1168,
|
||||
1.50104, -3.28114,
|
||||
0.080133, -4.63472,
|
||||
0.476592, -2.18093,
|
||||
0.44247, 40.304,
|
||||
1.07277, 27.592,
|
||||
-0.594738, -4.16681,
|
||||
0.42248, 7.61609,
|
||||
-0.927521, -7.27441,
|
||||
1.99162, 1.29636,
|
||||
0.291307, 2.39878,
|
||||
0.721081, -1.95062,
|
||||
-0.804256, 24.9295,
|
||||
1.64839, 19.1197,
|
||||
0.060852, -0.590639,
|
||||
0.266085, 9.10325,
|
||||
-1.9574, -2.88461,
|
||||
1.11693, 2.6724,
|
||||
0.35458, -2.74854,
|
||||
0.330733, -14.1561,
|
||||
-0.527851, 39.5756,
|
||||
0.991152, 43.195,
|
||||
-0.589619, 1.26919,
|
||||
0.787401, 8.73071,
|
||||
-1.0138, 1.02507,
|
||||
2.8254, 1.89538,
|
||||
0.24089, 2.74557,
|
||||
0.427195, 2.54446,
|
||||
-1.95311, 12.244,
|
||||
1.44862, 12.0607,
|
||||
-0.210492, -3.37906,
|
||||
-0.056713, 10.204,
|
||||
-1.65237, -5.10274,
|
||||
1.29475, -12.2708,
|
||||
0.111608, -8.67592,
|
||||
0.326634, -1.16763,
|
||||
0.021781, 31.1258,
|
||||
0.455335, 21.4684,
|
||||
-0.37544, -3.37121,
|
||||
0.39362, 11.302,
|
||||
-0.851456, -19.4149,
|
||||
2.10703, -2.22886,
|
||||
0.373233, 1.92406,
|
||||
0.884438, -1.72058,
|
||||
-0.975127, 9.84013,
|
||||
2.0033, 17.3954,
|
||||
-0.036915, -1.11137,
|
||||
0.148456, 5.39997,
|
||||
-1.91441, 4.77382,
|
||||
1.44791, 0.537122,
|
||||
0.194979, -1.03818,
|
||||
0.495771, -9.95502,
|
||||
-1.05899, 32.9471,
|
||||
2.01122, 32.4544,
|
||||
-0.30965, 4.71911,
|
||||
0.436082, 4.63552,
|
||||
-1.23711, -1.25428,
|
||||
2.02274, 9.42834,
|
||||
0.190342, 1.46077,
|
||||
0.479017, 2.48479,
|
||||
-1.07848, 16.2217,
|
||||
1.20764, 9.65421,
|
||||
-0.258087, -1.67236,
|
||||
0.071852, 13.416,
|
||||
-1.87723, -16.072,
|
||||
1.28957, -4.87118,
|
||||
0.067713, -13.4427,
|
||||
0.435551, -4.1655,
|
||||
0.46614, 30.5895,
|
||||
0.904895, 21.598,
|
||||
-0.518369, -2.53205,
|
||||
0.337363, 5.63726,
|
||||
-0.554975, -17.4005,
|
||||
1.69188, 1.14574,
|
||||
0.227934, 0.889297,
|
||||
0.587303, -5.72973,
|
||||
-0.262133, 18.6666,
|
||||
1.39505, 17.0029,
|
||||
-0.01909, 4.30838,
|
||||
0.304235, 12.6699,
|
||||
-2.07406, -6.46084,
|
||||
0.920546, 1.21296,
|
||||
0.284927, -1.78547,
|
||||
0.209724, -16.024,
|
||||
-0.636067, 31.5768,
|
||||
1.34989, 34.6775,
|
||||
-0.971625, 5.30086,
|
||||
0.590249, 4.44971,
|
||||
-1.56787, 3.60239,
|
||||
2.1455, 4.51666,
|
||||
0.296022, 4.12017,
|
||||
0.445299, 0.868772,
|
||||
-1.44193, 14.1284,
|
||||
1.35575, 6.0074,
|
||||
-0.012814, -7.49657,
|
||||
-0.43, 8.50012,
|
||||
-1.20469, -7.11326,
|
||||
1.10102, -6.83682,
|
||||
0.196463, -6.234,
|
||||
0.436747, -1.12979,
|
||||
0.141052, 22.8549,
|
||||
0.290821, 18.8114,
|
||||
-0.529536, -7.73251,
|
||||
0.63428, 10.7898,
|
||||
-1.33472, -20.3258,
|
||||
1.81564, -1.90332,
|
||||
0.394778, 3.79758,
|
||||
0.732682, -8.18382,
|
||||
-0.741244, 11.7683
|
||||
};
|
||||
|
||||
const struct lsp_codebook ge_cb[] =
|
||||
{
|
||||
/* codebook/gecb.txt */
|
||||
{
|
||||
2,
|
||||
8,
|
||||
256,
|
||||
codes30
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,98 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: codec2.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 21 August 2010
|
||||
|
||||
Codec 2 fully quantised encoder and decoder functions. If you want use
|
||||
Codec 2, these are the functions you need to call.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2010 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CODEC2__
|
||||
#define __CODEC2__
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include "codec2_internal.h"
|
||||
#include "defines.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "nlp.h"
|
||||
#include "quantise.h"
|
||||
|
||||
#define CODEC2_MODE_3200 0
|
||||
#define CODEC2_MODE_1600 2
|
||||
|
||||
#ifndef CODEC2_MODE_EN_DEFAULT
|
||||
#define CODEC2_MODE_EN_DEFAULT 1
|
||||
#endif
|
||||
|
||||
#define CODEC2_RAND_MAX 32767
|
||||
|
||||
class CCodec2
|
||||
{
|
||||
public:
|
||||
CCodec2(bool is_3200);
|
||||
~CCodec2();
|
||||
void codec2_encode(unsigned char *bits, const short *speech_in);
|
||||
void codec2_decode(short *speech_out, const unsigned char *bits);
|
||||
int codec2_samples_per_frame();
|
||||
int codec2_bits_per_frame();
|
||||
|
||||
private:
|
||||
// merged from other files
|
||||
void sample_phase(MODEL *model, std::complex<float> filter_phase[], std::complex<float> A[]);
|
||||
void phase_synth_zero_order(int n_samp, MODEL *model, float *ex_phase, std::complex<float> filter_phase[]);
|
||||
void postfilter(MODEL *model, float *bg_est);
|
||||
|
||||
C2CONST c2const_create(int Fs, float framelength_ms);
|
||||
|
||||
void make_analysis_window(C2CONST *c2const, FFT_STATE *fft_fwd_cfg, float w[], float W[]);
|
||||
void dft_speech(C2CONST *c2const, FFT_STATE &fft_fwd_cfg, std::complex<float> Sw[], float Sn[], float w[]);
|
||||
void two_stage_pitch_refinement(C2CONST *c2const, MODEL *model, std::complex<float> Sw[]);
|
||||
void estimate_amplitudes(MODEL *model, std::complex<float> Sw[], int est_phase);
|
||||
float est_voicing_mbe(C2CONST *c2const, MODEL *model, std::complex<float> Sw[], float W[]);
|
||||
void make_synthesis_window(C2CONST *c2const, float Pn[]);
|
||||
void synthesise(int n_samp, FFTR_STATE *fftr_inv_cfg, float Sn_[], MODEL *model, float Pn[], int shift);
|
||||
int codec2_rand(void);
|
||||
void hs_pitch_refinement(MODEL *model, std::complex<float> Sw[], float pmin, float pmax, float pstep);
|
||||
|
||||
void interp_Wo(MODEL *interp, MODEL *prev, MODEL *next, float Wo_min);
|
||||
void interp_Wo2(MODEL *interp, MODEL *prev, MODEL *next, float weight, float Wo_min);
|
||||
float interp_energy(float prev, float next);
|
||||
void interpolate_lsp_ver2(float interp[], float prev[], float next[], float weight, int order);
|
||||
|
||||
void analyse_one_frame(MODEL *model, const short *speech);
|
||||
void synthesise_one_frame(short speech[], MODEL *model, std::complex<float> Aw[], float gain);
|
||||
void codec2_encode_3200(unsigned char *bits, const short *speech);
|
||||
void codec2_encode_1600(unsigned char *bits, const short *speech);
|
||||
void codec2_decode_3200(short *speech, const unsigned char *bits);
|
||||
void codec2_decode_1600(short *speech, const unsigned char *bits);
|
||||
void ear_protection(float in_out[], int n);
|
||||
void lsp_to_lpc(float *freq, float *ak, int lpcrdr);
|
||||
|
||||
void (CCodec2::*encode)(unsigned char *bits, const short *speech);
|
||||
void (CCodec2::*decode)(short *speech, const unsigned char *bits);
|
||||
Cnlp nlp;
|
||||
CQuantize qt;
|
||||
CODEC2 c2;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,67 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: codec2_internal.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: April 16 2012
|
||||
|
||||
Header file for Codec2 internal states, exposed via this header
|
||||
file to assist in testing.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2012 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CODEC2_INTERNAL__
|
||||
#define __CODEC2_INTERNAL__
|
||||
|
||||
#include "kiss_fft.h"
|
||||
|
||||
using CODEC2 = struct codec2_tag {
|
||||
int mode;
|
||||
int Fs;
|
||||
int n_samp;
|
||||
int m_pitch;
|
||||
int gray; /* non-zero for gray encoding */
|
||||
int lpc_pf; /* LPC post filter on */
|
||||
int bass_boost; /* LPC post filter bass boost */
|
||||
int smoothing; /* enable smoothing for channels with errors */
|
||||
float ex_phase; /* excitation model phase track */
|
||||
float bg_est; /* background noise estimate for post filter */
|
||||
float prev_f0_enc; /* previous frame's f0 estimate */
|
||||
float prev_e_dec; /* previous frame's LPC energy */
|
||||
float beta; /* LPC post filter parameters */
|
||||
float gamma;
|
||||
float xq_enc[2]; /* joint pitch and energy VQ states */
|
||||
float xq_dec[2];
|
||||
float W[FFT_ENC]; /* DFT of w[] */
|
||||
float hpf_states[2]; /* high pass filter states */
|
||||
float prev_lsps_dec[LPC_ORD]; /* previous frame's LSPs */
|
||||
float *softdec; /* optional soft decn bits from demod */
|
||||
MODEL prev_model_dec; /* previous frame's model parameters */
|
||||
C2CONST c2const;
|
||||
FFT_STATE fft_fwd_cfg; /* forward FFT config */
|
||||
FFTR_STATE fftr_fwd_cfg; /* forward real FFT config */
|
||||
FFTR_STATE fftr_inv_cfg; /* inverse FFT config */
|
||||
std::vector<float> w; /* [m_pitch] time domain hamming window */
|
||||
std::vector<float> Pn; /* [2*n_samp] trapezoidal synthesis window */
|
||||
std::vector<float> Sn; /* [m_pitch] input speech */
|
||||
std::vector<float> Sn_; /* [2*n_samp] synthesised output speech */
|
||||
std::vector<float> bpf_buf; /* buffer for band pass filter */
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,127 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: defines.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 23/4/93
|
||||
|
||||
Defines and structures used throughout the codec.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DEFINES__
|
||||
#define __DEFINES__
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
DEFINES
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/* General defines */
|
||||
|
||||
#define N_S 0.01 /* internal proc frame length in secs */
|
||||
#define TW_S 0.005 /* trapezoidal synth window overlap */
|
||||
#define MAX_AMP 160 /* maximum number of harmonics */
|
||||
#ifndef PI
|
||||
#define PI 3.141592654 /* mathematical constant */
|
||||
#endif
|
||||
#define TWO_PI 6.283185307 /* mathematical constant */
|
||||
#define MAX_STR 2048 /* maximum string size */
|
||||
|
||||
#define FFT_ENC 512 /* size of FFT used for encoder */
|
||||
#define FFT_DEC 512 /* size of FFT used in decoder */
|
||||
#define V_THRESH 6.0 /* voicing threshold in dB */
|
||||
#define LPC_ORD 10 /* LPC order */
|
||||
#define LPC_ORD_LOW 6 /* LPC order for lower rates */
|
||||
|
||||
/* Pitch estimation defines */
|
||||
|
||||
#define M_PITCH_S 0.0400 /* pitch analysis window in s */
|
||||
#define P_MIN_S 0.0025 /* minimum pitch period in s */
|
||||
#define P_MAX_S 0.0200 /* maximum pitch period in s */
|
||||
#define MAXFACTORS 32 // e.g. an fft of length 128 has 4 factors
|
||||
// as far as kissfft is concerned 4*4*4*2
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
TYPEDEFS
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/* Structure to hold constants calculated at run time based on sample rate */
|
||||
|
||||
using C2CONST = struct c2const_tag
|
||||
{
|
||||
int Fs; /* sample rate of this instance */
|
||||
int n_samp; /* number of samples per 10ms frame at Fs */
|
||||
int max_amp; /* maximum number of harmonics */
|
||||
int m_pitch; /* pitch estimation window size in samples */
|
||||
int p_min; /* minimum pitch period in samples */
|
||||
int p_max; /* maximum pitch period in samples */
|
||||
float Wo_min;
|
||||
float Wo_max;
|
||||
int nw; /* analysis window size in samples */
|
||||
int tw; /* trapezoidal synthesis window overlap */
|
||||
};
|
||||
|
||||
/* Structure to hold model parameters for one frame */
|
||||
|
||||
using MODEL = struct model_tag
|
||||
{
|
||||
float Wo; /* fundamental frequency estimate in radians */
|
||||
int L; /* number of harmonics */
|
||||
float A[MAX_AMP+1]; /* amplitiude of each harmonic */
|
||||
float phi[MAX_AMP+1]; /* phase of each harmonic */
|
||||
int voiced; /* non-zero if this frame is voiced */
|
||||
};
|
||||
|
||||
/* describes each codebook */
|
||||
|
||||
struct lsp_codebook
|
||||
{
|
||||
int k; /* dimension of vector */
|
||||
int log2m; /* number of bits in m */
|
||||
int m; /* elements in codebook */
|
||||
float *cb; /* The elements */
|
||||
};
|
||||
|
||||
using FFT_STATE = struct fft_state_tag
|
||||
{
|
||||
int nfft;
|
||||
bool inverse;
|
||||
int factors[2*MAXFACTORS];
|
||||
std::vector<std::complex<float>> twiddles;
|
||||
};
|
||||
|
||||
using FFTR_STATE = struct fftr_state_tag
|
||||
{
|
||||
FFT_STATE substate;
|
||||
std::vector<std::complex<float>> tmpbuf;
|
||||
std::vector<std::complex<float>> super_twiddles;
|
||||
};
|
||||
|
||||
extern const struct lsp_codebook lsp_cb[];
|
||||
extern const struct lsp_codebook lsp_cbd[];
|
||||
extern const struct lsp_codebook ge_cb[];
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,435 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, Mark Borgerding
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include "defines.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
void CKissFFT::kf_bfly2(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
std::complex<float> *Fout2;
|
||||
std::complex<float> *tw1 = st.twiddles.data();
|
||||
std::complex<float> t;
|
||||
Fout2 = Fout + m;
|
||||
do
|
||||
{
|
||||
t = *Fout2 * *tw1;
|
||||
tw1 += fstride;
|
||||
*Fout2 = *Fout - t;
|
||||
*Fout += t;
|
||||
++Fout2;
|
||||
++Fout;
|
||||
}
|
||||
while (--m);
|
||||
}
|
||||
|
||||
void CKissFFT::kf_bfly3(std::complex<float> * Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
const size_t m2 = 2 * m;
|
||||
std::complex<float> *tw1,*tw2;
|
||||
std::complex<float> scratch[5];
|
||||
std::complex<float> epi3;
|
||||
epi3 = st.twiddles[fstride*m];
|
||||
|
||||
tw1 = tw2 = st.twiddles.data();
|
||||
|
||||
do
|
||||
{
|
||||
scratch[1] = Fout[m] * *tw1;
|
||||
scratch[2] = Fout[m2] * *tw2;
|
||||
|
||||
scratch[3] = scratch[1] + scratch[2];
|
||||
scratch[0] = scratch[1] - scratch[2];
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
|
||||
Fout[m] = *Fout - (0.5f * scratch[3]);
|
||||
|
||||
scratch[0] *= epi3.imag();
|
||||
|
||||
*Fout += scratch[3];
|
||||
|
||||
Fout[m2].real(Fout[m].real() + scratch[0].imag());
|
||||
Fout[m2].imag(Fout[m].imag() - scratch[0].real());
|
||||
|
||||
Fout[m].real(Fout[m].real() - scratch[0].imag());
|
||||
Fout[m].imag(Fout[m].imag() + scratch[0].real());
|
||||
|
||||
++Fout;
|
||||
}
|
||||
while(--m);
|
||||
}
|
||||
|
||||
void CKissFFT::kf_bfly4(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
std::complex<float> *tw1,*tw2,*tw3;
|
||||
std::complex<float> scratch[6];
|
||||
int k = m;
|
||||
const int m2 = 2 * m;
|
||||
const int m3 = 3 * m;
|
||||
|
||||
|
||||
tw3 = tw2 = tw1 = st.twiddles.data();
|
||||
|
||||
do
|
||||
{
|
||||
scratch[0] = Fout[m] * *tw1;
|
||||
scratch[1] = Fout[m2] * *tw2;
|
||||
scratch[2] = Fout[m3] * *tw3;
|
||||
|
||||
scratch[5] = *Fout - scratch[1];
|
||||
*Fout += scratch[1];
|
||||
scratch[3] = scratch[0] + scratch[2];
|
||||
scratch[4] = scratch[0] - scratch[2];
|
||||
Fout[m2] = *Fout - scratch[3];
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
tw3 += fstride*3;
|
||||
*Fout += scratch[3];
|
||||
|
||||
if(st.inverse)
|
||||
{
|
||||
Fout[m].real(scratch[5].real() - scratch[4].imag());
|
||||
Fout[m].imag(scratch[5].imag() + scratch[4].real());
|
||||
Fout[m3].real(scratch[5].real() + scratch[4].imag());
|
||||
Fout[m3].imag(scratch[5].imag() - scratch[4].real());
|
||||
}
|
||||
else
|
||||
{
|
||||
Fout[m].real(scratch[5].real() + scratch[4].imag());
|
||||
Fout[m].imag(scratch[5].imag() - scratch[4].real());
|
||||
Fout[m3].real(scratch[5].real() - scratch[4].imag());
|
||||
Fout[m3].imag(scratch[5].imag() + scratch[4].real());
|
||||
}
|
||||
++Fout;
|
||||
}
|
||||
while(--k);
|
||||
}
|
||||
|
||||
void CKissFFT::kf_bfly5(std::complex<float> * Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
std::complex<float> scratch[13];
|
||||
std::complex<float> *twiddles = st.twiddles.data();
|
||||
auto ya = twiddles[fstride*m];
|
||||
auto yb = twiddles[fstride*2*m];
|
||||
|
||||
auto Fout0 = Fout;
|
||||
auto Fout1 = Fout0 + m;
|
||||
auto Fout2 = Fout0 + 2 * m;
|
||||
auto Fout3 = Fout0 + 3 * m;
|
||||
auto Fout4 = Fout0 + 4 * m;
|
||||
|
||||
auto tw = st.twiddles.data();
|
||||
for (int u=0; u<m; ++u)
|
||||
{
|
||||
scratch[0] = *Fout0;
|
||||
|
||||
scratch[1] = *Fout1 * tw[u*fstride];
|
||||
scratch[2] = *Fout2 * tw[2*u*fstride];
|
||||
scratch[3] = *Fout3 * tw[3*u*fstride];
|
||||
scratch[4] = *Fout4 * tw[4*u*fstride];
|
||||
|
||||
scratch[7] = scratch[1] + scratch[4];
|
||||
scratch[10] = scratch[1] - scratch[4];
|
||||
scratch[8] = scratch[2] + scratch[3];
|
||||
scratch[9] = scratch[2] - scratch[3];
|
||||
|
||||
*Fout0 += scratch[7] + scratch[8];
|
||||
|
||||
scratch[5] = scratch[0] + (scratch[7] * ya.real()) + (scratch[8] * yb.real());
|
||||
|
||||
scratch[6].real( (scratch[10].imag() * ya.imag()) + (scratch[9].imag() * yb.imag()));
|
||||
scratch[6].imag(-(scratch[10].real() * ya.imag()) - (scratch[9].real() * yb.imag()));
|
||||
|
||||
*Fout1 = scratch[5] - scratch[6];
|
||||
*Fout4 = scratch[5] + scratch[6];
|
||||
|
||||
scratch[11] = scratch[0] + (scratch[7] * yb.real()) + (scratch[8] * ya.real());
|
||||
scratch[12].real(-(scratch[10].imag() * yb.imag()) + (scratch[9].imag() * ya.imag()));
|
||||
scratch[12].imag( (scratch[10].real() * yb.imag()) - (scratch[9].real() * ya.imag()));
|
||||
|
||||
*Fout2 = scratch[11] + scratch[12];
|
||||
*Fout3 = scratch[11] - scratch[12];
|
||||
|
||||
++Fout0;
|
||||
++Fout1;
|
||||
++Fout2;
|
||||
++Fout3;
|
||||
++Fout4;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform the butterfly for one stage of a mixed radix FFT */
|
||||
void CKissFFT::kf_bfly_generic(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m, int p)
|
||||
{
|
||||
auto twiddles = st.twiddles.data();
|
||||
std::complex<float> t;
|
||||
int Norig = st.nfft;
|
||||
|
||||
std::vector<std::complex<float>> scratch(p);
|
||||
|
||||
for (int u=0; u<m; ++u)
|
||||
{
|
||||
int k = u;
|
||||
for (int q1=0 ; q1<p ; ++q1)
|
||||
{
|
||||
scratch[q1] = Fout[k];
|
||||
k += m;
|
||||
}
|
||||
|
||||
k = u;
|
||||
for (int q1=0 ; q1<p ; ++q1)
|
||||
{
|
||||
int twidx = 0;
|
||||
Fout[k] = scratch[0];
|
||||
for (int q=1; q<p; ++q)
|
||||
{
|
||||
twidx += fstride * k;
|
||||
if (twidx >= Norig) twidx-=Norig;
|
||||
t = scratch[q] * twiddles[twidx];
|
||||
Fout[k] += t;
|
||||
}
|
||||
k += m;
|
||||
}
|
||||
}
|
||||
scratch.clear();
|
||||
}
|
||||
|
||||
void CKissFFT::kf_work(std::complex<float> *Fout, const std::complex<float> *f, const size_t fstride, int in_stride, int *factors, FFT_STATE &st)
|
||||
{
|
||||
auto Fout_beg = Fout;
|
||||
const int p = *factors++; /* the radix */
|
||||
const int m = *factors++; /* stage's fft length/p */
|
||||
const std::complex<float> *Fout_end = Fout + p*m;
|
||||
|
||||
if (m==1)
|
||||
{
|
||||
do
|
||||
{
|
||||
*Fout = *f;
|
||||
f += fstride*in_stride;
|
||||
}
|
||||
while( ++Fout != Fout_end );
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
// recursive call:
|
||||
// DFT of size m*p performed by doing
|
||||
// p instances of smaller DFTs of size m,
|
||||
// each one takes a decimated version of the input
|
||||
kf_work( Fout, f, fstride*p, in_stride, factors, st);
|
||||
f += fstride*in_stride;
|
||||
}
|
||||
while( (Fout += m) != Fout_end );
|
||||
}
|
||||
|
||||
Fout=Fout_beg;
|
||||
|
||||
// recombine the p smaller DFTs
|
||||
switch (p)
|
||||
{
|
||||
case 2:
|
||||
kf_bfly2(Fout,fstride,st,m);
|
||||
break;
|
||||
case 3:
|
||||
kf_bfly3(Fout,fstride,st,m);
|
||||
break;
|
||||
case 4:
|
||||
kf_bfly4(Fout,fstride,st,m);
|
||||
break;
|
||||
case 5:
|
||||
kf_bfly5(Fout,fstride,st,m);
|
||||
break;
|
||||
default:
|
||||
kf_bfly_generic(Fout,fstride,st,m,p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* facbuf is populated by p1,m1,p2,m2, ...
|
||||
where
|
||||
p[i] * m[i] = m[i-1]
|
||||
m0 = n */
|
||||
void CKissFFT::kf_factor(int n,int * facbuf)
|
||||
{
|
||||
int p=4;
|
||||
double floor_sqrt;
|
||||
floor_sqrt = floorf( sqrtf((double)n) );
|
||||
|
||||
/*factor out powers of 4, powers of 2, then any remaining primes */
|
||||
do
|
||||
{
|
||||
while (n % p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case 4:
|
||||
p = 2;
|
||||
break;
|
||||
case 2:
|
||||
p = 3;
|
||||
break;
|
||||
default:
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
if (p > floor_sqrt)
|
||||
p = n; /* no more factors, skip to end */
|
||||
}
|
||||
n /= p;
|
||||
*facbuf++ = p;
|
||||
*facbuf++ = n;
|
||||
}
|
||||
while (n > 1);
|
||||
}
|
||||
|
||||
void CKissFFT::fft_alloc(FFT_STATE &state, const int nfft, bool inverse_fft)
|
||||
{
|
||||
state.twiddles.resize(nfft);
|
||||
|
||||
state.nfft = nfft;
|
||||
state.inverse = inverse_fft;
|
||||
|
||||
for (int i=0; i<nfft; ++i)
|
||||
{
|
||||
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
|
||||
double phase = -2.0 * pi * i / nfft;
|
||||
if (state.inverse)
|
||||
phase *= -1.0;
|
||||
state.twiddles[i] = std::polar(1.0f, float(phase));
|
||||
}
|
||||
|
||||
kf_factor(nfft, state.factors);
|
||||
}
|
||||
|
||||
|
||||
void CKissFFT::fft_stride(FFT_STATE &st, const std::complex<float> *fin, std::complex<float> *fout, int in_stride)
|
||||
{
|
||||
if (fin == fout)
|
||||
{
|
||||
//NOTE: this is not really an in-place FFT algorithm.
|
||||
//It just performs an out-of-place FFT into a temp buffer
|
||||
std::vector<std::complex<float>> tmpbuf(st.nfft);
|
||||
kf_work(tmpbuf.data(), fin, true, in_stride, st.factors, st);
|
||||
memcpy(fout, tmpbuf.data(), sizeof(std::complex<float>)*st.nfft);
|
||||
tmpbuf.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
kf_work(fout, fin, 1, in_stride, st.factors, st);
|
||||
}
|
||||
}
|
||||
|
||||
void CKissFFT::fft(FFT_STATE &cfg, const std::complex<float> *fin, std::complex<float> *fout)
|
||||
{
|
||||
fft_stride(cfg, fin, fout, 1);
|
||||
}
|
||||
|
||||
int CKissFFT::fft_next_fast_size(int n)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
int m = n;
|
||||
while ( (m % 2) == 0 ) m /= 2;
|
||||
while ( (m % 3) == 0 ) m /= 3;
|
||||
while ( (m % 5) == 0 ) m /= 5;
|
||||
if (m <= 1)
|
||||
break; /* n is completely factorable by twos, threes, and fives */
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void CKissFFT::fftr_alloc(FFTR_STATE &st, int nfft, const bool inverse_fft)
|
||||
{
|
||||
nfft >>= 1;
|
||||
|
||||
fft_alloc(st.substate, nfft, inverse_fft);
|
||||
st.tmpbuf.resize(nfft);
|
||||
st.super_twiddles.resize(nfft);
|
||||
|
||||
for (int i=0; i<nfft/2; ++i)
|
||||
{
|
||||
double phase = -3.141592653589793238462643383279502884197169399375105820974944 * (double(i+1) / nfft + .5);
|
||||
if (inverse_fft)
|
||||
phase *= -1.0;
|
||||
st.super_twiddles[i] = std::polar(1.0f, float(phase));
|
||||
}
|
||||
}
|
||||
|
||||
void CKissFFT::fftr(FFTR_STATE &st, const float *timedata, std::complex<float> *freqdata)
|
||||
{
|
||||
assert(st.substate.inverse == false);
|
||||
|
||||
auto ncfft = st.substate.nfft;
|
||||
|
||||
/*perform the parallel fft of two real signals packed in real,imag*/
|
||||
fft( st.substate, (const std::complex<float>*)timedata, st.tmpbuf.data());
|
||||
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
|
||||
* contains the sum of the even-numbered elements of the input time sequence
|
||||
* The imag part is the sum of the odd-numbered elements
|
||||
*
|
||||
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
|
||||
* yielding DC of input time sequence
|
||||
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
|
||||
* yielding Nyquist bin of input time sequence
|
||||
*/
|
||||
|
||||
auto tdc = st.tmpbuf[0];
|
||||
freqdata[0].real(tdc.real() + tdc.imag());
|
||||
freqdata[ncfft].real(tdc.real() - tdc.imag());
|
||||
freqdata[ncfft].imag(0.f);
|
||||
freqdata[0].imag(0.f);
|
||||
|
||||
for (int k=1; k <= ncfft/2; ++k)
|
||||
{
|
||||
auto fpk = st.tmpbuf[k];
|
||||
auto fpnk = std::conj(st.tmpbuf[ncfft-k]);
|
||||
|
||||
auto f1k = fpk + fpnk;
|
||||
auto f2k = fpk - fpnk;
|
||||
auto tw = f2k * st.super_twiddles[k-1];
|
||||
|
||||
freqdata[k] = 0.5f * (f1k + tw);
|
||||
freqdata[ncfft-k].real(0.5f * (f1k.real() - tw.real()));
|
||||
freqdata[ncfft-k].imag(0.5f * (tw.imag() - f1k.imag()));
|
||||
}
|
||||
}
|
||||
|
||||
void CKissFFT::fftri(FFTR_STATE &st, const std::complex<float> *freqdata, float *timedata)
|
||||
{
|
||||
assert(st.substate.inverse == true);
|
||||
|
||||
auto ncfft = st.substate.nfft;
|
||||
|
||||
st.tmpbuf[0].real(freqdata[0].real() + freqdata[ncfft].real());
|
||||
st.tmpbuf[0].imag(freqdata[0].real() - freqdata[ncfft].real());
|
||||
|
||||
for (int k=1; k <= ncfft/2; ++k)
|
||||
{
|
||||
auto fk = freqdata[k];
|
||||
auto fnkc = std::conj(freqdata[ncfft - k]);
|
||||
|
||||
auto fek = fk + fnkc;
|
||||
auto tmp = fk - fnkc;
|
||||
auto fok = tmp * st.super_twiddles[k-1];
|
||||
st.tmpbuf[k] = fek + fok;
|
||||
st.tmpbuf[ncfft - k] = std::conj(fek - fok);
|
||||
}
|
||||
fft (st.substate, st.tmpbuf.data(), (std::complex<float> *)timedata);
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
#ifndef KISS_FFT_H
|
||||
#define KISS_FFT_H
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
/* for real ffts, we need an even size */
|
||||
#define kiss_fftr_next_fast_size_real(n) (kiss_fft_next_fast_size( ((n)+1) >> 1) << 1 )
|
||||
|
||||
class CKissFFT
|
||||
{
|
||||
public:
|
||||
void fft_alloc(FFT_STATE &state, const int nfft, const bool inverse_fft);
|
||||
void fft(FFT_STATE &cfg, const std::complex<float> *fin, std::complex<float> *fout);
|
||||
void fft_stride(FFT_STATE &cfg, const std::complex<float> *fin, std::complex<float> *fout, int fin_stride);
|
||||
int fft_next_fast_size(int n);
|
||||
void fftr_alloc(FFTR_STATE &state, int nfft, const bool inverse_fft);
|
||||
void fftr(FFTR_STATE &cfg,const float *timedata,std::complex<float> *freqdata);
|
||||
void fftri(FFTR_STATE &cfg,const std::complex<float> *freqdata,float *timedata);
|
||||
private:
|
||||
void kf_bfly2(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly3(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly4(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly5(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly_generic(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m, int p);
|
||||
void kf_work(std::complex<float> *Fout, const std::complex<float> *f, const size_t fstride, int in_stride, int *factors, FFT_STATE &st);
|
||||
void kf_factor(int n, int *facbuf);
|
||||
};
|
||||
#endif
|
||||
@ -0,0 +1,311 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: lpc.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 30 Sep 1990 (!)
|
||||
|
||||
Linear Prediction functions written in C.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009-2012 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define LPC_MAX_N 512 /* maximum no. of samples in frame */
|
||||
#define PI 3.141592654 /* mathematical constant */
|
||||
|
||||
#define ALPHA 1.0
|
||||
#define BETA 0.94
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "defines.h"
|
||||
#include "lpc.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
pre_emp()
|
||||
|
||||
Pre-emphasise (high pass filter with zero close to 0 Hz) a frame of
|
||||
speech samples. Helps reduce dynamic range of LPC spectrum, giving
|
||||
greater weight and hense a better match to low energy formants.
|
||||
|
||||
Should be balanced by de-emphasis of the output speech.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::pre_emp(
|
||||
float Sn_pre[], /* output frame of speech samples */
|
||||
float Sn[], /* input frame of speech samples */
|
||||
float *mem, /* Sn[-1]single sample memory */
|
||||
int Nsam /* number of speech samples to use */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
Sn_pre[i] = Sn[i] - ALPHA * mem[0];
|
||||
mem[0] = Sn[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
de_emp()
|
||||
|
||||
De-emphasis filter (low pass filter with a pole close to 0 Hz).
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::de_emp(
|
||||
float Sn_de[], /* output frame of speech samples */
|
||||
float Sn[], /* input frame of speech samples */
|
||||
float *mem, /* Sn[-1]single sample memory */
|
||||
int Nsam /* number of speech samples to use */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
Sn_de[i] = Sn[i] + BETA * mem[0];
|
||||
mem[0] = Sn_de[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
hanning_window()
|
||||
|
||||
Hanning windows a frame of speech samples.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::hanning_window(
|
||||
float Sn[], /* input frame of speech samples */
|
||||
float Wn[], /* output frame of windowed samples */
|
||||
int Nsam /* number of samples */
|
||||
)
|
||||
{
|
||||
int i; /* loop variable */
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
Wn[i] = Sn[i]*(0.5 - 0.5*cosf(2*PI*(float)i/(Nsam-1)));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
autocorrelate()
|
||||
|
||||
Finds the first P autocorrelation values of an array of windowed speech
|
||||
samples Sn[].
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::autocorrelate(
|
||||
float Sn[], /* frame of Nsam windowed speech samples */
|
||||
float Rn[], /* array of P+1 autocorrelation coefficients */
|
||||
int Nsam, /* number of windowed samples to use */
|
||||
int order /* order of LPC analysis */
|
||||
)
|
||||
{
|
||||
int i,j; /* loop variables */
|
||||
|
||||
for(j=0; j<order+1; j++)
|
||||
{
|
||||
Rn[j] = 0.0;
|
||||
for(i=0; i<Nsam-j; i++)
|
||||
Rn[j] += Sn[i]*Sn[i+j];
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
levinson_durbin()
|
||||
|
||||
Given P+1 autocorrelation coefficients, finds P Linear Prediction Coeff.
|
||||
(LPCs) where P is the order of the LPC all-pole model. The Levinson-Durbin
|
||||
algorithm is used, and is described in:
|
||||
|
||||
J. Makhoul
|
||||
"Linear prediction, a tutorial review"
|
||||
Proceedings of the IEEE
|
||||
Vol-63, No. 4, April 1975
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::levinson_durbin(
|
||||
float R[], /* order+1 autocorrelation coeff */
|
||||
float lpcs[], /* order+1 LPC's */
|
||||
int order /* order of the LPC analysis */
|
||||
)
|
||||
{
|
||||
float a[order+1][order+1];
|
||||
float sum, e, k;
|
||||
int i,j; /* loop variables */
|
||||
|
||||
e = R[0]; /* Equation 38a, Makhoul */
|
||||
|
||||
for(i=1; i<=order; i++)
|
||||
{
|
||||
sum = 0.0;
|
||||
for(j=1; j<=i-1; j++)
|
||||
sum += a[i-1][j]*R[i-j];
|
||||
k = -1.0*(R[i] + sum)/e; /* Equation 38b, Makhoul */
|
||||
if (fabsf(k) > 1.0)
|
||||
k = 0.0;
|
||||
|
||||
a[i][i] = k;
|
||||
|
||||
for(j=1; j<=i-1; j++)
|
||||
a[i][j] = a[i-1][j] + k*a[i-1][i-j]; /* Equation 38c, Makhoul */
|
||||
|
||||
e *= (1-k*k); /* Equation 38d, Makhoul */
|
||||
}
|
||||
|
||||
for(i=1; i<=order; i++)
|
||||
lpcs[i] = a[order][i];
|
||||
lpcs[0] = 1.0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
inverse_filter()
|
||||
|
||||
Inverse Filter, A(z). Produces an array of residual samples from an array
|
||||
of input samples and linear prediction coefficients.
|
||||
|
||||
The filter memory is stored in the first order samples of the input array.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::inverse_filter(
|
||||
float Sn[], /* Nsam input samples */
|
||||
float a[], /* LPCs for this frame of samples */
|
||||
int Nsam, /* number of samples */
|
||||
float res[], /* Nsam residual samples */
|
||||
int order /* order of LPC */
|
||||
)
|
||||
{
|
||||
int i,j; /* loop variables */
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
res[i] = 0.0;
|
||||
for(j=0; j<=order; j++)
|
||||
res[i] += Sn[i-j]*a[j];
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
synthesis_filter()
|
||||
|
||||
C version of the Speech Synthesis Filter, 1/A(z). Given an array of
|
||||
residual or excitation samples, and the the LP filter coefficients, this
|
||||
function will produce an array of speech samples. This filter structure is
|
||||
IIR.
|
||||
|
||||
The synthesis filter has memory as well, this is treated in the same way
|
||||
as the memory for the inverse filter (see inverse_filter() notes above).
|
||||
The difference is that the memory for the synthesis filter is stored in
|
||||
the output array, wheras the memory of the inverse filter is stored in the
|
||||
input array.
|
||||
|
||||
Note: the calling function must update the filter memory.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::synthesis_filter(
|
||||
float res[], /* Nsam input residual (excitation) samples */
|
||||
float a[], /* LPCs for this frame of speech samples */
|
||||
int Nsam, /* number of speech samples */
|
||||
int order, /* LPC order */
|
||||
float Sn_[] /* Nsam output synthesised speech samples */
|
||||
)
|
||||
{
|
||||
int i,j; /* loop variables */
|
||||
|
||||
/* Filter Nsam samples */
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
Sn_[i] = res[i]*a[0];
|
||||
for(j=1; j<=order; j++)
|
||||
Sn_[i] -= Sn_[i-j]*a[j];
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
find_aks()
|
||||
|
||||
This function takes a frame of samples, and determines the linear
|
||||
prediction coefficients for that frame of samples.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::find_aks(
|
||||
float Sn[], /* Nsam samples with order sample memory */
|
||||
float a[], /* order+1 LPCs with first coeff 1.0 */
|
||||
int Nsam, /* number of input speech samples */
|
||||
int order, /* order of the LPC analysis */
|
||||
float *E /* residual energy */
|
||||
)
|
||||
{
|
||||
float Wn[LPC_MAX_N]; /* windowed frame of Nsam speech samples */
|
||||
float R[order+1]; /* order+1 autocorrelation values of Sn[] */
|
||||
int i;
|
||||
|
||||
assert(Nsam < LPC_MAX_N);
|
||||
|
||||
hanning_window(Sn,Wn,Nsam);
|
||||
autocorrelate(Wn,R,Nsam,order);
|
||||
levinson_durbin(R,a,order);
|
||||
|
||||
*E = 0.0;
|
||||
for(i=0; i<=order; i++)
|
||||
*E += a[i]*R[i];
|
||||
if (*E < 0.0)
|
||||
*E = 1E-12;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
weight()
|
||||
|
||||
Weights a vector of LPCs.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::weight(
|
||||
float ak[], /* vector of order+1 LPCs */
|
||||
float gamma, /* weighting factor */
|
||||
int order, /* num LPCs (excluding leading 1.0) */
|
||||
float akw[] /* weighted vector of order+1 LPCs */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<=order; i++)
|
||||
akw[i] = ak[i]*powf(gamma,(float)i);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: lpc.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 24/8/09
|
||||
|
||||
Linear Prediction functions written in C.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009-2012 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __LPC__
|
||||
#define __LPC__
|
||||
|
||||
#define LPC_MAX_ORDER 20
|
||||
|
||||
class Clpc {
|
||||
public:
|
||||
void autocorrelate(float Sn[], float Rn[], int Nsam, int order);
|
||||
void levinson_durbin(float R[], float lpcs[], int order);
|
||||
private:
|
||||
void pre_emp(float Sn_pre[], float Sn[], float *mem, int Nsam);
|
||||
void de_emp(float Sn_se[], float Sn[], float *mem, int Nsam);
|
||||
void hanning_window(float Sn[], float Wn[], int Nsam);
|
||||
void inverse_filter(float Sn[], float a[], int Nsam, float res[], int order);
|
||||
void synthesis_filter(float res[], float a[], int Nsam, int order, float Sn_[]);
|
||||
void find_aks(float Sn[], float a[], int Nsam, int order, float *E);
|
||||
void weight(float ak[], float gamma, int order, float akw[]);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,520 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: nlp.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 23/3/93
|
||||
|
||||
Non Linear Pitch (NLP) estimation functions.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "nlp.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
extern CKissFFT kiss;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
GLOBALS
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/* 48 tap 600Hz low pass FIR filter coefficients */
|
||||
|
||||
static const float nlp_fir[] =
|
||||
{
|
||||
-1.0818124e-03,
|
||||
-1.1008344e-03,
|
||||
-9.2768838e-04,
|
||||
-4.2289438e-04,
|
||||
5.5034190e-04,
|
||||
2.0029849e-03,
|
||||
3.7058509e-03,
|
||||
5.1449415e-03,
|
||||
5.5924666e-03,
|
||||
4.3036754e-03,
|
||||
8.0284511e-04,
|
||||
-4.8204610e-03,
|
||||
-1.1705810e-02,
|
||||
-1.8199275e-02,
|
||||
-2.2065282e-02,
|
||||
-2.0920610e-02,
|
||||
-1.2808831e-02,
|
||||
3.2204775e-03,
|
||||
2.6683811e-02,
|
||||
5.5520624e-02,
|
||||
8.6305944e-02,
|
||||
1.1480192e-01,
|
||||
1.3674206e-01,
|
||||
1.4867556e-01,
|
||||
1.4867556e-01,
|
||||
1.3674206e-01,
|
||||
1.1480192e-01,
|
||||
8.6305944e-02,
|
||||
5.5520624e-02,
|
||||
2.6683811e-02,
|
||||
3.2204775e-03,
|
||||
-1.2808831e-02,
|
||||
-2.0920610e-02,
|
||||
-2.2065282e-02,
|
||||
-1.8199275e-02,
|
||||
-1.1705810e-02,
|
||||
-4.8204610e-03,
|
||||
8.0284511e-04,
|
||||
4.3036754e-03,
|
||||
5.5924666e-03,
|
||||
5.1449415e-03,
|
||||
3.7058509e-03,
|
||||
2.0029849e-03,
|
||||
5.5034190e-04,
|
||||
-4.2289438e-04,
|
||||
-9.2768838e-04,
|
||||
-1.1008344e-03,
|
||||
-1.0818124e-03
|
||||
};
|
||||
|
||||
static const float fdmdv_os_filter[]= {
|
||||
-0.0008215855034550382,
|
||||
-0.0007833023901802921,
|
||||
0.001075563790768233,
|
||||
0.001199092367787555,
|
||||
-0.001765309502928316,
|
||||
-0.002055372115328064,
|
||||
0.002986877604154257,
|
||||
0.003462567920638414,
|
||||
-0.004856570111126334,
|
||||
-0.005563143845031497,
|
||||
0.007533613299748122,
|
||||
0.008563932468880897,
|
||||
-0.01126857129039911,
|
||||
-0.01280782411693687,
|
||||
0.01651443896361847,
|
||||
0.01894875110322284,
|
||||
-0.02421604439474981,
|
||||
-0.02845107338464062,
|
||||
0.03672973563400258,
|
||||
0.04542046150312214,
|
||||
-0.06189165826716491,
|
||||
-0.08721876380763803,
|
||||
0.1496157094199961,
|
||||
0.4497962274137046,
|
||||
0.4497962274137046,
|
||||
0.1496157094199961,
|
||||
-0.08721876380763803,
|
||||
-0.0618916582671649,
|
||||
0.04542046150312216,
|
||||
0.03672973563400257,
|
||||
-0.02845107338464062,
|
||||
-0.02421604439474984,
|
||||
0.01894875110322284,
|
||||
0.01651443896361848,
|
||||
-0.01280782411693687,
|
||||
-0.0112685712903991,
|
||||
0.008563932468880899,
|
||||
0.007533613299748123,
|
||||
-0.005563143845031501,
|
||||
-0.004856570111126346,
|
||||
0.003462567920638419,
|
||||
0.002986877604154259,
|
||||
-0.002055372115328063,
|
||||
-0.001765309502928318,
|
||||
0.001199092367787557,
|
||||
0.001075563790768233,
|
||||
-0.0007833023901802925,
|
||||
-0.0008215855034550383
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
nlp_create()
|
||||
|
||||
Initialisation function for NLP pitch estimator.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Cnlp::nlp_create(C2CONST *c2const)
|
||||
{
|
||||
int i;
|
||||
int m = c2const->m_pitch;
|
||||
int Fs = c2const->Fs;
|
||||
|
||||
assert((Fs == 8000) || (Fs == 16000));
|
||||
snlp.Fs = Fs;
|
||||
|
||||
snlp.m = m;
|
||||
|
||||
/* if running at 16kHz allocate storage for decimating filter memory */
|
||||
|
||||
if (Fs == 16000)
|
||||
{
|
||||
snlp.Sn16k.resize(FDMDV_OS_TAPS_16K + c2const->n_samp);
|
||||
for(i=0; i<FDMDV_OS_TAPS_16K; i++)
|
||||
{
|
||||
snlp.Sn16k[i] = 0.0;
|
||||
}
|
||||
|
||||
/* most processing occurs at 8 kHz sample rate so halve m */
|
||||
|
||||
m /= 2;
|
||||
}
|
||||
|
||||
assert(m <= PMAX_M);
|
||||
|
||||
for(i=0; i<m/DEC; i++)
|
||||
{
|
||||
snlp.w[i] = 0.5 - 0.5*cosf(2*PI*i/(m/DEC-1));
|
||||
}
|
||||
|
||||
for(i=0; i<PMAX_M; i++)
|
||||
snlp.sq[i] = 0.0;
|
||||
snlp.mem_x = 0.0;
|
||||
snlp.mem_y = 0.0;
|
||||
for(i=0; i<NLP_NTAP; i++)
|
||||
snlp.mem_fir[i] = 0.0;
|
||||
|
||||
kiss.fft_alloc(snlp.fft_cfg, PE_FFT_SIZE, false);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
nlp_destroy()
|
||||
|
||||
Shut down function for NLP pitch estimator.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Cnlp::nlp_destroy()
|
||||
{
|
||||
snlp.fft_cfg.twiddles.clear();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
nlp()
|
||||
|
||||
Determines the pitch in samples using the Non Linear Pitch (NLP)
|
||||
algorithm [1]. Returns the fundamental in Hz. Note that the actual
|
||||
pitch estimate is for the centre of the M sample Sn[] vector, not
|
||||
the current N sample input vector. This is (I think) a delay of 2.5
|
||||
frames with N=80 samples. You should align further analysis using
|
||||
this pitch estimate to be centred on the middle of Sn[].
|
||||
|
||||
Two post processors have been tried, the MBE version (as discussed
|
||||
in [1]), and a post processor that checks sub-multiples. Both
|
||||
suffer occasional gross pitch errors (i.e. neither are perfect). In
|
||||
the presence of background noise the sub-multiple algorithm tends
|
||||
towards low F0 which leads to better sounding background noise than
|
||||
the MBE post processor.
|
||||
|
||||
A good way to test and develop the NLP pitch estimator is using the
|
||||
tnlp (codec2/unittest) and the codec2/octave/plnlp.m Octave script.
|
||||
|
||||
A pitch tracker searching a few frames forward and backward in time
|
||||
would be a useful addition.
|
||||
|
||||
References:
|
||||
|
||||
[1] http://rowetel.com/downloads/1997_rowe_phd_thesis.pdf Chapter 4
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float Cnlp::nlp(
|
||||
float Sn[], /* input speech vector */
|
||||
int n, /* frames shift (no. new samples in Sn[]) */
|
||||
float *pitch, /* estimated pitch period in samples at current Fs */
|
||||
// std::complex<float> Sw[], /* Freq domain version of Sn[] */
|
||||
// float W[], /* Freq domain window */
|
||||
float *prev_f0 /* previous pitch f0 in Hz, memory for pitch tracking */
|
||||
)
|
||||
{
|
||||
float notch; /* current notch filter output */
|
||||
std::complex<float> Fw[PE_FFT_SIZE]; /* DFT of squared signal (input/output) */
|
||||
float gmax;
|
||||
int gmax_bin;
|
||||
int m, i, j;
|
||||
float best_f0;
|
||||
|
||||
m = snlp.m;
|
||||
|
||||
/* Square, notch filter at DC, and LP filter vector */
|
||||
|
||||
/* If running at 16 kHz decimate to 8 kHz, as NLP ws designed for
|
||||
Fs = 8kHz. The decimating filter introduces about 3ms of delay,
|
||||
that shouldn't be a problem as pitch changes slowly. */
|
||||
|
||||
if (snlp.Fs == 8000)
|
||||
{
|
||||
/* Square latest input samples */
|
||||
|
||||
for(i=m-n; i<m; i++)
|
||||
{
|
||||
snlp.sq[i] = Sn[i]*Sn[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(snlp.Fs == 16000);
|
||||
|
||||
/* re-sample at 8 KHz */
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
snlp.Sn16k[FDMDV_OS_TAPS_16K+i] = Sn[m-n+i];
|
||||
}
|
||||
|
||||
m /= 2;
|
||||
n /= 2;
|
||||
|
||||
float Sn8k[n];
|
||||
fdmdv_16_to_8(Sn8k, &snlp.Sn16k[FDMDV_OS_TAPS_16K], n);
|
||||
|
||||
/* Square latest input samples */
|
||||
|
||||
for(i=m-n, j=0; i<m; i++, j++)
|
||||
{
|
||||
snlp.sq[i] = Sn8k[j]*Sn8k[j];
|
||||
}
|
||||
assert(j <= n);
|
||||
}
|
||||
|
||||
for(i=m-n; i<m; i++) /* notch filter at DC */
|
||||
{
|
||||
notch = snlp.sq[i] - snlp.mem_x;
|
||||
notch += COEFF*snlp.mem_y;
|
||||
snlp.mem_x = snlp.sq[i];
|
||||
snlp.mem_y = notch;
|
||||
snlp.sq[i] = notch + 1.0; /* With 0 input vectors to codec,
|
||||
kiss_fft() would take a long
|
||||
time to execute when running in
|
||||
real time. Problem was traced
|
||||
to kiss_fft function call in
|
||||
this function. Adding this small
|
||||
constant fixed problem. Not
|
||||
exactly sure why. */
|
||||
}
|
||||
|
||||
for(i=m-n; i<m; i++) /* FIR filter vector */
|
||||
{
|
||||
|
||||
for(j=0; j<NLP_NTAP-1; j++)
|
||||
snlp.mem_fir[j] = snlp.mem_fir[j+1];
|
||||
snlp.mem_fir[NLP_NTAP-1] = snlp.sq[i];
|
||||
|
||||
snlp.sq[i] = 0.0;
|
||||
for(j=0; j<NLP_NTAP; j++)
|
||||
snlp.sq[i] += snlp.mem_fir[j]*nlp_fir[j];
|
||||
}
|
||||
|
||||
/* Decimate and DFT */
|
||||
|
||||
for(i=0; i<PE_FFT_SIZE; i++)
|
||||
{
|
||||
Fw[i].real(0);
|
||||
Fw[i].imag(0);
|
||||
}
|
||||
for(i=0; i<m/DEC; i++)
|
||||
{
|
||||
Fw[i].real(snlp.sq[i*DEC]*snlp.w[i]);
|
||||
}
|
||||
|
||||
// FIXME: check if this can be converted to a real fft
|
||||
// since all imag inputs are 0
|
||||
codec2_fft_inplace(snlp.fft_cfg, Fw);
|
||||
|
||||
for(i=0; i<PE_FFT_SIZE; i++)
|
||||
Fw[i].real(Fw[i].real() * Fw[i].real() + Fw[i].imag() * Fw[i].imag());
|
||||
|
||||
/* todo: express everything in f0, as pitch in samples is dep on Fs */
|
||||
|
||||
int pmin = floor(SAMPLE_RATE*P_MIN_S);
|
||||
int pmax = floor(SAMPLE_RATE*P_MAX_S);
|
||||
|
||||
/* find global peak */
|
||||
|
||||
gmax = 0.0;
|
||||
gmax_bin = PE_FFT_SIZE*DEC/pmax;
|
||||
for(i=PE_FFT_SIZE*DEC/pmax; i<=PE_FFT_SIZE*DEC/pmin; i++)
|
||||
{
|
||||
if (Fw[i].real() > gmax)
|
||||
{
|
||||
gmax = Fw[i].real();
|
||||
gmax_bin = i;
|
||||
}
|
||||
}
|
||||
|
||||
best_f0 = post_process_sub_multiples(Fw, pmax, gmax, gmax_bin, prev_f0);
|
||||
|
||||
/* Shift samples in buffer to make room for new samples */
|
||||
|
||||
for(i=0; i<m-n; i++)
|
||||
snlp.sq[i] = snlp.sq[i+n];
|
||||
|
||||
/* return pitch period in samples and F0 estimate */
|
||||
|
||||
*pitch = (float)snlp.Fs/best_f0;
|
||||
|
||||
*prev_f0 = best_f0;
|
||||
|
||||
return(best_f0);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
post_process_sub_multiples()
|
||||
|
||||
Given the global maximma of Fw[] we search integer submultiples for
|
||||
local maxima. If local maxima exist and they are above an
|
||||
experimentally derived threshold (OK a magic number I pulled out of
|
||||
the air) we choose the submultiple as the F0 estimate.
|
||||
|
||||
The rational for this is that the lowest frequency peak of Fw[]
|
||||
should be F0, as Fw[] can be considered the autocorrelation function
|
||||
of Sw[] (the speech spectrum). However sometimes due to phase
|
||||
effects the lowest frequency maxima may not be the global maxima.
|
||||
|
||||
This works OK in practice and favours low F0 values in the presence
|
||||
of background noise which means the sinusoidal codec does an OK job
|
||||
of synthesising the background noise. High F0 in background noise
|
||||
tends to sound more periodic introducing annoying artifacts.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float Cnlp::post_process_sub_multiples(std::complex<float> Fw[], int pmax, float gmax, int gmax_bin, float *prev_f0)
|
||||
{
|
||||
int min_bin, cmax_bin;
|
||||
int mult;
|
||||
float thresh, best_f0;
|
||||
int b, bmin, bmax, lmax_bin;
|
||||
float lmax;
|
||||
int prev_f0_bin;
|
||||
|
||||
/* post process estimate by searching submultiples */
|
||||
|
||||
mult = 2;
|
||||
min_bin = PE_FFT_SIZE*DEC/pmax;
|
||||
cmax_bin = gmax_bin;
|
||||
prev_f0_bin = *prev_f0*(PE_FFT_SIZE*DEC)/SAMPLE_RATE;
|
||||
|
||||
while(gmax_bin/mult >= min_bin)
|
||||
{
|
||||
|
||||
b = gmax_bin/mult; /* determine search interval */
|
||||
bmin = 0.8*b;
|
||||
bmax = 1.2*b;
|
||||
if (bmin < min_bin)
|
||||
bmin = min_bin;
|
||||
|
||||
/* lower threshold to favour previous frames pitch estimate,
|
||||
this is a form of pitch tracking */
|
||||
|
||||
if ((prev_f0_bin > bmin) && (prev_f0_bin < bmax))
|
||||
thresh = CNLP*0.5*gmax;
|
||||
else
|
||||
thresh = CNLP*gmax;
|
||||
|
||||
lmax = 0;
|
||||
lmax_bin = bmin;
|
||||
for (b=bmin; b<=bmax; b++) /* look for maximum in interval */
|
||||
if (Fw[b].real() > lmax)
|
||||
{
|
||||
lmax = Fw[b].real();
|
||||
lmax_bin = b;
|
||||
}
|
||||
|
||||
if (lmax > thresh)
|
||||
if ((lmax > Fw[lmax_bin-1].real()) && (lmax > Fw[lmax_bin+1].real()))
|
||||
{
|
||||
cmax_bin = lmax_bin;
|
||||
}
|
||||
|
||||
mult++;
|
||||
}
|
||||
|
||||
best_f0 = (float)cmax_bin*SAMPLE_RATE/(PE_FFT_SIZE*DEC);
|
||||
|
||||
return best_f0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: fdmdv_16_to_8()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 9 May 2012
|
||||
|
||||
Changes the sample rate of a signal from 16 to 8 kHz.
|
||||
|
||||
n is the number of samples at the 8 kHz rate, there are FDMDV_OS*n
|
||||
samples at the 48 kHz rate. As above however a memory of
|
||||
FDMDV_OS_TAPS samples is reqd for in16k[] (see t16_8.c unit test as example).
|
||||
|
||||
Low pass filter the 16 kHz signal at 4 kHz using the same filter as
|
||||
the upsampler, then just output every FDMDV_OS-th filtered sample.
|
||||
|
||||
Note: this function copied from fdmdv.c, included in nlp.c as a convenience
|
||||
to avoid linking with another source file.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Cnlp::fdmdv_16_to_8(float out8k[], float in16k[], int n)
|
||||
{
|
||||
float acc;
|
||||
int i,j,k;
|
||||
|
||||
for(i=0, k=0; k<n; i+=FDMDV_OS, k++)
|
||||
{
|
||||
acc = 0.0;
|
||||
for(j=0; j<FDMDV_OS_TAPS_16K; j++)
|
||||
acc += fdmdv_os_filter[j]*in16k[i-j];
|
||||
out8k[k] = acc;
|
||||
}
|
||||
|
||||
/* update filter memory */
|
||||
|
||||
for(i=-FDMDV_OS_TAPS_16K; i<0; i++)
|
||||
in16k[i] = in16k[i + n*FDMDV_OS];
|
||||
}
|
||||
|
||||
// there is a little overhead for inplace kiss_fft but this is
|
||||
// on the powerful platforms like the Raspberry or even x86 PC based ones
|
||||
// not noticeable
|
||||
// the reduced usage of RAM and increased performance on STM32 platforms
|
||||
// should be worth it.
|
||||
void Cnlp::codec2_fft_inplace(FFT_STATE &cfg, std::complex<float> *inout)
|
||||
{
|
||||
std::complex<float> in[512];
|
||||
// decide whether to use the local stack based buffer for in
|
||||
// or to allow kiss_fft to allocate RAM
|
||||
// second part is just to play safe since first method
|
||||
// is much faster and uses less RAM
|
||||
if (cfg.nfft <= 512)
|
||||
{
|
||||
memcpy(in, inout, cfg.nfft*sizeof(std::complex<float>));
|
||||
kiss.fft(cfg, in, inout);
|
||||
}
|
||||
else
|
||||
{
|
||||
kiss.fft(cfg, inout, inout);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: nlp.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 23/3/93
|
||||
|
||||
Non Linear Pitch (NLP) estimation functions.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009 David Rowe
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __NLP__
|
||||
#define __NLP__
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
DEFINES
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#define PMAX_M 320 /* maximum NLP analysis window size */
|
||||
#define COEFF 0.95 /* notch filter parameter */
|
||||
#define PE_FFT_SIZE 512 /* DFT size for pitch estimation */
|
||||
#define DEC 5 /* decimation factor */
|
||||
#define SAMPLE_RATE 8000
|
||||
#define PI 3.141592654 /* mathematical constant */
|
||||
#define T 0.1 /* threshold for local minima candidate */
|
||||
#define F0_MAX 500
|
||||
#define CNLP 0.3 /* post processor constant */
|
||||
#define NLP_NTAP 48 /* Decimation LPF order */
|
||||
|
||||
/* 8 to 16 kHz sample rate conversion */
|
||||
|
||||
#define FDMDV_OS 2 /* oversampling rate */
|
||||
#define FDMDV_OS_TAPS_16K 48 /* number of OS filter taps at 16kHz */
|
||||
#define FDMDV_OS_TAPS_8K (FDMDV_OS_TAPS_16K/FDMDV_OS) /* number of OS filter taps at 8kHz */
|
||||
|
||||
|
||||
using NLP = struct nlp_tag
|
||||
{
|
||||
int Fs; /* sample rate in Hz */
|
||||
int m;
|
||||
float w[PMAX_M/DEC]; /* DFT window */
|
||||
float sq[PMAX_M]; /* squared speech samples */
|
||||
float mem_x,mem_y; /* memory for notch filter */
|
||||
float mem_fir[NLP_NTAP]; /* decimation FIR filter memory */
|
||||
FFT_STATE fft_cfg; /* kiss FFT config */
|
||||
std::vector<float> Sn16k; /* Fs=16kHz input speech vector */
|
||||
};
|
||||
|
||||
|
||||
class Cnlp {
|
||||
public:
|
||||
void nlp_create(C2CONST *c2const);
|
||||
void nlp_destroy();
|
||||
float nlp(float Sn[], int n, float *pitch_samples, float *prev_f0);
|
||||
void codec2_fft_inplace(FFT_STATE &cfg, std::complex<float> *inout);
|
||||
|
||||
private:
|
||||
float post_process_sub_multiples(std::complex<float> Fw[], int pmax, float gmax, int gmax_bin, float *prev_f0);
|
||||
void fdmdv_16_to_8(float out8k[], float in16k[], int n);
|
||||
|
||||
NLP snlp;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright (C) 2010 Perens LLC <bruce@perens.com>
|
||||
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
#include "quantise.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* Compile-time constants */
|
||||
/* Size of unsigned char in bits. Assumes 8 bits-per-char. */
|
||||
static const unsigned int WordSize = 8;
|
||||
|
||||
/* Mask to pick the bit component out of bitIndex. */
|
||||
static const unsigned int IndexMask = 0x7;
|
||||
|
||||
/* Used to pick the word component out of bitIndex. */
|
||||
static const unsigned int ShiftRight = 3;
|
||||
|
||||
/** Pack a bit field into a bit string, encoding the field in Gray code.
|
||||
*
|
||||
* The output is an array of unsigned char data. The fields are efficiently
|
||||
* packed into the bit string. The Gray coding is a naive attempt to reduce
|
||||
* the effect of single-bit errors, we expect to do a better job as the
|
||||
* codec develops.
|
||||
*
|
||||
* This code would be simpler if it just set one bit at a time in the string,
|
||||
* but would hit the same cache line more often. I'm not sure the complexity
|
||||
* gains us anything here.
|
||||
*
|
||||
* Although field is currently of int type rather than unsigned for
|
||||
* compatibility with the rest of the code, indices are always expected to
|
||||
* be >= 0.
|
||||
*/
|
||||
void CQuantize::pack(
|
||||
unsigned char *bitArray, /* The output bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
int field, /* The bit field to be packed. */
|
||||
unsigned int fieldWidth /* Width of the field in BITS, not bytes. */
|
||||
)
|
||||
{
|
||||
pack_natural_or_gray(bitArray, bitIndex, field, fieldWidth, 1);
|
||||
}
|
||||
|
||||
void CQuantize::pack_natural_or_gray(
|
||||
unsigned char *bitArray, /* The output bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
int field, /* The bit field to be packed. */
|
||||
unsigned int fieldWidth, /* Width of the field in BITS, not bytes. */
|
||||
unsigned int gray /* non-zero for gray coding */
|
||||
)
|
||||
{
|
||||
if (gray)
|
||||
{
|
||||
/* Convert the field to Gray code */
|
||||
field = (field >> 1) ^ field;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
unsigned int bI = *bitIndex;
|
||||
unsigned int bitsLeft = WordSize - (bI & IndexMask);
|
||||
unsigned int sliceWidth = bitsLeft < fieldWidth ? bitsLeft : fieldWidth;
|
||||
unsigned int wordIndex = bI >> ShiftRight;
|
||||
|
||||
bitArray[wordIndex] |= ((unsigned char)((field >> (fieldWidth - sliceWidth)) << (bitsLeft - sliceWidth)));
|
||||
|
||||
*bitIndex = bI + sliceWidth;
|
||||
fieldWidth -= sliceWidth;
|
||||
}
|
||||
while ( fieldWidth != 0 );
|
||||
}
|
||||
|
||||
/** Unpack a field from a bit string, converting from Gray code to binary.
|
||||
*
|
||||
*/
|
||||
int CQuantize::unpack(
|
||||
const unsigned char *bitArray, /* The input bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
unsigned int fieldWidth/* Width of the field in BITS, not bytes. */
|
||||
)
|
||||
{
|
||||
return unpack_natural_or_gray(bitArray, bitIndex, fieldWidth, 1);
|
||||
}
|
||||
|
||||
/** Unpack a field from a bit string, to binary, optionally using
|
||||
* natural or Gray code.
|
||||
*
|
||||
*/
|
||||
int CQuantize::unpack_natural_or_gray(
|
||||
const unsigned char *bitArray, /* The input bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
unsigned int fieldWidth,/* Width of the field in BITS, not bytes. */
|
||||
unsigned int gray /* non-zero for Gray coding */
|
||||
)
|
||||
{
|
||||
unsigned int field = 0;
|
||||
unsigned int t;
|
||||
|
||||
do
|
||||
{
|
||||
unsigned int bI = *bitIndex;
|
||||
unsigned int bitsLeft = WordSize - (bI & IndexMask);
|
||||
unsigned int sliceWidth = bitsLeft < fieldWidth ? bitsLeft : fieldWidth;
|
||||
|
||||
field |= (((bitArray[bI >> ShiftRight] >> (bitsLeft - sliceWidth)) & ((1 << sliceWidth) - 1)) << (fieldWidth - sliceWidth));
|
||||
|
||||
*bitIndex = bI + sliceWidth;
|
||||
fieldWidth -= sliceWidth;
|
||||
}
|
||||
while ( fieldWidth != 0 );
|
||||
|
||||
if (gray)
|
||||
{
|
||||
/* Convert from Gray code to binary. Works for maximum 8-bit fields. */
|
||||
t = field ^ (field >> 8);
|
||||
t ^= (t >> 4);
|
||||
t ^= (t >> 2);
|
||||
t ^= (t >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = field;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -0,0 +1,247 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "qbase.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
quantise
|
||||
|
||||
Quantises vec by choosing the nearest vector in codebook cb, and
|
||||
returns the vector index. The squared error of the quantised vector
|
||||
is added to se.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
long CQbase::quantise(const float *cb, float vec[], float w[], int k, int m, float *se)
|
||||
/* float cb[][K]; current VQ codebook */
|
||||
/* float vec[]; vector to quantise */
|
||||
/* float w[]; weighting vector */
|
||||
/* int k; dimension of vectors */
|
||||
/* int m; size of codebook */
|
||||
/* float *se; accumulated squared error */
|
||||
{
|
||||
float e; /* current error */
|
||||
long besti; /* best index so far */
|
||||
float beste; /* best error so far */
|
||||
long j;
|
||||
int i;
|
||||
float diff;
|
||||
|
||||
besti = 0;
|
||||
beste = 1E32;
|
||||
for(j=0; j<m; j++)
|
||||
{
|
||||
e = 0.0;
|
||||
for(i=0; i<k; i++)
|
||||
{
|
||||
diff = cb[j*k+i]-vec[i];
|
||||
e += (diff*w[i] * diff*w[i]);
|
||||
}
|
||||
if (e < beste)
|
||||
{
|
||||
beste = e;
|
||||
besti = j;
|
||||
}
|
||||
}
|
||||
|
||||
*se += beste;
|
||||
|
||||
return(besti);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_WoE()
|
||||
AUTHOR......: Jean-Marc Valin & David Rowe
|
||||
DATE CREATED: 11 May 2012
|
||||
|
||||
Joint Wo and LPC energy vector quantiser developed my Jean-Marc
|
||||
Valin. Returns index, and updated states xq[].
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQbase::encode_WoE(MODEL *model, float e, float xq[])
|
||||
{
|
||||
int i, n1;
|
||||
float x[2];
|
||||
float err[2];
|
||||
float w[2];
|
||||
const float *codebook1 = ge_cb[0].cb;
|
||||
int nb_entries = ge_cb[0].m;
|
||||
int ndim = ge_cb[0].k;
|
||||
|
||||
assert((1<<WO_E_BITS) == nb_entries);
|
||||
|
||||
if (e < 0.0) e = 0; /* occasional small negative energies due LPC round off I guess */
|
||||
|
||||
x[0] = log10f((model->Wo/PI)*4000.0/50.0)/log10f(2);
|
||||
x[1] = 10.0*log10f(1e-4 + e);
|
||||
|
||||
compute_weights2(x, xq, w);
|
||||
for (i=0; i<ndim; i++)
|
||||
err[i] = x[i]-ge_coeff[i]*xq[i];
|
||||
n1 = find_nearest_weighted(codebook1, nb_entries, err, w, ndim);
|
||||
|
||||
for (i=0; i<ndim; i++)
|
||||
{
|
||||
xq[i] = ge_coeff[i]*xq[i] + codebook1[ndim*n1+i];
|
||||
err[i] -= codebook1[ndim*n1+i];
|
||||
}
|
||||
|
||||
//printf("enc: %f %f (%f)(%f) \n", xq[0], xq[1], e, 10.0*log10(1e-4 + e));
|
||||
return n1;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_WoE()
|
||||
AUTHOR......: Jean-Marc Valin & David Rowe
|
||||
DATE CREATED: 11 May 2012
|
||||
|
||||
Joint Wo and LPC energy vector quantiser developed my Jean-Marc
|
||||
Valin. Given index and states xq[], returns Wo & E, and updates
|
||||
states xq[].
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQbase::decode_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[], int n1)
|
||||
{
|
||||
int i;
|
||||
const float *codebook1 = ge_cb[0].cb;
|
||||
int ndim = ge_cb[0].k;
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
|
||||
for (i=0; i<ndim; i++)
|
||||
{
|
||||
xq[i] = ge_coeff[i]*xq[i] + codebook1[ndim*n1+i];
|
||||
}
|
||||
|
||||
//printf("dec: %f %f\n", xq[0], xq[1]);
|
||||
model->Wo = powf(2.0, xq[0])*(PI*50.0)/4000.0;
|
||||
|
||||
/* bit errors can make us go out of range leading to all sorts of
|
||||
probs like seg faults */
|
||||
|
||||
if (model->Wo > Wo_max) model->Wo = Wo_max;
|
||||
if (model->Wo < Wo_min) model->Wo = Wo_min;
|
||||
|
||||
model->L = PI/model->Wo; /* if we quantise Wo re-compute L */
|
||||
|
||||
*e = exp10f(xq[1]/10.0);
|
||||
}
|
||||
|
||||
void CQbase::compute_weights2(const float *x, const float *xp, float *w)
|
||||
{
|
||||
w[0] = 30;
|
||||
w[1] = 1;
|
||||
if (x[1]<0)
|
||||
{
|
||||
w[0] *= .6;
|
||||
w[1] *= .3;
|
||||
}
|
||||
if (x[1]<-10)
|
||||
{
|
||||
w[0] *= .3;
|
||||
w[1] *= .3;
|
||||
}
|
||||
/* Higher weight if pitch is stable */
|
||||
if (fabsf(x[0]-xp[0])<.2)
|
||||
{
|
||||
w[0] *= 2;
|
||||
w[1] *= 1.5;
|
||||
}
|
||||
else if (fabsf(x[0]-xp[0])>.5) /* Lower if not stable */
|
||||
{
|
||||
w[0] *= .5;
|
||||
}
|
||||
|
||||
/* Lower weight for low energy */
|
||||
if (x[1] < xp[1]-10)
|
||||
{
|
||||
w[1] *= .5;
|
||||
}
|
||||
if (x[1] < xp[1]-20)
|
||||
{
|
||||
w[1] *= .5;
|
||||
}
|
||||
|
||||
//w[0] = 30;
|
||||
//w[1] = 1;
|
||||
|
||||
/* Square the weights because it's applied on the squared error */
|
||||
w[0] *= w[0];
|
||||
w[1] *= w[1];
|
||||
|
||||
}
|
||||
|
||||
int CQbase::find_nearest_weighted(const float *codebook, int nb_entries, float *x, const float *w, int ndim)
|
||||
{
|
||||
int i, j;
|
||||
float min_dist = 1e15;
|
||||
int nearest = 0;
|
||||
|
||||
for (i=0; i<nb_entries; i++)
|
||||
{
|
||||
float dist=0;
|
||||
for (j=0; j<ndim; j++)
|
||||
dist += w[j]*(x[j]-codebook[i*ndim+j])*(x[j]-codebook[i*ndim+j]);
|
||||
if (dist<min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = i;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_log_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Encodes Wo in the log domain using a WO_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQbase::encode_log_Wo(C2CONST *c2const, float Wo, int bits)
|
||||
{
|
||||
int index, Wo_levels = 1<<bits;
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float norm;
|
||||
|
||||
norm = (log10f(Wo) - log10f(Wo_min))/(log10f(Wo_max) - log10f(Wo_min));
|
||||
index = floorf(Wo_levels * norm + 0.5);
|
||||
if (index < 0 ) index = 0;
|
||||
if (index > (Wo_levels-1)) index = Wo_levels-1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_log_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Decodes Wo using a WO_LEVELS quantiser in the log domain.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQbase::decode_log_Wo(C2CONST *c2const, int index, int bits)
|
||||
{
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float step;
|
||||
float Wo;
|
||||
int Wo_levels = 1<<bits;
|
||||
|
||||
step = (log10f(Wo_max) - log10f(Wo_min))/Wo_levels;
|
||||
Wo = log10f(Wo_min) + step*(index);
|
||||
|
||||
return exp10f(Wo);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
#ifndef QBASE_H
|
||||
#define QBASE_H
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#define WO_BITS 7
|
||||
#define WO_LEVELS (1<<WO_BITS)
|
||||
#define WO_DT_BITS 3
|
||||
|
||||
#define E_BITS 5
|
||||
#define E_LEVELS (1<<E_BITS)
|
||||
#define E_MIN_DB -10.0
|
||||
#define E_MAX_DB 40.0
|
||||
|
||||
#define LSP_SCALAR_INDEXES 10
|
||||
#define LSPD_SCALAR_INDEXES 10
|
||||
#define LSP_PRED_VQ_INDEXES 3
|
||||
|
||||
#define WO_E_BITS 8
|
||||
|
||||
#define LPCPF_GAMMA 0.5
|
||||
#define LPCPF_BETA 0.2
|
||||
|
||||
class CQbase {
|
||||
public:
|
||||
int encode_WoE(MODEL *model, float e, float xq[]);
|
||||
void decode_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[], int n1);
|
||||
int encode_log_Wo(C2CONST *c2const, float Wo, int bits);
|
||||
float decode_log_Wo(C2CONST *c2const, int index, int bits);
|
||||
protected:
|
||||
long quantise(const float * cb, float vec[], float w[], int k, int m, float *se);
|
||||
void compute_weights2(const float *x, const float *xp, float *w);
|
||||
int find_nearest_weighted(const float *codebook, int nb_entries, float *x, const float *w, int ndim);
|
||||
|
||||
const float ge_coeff[2] = { 0.8, 0.9 };
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,897 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: quantise.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 31/5/92
|
||||
|
||||
Quantisation functions for the sinusoidal coder.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "quantise.h"
|
||||
#include "lpc.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
extern CKissFFT kiss;
|
||||
|
||||
#define LSP_DELTA1 0.01 /* grid spacing for LSP root searches */
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTIONS
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::lsp_bits(int i)
|
||||
{
|
||||
return lsp_cb[i].log2m;
|
||||
}
|
||||
|
||||
int CQuantize::lspd_bits(int i)
|
||||
{
|
||||
return lsp_cbd[i].log2m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
encode_lspds_scalar()
|
||||
|
||||
Scalar/VQ LSP difference quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::encode_lspds_scalar(int indexes[], float lsp[], int order)
|
||||
{
|
||||
int i,k,m;
|
||||
float lsp_hz[order];
|
||||
float lsp__hz[order];
|
||||
float dlsp[order];
|
||||
float dlsp_[order];
|
||||
float wt[order];
|
||||
const float *cb;
|
||||
float se;
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
wt[i] = 1.0;
|
||||
}
|
||||
|
||||
/* convert from radians to Hz so we can use human readable
|
||||
frequencies */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
lsp_hz[i] = (4000.0/PI)*lsp[i];
|
||||
|
||||
wt[0] = 1.0;
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
|
||||
/* find difference from previous qunatised lsp */
|
||||
|
||||
if (i)
|
||||
dlsp[i] = lsp_hz[i] - lsp__hz[i-1];
|
||||
else
|
||||
dlsp[0] = lsp_hz[0];
|
||||
|
||||
k = lsp_cbd[i].k;
|
||||
m = lsp_cbd[i].m;
|
||||
cb = lsp_cbd[i].cb;
|
||||
indexes[i] = quantise(cb, &dlsp[i], wt, k, m, &se);
|
||||
dlsp_[i] = cb[indexes[i]*k];
|
||||
|
||||
|
||||
if (i)
|
||||
lsp__hz[i] = lsp__hz[i-1] + dlsp_[i];
|
||||
else
|
||||
lsp__hz[0] = dlsp_[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CQuantize::decode_lspds_scalar( float lsp_[], int indexes[], int order)
|
||||
{
|
||||
int i,k;
|
||||
float lsp__hz[order];
|
||||
float dlsp_[order];
|
||||
const float *cb;
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
|
||||
k = lsp_cbd[i].k;
|
||||
cb = lsp_cbd[i].cb;
|
||||
dlsp_[i] = cb[indexes[i]*k];
|
||||
|
||||
if (i)
|
||||
lsp__hz[i] = lsp__hz[i-1] + dlsp_[i];
|
||||
else
|
||||
lsp__hz[0] = dlsp_[0];
|
||||
|
||||
lsp_[i] = (PI/4000.0)*lsp__hz[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#define MAX_ENTRIES 16384
|
||||
|
||||
void CQuantize::compute_weights(const float *x, float *w, int ndim)
|
||||
{
|
||||
int i;
|
||||
w[0] = MIN(x[0], x[1]-x[0]);
|
||||
for (i=1; i<ndim-1; i++)
|
||||
w[i] = MIN(x[i]-x[i-1], x[i+1]-x[i]);
|
||||
w[ndim-1] = MIN(x[ndim-1]-x[ndim-2], PI-x[ndim-1]);
|
||||
|
||||
for (i=0; i<ndim; i++)
|
||||
w[i] = 1./(.01+w[i]);
|
||||
}
|
||||
|
||||
int CQuantize::find_nearest(const float *codebook, int nb_entries, float *x, int ndim)
|
||||
{
|
||||
int i, j;
|
||||
float min_dist = 1e15;
|
||||
int nearest = 0;
|
||||
|
||||
for (i=0; i<nb_entries; i++)
|
||||
{
|
||||
float dist=0;
|
||||
for (j=0; j<ndim; j++)
|
||||
dist += (x[j]-codebook[i*ndim+j])*(x[j]-codebook[i*ndim+j]);
|
||||
if (dist<min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = i;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
int CQuantize::check_lsp_order(float lsp[], int order)
|
||||
{
|
||||
int i;
|
||||
float tmp;
|
||||
int swaps = 0;
|
||||
|
||||
for(i=1; i<order; i++)
|
||||
if (lsp[i] < lsp[i-1])
|
||||
{
|
||||
//fprintf(stderr, "swap %d\n",i);
|
||||
swaps++;
|
||||
tmp = lsp[i-1];
|
||||
lsp[i-1] = lsp[i]-0.1;
|
||||
lsp[i] = tmp+0.1;
|
||||
i = 1; /* start check again, as swap may have caused out of order */
|
||||
}
|
||||
|
||||
return swaps;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
lpc_post_filter()
|
||||
|
||||
Applies a post filter to the LPC synthesis filter power spectrum
|
||||
Pw, which supresses the inter-formant energy.
|
||||
|
||||
The algorithm is from p267 (Section 8.6) of "Digital Speech",
|
||||
edited by A.M. Kondoz, 1994 published by Wiley and Sons. Chapter 8
|
||||
of this text is on the MBE vocoder, and this is a freq domain
|
||||
adaptation of post filtering commonly used in CELP.
|
||||
|
||||
I used the Octave simulation lpcpf.m to get an understanding of the
|
||||
algorithm.
|
||||
|
||||
Requires two more FFTs which is significantly more MIPs. However
|
||||
it should be possible to implement this more efficiently in the
|
||||
time domain. Just not sure how to handle relative time delays
|
||||
between the synthesis stage and updating these coeffs. A smaller
|
||||
FFT size might also be accetable to save CPU.
|
||||
|
||||
TODO:
|
||||
[ ] sync var names between Octave and C version
|
||||
[ ] doc gain normalisation
|
||||
[ ] I think the first FFT is not rqd as we do the same
|
||||
thing in aks_to_M2().
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::lpc_post_filter(FFTR_STATE *fftr_fwd_cfg, float Pw[], float ak[], int order, float beta, float gamma, int bass_boost, float E)
|
||||
{
|
||||
int i;
|
||||
float x[FFT_ENC]; /* input to FFTs */
|
||||
std::complex<float> Ww[FFT_ENC/2+1]; /* weighting spectrum */
|
||||
float Rw[FFT_ENC/2+1]; /* R = WA */
|
||||
float e_before, e_after, gain;
|
||||
float Pfw;
|
||||
float max_Rw, min_Rw;
|
||||
float coeff;
|
||||
|
||||
/* Determine weighting filter spectrum W(exp(jw)) ---------------*/
|
||||
|
||||
for(i=0; i<FFT_ENC; i++)
|
||||
{
|
||||
x[i] = 0.0;
|
||||
}
|
||||
|
||||
x[0] = ak[0];
|
||||
coeff = gamma;
|
||||
for(i=1; i<=order; i++)
|
||||
{
|
||||
x[i] = ak[i] * coeff;
|
||||
coeff *= gamma;
|
||||
}
|
||||
kiss.fftr(*fftr_fwd_cfg, x, Ww);
|
||||
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Ww[i].real(Ww[i].real() * Ww[i].real() + Ww[i].imag() * Ww[i].imag());
|
||||
}
|
||||
|
||||
/* Determined combined filter R = WA ---------------------------*/
|
||||
|
||||
max_Rw = 0.0;
|
||||
min_Rw = 1E32;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Rw[i] = sqrtf(Ww[i].real() * Pw[i]);
|
||||
if (Rw[i] > max_Rw)
|
||||
max_Rw = Rw[i];
|
||||
if (Rw[i] < min_Rw)
|
||||
min_Rw = Rw[i];
|
||||
|
||||
}
|
||||
|
||||
/* create post filter mag spectrum and apply ------------------*/
|
||||
|
||||
/* measure energy before post filtering */
|
||||
|
||||
e_before = 1E-4;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
e_before += Pw[i];
|
||||
|
||||
/* apply post filter and measure energy */
|
||||
|
||||
|
||||
e_after = 1E-4;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pfw = powf(Rw[i], beta);
|
||||
Pw[i] *= Pfw * Pfw;
|
||||
e_after += Pw[i];
|
||||
}
|
||||
gain = e_before/e_after;
|
||||
|
||||
/* apply gain factor to normalise energy, and LPC Energy */
|
||||
|
||||
gain *= E;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pw[i] *= gain;
|
||||
}
|
||||
|
||||
if (bass_boost)
|
||||
{
|
||||
/* add 3dB to first 1 kHz to account for LP effect of PF */
|
||||
|
||||
for(i=0; i<FFT_ENC/8; i++)
|
||||
{
|
||||
Pw[i] *= 1.4*1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
aks_to_M2()
|
||||
|
||||
Transforms the linear prediction coefficients to spectral amplitude
|
||||
samples. This function determines A(m) from the average energy per
|
||||
band using an FFT.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::aks_to_M2(
|
||||
FFTR_STATE * fftr_fwd_cfg,
|
||||
float ak[], /* LPC's */
|
||||
int order,
|
||||
MODEL *model, /* sinusoidal model parameters for this frame */
|
||||
float E, /* energy term */
|
||||
float *snr, /* signal to noise ratio for this frame in dB */
|
||||
int sim_pf, /* true to simulate a post filter */
|
||||
int pf, /* true to enable actual LPC post filter */
|
||||
int bass_boost, /* enable LPC filter 0-1kHz 3dB boost */
|
||||
float beta,
|
||||
float gamma, /* LPC post filter parameters */
|
||||
std::complex<float> Aw[] /* output power spectrum */
|
||||
)
|
||||
{
|
||||
int i,m; /* loop variables */
|
||||
int am,bm; /* limits of current band */
|
||||
float r; /* no. rads/bin */
|
||||
float Em; /* energy in band */
|
||||
float Am; /* spectral amplitude sample */
|
||||
float signal, noise;
|
||||
|
||||
r = TWO_PI/(FFT_ENC);
|
||||
|
||||
/* Determine DFT of A(exp(jw)) --------------------------------------------*/
|
||||
{
|
||||
float a[FFT_ENC]; /* input to FFT for power spectrum */
|
||||
|
||||
for(i=0; i<FFT_ENC; i++)
|
||||
{
|
||||
a[i] = 0.0;
|
||||
}
|
||||
|
||||
for(i=0; i<=order; i++)
|
||||
a[i] = ak[i];
|
||||
kiss.fftr(*fftr_fwd_cfg, a, Aw);
|
||||
}
|
||||
|
||||
/* Determine power spectrum P(w) = E/(A(exp(jw))^2 ------------------------*/
|
||||
|
||||
float Pw[FFT_ENC/2];
|
||||
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pw[i] = 1.0/(Aw[i].real() * Aw[i].real() + Aw[i].imag() * Aw[i].imag() + 1E-6);
|
||||
}
|
||||
|
||||
if (pf)
|
||||
lpc_post_filter(fftr_fwd_cfg, Pw, ak, order, beta, gamma, bass_boost, E);
|
||||
else
|
||||
{
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pw[i] *= E;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine magnitudes from P(w) ----------------------------------------*/
|
||||
|
||||
/* when used just by decoder {A} might be all zeroes so init signal
|
||||
and noise to prevent log(0) errors */
|
||||
|
||||
signal = 1E-30;
|
||||
noise = 1E-32;
|
||||
|
||||
for(m=1; m<=model->L; m++)
|
||||
{
|
||||
am = (int)((m - 0.5)*model->Wo/r + 0.5);
|
||||
bm = (int)((m + 0.5)*model->Wo/r + 0.5);
|
||||
|
||||
// FIXME: With arm_rfft_fast_f32 we have to use this
|
||||
// otherwise sometimes a to high bm is calculated
|
||||
// which causes trouble later in the calculation
|
||||
// chain
|
||||
// it seems for some reason model->Wo is calculated somewhat too high
|
||||
if (bm>FFT_ENC/2)
|
||||
{
|
||||
bm = FFT_ENC/2;
|
||||
}
|
||||
Em = 0.0;
|
||||
|
||||
for(i=am; i<bm; i++)
|
||||
Em += Pw[i];
|
||||
Am = sqrtf(Em);
|
||||
|
||||
signal += model->A[m]*model->A[m];
|
||||
noise += (model->A[m] - Am)*(model->A[m] - Am);
|
||||
|
||||
/* This code significantly improves perf of LPC model, in
|
||||
particular when combined with phase0. The LPC spectrum tends
|
||||
to track just under the peaks of the spectral envelope, and
|
||||
just above nulls. This algorithm does the reverse to
|
||||
compensate - raising the amplitudes of spectral peaks, while
|
||||
attenuating the null. This enhances the formants, and
|
||||
supresses the energy between formants. */
|
||||
|
||||
if (sim_pf)
|
||||
{
|
||||
if (Am > model->A[m])
|
||||
Am *= 0.7;
|
||||
if (Am < model->A[m])
|
||||
Am *= 1.4;
|
||||
}
|
||||
model->A[m] = Am;
|
||||
}
|
||||
*snr = 10.0*log10f(signal/noise);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Encodes Wo using a WO_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::encode_Wo(C2CONST *c2const, float Wo, int bits)
|
||||
{
|
||||
int index, Wo_levels = 1<<bits;
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float norm;
|
||||
|
||||
norm = (Wo - Wo_min)/(Wo_max - Wo_min);
|
||||
index = floorf(Wo_levels * norm + 0.5);
|
||||
if (index < 0 ) index = 0;
|
||||
if (index > (Wo_levels-1)) index = Wo_levels-1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Decodes Wo using a WO_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::decode_Wo(C2CONST *c2const, int index, int bits)
|
||||
{
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float step;
|
||||
float Wo;
|
||||
int Wo_levels = 1<<bits;
|
||||
|
||||
step = (Wo_max - Wo_min)/Wo_levels;
|
||||
Wo = Wo_min + step*(index);
|
||||
|
||||
return Wo;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: speech_to_uq_lsps()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Analyse a windowed frame of time domain speech to determine LPCs
|
||||
which are the converted to LSPs for quantisation and transmission
|
||||
over the channel.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], int m_pitch, int order)
|
||||
{
|
||||
int i, roots;
|
||||
float Wn[m_pitch];
|
||||
float R[order+1];
|
||||
float e, E;
|
||||
Clpc lpc;
|
||||
|
||||
e = 0.0;
|
||||
for(i=0; i<m_pitch; i++)
|
||||
{
|
||||
Wn[i] = Sn[i]*w[i];
|
||||
e += Wn[i]*Wn[i];
|
||||
}
|
||||
|
||||
/* trap 0 energy case as LPC analysis will fail */
|
||||
|
||||
if (e == 0.0)
|
||||
{
|
||||
for(i=0; i<order; i++)
|
||||
lsp[i] = (PI/order)*(float)i;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
lpc.autocorrelate(Wn, R, m_pitch, order);
|
||||
lpc.levinson_durbin(R, ak, order);
|
||||
|
||||
E = 0.0;
|
||||
for(i=0; i<=order; i++)
|
||||
E += ak[i]*R[i];
|
||||
|
||||
/* 15 Hz BW expansion as I can't hear the difference and it may help
|
||||
help occasional fails in the LSP root finding. Important to do this
|
||||
after energy calculation to avoid -ve energy values.
|
||||
*/
|
||||
|
||||
for(i=0; i<=order; i++)
|
||||
ak[i] *= powf(0.994,(float)i);
|
||||
|
||||
roots = lpc_to_lsp(ak, order, lsp, 5, LSP_DELTA1);
|
||||
if (roots != order)
|
||||
{
|
||||
/* if root finding fails use some benign LSP values instead */
|
||||
for(i=0; i<order; i++)
|
||||
lsp[i] = (PI/order)*(float)i;
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_lsps_scalar()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Thirty-six bit sclar LSP quantiser. From a vector of unquantised
|
||||
(floating point) LSPs finds the quantised LSP indexes.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::encode_lsps_scalar(int indexes[], float lsp[], int order)
|
||||
{
|
||||
int i,k,m;
|
||||
float wt[1];
|
||||
float lsp_hz[order];
|
||||
const float *cb;
|
||||
float se;
|
||||
|
||||
/* convert from radians to Hz so we can use human readable
|
||||
frequencies */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
lsp_hz[i] = (4000.0/PI)*lsp[i];
|
||||
|
||||
/* scalar quantisers */
|
||||
|
||||
wt[0] = 1.0;
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
k = lsp_cb[i].k;
|
||||
m = lsp_cb[i].m;
|
||||
cb = lsp_cb[i].cb;
|
||||
indexes[i] = quantise(cb, &lsp_hz[i], wt, k, m, &se);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_lsps_scalar()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
From a vector of quantised LSP indexes, returns the quantised
|
||||
(floating point) LSPs.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::decode_lsps_scalar(float lsp[], int indexes[], int order)
|
||||
{
|
||||
int i,k;
|
||||
float lsp_hz[order];
|
||||
const float *cb;
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
k = lsp_cb[i].k;
|
||||
cb = lsp_cb[i].cb;
|
||||
lsp_hz[i] = cb[indexes[i]*k];
|
||||
}
|
||||
|
||||
/* convert back to radians */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
lsp[i] = (PI/4000.0)*lsp_hz[i];
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: bw_expand_lsps()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Applies Bandwidth Expansion (BW) to a vector of LSPs. Prevents any
|
||||
two LSPs getting too close together after quantisation. We know
|
||||
from experiment that LSP quantisation errors < 12.5Hz (25Hz step
|
||||
size) are inaudible so we use that as the minimum LSP separation.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::bw_expand_lsps(float lsp[], int order, float min_sep_low, float min_sep_high)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<4; i++)
|
||||
{
|
||||
|
||||
if ((lsp[i] - lsp[i-1]) < min_sep_low*(PI/4000.0))
|
||||
lsp[i] = lsp[i-1] + min_sep_low*(PI/4000.0);
|
||||
|
||||
}
|
||||
|
||||
/* As quantiser gaps increased, larger BW expansion was required
|
||||
to prevent twinkly noises. This may need more experiment for
|
||||
different quanstisers.
|
||||
*/
|
||||
|
||||
for(i=4; i<order; i++)
|
||||
{
|
||||
if (lsp[i] - lsp[i-1] < min_sep_high*(PI/4000.0))
|
||||
lsp[i] = lsp[i-1] + min_sep_high*(PI/4000.0);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: apply_lpc_correction()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Apply first harmonic LPC correction at decoder. This helps improve
|
||||
low pitch males after LPC modelling, like hts1a and morig.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::apply_lpc_correction(MODEL *model)
|
||||
{
|
||||
if (model->Wo < (PI*150.0/4000))
|
||||
{
|
||||
model->A[1] *= 0.032;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_energy()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Encodes LPC energy using an E_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::encode_energy(float e, int bits)
|
||||
{
|
||||
int index, e_levels = 1<<bits;
|
||||
float e_min = E_MIN_DB;
|
||||
float e_max = E_MAX_DB;
|
||||
float norm;
|
||||
|
||||
e = 10.0*log10f(e);
|
||||
norm = (e - e_min)/(e_max - e_min);
|
||||
index = floorf(e_levels * norm + 0.5);
|
||||
if (index < 0 ) index = 0;
|
||||
if (index > (e_levels-1)) index = e_levels-1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_energy()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Decodes energy using a E_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::decode_energy(int index, int bits)
|
||||
{
|
||||
float e_min = E_MIN_DB;
|
||||
float e_max = E_MAX_DB;
|
||||
float step;
|
||||
float e;
|
||||
int e_levels = 1<<bits;
|
||||
|
||||
step = (e_max - e_min)/e_levels;
|
||||
e = e_min + step*(index);
|
||||
e = exp10f(e/10.0);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: lpc_to_lsp()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 24/2/93
|
||||
|
||||
This function converts LPC coefficients to LSP coefficients.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::lpc_to_lsp(float *a, int order, float *freq, int nb, float delta)
|
||||
/* float *a lpc coefficients */
|
||||
/* int order order of LPC coefficients (10) */
|
||||
/* float *freq LSP frequencies in radians */
|
||||
/* int nb number of sub-intervals (4) */
|
||||
/* float delta grid spacing interval (0.02) */
|
||||
{
|
||||
float psuml,psumr,psumm,temp_xr,xl,xr,xm = 0;
|
||||
float temp_psumr;
|
||||
int i,j,m,flag,k;
|
||||
float *px; /* ptrs of respective P'(z) & Q'(z) */
|
||||
float *qx;
|
||||
float *p;
|
||||
float *q;
|
||||
float *pt; /* ptr used for cheb_poly_eval()
|
||||
whether P' or Q' */
|
||||
int roots=0; /* number of roots found */
|
||||
float Q[order + 1];
|
||||
float P[order + 1];
|
||||
|
||||
flag = 1;
|
||||
m = order/2; /* order of P'(z) & Q'(z) polynimials */
|
||||
|
||||
/* Allocate memory space for polynomials */
|
||||
|
||||
/* determine P'(z)'s and Q'(z)'s coefficients where
|
||||
P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */
|
||||
|
||||
px = P; /* initilaise ptrs */
|
||||
qx = Q;
|
||||
p = px;
|
||||
q = qx;
|
||||
*px++ = 1.0;
|
||||
*qx++ = 1.0;
|
||||
for(i=1; i<=m; i++)
|
||||
{
|
||||
*px++ = a[i]+a[order+1-i]-*p++;
|
||||
*qx++ = a[i]-a[order+1-i]+*q++;
|
||||
}
|
||||
px = P;
|
||||
qx = Q;
|
||||
for(i=0; i<m; i++)
|
||||
{
|
||||
*px = 2**px;
|
||||
*qx = 2**qx;
|
||||
px++;
|
||||
qx++;
|
||||
}
|
||||
px = P; /* re-initialise ptrs */
|
||||
qx = Q;
|
||||
|
||||
/* Search for a zero in P'(z) polynomial first and then alternate to Q'(z).
|
||||
Keep alternating between the two polynomials as each zero is found */
|
||||
|
||||
xr = 0; /* initialise xr to zero */
|
||||
xl = 1.0; /* start at point xl = 1 */
|
||||
|
||||
|
||||
for(j=0; j<order; j++)
|
||||
{
|
||||
if(j%2) /* determines whether P' or Q' is eval. */
|
||||
pt = qx;
|
||||
else
|
||||
pt = px;
|
||||
|
||||
psuml = cheb_poly_eva(pt,xl,order); /* evals poly. at xl */
|
||||
flag = 1;
|
||||
while(flag && (xr >= -1.0))
|
||||
{
|
||||
xr = xl - delta ; /* interval spacing */
|
||||
psumr = cheb_poly_eva(pt,xr,order);/* poly(xl-delta_x) */
|
||||
temp_psumr = psumr;
|
||||
temp_xr = xr;
|
||||
|
||||
/* if no sign change increment xr and re-evaluate
|
||||
poly(xr). Repeat til sign change. if a sign change has
|
||||
occurred the interval is bisected and then checked again
|
||||
for a sign change which determines in which interval the
|
||||
zero lies in. If there is no sign change between poly(xm)
|
||||
and poly(xl) set interval between xm and xr else set
|
||||
interval between xl and xr and repeat till root is located
|
||||
within the specified limits */
|
||||
|
||||
if(((psumr*psuml)<0.0) || (psumr == 0.0))
|
||||
{
|
||||
roots++;
|
||||
|
||||
psumm=psuml;
|
||||
for(k=0; k<=nb; k++)
|
||||
{
|
||||
xm = (xl+xr)/2; /* bisect the interval */
|
||||
psumm=cheb_poly_eva(pt,xm,order);
|
||||
if(psumm*psuml>0.)
|
||||
{
|
||||
psuml=psumm;
|
||||
xl=xm;
|
||||
}
|
||||
else
|
||||
{
|
||||
psumr=psumm;
|
||||
xr=xm;
|
||||
}
|
||||
}
|
||||
|
||||
/* once zero is found, reset initial interval to xr */
|
||||
freq[j] = (xm);
|
||||
xl = xm;
|
||||
flag = 0; /* reset flag for next search */
|
||||
}
|
||||
else
|
||||
{
|
||||
psuml=temp_psumr;
|
||||
xl=temp_xr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* convert from x domain to radians */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
freq[i] = acosf(freq[i]);
|
||||
}
|
||||
|
||||
return(roots);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: cheb_poly_eva()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 24/2/93
|
||||
|
||||
This function evalutes a series of chebyshev polynomials
|
||||
|
||||
FIXME: performing memory allocation at run time is very inefficient,
|
||||
replace with stack variables of MAX_P size.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::cheb_poly_eva(float *coef,float x,int order)
|
||||
/* float coef[] coefficients of the polynomial to be evaluated */
|
||||
/* float x the point where polynomial is to be evaluated */
|
||||
/* int order order of the polynomial */
|
||||
{
|
||||
int i;
|
||||
float *t,*u,*v,sum;
|
||||
float T[(order / 2) + 1];
|
||||
|
||||
/* Initialise pointers */
|
||||
|
||||
t = T; /* T[i-2] */
|
||||
*t++ = 1.0;
|
||||
u = t--; /* T[i-1] */
|
||||
*u++ = x;
|
||||
v = u--; /* T[i] */
|
||||
|
||||
/* Evaluate chebyshev series formulation using iterative approach */
|
||||
|
||||
for(i=2; i<=order/2; i++)
|
||||
*v++ = (2*x)*(*u++) - *t++; /* T[i] = 2*x*T[i-1] - T[i-2] */
|
||||
|
||||
sum=0.0; /* initialise sum to zero */
|
||||
t = T; /* reset pointer */
|
||||
|
||||
/* Evaluate polynomial and return value also free memory space */
|
||||
|
||||
for(i=0; i<=order/2; i++)
|
||||
sum+=coef[(order/2)-i]**t++;
|
||||
|
||||
return sum;
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: quantise.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 31/5/92
|
||||
|
||||
Quantisation functions for the sinusoidal coder.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
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 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __QUANTISE__
|
||||
#define __QUANTISE__
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include "qbase.h"
|
||||
|
||||
class CQuantize : public CQbase {
|
||||
public:
|
||||
void aks_to_M2(FFTR_STATE *fftr_fwd_cfg, float ak[], int order, MODEL *model, float E, float *snr, int sim_pf, int pf, int bass_boost, float beta, float gamma, std::complex<float> Aw[]);
|
||||
|
||||
int encode_Wo(C2CONST *c2const, float Wo, int bits);
|
||||
float decode_Wo(C2CONST *c2const, int index, int bits);
|
||||
void encode_lsps_scalar(int indexes[], float lsp[], int order);
|
||||
void decode_lsps_scalar(float lsp[], int indexes[], int order);
|
||||
void encode_lspds_scalar(int indexes[], float lsp[], int order);
|
||||
void decode_lspds_scalar(float lsp[], int indexes[], int order);
|
||||
|
||||
int encode_energy(float e, int bits);
|
||||
float decode_energy(int index, int bits);
|
||||
|
||||
void pack(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits);
|
||||
void pack_natural_or_gray(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits, unsigned int gray);
|
||||
int unpack(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits);
|
||||
int unpack_natural_or_gray(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits, unsigned int gray);
|
||||
|
||||
int lsp_bits(int i);
|
||||
int lspd_bits(int i);
|
||||
|
||||
void apply_lpc_correction(MODEL *model);
|
||||
float speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], int m_pitch, int order);
|
||||
int check_lsp_order(float lsp[], int lpc_order);
|
||||
void bw_expand_lsps(float lsp[], int order, float min_sep_low, float min_sep_high);
|
||||
|
||||
private:
|
||||
void compute_weights(const float *x, float *w, int ndim);
|
||||
int find_nearest(const float *codebook, int nb_entries, float *x, int ndim);
|
||||
void lpc_post_filter(FFTR_STATE *fftr_fwd_cfg, float Pw[], float ak[], int order, float beta, float gamma, int bass_boost, float E);
|
||||
int lpc_to_lsp (float *a, int lpcrdr, float *freq, int nb, float delta);
|
||||
float cheb_poly_eva(float *coef,float x,int order);
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue