speechflow 2.4.1 → 2.4.2

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 (60) hide show
  1. package/.ase/service.log +446 -0
  2. package/.ase/service.yaml +1 -1
  3. package/.ase/task/TASK-flush.md +44 -0
  4. package/CHANGELOG.md +17 -0
  5. package/README.md +10 -9
  6. package/etc/speechflow.yaml +1 -1
  7. package/etc/stx.conf +21 -21
  8. package/package.json +9 -5
  9. package/speechflow-cli/dst/speechflow-main-cli.js +2 -2
  10. package/speechflow-cli/dst/speechflow-main-cli.js.map +1 -1
  11. package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js +2 -0
  12. package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
  13. package/speechflow-cli/dst/speechflow-node-a2a-gender.js +2 -1
  14. package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
  15. package/speechflow-cli/dst/speechflow-node-a2a-meter.js +28 -12
  16. package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
  17. package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +9 -15
  18. package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -1
  19. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.d.ts +3 -0
  20. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +149 -101
  21. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
  22. package/speechflow-cli/dst/speechflow-node-t2t-opus.js.map +1 -1
  23. package/speechflow-cli/dst/speechflow-node-xio-exec.js +6 -4
  24. package/speechflow-cli/dst/speechflow-node-xio-exec.js.map +1 -1
  25. package/speechflow-cli/dst/speechflow-util-llm.js +8 -1
  26. package/speechflow-cli/dst/speechflow-util-llm.js.map +1 -1
  27. package/speechflow-cli/etc/oxlint.jsonc +4 -0
  28. package/speechflow-cli/etc/stx.conf +4 -4
  29. package/speechflow-cli/package.json +52 -45
  30. package/speechflow-cli/src/speechflow-main-cli.ts +1 -1
  31. package/speechflow-cli/src/speechflow-node-a2a-ffmpeg.ts +3 -1
  32. package/speechflow-cli/src/speechflow-node-a2a-gender.ts +3 -2
  33. package/speechflow-cli/src/speechflow-node-a2a-meter.ts +30 -13
  34. package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +12 -20
  35. package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +162 -108
  36. package/speechflow-cli/src/speechflow-node-t2t-opus.ts +1 -1
  37. package/speechflow-cli/src/speechflow-node-xio-exec.ts +7 -5
  38. package/speechflow-cli/src/speechflow-util-llm.ts +10 -2
  39. package/speechflow-ui-db/dst/app-font-fa-brands-400.woff2 +0 -0
  40. package/speechflow-ui-db/dst/app-font-fa-regular-400.woff2 +0 -0
  41. package/speechflow-ui-db/dst/app-font-fa-solid-900.woff2 +0 -0
  42. package/speechflow-ui-db/dst/app-font-fa-v4compatibility.woff2 +0 -0
  43. package/speechflow-ui-db/dst/index.css +1 -1
  44. package/speechflow-ui-db/dst/index.js +579 -57
  45. package/speechflow-ui-db/etc/stx.conf +3 -2
  46. package/speechflow-ui-db/etc/vite-client.mts +1 -1
  47. package/speechflow-ui-db/package.json +26 -21
  48. package/speechflow-ui-st/dst/app-font-fa-brands-400.woff2 +0 -0
  49. package/speechflow-ui-st/dst/app-font-fa-regular-400.woff2 +0 -0
  50. package/speechflow-ui-st/dst/app-font-fa-solid-900.woff2 +0 -0
  51. package/speechflow-ui-st/dst/app-font-fa-v4compatibility.woff2 +0 -0
  52. package/speechflow-ui-st/dst/index.css +1 -1
  53. package/speechflow-ui-st/dst/index.js +593 -71
  54. package/speechflow-ui-st/etc/stx.conf +3 -2
  55. package/speechflow-ui-st/etc/vite-client.mts +6 -0
  56. package/speechflow-ui-st/package.json +26 -21
  57. package/speechflow-cli/package.d/sherpa-onnx+1.12.25.patch +0 -12
  58. /package/speechflow-cli/package.d/{@typescript-eslint+typescript-estree+8.60.0.patch → @typescript-eslint+typescript-estree+8.64.0.patch} +0 -0
  59. /package/speechflow-ui-db/package.d/{@typescript-eslint+typescript-estree+8.60.0.patch → @typescript-eslint+typescript-estree+8.64.0.patch} +0 -0
  60. /package/speechflow-ui-st/package.d/{@typescript-eslint+typescript-estree+8.60.0.patch → @typescript-eslint+typescript-estree+8.64.0.patch} +0 -0
@@ -150,6 +150,10 @@
150
150
  "import-style": "off",
151
151
  "no-implicit-globals": "off",
152
152
  "no-anonymous-default-export": "off",
153
+ "prefer-named-capture-group": "off",
154
+ "prefer-number-coercion": "off",
155
+ "method-signature-style": "off",
156
+ "no-sync": "off",
153
157
 
154
158
  "complexity": [ "error", { "max": 40 } ]
155
159
  }
@@ -6,15 +6,15 @@
6
6
 
7
7
  # [speechflow-cli] make patches
8
8
  patch-make
9
- npm shrinkwrap && \
9
+ npm install --package-lock-only --save && \
10
+ shx echo "allow-remote=all" >.npmrc && \
10
11
  patch-package --patch-dir package.d \
11
12
  "@ericedouard/vad-node-realtime" \
12
- "@shiguredo" \
13
- "sherpa-onnx" \
13
+ "@shiguredo/rnnoise-wasm" \
14
14
  "kitten-tts-js" \
15
15
  "speex-resampler" \
16
16
  "@typescript-eslint/typescript-estree" && \
17
- shx rm -f npm-shrinkwrap.json
17
+ shx rm -f package-lock.json .npmrc
18
18
 
19
19
  # [speechflow-cli] (internal) apply patches
20
20
  patch-apply
@@ -18,56 +18,56 @@
18
18
  "cli-io": "0.9.13",
19
19
  "yargs": "18.0.0",
20
20
  "flowlink": "1.2.3",
21
- "js-yaml": "4.1.1",
21
+ "js-yaml": "5.2.1",
22
22
  "@gpeng/naudiodon": "2.4.1",
23
- "execa": "9.6.1",
23
+ "execa": "10.0.0",
24
24
  "shell-parser": "1.0.0",
25
- "@deepgram/sdk": "4.11.3",
25
+ "@deepgram/sdk": "5.6.0",
26
26
  "deepl-node": "1.27.0",
27
- "@elevenlabs/elevenlabs-js": "2.49.1",
27
+ "@elevenlabs/elevenlabs-js": "2.58.0",
28
28
  "get-stream": "9.0.1",
29
- "@dotenvx/dotenvx": "1.69.2",
29
+ "@dotenvx/dotenvx": "2.14.0",
30
30
  "speex-resampler": "3.0.1",
31
31
  "@sapphi-red/speex-preprocess-wasm": "0.4.0",
32
32
  "@shiguredo/rnnoise-wasm": "2025.1.5",
33
- "sherpa-onnx": "1.12.25",
34
- "axios": "1.16.1",
35
- "@aws-sdk/client-transcribe-streaming": "3.1057.0",
36
- "@aws-sdk/client-translate": "3.1057.0",
37
- "@aws-sdk/client-polly": "3.1057.0",
38
- "@google-cloud/translate": "9.4.1",
39
- "@google-cloud/speech": "7.3.1",
33
+ "sherpa-onnx": "1.13.4",
34
+ "axios": "1.18.1",
35
+ "@aws-sdk/client-transcribe-streaming": "3.1090.0",
36
+ "@aws-sdk/client-translate": "3.1090.0",
37
+ "@aws-sdk/client-polly": "3.1090.0",
38
+ "@google-cloud/translate": "9.4.2",
39
+ "@google-cloud/speech": "7.5.0",
40
40
  "@google-cloud/text-to-speech": "6.4.1",
41
41
  "node-web-audio-api": "2.0.0",
42
42
  "object-path": "0.11.8",
43
43
  "glob": "13.0.6",
44
- "ws": "8.21.0",
44
+ "ws": "8.21.1",
45
45
  "bufferutil": "4.1.0",
46
46
  "utf-8-validate": "6.0.6",
47
47
  "@hapi/hapi": "21.4.9",
48
48
  "@hapi/boom": "10.0.1",
49
- "@hapi/inert": "7.1.1",
49
+ "@hapi/inert": "7.1.2",
50
50
  "hapi-plugin-header": "1.1.8",
51
51
  "hapi-plugin-websocket": "2.4.11",
52
52
  "@opensumi/reconnecting-websocket": "4.4.0",
53
53
  "ollama": "0.6.3",
54
- "openai": "6.39.1",
55
- "@anthropic-ai/sdk": "0.100.1",
56
- "@google/genai": "1.52.0",
54
+ "openai": "6.48.0",
55
+ "@anthropic-ai/sdk": "0.112.3",
56
+ "@google/genai": "2.12.0",
57
57
  "@rse/ffmpeg": "1.4.2",
58
58
  "ffmpeg-stream": "1.0.1",
59
59
  "installed-packages": "1.0.13",
60
60
  "syspath": "1.0.8",
61
61
  "wav": "1.0.2",
62
- "mqtt": "5.15.1",
62
+ "mqtt": "5.15.2",
63
63
  "vban": "1.5.6",
64
64
  "cbor2": "2.3.0",
65
- "arktype": "2.2.0",
65
+ "arktype": "2.2.3",
66
66
  "pure-uuid": "2.0.0",
67
67
  "wavefile": "11.0.0",
68
- "audio-inspect": "0.0.4",
69
- "@huggingface/transformers": "3.8.1",
70
- "@huggingface/hub": "2.13.0",
68
+ "audio-inspect": "0.0.8",
69
+ "@huggingface/transformers": "4.2.0",
70
+ "@huggingface/hub": "2.13.3",
71
71
  "kokoro-js": "1.2.1",
72
72
  "kitten-tts-js": "0.1.2",
73
73
  "@ericedouard/vad-node-realtime": "0.2.0",
@@ -79,33 +79,33 @@
79
79
  "@2toad/profanity": "3.3.0",
80
80
  "cli-table3": "0.6.5",
81
81
  "mkdirp": "3.0.1",
82
- "@soundtouchjs/audio-worklet": "1.0.10",
82
+ "@soundtouchjs/audio-worklet": "2.1.0",
83
83
  "werift": "0.23.0",
84
84
  "@discordjs/opus": "0.10.0",
85
- "@rse/stx": "1.1.5"
85
+ "@rse/stx": "1.1.6"
86
86
  },
87
87
  "devDependencies": {
88
- "eslint": "9.39.4",
89
- "@eslint/js": "9.39.4",
88
+ "eslint": "9.39.5",
89
+ "@eslint/js": "9.39.5",
90
90
  "neostandard": "0.13.0",
91
91
  "eslint-plugin-promise": "7.3.0",
92
92
  "eslint-plugin-import": "2.32.0",
93
93
  "eslint-plugin-node": "11.1.0",
94
- "typescript-eslint": "8.60.0",
95
- "@typescript-eslint/eslint-plugin": "8.60.0",
96
- "@typescript-eslint/parser": "8.60.0",
97
- "oxlint": "1.67.0",
98
- "oxlint-plugin-complexity": "2.1.3",
99
- "eslint-plugin-oxlint": "1.67.0",
94
+ "typescript-eslint": "8.64.0",
95
+ "@typescript-eslint/eslint-plugin": "8.64.0",
96
+ "@typescript-eslint/parser": "8.64.0",
97
+ "oxlint": "1.73.0",
98
+ "oxlint-plugin-complexity": "2.1.5",
99
+ "eslint-plugin-oxlint": "1.73.0",
100
100
 
101
- "@types/node": "24.10.1",
101
+ "@types/node": "26.1.1",
102
102
  "@types/yargs": "17.0.35",
103
103
  "@types/js-yaml": "4.0.9",
104
104
  "@types/object-path": "0.11.4",
105
105
  "@types/ws": "8.18.1",
106
106
  "@types/resolve": "1.20.6",
107
107
  "@types/wav": "1.0.4",
108
- "@types/luxon": "3.7.1",
108
+ "@types/luxon": "3.7.2",
109
109
  "@types/wrap-text": "1.0.2",
110
110
 
111
111
  "check-dependencies": "2.0.0",
@@ -113,14 +113,12 @@
113
113
  "stmux": "1.8.11",
114
114
  "nodemon": "3.1.14",
115
115
  "shx": "0.4.0",
116
- "@yao-pkg/pkg": "6.20.0",
116
+ "@yao-pkg/pkg": "6.21.0",
117
117
  "typescript": "6.0.3",
118
118
  "delay-cli": "3.0.0",
119
119
  "cross-env": "10.1.0"
120
120
  },
121
121
  "overrides": {
122
- "@huggingface/transformers": { "onnxruntime-node": "1.22.0", "onnxruntime-web": "1.22.0" },
123
- "@ericedouard/vad-node-realtime": { "onnxruntime-node": "1.22.0", "onnxruntime-web": "1.22.0" },
124
122
  "typescript-eslint": { "typescript": ">=5.0.0" },
125
123
  "@typescript-eslint/parser": { "typescript": ">=5.0.0" },
126
124
  "@typescript-eslint/eslint-plugin": { "typescript": ">=5.0.0" },
@@ -130,16 +128,10 @@
130
128
  "neostandard": { "eslint": ">=9.0.0" }
131
129
  },
132
130
  "upd": [
133
- "!onnxruntime-node",
134
- "!@types/node",
135
- "!audio-inspect",
136
- "!@deepgram/sdk",
137
- "!sherpa-onnx",
131
+ "!oxlint",
138
132
  "!eslint",
139
133
  "!@eslint/js",
140
- "!@google/genai",
141
- "!@huggingface/transformers",
142
- "!@soundtouchjs/audio-worklet"
134
+ "!typescript"
143
135
  ],
144
136
  "engines": {
145
137
  "node": ">=22.0.0"
@@ -154,6 +146,21 @@
154
146
  "require": { "types": "./dst/speechflow-node.d.ts", "default": "./dst/speechflow-node.js" }
155
147
  }
156
148
  },
149
+ "allowScripts": {
150
+ "@discordjs/opus": true,
151
+ "@google/genai": true,
152
+ "@gpeng/naudiodon": true,
153
+ "@rse/ffmpeg": true,
154
+ "bufferutil": true,
155
+ "es5-ext": true,
156
+ "esbuild": true,
157
+ "fsevents": true,
158
+ "node-pty": true,
159
+ "onnxruntime-node": true,
160
+ "protobufjs": true,
161
+ "sharp": true,
162
+ "utf-8-validate": true
163
+ },
157
164
  "scripts": {
158
165
  "postinstall": "npm start patch-apply",
159
166
  "start": "stx -v4 -c etc/stx.conf"
@@ -11,7 +11,7 @@ import path from "node:path"
11
11
  import CLIio from "cli-io"
12
12
  import yargs from "yargs"
13
13
  import { hideBin } from "yargs/helpers"
14
- import jsYAML from "js-yaml"
14
+ import * as jsYAML from "js-yaml"
15
15
  import dotenvx from "@dotenvx/dotenvx"
16
16
  import syspath from "syspath"
17
17
  import chalk from "chalk"
@@ -93,10 +93,12 @@ export default class SpeechFlowNodeA2AFFMPEG extends SpeechFlowNode {
93
93
  util.run("starting FFmpeg process", () => this.ffmpeg!.run())
94
94
 
95
95
  /* establish a duplex stream and connect it to FFmpeg */
96
+ /* NOTICE: the object form of Stream.Duplex.from() accepts Node streams at
97
+ run-time, but @types/node types it for Web streams only, so we have to cast */
96
98
  const ffmpegStream = Stream.Duplex.from({
97
99
  writable: streamInput,
98
100
  readable: streamOutput
99
- })
101
+ } as unknown as Parameters<typeof Stream.Duplex.from>[0])
100
102
 
101
103
  /* wrap streams with conversions for chunk vs plain audio */
102
104
  const wrapper1 = util.createTransformStreamForWritableSide("audio", 1)
@@ -11,7 +11,7 @@ import Stream from "node:stream"
11
11
  /* external dependencies */
12
12
  import * as Transformers from "@huggingface/transformers"
13
13
  import { WaveFile } from "wavefile"
14
- import { getRMS, AudioData } from "audio-inspect"
14
+ import { analyze, AudioData } from "audio-inspect"
15
15
  import { Duration } from "luxon"
16
16
 
17
17
  /* internal dependencies */
@@ -145,7 +145,8 @@ export default class SpeechFlowNodeA2AGender extends SpeechFlowNode {
145
145
  duration: data.length / sampleRateTarget,
146
146
  length: data.length
147
147
  } satisfies AudioData
148
- const rms = getRMS(audioData, { asDB: true })
148
+ const analysis = await analyze(audioData, { features: { rms: { asDB: true } } })
149
+ const rms = analysis.results.rms ?? -60
149
150
  if (rms < this.params.volumeThreshold)
150
151
  return genderLast
151
152
 
@@ -8,7 +8,7 @@
8
8
  import Stream from "node:stream"
9
9
 
10
10
  /* external dependencies */
11
- import { getLUFS, getRMS, AudioData } from "audio-inspect"
11
+ import { analyze, AudioData } from "audio-inspect"
12
12
 
13
13
  /* internal dependencies */
14
14
  import SpeechFlowNode, { SpeechFlowChunk } from "./speechflow-node"
@@ -69,8 +69,8 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
69
69
  const samplesPerChunk = Math.floor(this.config.audioSampleRate * chunkDuration)
70
70
  this.chunkBuffer = new Float32Array(0)
71
71
 
72
- /* setup chunking interval */
73
- this.calcInterval = setInterval(() => {
72
+ /* calculate the loudness metrics of the accumulated chunk data */
73
+ const calcMeter = async () => {
74
74
  /* short-circuit during destruction */
75
75
  if (this.closing)
76
76
  return
@@ -99,14 +99,19 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
99
99
  duration: sampleWindowDuration,
100
100
  length: sampleWindow.length
101
101
  } satisfies AudioData
102
- const lufs = getLUFS(audioDataLUFS, {
103
- channelMode: this.config.audioChannels === 1 ? "mono" : "stereo",
104
- calculateShortTerm: false,
105
- calculateMomentary: true,
106
- calculateLoudnessRange: false,
107
- calculateTruePeak: false
102
+ const analysisLUFS = await analyze(audioDataLUFS, {
103
+ features: {
104
+ lufs: {
105
+ channelMode: this.config.audioChannels === 1 ? "mono" : "stereo",
106
+ calculateShortTerm: false,
107
+ calculateMomentary: true,
108
+ calculateLoudnessRange: false,
109
+ calculateTruePeak: false
110
+ }
111
+ }
108
112
  })
109
- lufsm = lufs.momentary ? Math.max(-60, lufs.momentary[0]) : -60
113
+ const lufs = analysisLUFS.results.lufs
114
+ lufsm = lufs?.momentary !== undefined ? Math.max(-60, lufs.momentary) : -60
110
115
 
111
116
  /* calculate the RMS metric */
112
117
  const totalSamples = chunkData.length / this.config.audioChannels
@@ -118,9 +123,14 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
118
123
  duration,
119
124
  length: chunkData.length
120
125
  } satisfies AudioData
121
- rms = Math.max(-60, getRMS(audioDataRMS, {
122
- asDB: true
123
- }))
126
+ const analysisRMS = await analyze(audioDataRMS, {
127
+ features: {
128
+ rms: {
129
+ asDB: true
130
+ }
131
+ }
132
+ })
133
+ rms = Math.max(-60, analysisRMS.results.rms ?? -60)
124
134
 
125
135
  /* automatically clear measurement (in case no new measurements happen) */
126
136
  if (this.silenceTimer !== null)
@@ -129,6 +139,13 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
129
139
  lufsm = -60
130
140
  rms = -60
131
141
  }, 500)
142
+ }
143
+
144
+ /* setup chunking interval */
145
+ this.calcInterval = setInterval(() => {
146
+ calcMeter().catch((err: unknown) => {
147
+ this.log("warning", `meter calculation failed: ${err instanceof Error ? err.message : String(err)}`)
148
+ })
132
149
  }, chunkDuration * 1000)
133
150
 
134
151
  /* setup loudness emitting interval */
@@ -18,7 +18,6 @@ import * as util from "./speechflow-util"
18
18
  /* parameter configuration */
19
19
  type AudioPitchShifterConfig = {
20
20
  rate?: number
21
- tempo?: number
22
21
  pitch?: number
23
22
  semitones?: number
24
23
  }
@@ -38,7 +37,6 @@ class AudioPitchShifter extends util.WebAudio {
38
37
  super(sampleRate, channels)
39
38
  this.config = {
40
39
  rate: config.rate ?? 1.0,
41
- tempo: config.tempo ?? 1.0,
42
40
  pitch: config.pitch ?? 1.0,
43
41
  semitones: config.semitones ?? 0.0
44
42
  }
@@ -50,10 +48,11 @@ class AudioPitchShifter extends util.WebAudio {
50
48
 
51
49
  /* add SoundTouch worklet module */
52
50
  const packagePath = path.join(__dirname, "../node_modules/@soundtouchjs/audio-worklet")
53
- const workletPath = path.join(packagePath, "dist/soundtouch-worklet.js")
51
+ const workletPath = path.join(packagePath, ".dist/soundtouch-processor.js")
54
52
  await this.audioContext.audioWorklet.addModule(workletPath)
55
53
 
56
- /* create SoundTouch worklet node */
54
+ /* create SoundTouch worklet node (the processor always operates on
55
+ stereo internally, but mixes down to the requested channel count) */
57
56
  this.pitchNode = new AudioWorkletNode(this.audioContext, "soundtouch-processor", {
58
57
  numberOfInputs: 1,
59
58
  numberOfOutputs: 1,
@@ -62,10 +61,9 @@ class AudioPitchShifter extends util.WebAudio {
62
61
 
63
62
  /* set initial parameter values */
64
63
  const params = this.pitchNode.parameters as Map<string, AudioParam>
65
- params.get("rate")!.value = this.config.rate
66
- params.get("tempo")!.value = this.config.tempo
67
- params.get("pitch")!.value = this.config.pitch
68
- params.get("pitchSemitones")!.value = this.config.semitones
64
+ params.get("playbackRate")!.value = this.config.rate
65
+ params.get("pitch")!.value = this.config.pitch
66
+ params.get("pitchSemitones")!.value = this.config.semitones
69
67
 
70
68
  /* connect nodes: source -> pitch -> capture */
71
69
  this.sourceNode!.connect(this.pitchNode)
@@ -83,14 +81,10 @@ class AudioPitchShifter extends util.WebAudio {
83
81
  this.config[configField] = value
84
82
  }
85
83
 
86
- /* update rate value */
84
+ /* update rate value (compensates the pitch for an upstream playback
85
+ rate change, i.e. the resulting pitch is divided by this value) */
87
86
  public setRate (rate: number): void {
88
- this.updateParameter("rate", rate, "rate")
89
- }
90
-
91
- /* update tempo value */
92
- public setTempo (tempo: number): void {
93
- this.updateParameter("tempo", tempo, "tempo")
87
+ this.updateParameter("playbackRate", rate, "rate")
94
88
  }
95
89
 
96
90
  /* update pitch shift value */
@@ -131,10 +125,9 @@ export default class SpeechFlowNodeA2APitch extends SpeechFlowNode {
131
125
 
132
126
  /* declare node configuration parameters */
133
127
  this.configure({
134
- rate: { type: "number", val: 1.0, match: (n: number) => n >= 0.25 && n <= 4.0 },
135
- tempo: { type: "number", val: 1.0, match: (n: number) => n >= 0.25 && n <= 4.0 },
136
- pitch: { type: "number", val: 1.0, match: (n: number) => n >= 0.25 && n <= 4.0 },
137
- semitones: { type: "number", val: 0.0, match: (n: number) => n >= -24 && n <= 24 }
128
+ rate: { type: "number", val: 1.0, match: (n: number) => n >= 0.1 && n <= 8.0 },
129
+ pitch: { type: "number", val: 1.0, match: (n: number) => n >= 0.1 && n <= 8.0 },
130
+ semitones: { type: "number", val: 0.0, match: (n: number) => n >= -24 && n <= 24 }
138
131
  })
139
132
 
140
133
  /* declare node input/output format */
@@ -152,7 +145,6 @@ export default class SpeechFlowNodeA2APitch extends SpeechFlowNode {
152
145
  this.config.audioSampleRate,
153
146
  this.config.audioChannels, {
154
147
  rate: this.params.rate,
155
- tempo: this.params.tempo,
156
148
  pitch: this.params.pitch,
157
149
  semitones: this.params.semitones
158
150
  }