@audio/speech-formant 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.
Files changed (3) hide show
  1. package/formant.d.ts +15 -0
  2. package/formant.js +41 -0
  3. package/package.json +43 -0
package/formant.d.ts ADDED
@@ -0,0 +1,15 @@
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 Formant { fc: number; bw?: number; gain?: number } // bw default 50, gain default 1
6
+
7
+ export interface FormantParams {
8
+ formants?: Formant[] // default 3-formant /a/ vowel bank
9
+ fs?: number
10
+ [key: string]: unknown
11
+ }
12
+
13
+ /** Parallel formant filter bank for vowel synthesis, in-place */
14
+ declare function formant(data: Buf, params: FormantParams): Buf
15
+ export default formant
package/formant.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Parallel formant filter bank.
3
+ * Used for vowel/formant synthesis.
4
+ *
5
+ * @module audio-filter/speech/formant
6
+ */
7
+
8
+ import resonator from '@audio/filter-resonator'
9
+
10
+ /**
11
+ * @param {Float64Array} data - Input (modified in-place)
12
+ * @param {object} params - { formants: [{fc, bw, gain}], fs }
13
+ */
14
+ export default function formant (data, params) {
15
+ let fs = params.fs || 44100
16
+ let formants = params.formants || [
17
+ {fc: 730, bw: 90, gain: 1}, // F1 (open vowel /a/)
18
+ {fc: 1090, bw: 110, gain: 0.5},
19
+ {fc: 2440, bw: 170, gain: 0.3}
20
+ ]
21
+
22
+ // Rebuild filter bank when band content (fc/bw/gain) or fs changes — keyed by
23
+ // content, not object identity, since params.formants is often reused/mutated in place
24
+ let key = fs + '|' + formants.map(f => f.fc + ',' + (f.bw || 50) + ',' + (f.gain ?? 1)).join(';')
25
+ if (params._formantsKey !== key) {
26
+ params._states = formants.map(f => ({fc: f.fc, bw: f.bw || 50, fs, _gain: f.gain ?? 1}))
27
+ params._formantsKey = key
28
+ }
29
+
30
+ let input = Float64Array.from(data)
31
+ data.fill(0)
32
+
33
+ for (let i = 0; i < formants.length; i++) {
34
+ let band = Float64Array.from(input)
35
+ resonator(band, params._states[i])
36
+ let g = params._states[i]._gain
37
+ for (let j = 0; j < data.length; j++) data[j] += band[j] * g
38
+ }
39
+
40
+ return data
41
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@audio/speech-formant",
3
+ "version": "1.0.0",
4
+ "description": "Parallel formant filter bank",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "formant.js",
8
+ "exports": {
9
+ ".": "./formant.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "files": [
13
+ "formant.js",
14
+ "formant.d.ts"
15
+ ],
16
+ "dependencies": {
17
+ "@audio/filter-resonator": "^1.0.0"
18
+ },
19
+ "keywords": [
20
+ "audio",
21
+ "dsp",
22
+ "speech",
23
+ "formant"
24
+ ],
25
+ "license": "MIT",
26
+ "author": "Dmitry Iv. <dfcreative@gmail.com>",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/audiojs/filter.git",
30
+ "directory": "packages/speech-formant"
31
+ },
32
+ "homepage": "https://github.com/audiojs/filter/tree/main/packages/speech-formant",
33
+ "bugs": {
34
+ "url": "https://github.com/audiojs/filter/issues"
35
+ },
36
+ "engines": {
37
+ "node": ">=18"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "types": "formant.d.ts"
43
+ }