@audio/speech-lpc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lpc.d.ts +26 -0
- package/lpc.js +88 -0
- package/package.json +40 -0
package/lpc.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type Buf = Float32Array | Float64Array | number[]
|
|
2
|
+
interface BiquadCoef { b0: number; b1: number; b2: number; a1: number; a2: number }
|
|
3
|
+
type SOS = BiquadCoef[]
|
|
4
|
+
|
|
5
|
+
export interface LpcParams {
|
|
6
|
+
order?: number // LPC order (default 12)
|
|
7
|
+
[key: string]: unknown
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface LpcResult {
|
|
11
|
+
coefs: Float64Array // LPC coefficients a[1..order] of A(z) = 1 + Σ a_k·z⁻ᵏ
|
|
12
|
+
gain: number // prediction-error gain (per-sample std of the whitening filter output, pre-normalization)
|
|
13
|
+
residual: Float64Array // whitened residual e[n] = A(z)x[n], normalized to unit power (divided by gain) — feed to lpcSynthesize as-is, or scale by a new gain to resynthesize
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** LPC analysis — autocorrelation + Levinson-Durbin. Throws if params.order is not set on a fresh params object (no default without one). */
|
|
17
|
+
export function lpcAnalysis(data: Buf, params: LpcParams): LpcResult
|
|
18
|
+
|
|
19
|
+
export interface LpcSynthParams {
|
|
20
|
+
coefs: Float64Array | number[]
|
|
21
|
+
gain?: number // default 1
|
|
22
|
+
[key: string]: unknown
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** LPC synthesis — all-pole filter reconstruction. y[n] = gain·excitation[n] − Σ coefs[k]·y[n−1−k], the algebraic inverse of lpcAnalysis's residual. */
|
|
26
|
+
export function lpcSynthesize(residual: Buf, params: LpcSynthParams): Buf
|
package/lpc.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linear Predictive Coding analysis/synthesis.
|
|
3
|
+
* Autocorrelation method with Levinson-Durbin recursion.
|
|
4
|
+
*
|
|
5
|
+
* @module audio-filter/speech/lpc
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* LPC analysis via autocorrelation + Levinson-Durbin.
|
|
10
|
+
* @param {Float64Array} data - Input signal
|
|
11
|
+
* @param {object} params - { order (12) }
|
|
12
|
+
* @returns {{ coefs: Float64Array, gain: number, residual: Float64Array }}
|
|
13
|
+
*/
|
|
14
|
+
export function lpcAnalysis(data, params) {
|
|
15
|
+
let order = params.order || 12
|
|
16
|
+
let N = data.length
|
|
17
|
+
|
|
18
|
+
// Autocorrelation r[0..order], normalized per-sample (Rabiner & Schafer biased
|
|
19
|
+
// estimator) so E/gain are frame-length invariant, not sum-length dependent
|
|
20
|
+
let r = new Float64Array(order + 1)
|
|
21
|
+
for (let i = 0; i <= order; i++) {
|
|
22
|
+
for (let n = i; n < N; n++) r[i] += data[n] * data[n - i]
|
|
23
|
+
r[i] /= N
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Levinson-Durbin
|
|
27
|
+
let a = new Float64Array(order + 1)
|
|
28
|
+
let prev = new Float64Array(order + 1)
|
|
29
|
+
a[0] = 1
|
|
30
|
+
let E = r[0]
|
|
31
|
+
|
|
32
|
+
for (let i = 1; i <= order; i++) {
|
|
33
|
+
let sum = 0
|
|
34
|
+
for (let j = 1; j < i; j++) sum += a[j] * r[i - j]
|
|
35
|
+
let k = -(r[i] + sum) / E
|
|
36
|
+
|
|
37
|
+
// Copy current coefficients
|
|
38
|
+
prev.set(a)
|
|
39
|
+
|
|
40
|
+
for (let j = 1; j < i; j++) a[j] = prev[j] + k * prev[i - j]
|
|
41
|
+
a[i] = k
|
|
42
|
+
|
|
43
|
+
E *= (1 - k * k)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let gain = Math.sqrt(E) // per-sample prediction-error std (E is already per-sample)
|
|
47
|
+
let coefs = a.subarray(1) // a[1..order] of A(z) = 1 + Σ a_k z⁻ᵏ
|
|
48
|
+
|
|
49
|
+
// Whitening filter e[n] = A(z)x[n] = x[n] + Σ coefs[k]·x[n−1−k], normalized to unit power
|
|
50
|
+
let residual = new Float64Array(N)
|
|
51
|
+
for (let n = 0; n < N; n++) {
|
|
52
|
+
let sum = 0
|
|
53
|
+
for (let k = 1; k <= order; k++) if (n - k >= 0) sum += coefs[k - 1] * data[n - k]
|
|
54
|
+
residual[n] = (data[n] + sum) / gain
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { coefs: new Float64Array(coefs), gain, residual }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* All-pole synthesis filter.
|
|
62
|
+
* @param {Float64Array} excitation - Excitation/residual signal, unit power (modified in-place)
|
|
63
|
+
* @param {object} params - { coefs, gain (1), _s (internal state) }
|
|
64
|
+
* @returns {Float64Array} Synthesized signal
|
|
65
|
+
*/
|
|
66
|
+
export function lpcSynthesize(excitation, params) {
|
|
67
|
+
let coefs = params.coefs
|
|
68
|
+
let gain = params.gain != null ? params.gain : 1
|
|
69
|
+
let order = coefs.length
|
|
70
|
+
let N = excitation.length
|
|
71
|
+
|
|
72
|
+
if (!params._s || params._s.length !== order) params._s = new Float64Array(order)
|
|
73
|
+
let s = params._s
|
|
74
|
+
|
|
75
|
+
// y[n] = gain·u[n] - Σ coefs[k]·y[n-1-k] — algebraic inverse of lpcAnalysis's
|
|
76
|
+
// e[n] = x[n] + Σ coefs[k]·x[n-1-k], u = e/gain
|
|
77
|
+
for (let n = 0; n < N; n++) {
|
|
78
|
+
let y = gain * excitation[n]
|
|
79
|
+
for (let k = 0; k < order; k++) y -= coefs[k] * s[k]
|
|
80
|
+
excitation[n] = y
|
|
81
|
+
|
|
82
|
+
// Shift state
|
|
83
|
+
for (let k = order - 1; k > 0; k--) s[k] = s[k - 1]
|
|
84
|
+
s[0] = y
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return excitation
|
|
88
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audio/speech-lpc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Linear Predictive Coding analysis/synthesis",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "lpc.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./lpc.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"lpc.js",
|
|
14
|
+
"lpc.d.ts"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"audio",
|
|
18
|
+
"dsp",
|
|
19
|
+
"speech",
|
|
20
|
+
"lpc"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "Dmitry Iv. <dfcreative@gmail.com>",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/audiojs/filter.git",
|
|
27
|
+
"directory": "packages/speech-lpc"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/audiojs/filter/tree/main/packages/speech-lpc",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/audiojs/filter/issues"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"types": "lpc.d.ts"
|
|
40
|
+
}
|