react-native-davoice-tts 1.0.410 → 1.0.412
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/README.md +19 -0
- package/TTSRNBridge.podspec +1 -1
- package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar +0 -0
- package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.md5 +1 -1
- package/android/libs/com/davoice/tts/1.0.0/tts-1.0.0.aar.sha1 +1 -1
- package/android/src/main/java/com/davoice/tts/rn/DaVoiceTTSBridge.java +64 -0
- package/ios/SpeechBridge/SpeechBridge.m +40 -0
- package/ios/TTSRNBridge/DaVoiceTTSBridge.m +40 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/DavoiceTTS +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Headers/DavoiceTTS-Swift.h +28 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.abi.json +505 -116
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.private.swiftinterface +4 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios.swiftinterface +4 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/DavoiceTTS +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Headers/DavoiceTTS-Swift.h +56 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.abi.json +505 -116
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +4 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftinterface +4 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.abi.json +505 -116
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +4 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +4 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeDirectory +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeRequirements-1 +0 -0
- package/ios/TTSRNBridge/DavoiceTTS.xcframework/ios-arm64_x86_64-simulator/DavoiceTTS.framework/_CodeSignature/CodeResources +33 -33
- package/package.json +1 -1
- package/speech/index.d.ts +33 -0
- package/speech/index.ts +65 -0
|
@@ -161,6 +161,10 @@ public enum AudioPlaybackHook {
|
|
|
161
161
|
}
|
|
162
162
|
@objc final public func getAllVoices() -> [Swift.String]
|
|
163
163
|
@objc final public func getVoiceAbilities(_ name: Swift.String) -> [Swift.String]
|
|
164
|
+
#if compiler(>=5.3) && $NonescapableTypes
|
|
165
|
+
@objc(setExternalVoicesPath:completion:) final public func setExternalVoicesPath(_ path: Swift.String?, completion: (([Swift.String]) -> Swift.Void)? = nil)
|
|
166
|
+
#endif
|
|
167
|
+
@objc public static func createVoiceClone(_ inputAudioPath: Swift.String, outputPath: Swift.String, embedderPath: Swift.String) throws -> [Swift.String : Any]
|
|
164
168
|
@objc(changeVoice:completion:) final public func changeVoice(_ name: Swift.String, completion: @escaping (Swift.Int) -> Swift.Void)
|
|
165
169
|
@objc final public var onLastUtteranceFinished: (() -> Swift.Void)?
|
|
166
170
|
@objc deinit
|
|
Binary file
|
|
@@ -161,6 +161,10 @@ public enum AudioPlaybackHook {
|
|
|
161
161
|
}
|
|
162
162
|
@objc final public func getAllVoices() -> [Swift.String]
|
|
163
163
|
@objc final public func getVoiceAbilities(_ name: Swift.String) -> [Swift.String]
|
|
164
|
+
#if compiler(>=5.3) && $NonescapableTypes
|
|
165
|
+
@objc(setExternalVoicesPath:completion:) final public func setExternalVoicesPath(_ path: Swift.String?, completion: (([Swift.String]) -> Swift.Void)? = nil)
|
|
166
|
+
#endif
|
|
167
|
+
@objc public static func createVoiceClone(_ inputAudioPath: Swift.String, outputPath: Swift.String, embedderPath: Swift.String) throws -> [Swift.String : Any]
|
|
164
168
|
@objc(changeVoice:completion:) final public func changeVoice(_ name: Swift.String, completion: @escaping (Swift.Int) -> Swift.Void)
|
|
165
169
|
@objc final public var onLastUtteranceFinished: (() -> Swift.Void)?
|
|
166
170
|
@objc deinit
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<dict>
|
|
7
7
|
<key>Headers/DavoiceTTS-Swift.h</key>
|
|
8
8
|
<data>
|
|
9
|
-
|
|
9
|
+
CayZ/2UHTVx8d3crJ59EEwyTj9M=
|
|
10
10
|
</data>
|
|
11
11
|
<key>Info.plist</key>
|
|
12
12
|
<data>
|
|
@@ -14,43 +14,43 @@
|
|
|
14
14
|
</data>
|
|
15
15
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
|
|
16
16
|
<data>
|
|
17
|
-
|
|
17
|
+
KWvzlkvZwNqGIqaxH0B1gfHtqic=
|
|
18
18
|
</data>
|
|
19
19
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
|
|
20
20
|
<data>
|
|
21
|
-
|
|
21
|
+
+SjLLdC9wzcmmVKdK3OspIIfl4c=
|
|
22
22
|
</data>
|
|
23
23
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
|
|
24
24
|
<data>
|
|
25
|
-
+
|
|
25
|
+
AtalCan8W74vSROBG2Y+VszUbo0=
|
|
26
26
|
</data>
|
|
27
27
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
|
|
28
28
|
<data>
|
|
29
|
-
|
|
29
|
+
+SjLLdC9wzcmmVKdK3OspIIfl4c=
|
|
30
30
|
</data>
|
|
31
31
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftmodule</key>
|
|
32
32
|
<data>
|
|
33
|
-
|
|
33
|
+
LFOxWYSLyaxM56QHAmqcH8h0ACo=
|
|
34
34
|
</data>
|
|
35
35
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
|
|
36
36
|
<data>
|
|
37
|
-
|
|
37
|
+
KWvzlkvZwNqGIqaxH0B1gfHtqic=
|
|
38
38
|
</data>
|
|
39
39
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
|
|
40
40
|
<data>
|
|
41
|
-
|
|
41
|
+
CCVbMysPRrLBmlDQ1ev8miGvbX4=
|
|
42
42
|
</data>
|
|
43
43
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
|
|
44
44
|
<data>
|
|
45
|
-
|
|
45
|
+
Y+jBdqRgb8hjAkzEQ+dx4dPeJaE=
|
|
46
46
|
</data>
|
|
47
47
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
|
|
48
48
|
<data>
|
|
49
|
-
|
|
49
|
+
CCVbMysPRrLBmlDQ1ev8miGvbX4=
|
|
50
50
|
</data>
|
|
51
51
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftmodule</key>
|
|
52
52
|
<data>
|
|
53
|
-
|
|
53
|
+
IN1uxp6gFqpaRyEzBkr1vqmlddQ=
|
|
54
54
|
</data>
|
|
55
55
|
<key>Modules/module.modulemap</key>
|
|
56
56
|
<data>
|
|
@@ -63,121 +63,121 @@
|
|
|
63
63
|
<dict>
|
|
64
64
|
<key>hash</key>
|
|
65
65
|
<data>
|
|
66
|
-
|
|
66
|
+
CayZ/2UHTVx8d3crJ59EEwyTj9M=
|
|
67
67
|
</data>
|
|
68
68
|
<key>hash2</key>
|
|
69
69
|
<data>
|
|
70
|
-
|
|
70
|
+
jJHyYm5Bz+b6+Gr1OBaA2Vwm5CfUUg2QAD0t3khjh6E=
|
|
71
71
|
</data>
|
|
72
72
|
</dict>
|
|
73
73
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.abi.json</key>
|
|
74
74
|
<dict>
|
|
75
75
|
<key>hash</key>
|
|
76
76
|
<data>
|
|
77
|
-
|
|
77
|
+
KWvzlkvZwNqGIqaxH0B1gfHtqic=
|
|
78
78
|
</data>
|
|
79
79
|
<key>hash2</key>
|
|
80
80
|
<data>
|
|
81
|
-
|
|
81
|
+
IJy/ubRByJPxcw2/2tr0kKPcmzOcUWVMjpHnQGhsbA8=
|
|
82
82
|
</data>
|
|
83
83
|
</dict>
|
|
84
84
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface</key>
|
|
85
85
|
<dict>
|
|
86
86
|
<key>hash</key>
|
|
87
87
|
<data>
|
|
88
|
-
|
|
88
|
+
+SjLLdC9wzcmmVKdK3OspIIfl4c=
|
|
89
89
|
</data>
|
|
90
90
|
<key>hash2</key>
|
|
91
91
|
<data>
|
|
92
|
-
|
|
92
|
+
e9/3r3eXLtlmcPkmnRU0xYdk/hzgUy0Rpv8GzYPXK2o=
|
|
93
93
|
</data>
|
|
94
94
|
</dict>
|
|
95
95
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftdoc</key>
|
|
96
96
|
<dict>
|
|
97
97
|
<key>hash</key>
|
|
98
98
|
<data>
|
|
99
|
-
+
|
|
99
|
+
AtalCan8W74vSROBG2Y+VszUbo0=
|
|
100
100
|
</data>
|
|
101
101
|
<key>hash2</key>
|
|
102
102
|
<data>
|
|
103
|
-
|
|
103
|
+
eU2dx0sPZRWhE+65rFlT50UaJiM1ds4VmlV8NpEvyh8=
|
|
104
104
|
</data>
|
|
105
105
|
</dict>
|
|
106
106
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftinterface</key>
|
|
107
107
|
<dict>
|
|
108
108
|
<key>hash</key>
|
|
109
109
|
<data>
|
|
110
|
-
|
|
110
|
+
+SjLLdC9wzcmmVKdK3OspIIfl4c=
|
|
111
111
|
</data>
|
|
112
112
|
<key>hash2</key>
|
|
113
113
|
<data>
|
|
114
|
-
|
|
114
|
+
e9/3r3eXLtlmcPkmnRU0xYdk/hzgUy0Rpv8GzYPXK2o=
|
|
115
115
|
</data>
|
|
116
116
|
</dict>
|
|
117
117
|
<key>Modules/DavoiceTTS.swiftmodule/arm64-apple-ios-simulator.swiftmodule</key>
|
|
118
118
|
<dict>
|
|
119
119
|
<key>hash</key>
|
|
120
120
|
<data>
|
|
121
|
-
|
|
121
|
+
LFOxWYSLyaxM56QHAmqcH8h0ACo=
|
|
122
122
|
</data>
|
|
123
123
|
<key>hash2</key>
|
|
124
124
|
<data>
|
|
125
|
-
|
|
125
|
+
b0HdHL72+oq00ajrgipy9IW6xmrsIPmAWUhTKbxRxAc=
|
|
126
126
|
</data>
|
|
127
127
|
</dict>
|
|
128
128
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.abi.json</key>
|
|
129
129
|
<dict>
|
|
130
130
|
<key>hash</key>
|
|
131
131
|
<data>
|
|
132
|
-
|
|
132
|
+
KWvzlkvZwNqGIqaxH0B1gfHtqic=
|
|
133
133
|
</data>
|
|
134
134
|
<key>hash2</key>
|
|
135
135
|
<data>
|
|
136
|
-
|
|
136
|
+
IJy/ubRByJPxcw2/2tr0kKPcmzOcUWVMjpHnQGhsbA8=
|
|
137
137
|
</data>
|
|
138
138
|
</dict>
|
|
139
139
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface</key>
|
|
140
140
|
<dict>
|
|
141
141
|
<key>hash</key>
|
|
142
142
|
<data>
|
|
143
|
-
|
|
143
|
+
CCVbMysPRrLBmlDQ1ev8miGvbX4=
|
|
144
144
|
</data>
|
|
145
145
|
<key>hash2</key>
|
|
146
146
|
<data>
|
|
147
|
-
|
|
147
|
+
zs5TSJY3M0yp73wG3kcfebXGiEGjaBbjDvBJN1eDcEg=
|
|
148
148
|
</data>
|
|
149
149
|
</dict>
|
|
150
150
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftdoc</key>
|
|
151
151
|
<dict>
|
|
152
152
|
<key>hash</key>
|
|
153
153
|
<data>
|
|
154
|
-
|
|
154
|
+
Y+jBdqRgb8hjAkzEQ+dx4dPeJaE=
|
|
155
155
|
</data>
|
|
156
156
|
<key>hash2</key>
|
|
157
157
|
<data>
|
|
158
|
-
|
|
158
|
+
MY670aR0rAe1lIS0ea8ReB4Vgq8WweloNM+OAYzY6oc=
|
|
159
159
|
</data>
|
|
160
160
|
</dict>
|
|
161
161
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftinterface</key>
|
|
162
162
|
<dict>
|
|
163
163
|
<key>hash</key>
|
|
164
164
|
<data>
|
|
165
|
-
|
|
165
|
+
CCVbMysPRrLBmlDQ1ev8miGvbX4=
|
|
166
166
|
</data>
|
|
167
167
|
<key>hash2</key>
|
|
168
168
|
<data>
|
|
169
|
-
|
|
169
|
+
zs5TSJY3M0yp73wG3kcfebXGiEGjaBbjDvBJN1eDcEg=
|
|
170
170
|
</data>
|
|
171
171
|
</dict>
|
|
172
172
|
<key>Modules/DavoiceTTS.swiftmodule/x86_64-apple-ios-simulator.swiftmodule</key>
|
|
173
173
|
<dict>
|
|
174
174
|
<key>hash</key>
|
|
175
175
|
<data>
|
|
176
|
-
|
|
176
|
+
IN1uxp6gFqpaRyEzBkr1vqmlddQ=
|
|
177
177
|
</data>
|
|
178
178
|
<key>hash2</key>
|
|
179
179
|
<data>
|
|
180
|
-
|
|
180
|
+
8NrcKhKsP3QhU/mgYfgIokKzZlFrHsKSAcjtPOK7b/8=
|
|
181
181
|
</data>
|
|
182
182
|
</dict>
|
|
183
183
|
<key>Modules/module.modulemap</key>
|
package/package.json
CHANGED
package/speech/index.d.ts
CHANGED
|
@@ -37,6 +37,14 @@ export type NewSpeechWAVEvent = {
|
|
|
37
37
|
};
|
|
38
38
|
export type RNAssetLike = any;
|
|
39
39
|
export type ModelRef = string | RNAssetLike;
|
|
40
|
+
/** createVoiceClone() result. */
|
|
41
|
+
export type VoiceCloneResult = {
|
|
42
|
+
/** The .emd written (its file name without .emd is the voice name). */
|
|
43
|
+
path: string;
|
|
44
|
+
voice: string;
|
|
45
|
+
/** Non-empty when the user should record again (e.g. too little speech). */
|
|
46
|
+
warnings: string[];
|
|
47
|
+
};
|
|
40
48
|
/** iOS AVAudioSession routing entry shared by STT and TTS. */
|
|
41
49
|
export type PreferredAudioInput = 'bluetoothHighQualityMic' | 'builtInMic' | 'none';
|
|
42
50
|
export type RouteConfigEntry = {
|
|
@@ -155,6 +163,30 @@ declare class Speech {
|
|
|
155
163
|
* Resolves [] for voices without variants or when unavailable.
|
|
156
164
|
*/
|
|
157
165
|
getVoiceAbilities(name: string): Promise<string[]>;
|
|
166
|
+
/** Also look for voices in the folder `path`: <name>.emd files made by
|
|
167
|
+
* createVoiceClone() (or .npy). They are listed by getAllVoices() after
|
|
168
|
+
* the bundled voices and selected with changeVoice() like them; a bundled
|
|
169
|
+
* voice wins over a file with the same name. Call again to pick up new files;
|
|
170
|
+
* null or "" removes them. Resolves the external voice names found.
|
|
171
|
+
*/
|
|
172
|
+
setExternalVoicesPath(path: string | null): Promise<string[]>;
|
|
173
|
+
/** Voice cloning: creates a voice from a recording and saves it as a
|
|
174
|
+
* scrambled .emd at `outputPath`.
|
|
175
|
+
*
|
|
176
|
+
* - inputAudio: path/URI of a recording of one speaker (wav, mp3, m4a/aac,
|
|
177
|
+
* ogg, flac, ...). It is prepared for cloning automatically.
|
|
178
|
+
* - outputPath: the .emd file to write (".emd" is added when missing), or a
|
|
179
|
+
* folder ending in "/" (-> <folder>/<input name>.emd). The file name is the
|
|
180
|
+
* voice name.
|
|
181
|
+
* - embedder: the language's voice encoder embedder_<code>.dm, e.g.
|
|
182
|
+
* require('./assets/models/embedder_en.dm') or a path; it is unscrambled in
|
|
183
|
+
* memory only.
|
|
184
|
+
*
|
|
185
|
+
* Resolves { path, voice, warnings }; when warnings is non-empty, ask the user
|
|
186
|
+
* to record again. When the .emd lands in the folder given to setExternalVoicesPath(), the new
|
|
187
|
+
* voice is usable right away.
|
|
188
|
+
*/
|
|
189
|
+
createVoiceClone(inputAudio: ModelRef, outputPath: string, embedder: ModelRef): Promise<VoiceCloneResult>;
|
|
158
190
|
/** Reference voice, matched case-insensitively without .wav.
|
|
159
191
|
* Returns 0 on match; -1 on fallback/unavailability. Missing names select the
|
|
160
192
|
* first WAV (alphabetical order). Already generated audio keeps its voice.
|
|
@@ -176,6 +208,7 @@ declare class Speech {
|
|
|
176
208
|
private hasCompletedFullInit;
|
|
177
209
|
private hasCompletedTtsInit;
|
|
178
210
|
private iosTtsOnly;
|
|
211
|
+
private externalVoicesPath;
|
|
179
212
|
private logCall;
|
|
180
213
|
private resolveModelExt;
|
|
181
214
|
private resolveModelToPath;
|
package/speech/index.ts
CHANGED
|
@@ -137,6 +137,15 @@ export type NewSpeechWAVEvent = { path: string };
|
|
|
137
137
|
export type RNAssetLike = any; // keep permissive (Metro asset numbers/objects vary)
|
|
138
138
|
export type ModelRef = string | RNAssetLike;
|
|
139
139
|
|
|
140
|
+
/** createVoiceClone() result. */
|
|
141
|
+
export type VoiceCloneResult = {
|
|
142
|
+
/** The .emd written (its file name without .emd is the voice name). */
|
|
143
|
+
path: string;
|
|
144
|
+
voice: string;
|
|
145
|
+
/** Non-empty when the user should record again (e.g. too little speech). */
|
|
146
|
+
warnings: string[];
|
|
147
|
+
};
|
|
148
|
+
|
|
140
149
|
/** iOS AVAudioSession routing entry shared by STT and TTS. */
|
|
141
150
|
export type PreferredAudioInput =
|
|
142
151
|
| 'bluetoothHighQualityMic'
|
|
@@ -337,6 +346,61 @@ class Speech {
|
|
|
337
346
|
}
|
|
338
347
|
}
|
|
339
348
|
|
|
349
|
+
/** Also look for voices in the folder `path`: <name>.emd files made by
|
|
350
|
+
* createVoiceClone() (or .npy). They are listed by getAllVoices() after
|
|
351
|
+
* the bundled voices and selected with changeVoice() like them; a bundled
|
|
352
|
+
* voice wins over a file with the same name. Call again to pick up new files;
|
|
353
|
+
* null or "" removes them. Resolves the external voice names found.
|
|
354
|
+
*/
|
|
355
|
+
async setExternalVoicesPath(path: string | null): Promise<string[]> {
|
|
356
|
+
const bridge = Platform.OS === 'ios' && !this.iosTtsOnly && this.hasCompletedFullInit
|
|
357
|
+
? NativeSpeech : NativeTTS;
|
|
358
|
+
if ((Platform.OS !== 'android' && Platform.OS !== 'ios') || typeof bridge?.setExternalVoicesPath !== 'function') return [];
|
|
359
|
+
this.externalVoicesPath = path || null;
|
|
360
|
+
try {
|
|
361
|
+
const names = await bridge.setExternalVoicesPath(path || null);
|
|
362
|
+
return Array.isArray(names) ? names.filter((v: unknown): v is string => typeof v === 'string') : [];
|
|
363
|
+
} catch {
|
|
364
|
+
return [];
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** Voice cloning: creates a voice from a recording and saves it as a
|
|
369
|
+
* scrambled .emd at `outputPath`.
|
|
370
|
+
*
|
|
371
|
+
* - inputAudio: path/URI of a recording of one speaker (wav, mp3, m4a/aac,
|
|
372
|
+
* ogg, flac, ...). It is prepared for cloning automatically.
|
|
373
|
+
* - outputPath: the .emd file to write (".emd" is added when missing), or a
|
|
374
|
+
* folder ending in "/" (-> <folder>/<input name>.emd). The file name is the
|
|
375
|
+
* voice name.
|
|
376
|
+
* - embedder: the language's voice encoder embedder_<code>.dm, e.g.
|
|
377
|
+
* require('./assets/models/embedder_en.dm') or a path; it is unscrambled in
|
|
378
|
+
* memory only.
|
|
379
|
+
*
|
|
380
|
+
* Resolves { path, voice, warnings }; when warnings is non-empty, ask the user
|
|
381
|
+
* to record again. When the .emd lands in the folder given to setExternalVoicesPath(), the new
|
|
382
|
+
* voice is usable right away.
|
|
383
|
+
*/
|
|
384
|
+
async createVoiceClone(inputAudio: ModelRef, outputPath: string, embedder: ModelRef): Promise<VoiceCloneResult> {
|
|
385
|
+
const bridge = (typeof NativeTTS?.createVoiceClone === 'function') ? NativeTTS : NativeSpeech;
|
|
386
|
+
if (typeof bridge?.createVoiceClone !== 'function') {
|
|
387
|
+
throw new Error('createVoiceClone is not available on this platform');
|
|
388
|
+
}
|
|
389
|
+
const result = await bridge.createVoiceClone(
|
|
390
|
+
this.resolveModelToPath(inputAudio), String(outputPath), this.resolveModelToPath(embedder));
|
|
391
|
+
const folder = this.externalVoicesPath;
|
|
392
|
+
if (folder && typeof result?.path === 'string') {
|
|
393
|
+
const strip = (p: string) => p.replace(/^file:\/\//, '').replace(/\/+$/, '');
|
|
394
|
+
const parent = result.path.substring(0, result.path.lastIndexOf('/'));
|
|
395
|
+
if (strip(parent) === strip(folder)) await this.setExternalVoicesPath(folder);
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
path: String(result?.path ?? ''),
|
|
399
|
+
voice: String(result?.voice ?? ''),
|
|
400
|
+
warnings: Array.isArray(result?.warnings) ? result.warnings.map(String) : [],
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
340
404
|
/** Reference voice, matched case-insensitively without .wav.
|
|
341
405
|
* Returns 0 on match; -1 on fallback/unavailability. Missing names select the
|
|
342
406
|
* first WAV (alphabetical order). Already generated audio keeps its voice.
|
|
@@ -423,6 +487,7 @@ class Speech {
|
|
|
423
487
|
private hasCompletedFullInit = false;
|
|
424
488
|
private hasCompletedTtsInit = false;
|
|
425
489
|
private iosTtsOnly = false; // when true, use NativeTTS directly on iOS
|
|
490
|
+
private externalVoicesPath: string | null = null; // setExternalVoicesPath()
|
|
426
491
|
|
|
427
492
|
|
|
428
493
|
private logCall(name: string, payload?: any) {
|