cantor-digitalis 0.0.1

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 (35) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +164 -0
  3. package/dist/index.d.ts +35 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +1486 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/nodes/anti-resonance.d.ts +58 -0
  8. package/dist/nodes/anti-resonance.d.ts.map +1 -0
  9. package/dist/nodes/formant-bank.d.ts +76 -0
  10. package/dist/nodes/formant-bank.d.ts.map +1 -0
  11. package/dist/nodes/formant-resonator.d.ts +67 -0
  12. package/dist/nodes/formant-resonator.d.ts.map +1 -0
  13. package/dist/nodes/gain.d.ts +16 -0
  14. package/dist/nodes/gain.d.ts.map +1 -0
  15. package/dist/nodes/glottal-flow-derivative.d.ts +119 -0
  16. package/dist/nodes/glottal-flow-derivative.d.ts.map +1 -0
  17. package/dist/nodes/glottal-formant.d.ts +64 -0
  18. package/dist/nodes/glottal-formant.d.ts.map +1 -0
  19. package/dist/nodes/noise-source.d.ts +51 -0
  20. package/dist/nodes/noise-source.d.ts.map +1 -0
  21. package/dist/nodes/pulse-train.d.ts +51 -0
  22. package/dist/nodes/pulse-train.d.ts.map +1 -0
  23. package/dist/nodes/spectral-tilt.d.ts +69 -0
  24. package/dist/nodes/spectral-tilt.d.ts.map +1 -0
  25. package/dist/nodes/types.d.ts +10 -0
  26. package/dist/nodes/types.d.ts.map +1 -0
  27. package/dist/nodes/vocal-tract.d.ts +83 -0
  28. package/dist/nodes/vocal-tract.d.ts.map +1 -0
  29. package/dist/nodes/voice.d.ts +102 -0
  30. package/dist/nodes/voice.d.ts.map +1 -0
  31. package/dist/parameters/index.d.ts +111 -0
  32. package/dist/parameters/index.d.ts.map +1 -0
  33. package/dist/parameters/vowels.d.ts +28 -0
  34. package/dist/parameters/vowels.d.ts.map +1 -0
  35. package/package.json +52 -0
@@ -0,0 +1,64 @@
1
+ import type { Node } from "./types";
2
+ export type GlottalFormantParams = {
3
+ /** Glottal formant centre frequency in Hz, computed as f0 / (2 * Oq) */
4
+ Fg: number;
5
+ /** Glottal formant bandwidth in Hz, computed from f0, Oq, and αm */
6
+ Bg: number;
7
+ /** Source amplitude, derived from E, Oq, and R (shimmer) */
8
+ Ag: number;
9
+ };
10
+ /**
11
+ * Glottal Formant (GF)
12
+ *
13
+ * The glottal formant represents the main spectral peak of the voice source,
14
+ * corresponding to the resonance characteristics of the glottal pulse. It is
15
+ * implemented as a 2-pole 1-zero digital resonant filter in series with a
16
+ * 1-zero differentiation filter.
17
+ *
18
+ * The transfer function (Section 3.2.1) is:
19
+ *
20
+ * GF(z) = -Ag * z^{-1} * (1 - z^{-1}) / (1 - 2R*cos(θ)*z^{-1} + R²*z^{-2})
21
+ *
22
+ * Where:
23
+ * R = e^(-π * Bg * Ts) (pole radius, Ts = sampling period)
24
+ * θ = 2π * Fg * Ts (pole angle)
25
+ *
26
+ * The filter shapes the periodic impulse train (at frequency f0) to produce
27
+ * the characteristic spectrum of the glottal flow derivative.
28
+ *
29
+ * Paper reference: Section 3.2.1 (filter structure), Section 4.2.2 (parameter mapping)
30
+ *
31
+ * Input parameters:
32
+ * - Fg (glottal formant centre frequency) — computed as f0 / (2·Oq)
33
+ * - Bg (glottal formant bandwidth) — computed from f0, Oq, and αm
34
+ * - Ag (source amplitude) — derived from E, Oq, and R (shimmer)
35
+ *
36
+ * The intermediate parameters Oq (open quotient) and αm (asymmetry coefficient)
37
+ * are computed from T (tenseness), E (vocal effort), and M (laryngeal mechanism).
38
+ */
39
+ export declare class GlottalFormant implements Node<GlottalFormantParams> {
40
+ private ctx;
41
+ private workletNode;
42
+ in: AudioNode;
43
+ out: AudioNode;
44
+ private constructor();
45
+ /** Glottal formant centre frequency AudioParam (a-rate, 20-2000 Hz) */
46
+ get Fg(): AudioParam;
47
+ /** Glottal formant bandwidth AudioParam (a-rate, 10-500 Hz) */
48
+ get Bg(): AudioParam;
49
+ /** Source amplitude AudioParam (a-rate, 0-10) */
50
+ get Ag(): AudioParam;
51
+ /**
52
+ * Creates a new GlottalFormant node.
53
+ *
54
+ * The AudioWorklet module is registered automatically on first use.
55
+ */
56
+ static create(ctx: AudioContext, params: GlottalFormantParams): Promise<GlottalFormant>;
57
+ /**
58
+ * Updates the glottal formant parameters.
59
+ * Sets AudioParams via setTargetAtTime for smooth transitions.
60
+ */
61
+ update(params: GlottalFormantParams): void;
62
+ destroy(): void;
63
+ }
64
+ //# sourceMappingURL=glottal-formant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glottal-formant.d.ts","sourceRoot":"","sources":["../../src/nodes/glottal-formant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,oBAAoB,GAAG;IACjC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAqHF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,cAAe,YAAW,IAAI,CAAC,oBAAoB,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,WAAW,CAAmB;IAC/B,EAAE,EAAE,SAAS,CAAC;IACd,GAAG,EAAE,SAAS,CAAC;IAEtB,OAAO;IAOP,uEAAuE;IACvE,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED,+DAA+D;IAC/D,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED,iDAAiD;IACjD,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED;;;;OAIG;WACU,MAAM,CACjB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,cAAc,CAAC;IAU1B;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAM1C,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,51 @@
1
+ import type { Node } from "./types";
2
+ export type NoiseSourceParams = {
3
+ /** Noise amplitude, derived directly from B (breathiness) */
4
+ An: number;
5
+ };
6
+ /**
7
+ * Noise Source (NS)
8
+ *
9
+ * The noise source provides the aspiration component for breathy voice qualities.
10
+ * It consists of Gaussian white noise filtered through a bandpass filter
11
+ * (Butterworth, 1000–6000 Hz cutoff frequencies) and scaled by an amplitude factor.
12
+ *
13
+ * The noise can be modulated by the glottal flow derivative for mixed voice
14
+ * qualities (not implemented in this basic version).
15
+ *
16
+ * Paper reference: Section 3.2.3 (filter structure), Section 4.2.5 (parameter mapping)
17
+ *
18
+ * Input parameters:
19
+ * - An (noise amplitude) — derived directly from B (breathiness), with
20
+ * scaling by E when voicing is off
21
+ *
22
+ * Signal flow:
23
+ * Gaussian Noise → Highpass (1000 Hz) → Lowpass (6000 Hz) → Output
24
+ *
25
+ * The bandpass is implemented as a cascade of 2nd-order Butterworth highpass
26
+ * and lowpass filters using native BiquadFilterNodes.
27
+ */
28
+ export declare class NoiseSource implements Node<NoiseSourceParams> {
29
+ private ctx;
30
+ private workletNode;
31
+ private highpassFilter;
32
+ private lowpassFilter;
33
+ in: AudioNode | null;
34
+ out: AudioNode;
35
+ private constructor();
36
+ /** Noise amplitude AudioParam (a-rate, 0-1) */
37
+ get An(): AudioParam;
38
+ /**
39
+ * Creates a new NoiseSource node.
40
+ *
41
+ * The AudioWorklet module is registered automatically on first use.
42
+ */
43
+ static create(ctx: AudioContext, params: NoiseSourceParams): Promise<NoiseSource>;
44
+ /**
45
+ * Updates the noise source amplitude.
46
+ * Sets AudioParam via setTargetAtTime for smooth transitions.
47
+ */
48
+ update(params: NoiseSourceParams): void;
49
+ destroy(): void;
50
+ }
51
+ //# sourceMappingURL=noise-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noise-source.d.ts","sourceRoot":"","sources":["../../src/nodes/noise-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6DAA6D;IAC7D,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AA0FF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAY,YAAW,IAAI,CAAC,iBAAiB,CAAC;IACzD,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,aAAa,CAAmB;IAEjC,EAAE,EAAE,SAAS,GAAG,IAAI,CAAQ;IAC5B,GAAG,EAAE,SAAS,CAAC;IAEtB,OAAO;IAaP,+CAA+C;IAC/C,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED;;;;OAIG;WACU,MAAM,CACjB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,WAAW,CAAC;IA6BvB;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAIvC,OAAO,IAAI,IAAI;CAKhB"}
@@ -0,0 +1,51 @@
1
+ import type { Node } from "./types";
2
+ export type PulseTrainParams = {
3
+ /** Fundamental frequency in Hz (derived from P, P₀) */
4
+ f0: number;
5
+ /** Jitter depth: maximum f₀ perturbation as a fraction (0-0.3 for ±30%) */
6
+ jitterDepth: number;
7
+ /** Shimmer depth: maximum amplitude perturbation as a fraction (0-1 for ±100%) */
8
+ shimmerDepth: number;
9
+ };
10
+ /**
11
+ * Pulse Train (Voiced Excitation Source)
12
+ *
13
+ * Generates a periodic impulse train at the fundamental frequency f₀,
14
+ * with integrated jitter (f₀ perturbation) and shimmer (amplitude perturbation)
15
+ * for roughness simulation.
16
+ *
17
+ * In the spectral domain, the unperturbed output is a Dirac comb: Σδ(f − n·f₀),
18
+ * representing energy at each harmonic frequency. Jitter spreads energy around
19
+ * harmonics, and shimmer modulates the overall amplitude cycle-to-cycle.
20
+ *
21
+ * The impulse train is the input to the glottal formant filter, which shapes
22
+ * each impulse into the characteristic glottal pulse waveform.
23
+ *
24
+ * Paper reference: Section 3.1 (spectral equation showing the Dirac comb term),
25
+ * Section 4.1.2 (jitter), Section 4.2.4 (shimmer)
26
+ *
27
+ * Input parameters:
28
+ * - f0: Fundamental frequency in Hz
29
+ * - jitterDepth: Maximum f₀ perturbation (0-0.3 for up to ±30%)
30
+ * - shimmerDepth: Maximum amplitude perturbation (0-1 for up to ±100%)
31
+ */
32
+ export declare class PulseTrain implements Node<PulseTrainParams> {
33
+ private ctx;
34
+ private workletNode;
35
+ private gain;
36
+ in: null;
37
+ out: AudioNode;
38
+ private constructor();
39
+ /** Fundamental frequency AudioParam (a-rate, 20-20000 Hz) */
40
+ get f0(): AudioParam;
41
+ /** Jitter depth AudioParam (k-rate, 0-0.3) */
42
+ get jitterDepth(): AudioParam;
43
+ /** Shimmer depth AudioParam (k-rate, 0-1) */
44
+ get shimmerDepth(): AudioParam;
45
+ static create(ctx: AudioContext, params: PulseTrainParams): Promise<PulseTrain>;
46
+ update(params: PulseTrainParams): void;
47
+ destroy(): void;
48
+ start(): void;
49
+ stop(): void;
50
+ }
51
+ //# sourceMappingURL=pulse-train.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pulse-train.d.ts","sourceRoot":"","sources":["../../src/nodes/pulse-train.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAGpC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AA2LF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,UAAW,YAAW,IAAI,CAAC,gBAAgB,CAAC;IACvD,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,IAAI,CAAO;IAEZ,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,EAAE,SAAS,CAAC;IAEtB,OAAO;IAQP,6DAA6D;IAC7D,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED,8CAA8C;IAC9C,IAAI,WAAW,IAAI,UAAU,CAE5B;IAED,6CAA6C;IAC7C,IAAI,YAAY,IAAI,UAAU,CAE7B;WAEY,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAcrF,MAAM,CAAC,MAAM,EAAE,gBAAgB;IAM/B,OAAO;IAKP,KAAK;IAIL,IAAI;CAGL"}
@@ -0,0 +1,69 @@
1
+ import type { Node } from "./types";
2
+ export type SpectralTiltParams = {
3
+ /** First stage attenuation in dB at 3000 Hz, derived from E and M */
4
+ Tl1: number;
5
+ /** Second stage attenuation in dB at 3000 Hz, derived from E and M */
6
+ Tl2: number;
7
+ };
8
+ /**
9
+ * Spectral Tilt (ST)
10
+ *
11
+ * The spectral tilt filter models the high-frequency roll-off of the glottal
12
+ * source spectrum. Louder, more pressed phonation has less spectral tilt
13
+ * (brighter sound), while softer or breathier phonation has more tilt
14
+ * (darker sound).
15
+ *
16
+ * It is implemented as a cascade of two 1-pole 1-zero low-pass filters, each
17
+ * providing attenuation specified in dB at 3000 Hz.
18
+ *
19
+ * The transfer function (Section 3.2.2) is:
20
+ *
21
+ * ST(z) = ST₁(z) × ST₂(z)
22
+ *
23
+ * Where each stage is:
24
+ * STᵢ(z) = (1 - aᵢ) / (1 - aᵢ·z⁻¹)
25
+ *
26
+ * With:
27
+ * aᵢ = νᵢ - √(νᵢ² - 1)
28
+ * νᵢ = 1 + (1 - cos(2π·3000·Ts)) / (10^(Tlᵢ/10) - 1)
29
+ *
30
+ * Paper reference: Section 3.2.2 (filter structure), Section 4.2.3 (parameter mapping)
31
+ *
32
+ * Input parameters:
33
+ * - Tl₁ (first tilt stage attenuation in dB at 3 kHz) — derived from E and M
34
+ * - Tl₂ (second tilt stage attenuation in dB at 3 kHz) — derived from E and M
35
+ *
36
+ * Parameter mapping from Section 4.2.3:
37
+ * For M=1 (chest voice):
38
+ * Tl₁ = 27 - 21·Ep dB
39
+ * Tl₂ = 11 - 11·Ep dB
40
+ * For M=2 (falsetto):
41
+ * Tl₁ = 45 - 36·Ep dB
42
+ * Tl₂ = 20 - 18.5·Ep dB
43
+ *
44
+ * Where Ep is the perturbed vocal effort (E with heartbeat and slow perturbations).
45
+ */
46
+ export declare class SpectralTilt implements Node<SpectralTiltParams> {
47
+ private ctx;
48
+ private workletNode;
49
+ in: AudioNode;
50
+ out: AudioNode;
51
+ private constructor();
52
+ /** First stage spectral tilt attenuation AudioParam (k-rate, 0-50 dB at 3kHz) */
53
+ get Tl1(): AudioParam;
54
+ /** Second stage spectral tilt attenuation AudioParam (k-rate, 0-30 dB at 3kHz) */
55
+ get Tl2(): AudioParam;
56
+ /**
57
+ * Creates a new SpectralTilt node.
58
+ *
59
+ * The AudioWorklet module is registered automatically on first use.
60
+ */
61
+ static create(ctx: AudioContext, params: SpectralTiltParams): Promise<SpectralTilt>;
62
+ /**
63
+ * Updates the spectral tilt parameters.
64
+ * Sets AudioParams via setTargetAtTime for smooth transitions.
65
+ */
66
+ update(params: SpectralTiltParams): void;
67
+ destroy(): void;
68
+ }
69
+ //# sourceMappingURL=spectral-tilt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spectral-tilt.d.ts","sourceRoot":"","sources":["../../src/nodes/spectral-tilt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAwIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,YAAa,YAAW,IAAI,CAAC,kBAAkB,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,WAAW,CAAmB;IAC/B,EAAE,EAAE,SAAS,CAAC;IACd,GAAG,EAAE,SAAS,CAAC;IAEtB,OAAO;IAOP,iFAAiF;IACjF,IAAI,GAAG,IAAI,UAAU,CAEpB;IAED,kFAAkF;IAClF,IAAI,GAAG,IAAI,UAAU,CAEpB;IAED;;;;OAIG;WACU,MAAM,CACjB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,YAAY,CAAC;IAUxB;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAKxC,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,10 @@
1
+ export interface Node<T extends Record<string, any>> {
2
+ update(params: T): void;
3
+ destroy(): void;
4
+ in: AudioNode | null;
5
+ out: AudioNode | null;
6
+ }
7
+ export interface NodeStatic<T extends Record<string, any>> {
8
+ create(ctx: AudioContext, params: T): Node<T>;
9
+ }
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/nodes/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACjD,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,OAAO,IAAI,IAAI,CAAC;IAEhB,EAAE,EAAE,SAAS,GAAG,IAAI,CAAC;IACrB,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IACvD,MAAM,CAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;CAChD"}
@@ -0,0 +1,83 @@
1
+ import type { Node } from "./types";
2
+ import { FormantResonator, FormantResonatorParams } from "./formant-resonator";
3
+ import { AntiResonance } from "./anti-resonance";
4
+ export type VocalTractParams = {
5
+ /** Array of formant parameters (F, B, A) for each resonator */
6
+ formants: FormantResonatorParams[];
7
+ /** Anti-formant centre frequency in Hz (nominally 4700 Hz, scaled by αS) */
8
+ F_BQ: number;
9
+ /** Anti-formant quality factor (nominally 2.5) */
10
+ Q_BQ: number;
11
+ };
12
+ /**
13
+ * Vocal Tract Model
14
+ *
15
+ * The vocal tract model shapes the glottal source spectrum to produce
16
+ * recognisable vowels and voice timbres. It consists of parallel formant
17
+ * resonators (simulating the resonances of the oral cavity) followed by
18
+ * a cascaded anti-resonance filter (simulating the effect of the hypo-pharynx).
19
+ *
20
+ * Signal flow:
21
+ *
22
+ * ┌─→ R1(F1, B1, A1) ─┐
23
+ * ├─→ R2(F2, B2, A2) ─┤
24
+ * Input ─────┼─→ R3(F3, B3, A3) ─┼─────→ BQ(F_BQ, Q_BQ) ─────→ Output
25
+ * ├─→ ... ─┤
26
+ * └─→ Rn(Fn, Bn, An) ─┘
27
+ *
28
+ * The paper uses six formants (R1-R6):
29
+ * - F1-F3: Primary formants that determine vowel identity
30
+ * - F4-F6: Higher formants that contribute to voice timbre
31
+ *
32
+ * The anti-resonance (BQ) models spectral dips caused by the hypo-pharynx
33
+ * cavity at approximately 2.5–3.5 kHz and 4–5 kHz.
34
+ *
35
+ * Paper reference: Section 3.3 (overall structure), Section 3.3.1 (formants),
36
+ * Section 3.3.2 (anti-resonance)
37
+ *
38
+ * Input parameters:
39
+ * - formants: Array of {F, B, A} objects for each resonator
40
+ * - F_BQ: Anti-formant centre frequency (nominally 4700 Hz, scaled by αS)
41
+ * - Q_BQ: Anti-formant quality factor (nominally 2.5)
42
+ */
43
+ export declare class VocalTract implements Node<VocalTractParams> {
44
+ private formantBank;
45
+ private antiResonance;
46
+ in: AudioNode;
47
+ out: AudioNode;
48
+ private constructor();
49
+ /**
50
+ * Creates a new VocalTract node.
51
+ *
52
+ * Sets up the parallel formant bank followed by the anti-resonance filter.
53
+ */
54
+ static create(ctx: AudioContext, params: VocalTractParams): Promise<VocalTract>;
55
+ /**
56
+ * Updates all vocal tract parameters.
57
+ *
58
+ * @throws Error if the formants array length doesn't match the original
59
+ */
60
+ update(params: VocalTractParams): void;
61
+ /**
62
+ * Returns the number of formant resonators in the vocal tract.
63
+ */
64
+ get formantCount(): number;
65
+ /**
66
+ * Returns the array of formant resonators for direct AudioParam access.
67
+ *
68
+ * Example usage:
69
+ * vocalTract.formants[0].F.setValueAtTime(800, ctx.currentTime);
70
+ * vocalTract.formants[2].B.linearRampToValueAtTime(100, ctx.currentTime + 0.1);
71
+ */
72
+ get formants(): readonly FormantResonator[];
73
+ /**
74
+ * Returns the anti-resonance node for direct AudioParam access.
75
+ *
76
+ * Example usage:
77
+ * vocalTract.antiResonanceNode.F.setValueAtTime(4500, ctx.currentTime);
78
+ * vocalTract.antiResonanceNode.Q.setValueAtTime(3, ctx.currentTime);
79
+ */
80
+ get antiResonanceNode(): AntiResonance;
81
+ destroy(): void;
82
+ }
83
+ //# sourceMappingURL=vocal-tract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vocal-tract.d.ts","sourceRoot":"","sources":["../../src/nodes/vocal-tract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+DAA+D;IAC/D,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,UAAW,YAAW,IAAI,CAAC,gBAAgB,CAAC;IACvD,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,aAAa,CAAgB;IAE9B,EAAE,EAAE,SAAS,CAAC;IACd,GAAG,EAAE,SAAS,CAAC;IAEtB,OAAO;IAUP;;;;OAIG;WACU,MAAM,CACjB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,UAAU,CAAC;IAatB;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAKtC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;;;;OAMG;IACH,IAAI,QAAQ,IAAI,SAAS,gBAAgB,EAAE,CAE1C;IAED;;;;;;OAMG;IACH,IAAI,iBAAiB,IAAI,aAAa,CAErC;IAED,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,102 @@
1
+ import type { Node } from "./types";
2
+ import { GlottalFlowDerivative } from "./glottal-flow-derivative";
3
+ import { VocalTract } from "./vocal-tract";
4
+ import { Gain } from "./gain";
5
+ import { SynthParams } from "../parameters";
6
+ /**
7
+ * Voice Synthesizer
8
+ *
9
+ * The complete voice synthesis pipeline combining the glottal flow derivative
10
+ * (voice source) with the vocal tract model (formant filtering). This implements
11
+ * the full source-filter model described in the paper.
12
+ *
13
+ * Signal flow:
14
+ *
15
+ * ┌─────────────────────────────────────────────────────────────────────────┐
16
+ * │ Glottal Flow Derivative (Source) │
17
+ * │ │
18
+ * │ PulseTrain(f0) → GlottalFormant(Fg,Bg,Ag) → SpectralTilt(Tl1,Tl2) ─┬─┤
19
+ * │ ↓ (mod) │ │
20
+ * │ NoiseSource(An) ──────────────────────────────────→ [×] ───────────┘ │
21
+ * └─────────────────────────────────────────────────────────────────────────┘
22
+ * │
23
+ * ↓
24
+ * ┌─────────────────────────────────────────────────────────────────────────┐
25
+ * │ Vocal Tract (Filter) │
26
+ * │ │
27
+ * │ ┌─→ R1(F1, B1, A1) ─┐ │
28
+ * │ ├─→ R2(F2, B2, A2) ─┤ │
29
+ * │ Input ───┼─→ R3(F3, B3, A3) ─┼───→ BQ(F_BQ, Q_BQ) ───→ Output │
30
+ * │ ├─→ ... ─┤ │
31
+ * │ └─→ Rn(Fn, Bn, An) ─┘ │
32
+ * └─────────────────────────────────────────────────────────────────────────┘
33
+ * │
34
+ * ↓
35
+ * OutputGain ───→ Output
36
+ *
37
+ * Paper reference: Section 3.1 (overall model), Section 3.2 (voice source),
38
+ * Section 3.3 (vocal tract)
39
+ *
40
+ * Input parameters:
41
+ * - source: GlottalFlowDerivativeParams (f0, Fg, Bg, Ag, Tl1, Tl2, An)
42
+ * - tract: VocalTractParams (formants array, F_BQ, Q_BQ)
43
+ * - outputGain: Overall output level (optional, defaults to 1)
44
+ */
45
+ export declare class Voice implements Node<SynthParams> {
46
+ private glottalFlowDerivative;
47
+ private vocalTract;
48
+ private outputGainNode;
49
+ in: AudioNode | null;
50
+ out: AudioNode;
51
+ private constructor();
52
+ /**
53
+ * Creates a new Voice synthesizer node.
54
+ *
55
+ * Sets up the complete source-filter synthesis pipeline.
56
+ */
57
+ static create(ctx: AudioContext, params: SynthParams): Promise<Voice>;
58
+ /**
59
+ * Updates all voice parameters.
60
+ *
61
+ * @throws Error if the formants array length doesn't match the original
62
+ */
63
+ update(params: SynthParams): void;
64
+ /**
65
+ * Starts the voice (begins voiced excitation).
66
+ */
67
+ start(): void;
68
+ /**
69
+ * Stops the voice (stops voiced excitation).
70
+ * Note: Noise component continues based on An parameter.
71
+ */
72
+ stop(): void;
73
+ /**
74
+ * Returns the number of formant resonators in the vocal tract.
75
+ */
76
+ get formantCount(): number;
77
+ /**
78
+ * Returns the glottal flow derivative node for direct AudioParam access.
79
+ *
80
+ * Example usage:
81
+ * voice.source.pulseTrainNode.f0.setValueAtTime(440, ctx.currentTime);
82
+ * voice.source.glottalFormantNode.Ag.setTargetAtTime(0.5, ctx.currentTime, 0.1);
83
+ */
84
+ get source(): GlottalFlowDerivative;
85
+ /**
86
+ * Returns the vocal tract node for direct AudioParam access.
87
+ *
88
+ * Example usage:
89
+ * voice.tract.formants[0].F.linearRampToValueAtTime(800, ctx.currentTime + 0.1);
90
+ * voice.tract.antiResonanceNode.F.setValueAtTime(4500, ctx.currentTime);
91
+ */
92
+ get tract(): VocalTract;
93
+ /**
94
+ * Returns the output gain node for direct AudioParam access.
95
+ *
96
+ * Example usage:
97
+ * voice.outputGain.gain.linearRampToValueAtTime(0.5, ctx.currentTime + 1);
98
+ */
99
+ get outputGain(): Gain;
100
+ destroy(): void;
101
+ }
102
+ //# sourceMappingURL=voice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../../src/nodes/voice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBAAa,KAAM,YAAW,IAAI,CAAC,WAAW,CAAC;IAC7C,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,cAAc,CAAO;IAEtB,EAAE,EAAE,SAAS,GAAG,IAAI,CAAQ;IAC5B,GAAG,EAAE,SAAS,CAAC;IAEtB,OAAO;IAWP;;;;OAIG;WACU,MAAM,CACjB,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,KAAK,CAAC;IAejB;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAQjC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,qBAAqB,CAElC;IAED;;;;;;OAMG;IACH,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED;;;;;OAKG;IACH,IAAI,UAAU,IAAI,IAAI,CAErB;IAED,OAAO,IAAI,IAAI;CAKhB"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Perceptual and Synth Parameters
3
+ *
4
+ * There are high-level, user-controllable parameters for the voice synthesiser.
5
+ * They map to the perceptually meaningful dimensions described in Section 2.1 of the paper.
6
+ * These are converted to the low-level synthesis parameters required by
7
+ * the voice engine using the generateSynthParams function.
8
+ *
9
+ * All normalised parameters range from 0 to 1 unless otherwise noted.
10
+ */
11
+ export type SynthFormant = {
12
+ /** Formant centre frequency in Hz */
13
+ F: number;
14
+ /** Formant bandwidth in Hz */
15
+ B: number;
16
+ /** Formant amplitude (linear gain) */
17
+ A: number;
18
+ };
19
+ export type SynthParams = {
20
+ /** Fundamental frequency in Hz */
21
+ f0: number;
22
+ /** Glottal formant centre frequency in Hz */
23
+ Fg: number;
24
+ /** Glottal formant bandwidth in Hz */
25
+ Bg: number;
26
+ /** Source amplitude */
27
+ Ag: number;
28
+ /** First stage spectral tilt attenuation in dB at 3 kHz */
29
+ Tl1: number;
30
+ /** Second stage spectral tilt attenuation in dB at 3 kHz */
31
+ Tl2: number;
32
+ /** Noise amplitude */
33
+ An: number;
34
+ /** Jitter depth: maximum f₀ perturbation as a fraction (0-0.3 for ±30%) */
35
+ jitterDepth: number;
36
+ /** Shimmer depth: maximum amplitude perturbation as a fraction (0-1 for ±100%) */
37
+ shimmerDepth: number;
38
+ /** Array of formant parameters (F, B, A) for each resonator */
39
+ formants: SynthFormant[];
40
+ /** Anti-formant centre frequency in Hz */
41
+ F_BQ: number;
42
+ /** Anti-formant quality factor */
43
+ Q_BQ: number;
44
+ /** Overall output gain (linear) */
45
+ outputGain?: number;
46
+ };
47
+ export type PerceptualParams = {
48
+ /** (P) Normalised melodic position across the pitch range (0-1) */
49
+ pitch: number;
50
+ /** (P₀) Base MIDI note number (e.g., 48 for C3, 60 for C4) */
51
+ pitchOffset: number;
52
+ /** (E) Perceived force/dynamics of the voice (0-1) */
53
+ vocalEffort: number;
54
+ /** (H) Vertical tongue position: 0 = close (e.g., /i/, /u/), 1 = open (e.g., /a/) */
55
+ vowelHeight: number;
56
+ /** (V) Horizontal tongue position: 0 = back (e.g., /u/), 1 = front (e.g., /i/) */
57
+ vowelBackness: number;
58
+ /** (T) Degree of vocal fold adduction: 0 = lax, 1 = tense */
59
+ tenseness: number;
60
+ /** (B) Amount of aspiration noise (0-1) */
61
+ breathiness: number;
62
+ /** (R) Structural aperiodicities causing jitter/shimmer (0-1) */
63
+ roughness: number;
64
+ /** (S) Apparent size of the vocal tract: 0 = small/child, 1 = large/giant */
65
+ vocalTractSize: number;
66
+ /** (M) Vocal fold vibration mode: false = chest voice (M1), true = falsetto (M2) */
67
+ isFalsetto: boolean;
68
+ };
69
+ /**
70
+ * Feature flags for the voice parameter conversion.
71
+ * All features are enabled by default (true). Set to false to disable.
72
+ */
73
+ export type SynthFeatures = {
74
+ /**
75
+ * Attenuate formant amplitudes when harmonics coincide with formant frequencies.
76
+ * Paper reference: Section 4.3.7
77
+ */
78
+ harmonicCoincidenceAttenuation?: boolean;
79
+ /**
80
+ * Scale formant frequencies by larynx position factor (K) and vocal tract size (αS).
81
+ * Paper reference: Sections 4.3.2, 4.3.3
82
+ */
83
+ formantFrequencyScaling?: boolean;
84
+ /**
85
+ * Raise F1 with vocal effort and constrain it above f₀ + 50 Hz.
86
+ * Paper reference: Section 4.3.4
87
+ */
88
+ f1Tuning?: boolean;
89
+ /**
90
+ * Constrain F2 above 2·f₀ + 50 Hz.
91
+ * Paper reference: Section 4.3.5
92
+ */
93
+ f2Tuning?: boolean;
94
+ /**
95
+ * Scale the anti-resonance frequency (F_BQ) by vocal tract size (αS).
96
+ * When disabled, uses nominal 4700 Hz.
97
+ */
98
+ antiResonanceScaling?: boolean;
99
+ };
100
+ /**
101
+ * Converts high-level perceptually relevant voice parameters to internal synthesizer parameters.
102
+ *
103
+ * This implements the parameter mapping rules from Section 4 of the paper,
104
+ * converting perceptually meaningful high-level parameters to the low-level
105
+ * synthesis parameters needed by the voice engine.
106
+ *
107
+ * @param params - The high-level, perceptual voice parameters
108
+ * @param features - Optional feature flags to enable/disable specific behaviours (all enabled by default)
109
+ */
110
+ export declare function generateSynthParams(params: PerceptualParams, features?: SynthFeatures): SynthParams;
111
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parameters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,MAAM,YAAY,GAAG;IACzB,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,8BAA8B;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,sCAAsC;IACtC,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,uBAAuB;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;IACZ,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,WAAW,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,cAAc,EAAE,MAAM,CAAC;IACvB,oFAAoF;IACpF,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;OAGG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AA2KF;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,QAAQ,GAAE,aAAkB,GAC3B,WAAW,CA+Fb"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Vowel formant data from Cantor Digitalis Table 3
3
+ *
4
+ * Reference: Section 4.3.1 "Generic Formant Values"
5
+ *
6
+ * The sixth formant is derived: F6 = 2*F4, A6 = -15 dB, B6 = 150 Hz
7
+ */
8
+ export interface Formant {
9
+ frequency: number;
10
+ amplitude: number;
11
+ bandwidth: number;
12
+ }
13
+ export interface VowelData {
14
+ ipa: string;
15
+ v: number;
16
+ h: number;
17
+ formants: [Formant, Formant, Formant, Formant, Formant, Formant];
18
+ }
19
+ /**
20
+ * Interpolate formants for arbitrary vowel coordinates using bilinear interpolation.
21
+ *
22
+ * @param v - Vowel backness (0 = back, 1 = front)
23
+ * @param h - Vowel height (0 = close, 1 = open)
24
+ * @returns Interpolated formant array
25
+ */
26
+ export declare function interpolateFormants(v: number, h: number): [Formant, Formant, Formant, Formant, Formant, Formant];
27
+ export declare const vowels: VowelData[];
28
+ //# sourceMappingURL=vowels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vowels.d.ts","sourceRoot":"","sources":["../../src/parameters/vowels.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;CAClE;AAgDD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CA4CxD;AAED,eAAO,MAAM,MAAM,EAAE,SAAS,EAmI7B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "cantor-digitalis",
3
+ "version": "0.0.1",
4
+ "description": "A physically-informed source-filter model for singing voice synthesis using the Web Audio API",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "dev": "vite",
20
+ "build": "npm run build:lib",
21
+ "build:lib": "vite build --mode lib && tsc -p tsconfig.build.json",
22
+ "build:example": "vite build",
23
+ "preview": "vite preview",
24
+ "typecheck": "tsc --noEmit",
25
+ "prepublishOnly": "npm run build:lib"
26
+ },
27
+ "keywords": [
28
+ "audio",
29
+ "web-audio",
30
+ "synthesizer",
31
+ "voice",
32
+ "singing",
33
+ "speech",
34
+ "formant",
35
+ "source-filter"
36
+ ],
37
+ "author": "Edward Browncross",
38
+ "license": "ISC",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/edwardbrowncross/cantor-digitalis.git"
42
+ },
43
+ "homepage": "https://edwardbrowncross.github.io/cantor-digitalis/",
44
+ "bugs": {
45
+ "url": "https://github.com/edwardbrowncross/cantor-digitalis/issues"
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^25.0.10",
49
+ "typescript": "^5.9.3",
50
+ "vite": "^6.4.1"
51
+ }
52
+ }