@mentra/bluetooth-sdk 0.1.8 → 0.1.10
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 +116 -18
- package/android/build.gradle +289 -16
- package/android/gradle.properties.example +9 -0
- package/android/lc3Lib/build.gradle +95 -6
- package/android/settings.gradle +3 -0
- package/android/silero/LICENSE.md +17 -0
- package/android/silero/build.gradle +42 -0
- package/android/silero/proguard-rules.pro +24 -0
- package/android/silero/src/androidTest/assets/hello.wav +0 -0
- package/android/silero/src/androidTest/java/com/konovalov/vad/silero/VadSileroTest.kt +79 -0
- package/android/silero/src/main/assets/LICENSE +21 -0
- package/android/silero/src/main/assets/silero_vad.onnx +0 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/Vad.kt +160 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/VadSilero.kt +449 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/config/FrameSize.kt +15 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/config/Mode.kt +14 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/config/SampleRate.kt +12 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/utils/AudioUtils.kt +47 -0
- package/android/silero/src/main/java/com/konovalov/vad/silero/utils/TensorMap.kt +41 -0
- package/android/silero/src/test/java/com/konovalov/vad/silero/utils/AudioUtilsTest.kt +44 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkDefaults.kt +6 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +165 -27
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +89 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +189 -16
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +22 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +787 -85
- package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +6 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +123 -10
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/ControllerManager.kt +12 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/controllers/R1.kt +8 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/debug/BleTraceLogger.kt +33 -17
- package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +101 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +8 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +399 -74
- package/android/src/main/java/com/mentra/bluetoothsdk/photoreceiver/MentraPhotoReceiverModule.kt +100 -17
- package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +17 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.java +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +569 -220
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Mach1.java +2 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.java +271 -66
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +176 -104
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +12753 -27036
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +54 -2
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/Simulated.kt +16 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +60 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +12 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/STTTools.kt +87 -36
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +13 -4
- package/android/src/main/java/com/mentra/bluetoothsdk/stt/VadGateSpeechPolicy.kt +229 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/tts/TTSTools.kt +180 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/AvifExifStripper.java +573 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +488 -50
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +18 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +64 -18
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +48 -39
- package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +23 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/AvifExifStripperTest.java +30 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +98 -0
- package/android/src/test/resources/avif_with_exif.avif +0 -0
- package/build/BluetoothSdk.types.d.ts +241 -43
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js +11 -10
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +36 -23
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +30 -52
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/_private/photoRequestPayload.d.ts +4 -0
- package/build/_private/photoRequestPayload.d.ts.map +1 -0
- package/build/_private/photoRequestPayload.js +25 -0
- package/build/_private/photoRequestPayload.js.map +1 -0
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +23 -0
- package/build/index.js.map +1 -1
- package/build/react/useMentraBluetooth.d.ts +2 -2
- package/build/react/useMentraBluetooth.d.ts.map +1 -1
- package/build/react/useMentraBluetooth.js +3 -3
- package/build/react/useMentraBluetooth.js.map +1 -1
- package/ios/BluetoothSdkModule.swift +174 -70
- package/ios/LocalPhotoUploadServer.swift +370 -105
- package/ios/MentraBluetoothSDK.podspec +3 -1
- package/ios/MentraPhotoReceiverModule.swift +62 -10
- package/ios/Packages/CoreObjC/include/PcmConverter.h +22 -0
- package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +668 -26
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +13 -9
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4551 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +1745 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/libsherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/c-api.h +4551 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +1745 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Source/BluetoothSdkDefaults.swift +6 -0
- package/ios/Source/Bridge.swift +58 -19
- package/ios/Source/DeviceManager.swift +149 -17
- package/ios/Source/DeviceStore.swift +16 -6
- package/ios/Source/MentraBluetoothSDK.swift +803 -47
- package/ios/Source/ObservableStore.swift +8 -2
- package/ios/Source/{Audio → audio}/AudioModels.swift +9 -7
- package/ios/Source/{Camera → camera}/CameraModels.swift +225 -16
- package/ios/Source/controllers/ControllerManager.swift +4 -3
- package/ios/Source/controllers/R1.swift +3 -3
- package/ios/Source/{Events → events}/BluetoothEvents.swift +183 -1
- package/ios/Source/{Internal → internal}/ValueParsing.swift +10 -1
- package/ios/Source/{Requests → requests}/DisplayRequests.swift +28 -4
- package/ios/Source/services/PhoneMic.swift +1 -0
- package/ios/Source/sgcs/G1.swift +2 -2
- package/ios/Source/sgcs/G2.swift +645 -403
- package/ios/Source/sgcs/Mach1.swift +2 -2
- package/ios/Source/sgcs/MentraLive.swift +812 -319
- package/ios/Source/sgcs/MentraNex.swift +412 -182
- package/ios/Source/sgcs/SGCManager.swift +57 -3
- package/ios/Source/sgcs/Simulated.swift +7 -3
- package/ios/Source/sgcs/mentraos_ble.pb.swift +3073 -3134
- package/ios/Source/status/DeviceStatus.swift +974 -0
- package/ios/Source/{Status → status}/WifiHotspotStatus.swift +4 -4
- package/ios/Source/{Streaming → streaming}/StreamModels.swift +24 -9
- package/ios/Source/stt/STTTools.swift +27 -12
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +31 -8
- package/ios/Source/tts/TTSTools.swift +164 -0
- package/ios/Source/utils/JSCExperiment.swift +7 -7
- package/ios/Source/utils/MessageChunkReassembler.swift +20 -1
- package/ios/Source/utils/MessageChunker.swift +78 -21
- package/ios/Source/utils/TarBz2Extractor.swift +53 -2
- package/package.json +1 -1
- package/plugin/build/withAndroid.js +68 -4
- package/src/BluetoothSdk.types.ts +331 -59
- package/src/_private/BluetoothSdkModule.ts +113 -102
- package/src/_private/photoRequestPayload.ts +28 -0
- package/src/index.ts +58 -15
- package/src/react/useMentraBluetooth.ts +6 -4
- package/android/.project +0 -28
- package/android/lc3Lib/.project +0 -28
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/cargs.h +0 -162
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/c-api.h +0 -1852
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Headers/sherpa-onnx/c-api/cxx-api.h +0 -674
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/sherpa-onnx.a +0 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/sherpa-onnx.a +0 -0
- package/ios/Source/Status/DeviceStatus.swift +0 -471
- /package/ios/Source/{Connection → connection}/ScanSession.swift +0 -0
- /package/ios/Source/{Errors → errors}/BluetoothError.swift +0 -0
- /package/ios/Source/{Internal → internal}/BluetoothAvailability.swift +0 -0
- /package/ios/Source/{Status → status}/RuntimeState.swift +0 -0
- /package/ios/Source/{Types → types}/DeviceModels.swift +0 -0
|
@@ -76,6 +76,14 @@ func sherpaOnnxOnlineNemoCtcModelConfig(
|
|
|
76
76
|
)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
func sherpaOnnxOnlineToneCtcModelConfig(
|
|
80
|
+
model: String = ""
|
|
81
|
+
) -> SherpaOnnxOnlineToneCtcModelConfig {
|
|
82
|
+
return SherpaOnnxOnlineToneCtcModelConfig(
|
|
83
|
+
model: toCPointer(model)
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
79
87
|
/// Return an instance of SherpaOnnxOnlineModelConfig.
|
|
80
88
|
///
|
|
81
89
|
/// Please refer to
|
|
@@ -101,7 +109,8 @@ func sherpaOnnxOnlineModelConfig(
|
|
|
101
109
|
bpeVocab: String = "",
|
|
102
110
|
tokensBuf: String = "",
|
|
103
111
|
tokensBufSize: Int = 0,
|
|
104
|
-
nemoCtc: SherpaOnnxOnlineNemoCtcModelConfig = sherpaOnnxOnlineNemoCtcModelConfig()
|
|
112
|
+
nemoCtc: SherpaOnnxOnlineNemoCtcModelConfig = sherpaOnnxOnlineNemoCtcModelConfig(),
|
|
113
|
+
toneCtc: SherpaOnnxOnlineToneCtcModelConfig = sherpaOnnxOnlineToneCtcModelConfig()
|
|
105
114
|
) -> SherpaOnnxOnlineModelConfig {
|
|
106
115
|
return SherpaOnnxOnlineModelConfig(
|
|
107
116
|
transducer: transducer,
|
|
@@ -116,7 +125,8 @@ func sherpaOnnxOnlineModelConfig(
|
|
|
116
125
|
bpe_vocab: toCPointer(bpeVocab),
|
|
117
126
|
tokens_buf: toCPointer(tokensBuf),
|
|
118
127
|
tokens_buf_size: Int32(tokensBufSize),
|
|
119
|
-
nemo_ctc: nemoCtc
|
|
128
|
+
nemo_ctc: nemoCtc,
|
|
129
|
+
t_one_ctc: toneCtc
|
|
120
130
|
)
|
|
121
131
|
}
|
|
122
132
|
|
|
@@ -361,6 +371,38 @@ func sherpaOnnxOfflineZipformerCtcModelConfig(
|
|
|
361
371
|
)
|
|
362
372
|
}
|
|
363
373
|
|
|
374
|
+
func sherpaOnnxOfflineWenetCtcModelConfig(
|
|
375
|
+
model: String = ""
|
|
376
|
+
) -> SherpaOnnxOfflineWenetCtcModelConfig {
|
|
377
|
+
return SherpaOnnxOfflineWenetCtcModelConfig(
|
|
378
|
+
model: toCPointer(model)
|
|
379
|
+
)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
func sherpaOnnxOfflineOmnilingualAsrCtcModelConfig(
|
|
383
|
+
model: String = ""
|
|
384
|
+
) -> SherpaOnnxOfflineOmnilingualAsrCtcModelConfig {
|
|
385
|
+
return SherpaOnnxOfflineOmnilingualAsrCtcModelConfig(
|
|
386
|
+
model: toCPointer(model)
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
func sherpaOnnxOfflineMedAsrCtcModelConfig(
|
|
391
|
+
model: String = ""
|
|
392
|
+
) -> SherpaOnnxOfflineMedAsrCtcModelConfig {
|
|
393
|
+
return SherpaOnnxOfflineMedAsrCtcModelConfig(
|
|
394
|
+
model: toCPointer(model)
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
func sherpaOnnxOfflineFireRedAsrCtcModelConfig(
|
|
399
|
+
model: String = ""
|
|
400
|
+
) -> SherpaOnnxOfflineFireRedAsrCtcModelConfig {
|
|
401
|
+
return SherpaOnnxOfflineFireRedAsrCtcModelConfig(
|
|
402
|
+
model: toCPointer(model)
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
364
406
|
func sherpaOnnxOfflineNemoEncDecCtcModelConfig(
|
|
365
407
|
model: String = ""
|
|
366
408
|
) -> SherpaOnnxOfflineNemoEncDecCtcModelConfig {
|
|
@@ -382,14 +424,18 @@ func sherpaOnnxOfflineWhisperModelConfig(
|
|
|
382
424
|
decoder: String = "",
|
|
383
425
|
language: String = "",
|
|
384
426
|
task: String = "transcribe",
|
|
385
|
-
tailPaddings: Int = -1
|
|
427
|
+
tailPaddings: Int = -1,
|
|
428
|
+
enableTokenTimestamps: Bool = false,
|
|
429
|
+
enableSegmentTimestamps: Bool = false
|
|
386
430
|
) -> SherpaOnnxOfflineWhisperModelConfig {
|
|
387
431
|
return SherpaOnnxOfflineWhisperModelConfig(
|
|
388
432
|
encoder: toCPointer(encoder),
|
|
389
433
|
decoder: toCPointer(decoder),
|
|
390
434
|
language: toCPointer(language),
|
|
391
435
|
task: toCPointer(task),
|
|
392
|
-
tail_paddings: Int32(tailPaddings)
|
|
436
|
+
tail_paddings: Int32(tailPaddings),
|
|
437
|
+
enable_token_timestamps: enableTokenTimestamps ? 1 : 0,
|
|
438
|
+
enable_segment_timestamps: enableSegmentTimestamps ? 1 : 0
|
|
393
439
|
)
|
|
394
440
|
}
|
|
395
441
|
|
|
@@ -409,6 +455,22 @@ func sherpaOnnxOfflineCanaryModelConfig(
|
|
|
409
455
|
)
|
|
410
456
|
}
|
|
411
457
|
|
|
458
|
+
func sherpaOnnxOfflineCohereTranscribeModelConfig(
|
|
459
|
+
encoder: String = "",
|
|
460
|
+
decoder: String = "",
|
|
461
|
+
language: String = "",
|
|
462
|
+
usePunct: Bool = true,
|
|
463
|
+
useInverseTextNormalization: Bool = true
|
|
464
|
+
) -> SherpaOnnxOfflineCohereTranscribeModelConfig {
|
|
465
|
+
return SherpaOnnxOfflineCohereTranscribeModelConfig(
|
|
466
|
+
encoder: toCPointer(encoder),
|
|
467
|
+
decoder: toCPointer(decoder),
|
|
468
|
+
language: toCPointer(language),
|
|
469
|
+
use_punct: usePunct ? 1 : 0,
|
|
470
|
+
use_itn: useInverseTextNormalization ? 1 : 0
|
|
471
|
+
)
|
|
472
|
+
}
|
|
473
|
+
|
|
412
474
|
func sherpaOnnxOfflineFireRedAsrModelConfig(
|
|
413
475
|
encoder: String = "",
|
|
414
476
|
decoder: String = ""
|
|
@@ -419,17 +481,48 @@ func sherpaOnnxOfflineFireRedAsrModelConfig(
|
|
|
419
481
|
)
|
|
420
482
|
}
|
|
421
483
|
|
|
484
|
+
/// there are two versions of Moonshine
|
|
485
|
+
/// For v1, you need four models: preprocessor, encoder, uncachedDecoder, cachedDecoder
|
|
486
|
+
/// For v2, you need two models: encoder, mergedDecoder
|
|
422
487
|
func sherpaOnnxOfflineMoonshineModelConfig(
|
|
423
488
|
preprocessor: String = "",
|
|
424
489
|
encoder: String = "",
|
|
425
490
|
uncachedDecoder: String = "",
|
|
426
|
-
cachedDecoder: String = ""
|
|
491
|
+
cachedDecoder: String = "",
|
|
492
|
+
mergedDecoder: String = ""
|
|
427
493
|
) -> SherpaOnnxOfflineMoonshineModelConfig {
|
|
428
494
|
return SherpaOnnxOfflineMoonshineModelConfig(
|
|
429
495
|
preprocessor: toCPointer(preprocessor),
|
|
430
496
|
encoder: toCPointer(encoder),
|
|
431
497
|
uncached_decoder: toCPointer(uncachedDecoder),
|
|
432
|
-
cached_decoder: toCPointer(cachedDecoder)
|
|
498
|
+
cached_decoder: toCPointer(cachedDecoder),
|
|
499
|
+
merged_decoder: toCPointer(mergedDecoder)
|
|
500
|
+
)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
func sherpaOnnxOfflineQwen3ASRModelConfig(
|
|
504
|
+
convFrontend: String = "",
|
|
505
|
+
encoder: String = "",
|
|
506
|
+
decoder: String = "",
|
|
507
|
+
tokenizer: String = "",
|
|
508
|
+
maxTotalLen: Int = 512,
|
|
509
|
+
maxNewTokens: Int = 128,
|
|
510
|
+
temperature: Float = 1e-6,
|
|
511
|
+
topP: Float = 0.8,
|
|
512
|
+
seed: Int = 42,
|
|
513
|
+
hotwords: String = ""
|
|
514
|
+
) -> SherpaOnnxOfflineQwen3ASRModelConfig {
|
|
515
|
+
return SherpaOnnxOfflineQwen3ASRModelConfig(
|
|
516
|
+
conv_frontend: toCPointer(convFrontend),
|
|
517
|
+
encoder: toCPointer(encoder),
|
|
518
|
+
decoder: toCPointer(decoder),
|
|
519
|
+
tokenizer: toCPointer(tokenizer),
|
|
520
|
+
max_total_len: Int32(maxTotalLen),
|
|
521
|
+
max_new_tokens: Int32(maxNewTokens),
|
|
522
|
+
temperature: temperature,
|
|
523
|
+
top_p: topP,
|
|
524
|
+
seed: Int32(seed),
|
|
525
|
+
hotwords: toCPointer(hotwords)
|
|
433
526
|
)
|
|
434
527
|
}
|
|
435
528
|
|
|
@@ -463,6 +556,38 @@ func sherpaOnnxOfflineLMConfig(
|
|
|
463
556
|
)
|
|
464
557
|
}
|
|
465
558
|
|
|
559
|
+
func sherpaOnnxOfflineFunASRNanoModelConfig(
|
|
560
|
+
encoderAdaptor: String = "",
|
|
561
|
+
llm: String = "",
|
|
562
|
+
embedding: String = "",
|
|
563
|
+
tokenizer: String = "",
|
|
564
|
+
systemPrompt: String = "You are a helpful assistant.",
|
|
565
|
+
userPrompt: String = "语音转写:",
|
|
566
|
+
maxNewTokens: Int = 512,
|
|
567
|
+
temperature: Float = 1e-6,
|
|
568
|
+
topP: Float = 0.8,
|
|
569
|
+
seed: Int = 42,
|
|
570
|
+
language: String = "",
|
|
571
|
+
itn: Bool = true,
|
|
572
|
+
hotwords: String = ""
|
|
573
|
+
) -> SherpaOnnxOfflineFunASRNanoModelConfig {
|
|
574
|
+
return SherpaOnnxOfflineFunASRNanoModelConfig(
|
|
575
|
+
encoder_adaptor: toCPointer(encoderAdaptor),
|
|
576
|
+
llm: toCPointer(llm),
|
|
577
|
+
embedding: toCPointer(embedding),
|
|
578
|
+
tokenizer: toCPointer(tokenizer),
|
|
579
|
+
system_prompt: toCPointer(systemPrompt),
|
|
580
|
+
user_prompt: toCPointer(userPrompt),
|
|
581
|
+
max_new_tokens: Int32(maxNewTokens),
|
|
582
|
+
temperature: temperature,
|
|
583
|
+
top_p: topP,
|
|
584
|
+
seed: Int32(seed),
|
|
585
|
+
language: toCPointer(language),
|
|
586
|
+
itn: itn ? 1 : 0,
|
|
587
|
+
hotwords: toCPointer(hotwords)
|
|
588
|
+
)
|
|
589
|
+
}
|
|
590
|
+
|
|
466
591
|
func sherpaOnnxOfflineModelConfig(
|
|
467
592
|
tokens: String,
|
|
468
593
|
transducer: SherpaOnnxOfflineTransducerModelConfig = sherpaOnnxOfflineTransducerModelConfig(),
|
|
@@ -483,7 +608,21 @@ func sherpaOnnxOfflineModelConfig(
|
|
|
483
608
|
dolphin: SherpaOnnxOfflineDolphinModelConfig = sherpaOnnxOfflineDolphinModelConfig(),
|
|
484
609
|
zipformerCtc: SherpaOnnxOfflineZipformerCtcModelConfig =
|
|
485
610
|
sherpaOnnxOfflineZipformerCtcModelConfig(),
|
|
486
|
-
canary: SherpaOnnxOfflineCanaryModelConfig = sherpaOnnxOfflineCanaryModelConfig()
|
|
611
|
+
canary: SherpaOnnxOfflineCanaryModelConfig = sherpaOnnxOfflineCanaryModelConfig(),
|
|
612
|
+
wenetCtc: SherpaOnnxOfflineWenetCtcModelConfig =
|
|
613
|
+
sherpaOnnxOfflineWenetCtcModelConfig(),
|
|
614
|
+
omnilingual: SherpaOnnxOfflineOmnilingualAsrCtcModelConfig =
|
|
615
|
+
sherpaOnnxOfflineOmnilingualAsrCtcModelConfig(),
|
|
616
|
+
medasr: SherpaOnnxOfflineMedAsrCtcModelConfig =
|
|
617
|
+
sherpaOnnxOfflineMedAsrCtcModelConfig(),
|
|
618
|
+
funasrNano: SherpaOnnxOfflineFunASRNanoModelConfig =
|
|
619
|
+
sherpaOnnxOfflineFunASRNanoModelConfig(),
|
|
620
|
+
fireRedAsrCtc: SherpaOnnxOfflineFireRedAsrCtcModelConfig =
|
|
621
|
+
sherpaOnnxOfflineFireRedAsrCtcModelConfig(),
|
|
622
|
+
qwen3Asr: SherpaOnnxOfflineQwen3ASRModelConfig =
|
|
623
|
+
sherpaOnnxOfflineQwen3ASRModelConfig(),
|
|
624
|
+
cohereTranscribe: SherpaOnnxOfflineCohereTranscribeModelConfig =
|
|
625
|
+
sherpaOnnxOfflineCohereTranscribeModelConfig()
|
|
487
626
|
) -> SherpaOnnxOfflineModelConfig {
|
|
488
627
|
return SherpaOnnxOfflineModelConfig(
|
|
489
628
|
transducer: transducer,
|
|
@@ -504,7 +643,14 @@ func sherpaOnnxOfflineModelConfig(
|
|
|
504
643
|
fire_red_asr: fireRedAsr,
|
|
505
644
|
dolphin: dolphin,
|
|
506
645
|
zipformer_ctc: zipformerCtc,
|
|
507
|
-
canary: canary
|
|
646
|
+
canary: canary,
|
|
647
|
+
wenet_ctc: wenetCtc,
|
|
648
|
+
omnilingual: omnilingual,
|
|
649
|
+
medasr: medasr,
|
|
650
|
+
funasr_nano: funasrNano,
|
|
651
|
+
fire_red_asr_ctc: fireRedAsrCtc,
|
|
652
|
+
qwen3_asr: qwen3Asr,
|
|
653
|
+
cohere_transcribe: cohereTranscribe
|
|
508
654
|
)
|
|
509
655
|
}
|
|
510
656
|
|
|
@@ -550,6 +696,11 @@ class SherpaOnnxOfflineRecongitionResult {
|
|
|
550
696
|
return (0 ..< result.pointee.count).map { p[Int($0)] }
|
|
551
697
|
}()
|
|
552
698
|
|
|
699
|
+
private lazy var _durations: [Float] = {
|
|
700
|
+
guard let p = result.pointee.durations else { return [] }
|
|
701
|
+
return (0 ..< result.pointee.count).map { p[Int($0)] }
|
|
702
|
+
}()
|
|
703
|
+
|
|
553
704
|
private lazy var _lang: String = {
|
|
554
705
|
guard let cstr = result.pointee.lang else { return "" }
|
|
555
706
|
return String(cString: cstr)
|
|
@@ -565,6 +716,24 @@ class SherpaOnnxOfflineRecongitionResult {
|
|
|
565
716
|
return String(cString: cstr)
|
|
566
717
|
}()
|
|
567
718
|
|
|
719
|
+
private lazy var _segmentTimestamps: [Float] = {
|
|
720
|
+
guard let p = result.pointee.segment_timestamps else { return [] }
|
|
721
|
+
return (0 ..< result.pointee.segment_count).map { p[Int($0)] }
|
|
722
|
+
}()
|
|
723
|
+
|
|
724
|
+
private lazy var _segmentDurations: [Float] = {
|
|
725
|
+
guard let p = result.pointee.segment_durations else { return [] }
|
|
726
|
+
return (0 ..< result.pointee.segment_count).map { p[Int($0)] }
|
|
727
|
+
}()
|
|
728
|
+
|
|
729
|
+
private lazy var _segmentTexts: [String] = {
|
|
730
|
+
guard let arr = result.pointee.segment_texts_arr else { return [] }
|
|
731
|
+
return (0 ..< result.pointee.segment_count).compactMap { idx -> String? in
|
|
732
|
+
guard let ptr = arr[Int(idx)] else { return nil }
|
|
733
|
+
return String(cString: ptr)
|
|
734
|
+
}
|
|
735
|
+
}()
|
|
736
|
+
|
|
568
737
|
/// Return the actual recognition result.
|
|
569
738
|
/// For English models, it contains words separated by spaces.
|
|
570
739
|
/// For Chinese models, it contains Chinese words.
|
|
@@ -580,6 +749,11 @@ class SherpaOnnxOfflineRecongitionResult {
|
|
|
580
749
|
_timestamps
|
|
581
750
|
}
|
|
582
751
|
|
|
752
|
+
/// Non-empty for TDT models. Empty for all other non-TDT models
|
|
753
|
+
var durations: [Float] {
|
|
754
|
+
_durations
|
|
755
|
+
}
|
|
756
|
+
|
|
583
757
|
/// For SenseVoice models, it can be zh, en, ja, yue, ko
|
|
584
758
|
/// where zh is for Chinese
|
|
585
759
|
/// en is for English
|
|
@@ -600,6 +774,23 @@ class SherpaOnnxOfflineRecongitionResult {
|
|
|
600
774
|
_event
|
|
601
775
|
}
|
|
602
776
|
|
|
777
|
+
/// Segment-level timestamps (for Whisper with segment timestamps enabled)
|
|
778
|
+
var segmentCount: Int {
|
|
779
|
+
Int(result.pointee.segment_count)
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
var segmentTimestamps: [Float] {
|
|
783
|
+
_segmentTimestamps
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
var segmentDurations: [Float] {
|
|
787
|
+
_segmentDurations
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
var segmentTexts: [String] {
|
|
791
|
+
_segmentTexts
|
|
792
|
+
}
|
|
793
|
+
|
|
603
794
|
init(result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>) {
|
|
604
795
|
self.result = result
|
|
605
796
|
}
|
|
@@ -633,25 +824,54 @@ class SherpaOnnxOfflineRecognizer {
|
|
|
633
824
|
/// - sampleRate: Sample rate of the input audio samples. Must match
|
|
634
825
|
/// the one expected by the model.
|
|
635
826
|
func decode(samples: [Float], sampleRate: Int = 16000) -> SherpaOnnxOfflineRecongitionResult {
|
|
827
|
+
let stream = createStream()
|
|
828
|
+
stream.acceptWaveform(samples: samples, sampleRate: sampleRate)
|
|
829
|
+
decode(stream: stream)
|
|
830
|
+
return getResult(stream: stream)
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
func setConfig(config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig>) {
|
|
834
|
+
SherpaOnnxOfflineRecognizerSetConfig(recognizer, config)
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
func createStream() -> SherpaOnnxOfflineStreamWrapper {
|
|
636
838
|
guard let stream = SherpaOnnxCreateOfflineStream(recognizer) else {
|
|
637
839
|
fatalError("Failed to create offline stream")
|
|
638
840
|
}
|
|
639
841
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
SherpaOnnxAcceptWaveformOffline(stream, Int32(sampleRate), samples, Int32(samples.count))
|
|
842
|
+
return SherpaOnnxOfflineStreamWrapper(stream: stream)
|
|
843
|
+
}
|
|
643
844
|
|
|
644
|
-
|
|
845
|
+
func decode(stream: SherpaOnnxOfflineStreamWrapper) {
|
|
846
|
+
SherpaOnnxDecodeOfflineStream(recognizer, stream.stream)
|
|
847
|
+
}
|
|
645
848
|
|
|
646
|
-
|
|
849
|
+
func getResult(stream: SherpaOnnxOfflineStreamWrapper) -> SherpaOnnxOfflineRecongitionResult {
|
|
850
|
+
guard let resultPtr = SherpaOnnxGetOfflineStreamResult(stream.stream) else {
|
|
647
851
|
fatalError("Failed to get offline recognition result")
|
|
648
852
|
}
|
|
649
853
|
|
|
650
854
|
return SherpaOnnxOfflineRecongitionResult(result: resultPtr)
|
|
651
855
|
}
|
|
856
|
+
}
|
|
652
857
|
|
|
653
|
-
|
|
654
|
-
|
|
858
|
+
class SherpaOnnxOfflineStreamWrapper {
|
|
859
|
+
let stream: OpaquePointer
|
|
860
|
+
|
|
861
|
+
init(stream: OpaquePointer) {
|
|
862
|
+
self.stream = stream
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
deinit {
|
|
866
|
+
SherpaOnnxDestroyOfflineStream(stream)
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
func setOption(key: String, value: String) {
|
|
870
|
+
SherpaOnnxOfflineStreamSetOption(stream, toCPointer(key), toCPointer(value))
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
func acceptWaveform(samples: [Float], sampleRate: Int = 16000) {
|
|
874
|
+
SherpaOnnxAcceptWaveformOffline(stream, Int32(sampleRate), samples, Int32(samples.count))
|
|
655
875
|
}
|
|
656
876
|
}
|
|
657
877
|
|
|
@@ -910,6 +1130,74 @@ func sherpaOnnxOfflineTtsKittenModelConfig(
|
|
|
910
1130
|
)
|
|
911
1131
|
}
|
|
912
1132
|
|
|
1133
|
+
func sherpaOnnxOfflineTtsZipvoiceModelConfig(
|
|
1134
|
+
tokens: String = "",
|
|
1135
|
+
encoder: String = "",
|
|
1136
|
+
decoder: String = "",
|
|
1137
|
+
vocoder: String = "",
|
|
1138
|
+
dataDir: String = "",
|
|
1139
|
+
lexicon: String = "",
|
|
1140
|
+
featScale: Float = 0.1,
|
|
1141
|
+
tShift: Float = 0.5,
|
|
1142
|
+
targetRms: Float = 0.1,
|
|
1143
|
+
guidanceScale: Float = 1.0
|
|
1144
|
+
) -> SherpaOnnxOfflineTtsZipvoiceModelConfig {
|
|
1145
|
+
return SherpaOnnxOfflineTtsZipvoiceModelConfig(
|
|
1146
|
+
tokens: toCPointer(tokens),
|
|
1147
|
+
encoder: toCPointer(encoder),
|
|
1148
|
+
decoder: toCPointer(decoder),
|
|
1149
|
+
vocoder: toCPointer(vocoder),
|
|
1150
|
+
data_dir: toCPointer(dataDir),
|
|
1151
|
+
lexicon: toCPointer(lexicon),
|
|
1152
|
+
feat_scale: featScale,
|
|
1153
|
+
t_shift: tShift,
|
|
1154
|
+
target_rms: targetRms,
|
|
1155
|
+
guidance_scale: guidanceScale
|
|
1156
|
+
)
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
func sherpaOnnxOfflineTtsPocketModelConfig(
|
|
1160
|
+
lmFlow: String = "",
|
|
1161
|
+
lmMain: String = "",
|
|
1162
|
+
encoder: String = "",
|
|
1163
|
+
decoder: String = "",
|
|
1164
|
+
textConditioner: String = "",
|
|
1165
|
+
vocabJson: String = "",
|
|
1166
|
+
tokenScoresJson: String = "",
|
|
1167
|
+
voiceEmbeddingCacheCapacity: Int = 50
|
|
1168
|
+
) -> SherpaOnnxOfflineTtsPocketModelConfig {
|
|
1169
|
+
return SherpaOnnxOfflineTtsPocketModelConfig(
|
|
1170
|
+
lm_flow: toCPointer(lmFlow),
|
|
1171
|
+
lm_main: toCPointer(lmMain),
|
|
1172
|
+
encoder: toCPointer(encoder),
|
|
1173
|
+
decoder: toCPointer(decoder),
|
|
1174
|
+
text_conditioner: toCPointer(textConditioner),
|
|
1175
|
+
vocab_json: toCPointer(vocabJson),
|
|
1176
|
+
token_scores_json: toCPointer(tokenScoresJson),
|
|
1177
|
+
voice_embedding_cache_capacity: Int32(voiceEmbeddingCacheCapacity)
|
|
1178
|
+
)
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
func sherpaOnnxOfflineTtsSupertonicModelConfig(
|
|
1182
|
+
durationPredictor: String = "",
|
|
1183
|
+
textEncoder: String = "",
|
|
1184
|
+
vectorEstimator: String = "",
|
|
1185
|
+
vocoder: String = "",
|
|
1186
|
+
ttsJson: String = "",
|
|
1187
|
+
unicodeIndexer: String = "",
|
|
1188
|
+
voiceStyle: String = ""
|
|
1189
|
+
) -> SherpaOnnxOfflineTtsSupertonicModelConfig {
|
|
1190
|
+
return SherpaOnnxOfflineTtsSupertonicModelConfig(
|
|
1191
|
+
duration_predictor: toCPointer(durationPredictor),
|
|
1192
|
+
text_encoder: toCPointer(textEncoder),
|
|
1193
|
+
vector_estimator: toCPointer(vectorEstimator),
|
|
1194
|
+
vocoder: toCPointer(vocoder),
|
|
1195
|
+
tts_json: toCPointer(ttsJson),
|
|
1196
|
+
unicode_indexer: toCPointer(unicodeIndexer),
|
|
1197
|
+
voice_style: toCPointer(voiceStyle)
|
|
1198
|
+
)
|
|
1199
|
+
}
|
|
1200
|
+
|
|
913
1201
|
func sherpaOnnxOfflineTtsModelConfig(
|
|
914
1202
|
vits: SherpaOnnxOfflineTtsVitsModelConfig = sherpaOnnxOfflineTtsVitsModelConfig(),
|
|
915
1203
|
matcha: SherpaOnnxOfflineTtsMatchaModelConfig = sherpaOnnxOfflineTtsMatchaModelConfig(),
|
|
@@ -917,7 +1205,11 @@ func sherpaOnnxOfflineTtsModelConfig(
|
|
|
917
1205
|
numThreads: Int = 1,
|
|
918
1206
|
debug: Int = 0,
|
|
919
1207
|
provider: String = "cpu",
|
|
920
|
-
kitten: SherpaOnnxOfflineTtsKittenModelConfig = sherpaOnnxOfflineTtsKittenModelConfig()
|
|
1208
|
+
kitten: SherpaOnnxOfflineTtsKittenModelConfig = sherpaOnnxOfflineTtsKittenModelConfig(),
|
|
1209
|
+
zipvoice: SherpaOnnxOfflineTtsZipvoiceModelConfig = sherpaOnnxOfflineTtsZipvoiceModelConfig(),
|
|
1210
|
+
pocket: SherpaOnnxOfflineTtsPocketModelConfig = sherpaOnnxOfflineTtsPocketModelConfig(),
|
|
1211
|
+
supertonic: SherpaOnnxOfflineTtsSupertonicModelConfig =
|
|
1212
|
+
sherpaOnnxOfflineTtsSupertonicModelConfig()
|
|
921
1213
|
) -> SherpaOnnxOfflineTtsModelConfig {
|
|
922
1214
|
return SherpaOnnxOfflineTtsModelConfig(
|
|
923
1215
|
vits: vits,
|
|
@@ -926,7 +1218,10 @@ func sherpaOnnxOfflineTtsModelConfig(
|
|
|
926
1218
|
provider: toCPointer(provider),
|
|
927
1219
|
matcha: matcha,
|
|
928
1220
|
kokoro: kokoro,
|
|
929
|
-
kitten: kitten
|
|
1221
|
+
kitten: kitten,
|
|
1222
|
+
zipvoice: zipvoice,
|
|
1223
|
+
pocket: pocket,
|
|
1224
|
+
supertonic: supertonic
|
|
930
1225
|
)
|
|
931
1226
|
}
|
|
932
1227
|
|
|
@@ -1024,6 +1319,94 @@ typealias TtsCallbackWithArg = (
|
|
|
1024
1319
|
) -> Int32
|
|
1025
1320
|
)?
|
|
1026
1321
|
|
|
1322
|
+
class SherpaOnnxCallbackPair {
|
|
1323
|
+
var cb: TtsCallbackWithArg
|
|
1324
|
+
var arg: UnsafeMutableRawPointer?
|
|
1325
|
+
init(cb: TtsCallbackWithArg, arg: UnsafeMutableRawPointer?) {
|
|
1326
|
+
self.cb = cb
|
|
1327
|
+
self.arg = arg
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
typealias TtsProgressCallbackWithArg =
|
|
1332
|
+
@convention(c) (
|
|
1333
|
+
UnsafePointer<Float>?, Int32, Float, UnsafeMutableRawPointer?
|
|
1334
|
+
) -> Int32
|
|
1335
|
+
|
|
1336
|
+
struct SherpaOnnxGenerationConfigSwift {
|
|
1337
|
+
var silenceScale: Float = 0.2
|
|
1338
|
+
var speed: Float = 1.0
|
|
1339
|
+
var sid: Int = 0
|
|
1340
|
+
var referenceAudio: [Float] = []
|
|
1341
|
+
var referenceSampleRate: Int = 16000
|
|
1342
|
+
var referenceText: String = ""
|
|
1343
|
+
var numSteps: Int = 1
|
|
1344
|
+
var extra: [String: Any] = [:] // Any can be String, Int, Float, Double
|
|
1345
|
+
|
|
1346
|
+
/// Convert the extra dictionary into a JSON string
|
|
1347
|
+
func extraJsonString() -> String {
|
|
1348
|
+
var jsonCompatible: [String: Any] = [:]
|
|
1349
|
+
|
|
1350
|
+
for (key, value) in extra {
|
|
1351
|
+
switch value {
|
|
1352
|
+
case let v as String:
|
|
1353
|
+
jsonCompatible[key] = v
|
|
1354
|
+
case let v as Int:
|
|
1355
|
+
jsonCompatible[key] = v
|
|
1356
|
+
case let v as Float:
|
|
1357
|
+
jsonCompatible[key] = v
|
|
1358
|
+
case let v as Double:
|
|
1359
|
+
jsonCompatible[key] = v
|
|
1360
|
+
default:
|
|
1361
|
+
// ignore unsupported types
|
|
1362
|
+
print("Warning: unsupported type for key '\(key)' in extra")
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
guard let data = try? JSONSerialization.data(withJSONObject: jsonCompatible, options: []),
|
|
1367
|
+
let json = String(data: data, encoding: .utf8)
|
|
1368
|
+
else {
|
|
1369
|
+
return "{}"
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
return json
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
final class SherpaOnnxGenerationConfigC {
|
|
1377
|
+
/// The underlying C struct
|
|
1378
|
+
var cConfig: SherpaOnnxGenerationConfig
|
|
1379
|
+
|
|
1380
|
+
/// Storage for reference audio so the pointer stays valid during the C call
|
|
1381
|
+
private let referenceAudioStorage: [Float]
|
|
1382
|
+
|
|
1383
|
+
/// Extra JSON string for C API
|
|
1384
|
+
let extraJson: String
|
|
1385
|
+
|
|
1386
|
+
init(_ swiftConfig: SherpaOnnxGenerationConfigSwift) {
|
|
1387
|
+
let referenceAudio = swiftConfig.referenceAudio
|
|
1388
|
+
|
|
1389
|
+
let extraJson = swiftConfig.extraJsonString()
|
|
1390
|
+
self.extraJson = extraJson
|
|
1391
|
+
|
|
1392
|
+
referenceAudioStorage = referenceAudio
|
|
1393
|
+
|
|
1394
|
+
cConfig = referenceAudioStorage.withUnsafeBufferPointer { buffer in
|
|
1395
|
+
SherpaOnnxGenerationConfig(
|
|
1396
|
+
silence_scale: swiftConfig.silenceScale,
|
|
1397
|
+
speed: swiftConfig.speed,
|
|
1398
|
+
sid: Int32(swiftConfig.sid),
|
|
1399
|
+
reference_audio: buffer.count > 0 ? buffer.baseAddress : nil,
|
|
1400
|
+
reference_audio_len: Int32(buffer.count),
|
|
1401
|
+
reference_sample_rate: Int32(swiftConfig.referenceSampleRate),
|
|
1402
|
+
reference_text: toCPointer(swiftConfig.referenceText),
|
|
1403
|
+
num_steps: Int32(swiftConfig.numSteps),
|
|
1404
|
+
extra: toCPointer(extraJson)
|
|
1405
|
+
)
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1027
1410
|
class SherpaOnnxOfflineTtsWrapper {
|
|
1028
1411
|
/// A pointer to the underlying counterpart in C
|
|
1029
1412
|
let tts: OpaquePointer!
|
|
@@ -1042,21 +1425,47 @@ class SherpaOnnxOfflineTtsWrapper {
|
|
|
1042
1425
|
}
|
|
1043
1426
|
|
|
1044
1427
|
func generate(text: String, sid: Int = 0, speed: Float = 1.0) -> SherpaOnnxGeneratedAudioWrapper {
|
|
1045
|
-
let
|
|
1046
|
-
|
|
1047
|
-
)
|
|
1048
|
-
|
|
1049
|
-
return SherpaOnnxGeneratedAudioWrapper(audio: audio)
|
|
1428
|
+
let config = SherpaOnnxGenerationConfigSwift(speed: speed, sid: sid)
|
|
1429
|
+
return generateWithConfig(text: text, config: config, callback: nil, arg: nil)
|
|
1050
1430
|
}
|
|
1051
1431
|
|
|
1052
1432
|
func generateWithCallbackWithArg(
|
|
1053
1433
|
text: String, callback: TtsCallbackWithArg, arg: UnsafeMutableRawPointer, sid: Int = 0,
|
|
1054
1434
|
speed: Float = 1.0
|
|
1055
1435
|
) -> SherpaOnnxGeneratedAudioWrapper {
|
|
1436
|
+
let config = SherpaOnnxGenerationConfigSwift(speed: speed, sid: sid)
|
|
1437
|
+
|
|
1438
|
+
let pair = SherpaOnnxCallbackPair(cb: callback, arg: arg)
|
|
1439
|
+
let unmanaged = Unmanaged.passRetained(pair)
|
|
1440
|
+
let wrapper: TtsProgressCallbackWithArg = { samples, n, _, rawArg in
|
|
1441
|
+
let p = Unmanaged<SherpaOnnxCallbackPair>.fromOpaque(rawArg!).takeUnretainedValue()
|
|
1442
|
+
return p.cb!(samples, n, p.arg)
|
|
1443
|
+
}
|
|
1444
|
+
let result = generateWithConfig(
|
|
1445
|
+
text: text, config: config, callback: wrapper, arg: unmanaged.toOpaque()
|
|
1446
|
+
)
|
|
1447
|
+
unmanaged.release()
|
|
1448
|
+
return result
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
func generateWithConfig(
|
|
1452
|
+
text: String,
|
|
1453
|
+
config: SherpaOnnxGenerationConfigSwift,
|
|
1454
|
+
callback: TtsProgressCallbackWithArg?,
|
|
1455
|
+
arg: UnsafeMutableRawPointer?
|
|
1456
|
+
) -> SherpaOnnxGeneratedAudioWrapper {
|
|
1457
|
+
let bridge = SherpaOnnxGenerationConfigC(config)
|
|
1458
|
+
|
|
1056
1459
|
let audio: UnsafePointer<SherpaOnnxGeneratedAudio>? =
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1460
|
+
withUnsafePointer(to: &bridge.cConfig) { configPtr in
|
|
1461
|
+
SherpaOnnxOfflineTtsGenerateWithConfig(
|
|
1462
|
+
tts,
|
|
1463
|
+
toCPointer(text),
|
|
1464
|
+
configPtr,
|
|
1465
|
+
callback,
|
|
1466
|
+
arg
|
|
1467
|
+
)
|
|
1468
|
+
}
|
|
1060
1469
|
|
|
1061
1470
|
return SherpaOnnxGeneratedAudioWrapper(audio: audio)
|
|
1062
1471
|
}
|
|
@@ -1553,9 +1962,17 @@ func sherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig(model: String = "")
|
|
|
1553
1962
|
return SherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig(model: toCPointer(model))
|
|
1554
1963
|
}
|
|
1555
1964
|
|
|
1965
|
+
func sherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig(model: String = "")
|
|
1966
|
+
-> SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig
|
|
1967
|
+
{
|
|
1968
|
+
return SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig(model: toCPointer(model))
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1556
1971
|
func sherpaOnnxOfflineSpeechDenoiserModelConfig(
|
|
1557
1972
|
gtcrn: SherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig =
|
|
1558
1973
|
sherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig(),
|
|
1974
|
+
dpdfnet: SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig =
|
|
1975
|
+
sherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig(),
|
|
1559
1976
|
numThreads: Int = 1,
|
|
1560
1977
|
provider: String = "cpu",
|
|
1561
1978
|
debug: Int = 0
|
|
@@ -1564,7 +1981,8 @@ func sherpaOnnxOfflineSpeechDenoiserModelConfig(
|
|
|
1564
1981
|
gtcrn: gtcrn,
|
|
1565
1982
|
num_threads: Int32(numThreads),
|
|
1566
1983
|
debug: Int32(debug),
|
|
1567
|
-
provider: toCPointer(provider)
|
|
1984
|
+
provider: toCPointer(provider),
|
|
1985
|
+
dpdfnet: dpdfnet
|
|
1568
1986
|
)
|
|
1569
1987
|
}
|
|
1570
1988
|
|
|
@@ -1592,14 +2010,24 @@ class SherpaOnnxDenoisedAudioWrapper {
|
|
|
1592
2010
|
}
|
|
1593
2011
|
|
|
1594
2012
|
var n: Int32 {
|
|
2013
|
+
guard let audio else {
|
|
2014
|
+
return 0
|
|
2015
|
+
}
|
|
1595
2016
|
return audio.pointee.n
|
|
1596
2017
|
}
|
|
1597
2018
|
|
|
1598
2019
|
var sampleRate: Int32 {
|
|
2020
|
+
guard let audio else {
|
|
2021
|
+
return 0
|
|
2022
|
+
}
|
|
1599
2023
|
return audio.pointee.sample_rate
|
|
1600
2024
|
}
|
|
1601
2025
|
|
|
1602
2026
|
var samples: [Float] {
|
|
2027
|
+
guard let audio else {
|
|
2028
|
+
return []
|
|
2029
|
+
}
|
|
2030
|
+
|
|
1603
2031
|
if let p = audio.pointee.samples {
|
|
1604
2032
|
var samples: [Float] = []
|
|
1605
2033
|
for index in 0 ..< n {
|
|
@@ -1612,6 +2040,9 @@ class SherpaOnnxDenoisedAudioWrapper {
|
|
|
1612
2040
|
}
|
|
1613
2041
|
|
|
1614
2042
|
func save(filename: String) -> Int32 {
|
|
2043
|
+
guard let audio else {
|
|
2044
|
+
return 0
|
|
2045
|
+
}
|
|
1615
2046
|
return SherpaOnnxWriteWave(audio.pointee.samples, n, sampleRate, toCPointer(filename))
|
|
1616
2047
|
}
|
|
1617
2048
|
}
|
|
@@ -1646,6 +2077,53 @@ class SherpaOnnxOfflineSpeechDenoiserWrapper {
|
|
|
1646
2077
|
}
|
|
1647
2078
|
}
|
|
1648
2079
|
|
|
2080
|
+
func sherpaOnnxOnlineSpeechDenoiserConfig(
|
|
2081
|
+
model: SherpaOnnxOfflineSpeechDenoiserModelConfig =
|
|
2082
|
+
sherpaOnnxOfflineSpeechDenoiserModelConfig()
|
|
2083
|
+
) -> SherpaOnnxOnlineSpeechDenoiserConfig {
|
|
2084
|
+
return SherpaOnnxOnlineSpeechDenoiserConfig(model: model)
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
class SherpaOnnxOnlineSpeechDenoiserWrapper {
|
|
2088
|
+
let impl: OpaquePointer!
|
|
2089
|
+
|
|
2090
|
+
init(
|
|
2091
|
+
config: UnsafePointer<SherpaOnnxOnlineSpeechDenoiserConfig>!
|
|
2092
|
+
) {
|
|
2093
|
+
impl = SherpaOnnxCreateOnlineSpeechDenoiser(config)
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
deinit {
|
|
2097
|
+
if let impl {
|
|
2098
|
+
SherpaOnnxDestroyOnlineSpeechDenoiser(impl)
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
func run(samples: [Float], sampleRate: Int) -> SherpaOnnxDenoisedAudioWrapper {
|
|
2103
|
+
let audio: UnsafePointer<SherpaOnnxDenoisedAudio>? = SherpaOnnxOnlineSpeechDenoiserRun(
|
|
2104
|
+
impl, samples, Int32(samples.count), Int32(sampleRate)
|
|
2105
|
+
)
|
|
2106
|
+
return SherpaOnnxDenoisedAudioWrapper(audio: audio)
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
func flush() -> SherpaOnnxDenoisedAudioWrapper {
|
|
2110
|
+
let audio: UnsafePointer<SherpaOnnxDenoisedAudio>? = SherpaOnnxOnlineSpeechDenoiserFlush(impl)
|
|
2111
|
+
return SherpaOnnxDenoisedAudioWrapper(audio: audio)
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
func reset() {
|
|
2115
|
+
SherpaOnnxOnlineSpeechDenoiserReset(impl)
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
var sampleRate: Int {
|
|
2119
|
+
return Int(SherpaOnnxOnlineSpeechDenoiserGetSampleRate(impl))
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
var frameShiftInSamples: Int {
|
|
2123
|
+
return Int(SherpaOnnxOnlineSpeechDenoiserGetFrameShiftInSamples(impl))
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
|
|
1649
2127
|
func getSherpaOnnxVersion() -> String {
|
|
1650
2128
|
return String(cString: SherpaOnnxGetVersionStr())
|
|
1651
2129
|
}
|
|
@@ -1657,3 +2135,167 @@ func getSherpaOnnxGitSha1() -> String {
|
|
|
1657
2135
|
func getSherpaOnnxGitDate() -> String {
|
|
1658
2136
|
return String(cString: SherpaOnnxGetGitDate())
|
|
1659
2137
|
}
|
|
2138
|
+
|
|
2139
|
+
// ---------------------------
|
|
2140
|
+
// Source separation
|
|
2141
|
+
// ---------------------------
|
|
2142
|
+
|
|
2143
|
+
struct AudioData {
|
|
2144
|
+
private enum Storage {
|
|
2145
|
+
case owned([Float])
|
|
2146
|
+
case wrapped(ManagedWave)
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
private class ManagedWave {
|
|
2150
|
+
let pointer: UnsafePointer<SherpaOnnxMultiChannelWave>
|
|
2151
|
+
init(_ p: UnsafePointer<SherpaOnnxMultiChannelWave>) {
|
|
2152
|
+
pointer = p
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
deinit { SherpaOnnxFreeMultiChannelWave(pointer) }
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
private let storage: Storage
|
|
2159
|
+
let channelCount: Int
|
|
2160
|
+
let samplesPerChannel: Int
|
|
2161
|
+
let sampleRate: Int
|
|
2162
|
+
|
|
2163
|
+
init(samples: [Float], channelCount: Int, sampleRate: Int) {
|
|
2164
|
+
storage = .owned(samples)
|
|
2165
|
+
self.channelCount = channelCount
|
|
2166
|
+
self.sampleRate = sampleRate
|
|
2167
|
+
samplesPerChannel = channelCount > 0 ? samples.count / channelCount : 0
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
init?(filename: String) {
|
|
2171
|
+
guard let ptr = SherpaOnnxReadWaveMultiChannel(filename) else { return nil }
|
|
2172
|
+
storage = .wrapped(ManagedWave(ptr))
|
|
2173
|
+
channelCount = Int(ptr.pointee.num_channels)
|
|
2174
|
+
samplesPerChannel = Int(ptr.pointee.num_samples)
|
|
2175
|
+
sampleRate = Int(ptr.pointee.sample_rate)
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Float>) -> R) -> R {
|
|
2179
|
+
switch storage {
|
|
2180
|
+
case let .owned(array):
|
|
2181
|
+
return array.withUnsafeBufferPointer(body)
|
|
2182
|
+
case let .wrapped(managed):
|
|
2183
|
+
let total = Int(managed.pointer.pointee.num_channels * managed.pointer.pointee.num_samples)
|
|
2184
|
+
// Ensure we start from the first channel's pointer
|
|
2185
|
+
return body(UnsafeBufferPointer(start: managed.pointer.pointee.samples[0], count: total))
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
@discardableResult
|
|
2190
|
+
func save(to filename: String) -> Bool {
|
|
2191
|
+
return withUnsafeBufferPointer { buf in
|
|
2192
|
+
guard let base = buf.baseAddress else { return false }
|
|
2193
|
+
// FIX: Explicitly type the array as Optional pointers to match C 'float* const*'
|
|
2194
|
+
var ptrs: [UnsafePointer<Float>?] = (0 ..< channelCount).map { base + ($0 * samplesPerChannel) }
|
|
2195
|
+
|
|
2196
|
+
return SherpaOnnxWriteWaveMultiChannel(
|
|
2197
|
+
&ptrs,
|
|
2198
|
+
Int32(samplesPerChannel),
|
|
2199
|
+
Int32(sampleRate),
|
|
2200
|
+
Int32(channelCount),
|
|
2201
|
+
filename
|
|
2202
|
+
) == 1
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
struct SourceSeparationConfig {
|
|
2208
|
+
struct Spleeter {
|
|
2209
|
+
var vocals: String
|
|
2210
|
+
var accompaniment: String
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
struct Uvr { var model: String }
|
|
2214
|
+
|
|
2215
|
+
var spleeter: Spleeter?
|
|
2216
|
+
var uvr: Uvr?
|
|
2217
|
+
var numThreads: Int = 1
|
|
2218
|
+
var debug: Bool = false
|
|
2219
|
+
var provider: String = "cpu"
|
|
2220
|
+
|
|
2221
|
+
func withCConfig<R>(_ body: (UnsafePointer<SherpaOnnxOfflineSourceSeparationConfig>) -> R) -> R {
|
|
2222
|
+
var cConfig = SherpaOnnxOfflineSourceSeparationConfig()
|
|
2223
|
+
cConfig.model.num_threads = Int32(numThreads)
|
|
2224
|
+
cConfig.model.debug = debug ? 1 : 0
|
|
2225
|
+
|
|
2226
|
+
var s: [String: [Int8]] = [:]
|
|
2227
|
+
func b(_ k: String, _ v: String?) -> UnsafePointer<Int8>? {
|
|
2228
|
+
guard let v = v else { return nil }
|
|
2229
|
+
s[k] = Array(v.utf8CString)
|
|
2230
|
+
return s[k]!.withUnsafeBufferPointer { $0.baseAddress }
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
cConfig.model.provider = b("provider", provider)
|
|
2234
|
+
cConfig.model.spleeter.vocals = b("spleeter.vocals", spleeter?.vocals)
|
|
2235
|
+
cConfig.model.spleeter.accompaniment = b("spleeter.accompaniment", spleeter?.accompaniment)
|
|
2236
|
+
cConfig.model.uvr.model = b("uvr.model", uvr?.model)
|
|
2237
|
+
|
|
2238
|
+
return body(&cConfig)
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
class SourceSeparator {
|
|
2243
|
+
private var engine: OpaquePointer?
|
|
2244
|
+
|
|
2245
|
+
init?(config: SourceSeparationConfig) {
|
|
2246
|
+
engine = config.withCConfig { SherpaOnnxCreateOfflineSourceSeparation($0) }
|
|
2247
|
+
|
|
2248
|
+
if engine == nil { return nil }
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
deinit {
|
|
2252
|
+
if let e = engine {
|
|
2253
|
+
SherpaOnnxDestroyOfflineSourceSeparation(e)
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
func process(buffer: AudioData) -> [AudioData]? {
|
|
2258
|
+
guard let engine = engine else { return nil }
|
|
2259
|
+
|
|
2260
|
+
return buffer.withUnsafeBufferPointer { flatBuf in
|
|
2261
|
+
guard let base = flatBuf.baseAddress else { return nil }
|
|
2262
|
+
var ptrs: [UnsafePointer<Float>?] = (0 ..< buffer.channelCount).map {
|
|
2263
|
+
base + ($0 * buffer.samplesPerChannel)
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
guard
|
|
2267
|
+
let raw = SherpaOnnxOfflineSourceSeparationProcess(
|
|
2268
|
+
engine,
|
|
2269
|
+
&ptrs,
|
|
2270
|
+
Int32(buffer.channelCount),
|
|
2271
|
+
Int32(buffer.samplesPerChannel),
|
|
2272
|
+
Int32(buffer.sampleRate)
|
|
2273
|
+
)
|
|
2274
|
+
else { return nil }
|
|
2275
|
+
|
|
2276
|
+
let stemCount = Int(raw.pointee.num_stems)
|
|
2277
|
+
let result = (0 ..< stemCount).map { i in
|
|
2278
|
+
let stem = raw.pointee.stems[i]
|
|
2279
|
+
let chs = Int(stem.num_channels)
|
|
2280
|
+
let n = Int(stem.n)
|
|
2281
|
+
var flat = [Float](repeating: 0, count: chs * n)
|
|
2282
|
+
|
|
2283
|
+
for c in 0 ..< chs {
|
|
2284
|
+
if let src = stem.samples[c] {
|
|
2285
|
+
let offset = c * n
|
|
2286
|
+
flat.withUnsafeMutableBufferPointer { dest in
|
|
2287
|
+
let destPtr = dest.baseAddress!.advanced(by: offset)
|
|
2288
|
+
destPtr.initialize(from: src, count: n)
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
return AudioData(
|
|
2293
|
+
samples: flat, channelCount: chs, sampleRate: Int(raw.pointee.sample_rate)
|
|
2294
|
+
)
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
SherpaOnnxDestroySourceSeparationOutput(raw)
|
|
2298
|
+
return result
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
}
|