@glassly/bluetooth-sdk 0.1.0-dev.26
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 +563 -0
- package/android/build.gradle +450 -0
- package/android/gradle.properties.example +9 -0
- package/android/lc3Lib/CMakeLists.txt +6 -0
- package/android/lc3Lib/build.gradle +212 -0
- package/android/lc3Lib/proguard-rules.pro +33 -0
- package/android/lc3Lib/src/main/AndroidManifest.xml +2 -0
- package/android/lc3Lib/src/main/cpp/CMakeLists.txt +8 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/CMakeLists.txt +30 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/CMakeLists.txt +7 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.cc +96 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/jni/ogg_opus_encoder.h +53 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/Makefile.am +6 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/config_types.h.in +26 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/ogg.h +209 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libogg/os_types.h +158 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus.h +981 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_custom.h +342 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_defines.h +799 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_multistream.h +660 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_projection.h +568 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/libopus/opus_types.h +166 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.cc +268 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/ogg_opus_encoder.h +115 -0
- package/android/lc3Lib/src/main/cpp/google_opus_stuff/opus_tools/opus_header.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/CMakeLists.txt +38 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3.h +309 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/lc3_private.h +162 -0
- package/android/lc3Lib/src/main/cpp/liblc3/include/rnnoise.h +114 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/CMakeLists.txt +19 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.c +92 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/attdet.h +44 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.c +375 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bits.h +315 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.c +129 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/bwdet.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/common.h +148 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.c +70 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/energy.h +43 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/fastmath.h +158 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/lc3.c +702 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.c +893 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf.h +111 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_arm.h +506 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/ltpf_neon.h +281 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/makefile.mk +35 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.c +452 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/mdct_neon.h +296 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/meson.build +46 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.c +61 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/plc.h +57 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.c +880 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/sns.h +103 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.c +904 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/spec.h +119 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.c +3457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tables.h +94 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.c +457 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3/tns.h +99 -0
- package/android/lc3Lib/src/main/cpp/liblc3/liblc3.cpp +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/_kiss_fft_guts.h +182 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/arch.h +261 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.c +279 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/celt_lpc.h +59 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/common.h +48 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/compile.sh +3 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/denoise.c +646 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.c +601 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/kiss_fft.h +203 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/opus_types.h +159 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.c +526 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/pitch.h +149 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.c +178 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn.h +69 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.c +11051 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_data.h +34 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_reader.c +168 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/rnn_train.py +66 -0
- package/android/lc3Lib/src/main/cpp/liblc3/rnnoise/tansig_table.h +45 -0
- package/android/lc3Lib/src/main/java/com/glassly/lc3Lib/Lc3Cpp.java +38 -0
- package/android/lc3Lib/third_party/CMakeLists.txt +23 -0
- package/android/lc3Lib/third_party/CMakeLists_libogg.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_libopus.txt +18 -0
- package/android/lc3Lib/third_party/CMakeLists_opus-tools.txt +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/AUTHORS +5 -0
- package/android/lc3Lib/third_party/opus_tools/src/CMakeLists.txt +4 -0
- package/android/lc3Lib/third_party/opus_tools/src/COPYING +371 -0
- package/android/lc3Lib/third_party/opus_tools/src/ChangeLog +3 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.am +42 -0
- package/android/lc3Lib/third_party/opus_tools/src/Makefile.unix +23 -0
- package/android/lc3Lib/third_party/opus_tools/src/NEWS +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/README +0 -0
- package/android/lc3Lib/third_party/opus_tools/src/autogen.sh +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/configure.ac +293 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/arch.h +239 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/audio-in.c +1046 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.c +245 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/diag_range.h +28 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.c +320 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/info_opus.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.c +157 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/lpc.h +27 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.c +286 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opus_header.h +59 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusdec.c +884 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.c +1021 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusenc.h +101 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.c +639 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/opusinfo.h +51 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/os_support.h +167 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/resample.c +1137 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/speex_resampler.h +344 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/stack_alloc.h +115 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.c +125 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wav_io.h +62 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.c +223 -0
- package/android/lc3Lib/third_party/opus_tools/src/src/wave_out.h +60 -0
- package/android/settings.gradle +4 -0
- package/android/silero/LICENSE.md +17 -0
- package/android/silero/build.gradle +50 -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/AndroidManifest.xml +42 -0
- package/android/src/main/assets/G2Firmware/README.md +11 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdk.kt +2325 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkAnalytics.kt +216 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDebug.kt +14 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkDefaults.kt +7 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/BluetoothSdkModule.kt +1088 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/Bridge.kt +953 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/DeviceManager.kt +2528 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/DeviceStore.kt +360 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedChangelogCatalog.kt +8 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/GeneratedReleaseMetadata.kt +11 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/LocalNetworkModule.kt +414 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/ObservableStore.kt +88 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/OtaManifest.kt +191 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/ReleaseChangelog.kt +61 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/ScopedNetworkReadiness.kt +17 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/audio/AudioModels.kt +144 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/camera/CameraModels.kt +486 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/connection/ConnectionModels.kt +78 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/controllers/ControllerManager.kt +158 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/controllers/R1.kt +937 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/debug/BleTraceLogger.kt +165 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/events/BluetoothEvents.kt +178 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/internal/MapParsing.kt +140 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/net/LocalIpv4.kt +57 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServer.kt +304 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/otaserver/OtaServerModule.kt +120 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistry.java +108 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoUploadServer.kt +622 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/photoreceiver/PhotoReceiverModule.kt +156 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/requests/DisplayRequests.kt +56 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/services/Foreground.kt +272 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/services/PhoneMic.kt +1195 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Ar99.java +2653 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuard.kt +49 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapper.kt +27 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1.kt +3878 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizer.kt +38 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2.kt +6428 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassification.kt +49 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwRenderer.kt +1241 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCache.kt +270 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocol.kt +291 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/G2Flasher.kt +411 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/GlasslyBle.java +43189 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Mach1.kt +1280 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLive.kt +10817 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisement.kt +54 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/MentraNex.kt +2011 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Nimo.kt +2532 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/SGCManager.kt +470 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/Simulated.kt +228 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/Ar99OtaManager.java +566 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaByteUtils.java +18 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCommandConstants.java +35 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaCrc32Util.java +13 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaGattTransport.java +11 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/sgcs/ar99/ota/OtaProtocol.java +92 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/speakerid/SpeakerIdEngine.kt +525 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/status/DeviceStatus.kt +669 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/status/RuntimeState.kt +201 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/status/WifiHotspotStatus.kt +189 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/streaming/StreamModels.kt +518 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/stt/STTTools.kt +391 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/stt/SherpaOnnxTranscriber.kt +518 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/stt/VadGateSpeechPolicy.kt +229 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/tts/TTSTools.kt +248 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/types/DeviceModels.kt +96 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/AES.java +106 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/AudioSessionMonitor.kt +189 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/AvifExifStripper.java +573 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BitmapJavaUtils.java +169 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleJsonCompact.java +496 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadService.java +677 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/BleWireProtocol.java +108 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/Constants.kt +46 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/G1Text.kt +436 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/HeifExifTagReader.java +199 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleRelayNaming.java +29 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/IncidentLogBleUploadService.java +77 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900LengthCodec.java +115 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtils.java +827 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunkReassembler.java +228 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/MessageChunker.java +325 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/NexSGCUtils.kt +698 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitor.kt +348 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/SmartGlassesConnectionState.java +9 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Ar99OpusPcmDecoder.java +398 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/ByteUtilAudioPlayer.java +655 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/Lc3Player.java +441 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PCMAudioPlayer.java +431 -0
- package/android/src/main/java/com/glassly/bluetoothsdk/utils/audio/PcmStreamPlayer.kt +328 -0
- package/android/src/main/res/values/strings.xml +4 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/BluetoothSdkExceptionTest.kt +18 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/OtaManifestDowngradeTest.kt +86 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/OtaStartResponsePolicyTest.kt +30 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/ReleaseChangelogTest.kt +13 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/ScopedNetworkReadinessTest.kt +39 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/StreamStatusEventTest.kt +29 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/camera/PhotoRequestTest.kt +141 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/otaserver/LocalOtaServerTest.kt +82 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/photoreceiver/LocalPhotoReceiverRegistryTest.java +75 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/services/ForegroundServiceTypeTest.kt +69 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/Ar99AdvertisementMatcherTest.java +22 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaHeartbeatGuardTest.kt +73 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/BesOtaProgressMapperTest.kt +67 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/EvenRleTest.kt +63 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G1TextSanitizerTest.kt +31 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwClassificationTest.kt +89 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwRendererTest.kt +344 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2CfwTextureCacheTest.kt +200 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/G2FlashProtocolTest.kt +131 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLiveGattCharacteristicsTest.kt +39 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/MentraLivePairingAdvertisementParserTest.kt +133 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/sgcs/NimoProtocolTest.kt +333 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/AvifExifStripperTest.java +46 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/BleJsonCompactTest.java +319 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +107 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
- package/android/src/test/java/com/glassly/bluetoothsdk/utils/PhoneAudioMonitorTest.kt +45 -0
- package/android/src/test/resources/avif_with_exif.avif +0 -0
- package/app.plugin.js +3 -0
- package/build/BluetoothSdk.types.d.ts +1354 -0
- package/build/BluetoothSdk.types.d.ts.map +1 -0
- package/build/BluetoothSdk.types.js +41 -0
- package/build/BluetoothSdk.types.js.map +1 -0
- package/build/_internal.d.ts +17 -0
- package/build/_internal.d.ts.map +1 -0
- package/build/_internal.js +16 -0
- package/build/_internal.js.map +1 -0
- package/build/_private/BluetoothSdkModule.d.ts +172 -0
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -0
- package/build/_private/BluetoothSdkModule.js +300 -0
- package/build/_private/BluetoothSdkModule.js.map +1 -0
- package/build/_private/LocalNetworkModule.d.ts +38 -0
- package/build/_private/LocalNetworkModule.d.ts.map +1 -0
- package/build/_private/LocalNetworkModule.js +3 -0
- package/build/_private/LocalNetworkModule.js.map +1 -0
- package/build/_private/cameraRequestPayload.d.ts +4 -0
- package/build/_private/cameraRequestPayload.d.ts.map +1 -0
- package/build/_private/cameraRequestPayload.js +32 -0
- package/build/_private/cameraRequestPayload.js.map +1 -0
- package/build/_private/photoRequestPayload.d.ts +6 -0
- package/build/_private/photoRequestPayload.d.ts.map +1 -0
- package/build/_private/photoRequestPayload.js +86 -0
- package/build/_private/photoRequestPayload.js.map +1 -0
- package/build/_private/sdkOtaManifest.d.ts +11 -0
- package/build/_private/sdkOtaManifest.d.ts.map +1 -0
- package/build/_private/sdkOtaManifest.js +15 -0
- package/build/_private/sdkOtaManifest.js.map +1 -0
- package/build/changelogs.d.ts +7 -0
- package/build/changelogs.d.ts.map +1 -0
- package/build/changelogs.js +46 -0
- package/build/changelogs.js.map +1 -0
- package/build/debug.d.ts +3 -0
- package/build/debug.d.ts.map +1 -0
- package/build/debug.js +8 -0
- package/build/debug.js.map +1 -0
- package/build/generated/changelogCatalog.d.ts +9 -0
- package/build/generated/changelogCatalog.d.ts.map +1 -0
- package/build/generated/changelogCatalog.js +12 -0
- package/build/generated/changelogCatalog.js.map +1 -0
- package/build/generated/releaseMetadata.d.ts +12 -0
- package/build/generated/releaseMetadata.d.ts.map +1 -0
- package/build/generated/releaseMetadata.js +10 -0
- package/build/generated/releaseMetadata.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +171 -0
- package/build/index.js.map +1 -0
- package/build/ota-server/OtaServer.types.d.ts +14 -0
- package/build/ota-server/OtaServer.types.d.ts.map +1 -0
- package/build/ota-server/OtaServer.types.js +2 -0
- package/build/ota-server/OtaServer.types.js.map +1 -0
- package/build/ota-server/OtaServerModule.d.ts +21 -0
- package/build/ota-server/OtaServerModule.d.ts.map +1 -0
- package/build/ota-server/OtaServerModule.js +3 -0
- package/build/ota-server/OtaServerModule.js.map +1 -0
- package/build/ota-server/OtaServerModule.web.d.ts +10 -0
- package/build/ota-server/OtaServerModule.web.d.ts.map +1 -0
- package/build/ota-server/OtaServerModule.web.js +12 -0
- package/build/ota-server/OtaServerModule.web.js.map +1 -0
- package/build/ota-server/index.d.ts +3 -0
- package/build/ota-server/index.d.ts.map +1 -0
- package/build/ota-server/index.js +3 -0
- package/build/ota-server/index.js.map +1 -0
- package/build/ota-transport/index.d.ts +67 -0
- package/build/ota-transport/index.d.ts.map +1 -0
- package/build/ota-transport/index.js +58 -0
- package/build/ota-transport/index.js.map +1 -0
- package/build/photo-receiver/PhotoReceiver.types.d.ts +18 -0
- package/build/photo-receiver/PhotoReceiver.types.d.ts.map +1 -0
- package/build/photo-receiver/PhotoReceiver.types.js +2 -0
- package/build/photo-receiver/PhotoReceiver.types.js.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.d.ts +10 -0
- package/build/photo-receiver/PhotoReceiverModule.d.ts.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.js +3 -0
- package/build/photo-receiver/PhotoReceiverModule.js.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.web.d.ts +10 -0
- package/build/photo-receiver/PhotoReceiverModule.web.d.ts.map +1 -0
- package/build/photo-receiver/PhotoReceiverModule.web.js +12 -0
- package/build/photo-receiver/PhotoReceiverModule.web.js.map +1 -0
- package/build/photo-receiver/index.d.ts +3 -0
- package/build/photo-receiver/index.d.ts.map +1 -0
- package/build/photo-receiver/index.js +3 -0
- package/build/photo-receiver/index.js.map +1 -0
- package/build/react/index.d.ts +5 -0
- package/build/react/index.d.ts.map +1 -0
- package/build/react/index.js +4 -0
- package/build/react/index.js.map +1 -0
- package/build/react/useBluetooth.d.ts +100 -0
- package/build/react/useBluetooth.d.ts.map +1 -0
- package/build/react/useBluetooth.js +167 -0
- package/build/react/useBluetooth.js.map +1 -0
- package/build/react/useBluetoothEvent.d.ts +6 -0
- package/build/react/useBluetoothEvent.d.ts.map +1 -0
- package/build/react/useBluetoothEvent.js +21 -0
- package/build/react/useBluetoothEvent.js.map +1 -0
- package/build/react/useBluetoothScan.d.ts +22 -0
- package/build/react/useBluetoothScan.d.ts.map +1 -0
- package/build/react/useBluetoothScan.js +135 -0
- package/build/react/useBluetoothScan.js.map +1 -0
- package/build/react/useBluetoothStatus.d.ts +16 -0
- package/build/react/useBluetoothStatus.d.ts.map +1 -0
- package/build/react/useBluetoothStatus.js +137 -0
- package/build/react/useBluetoothStatus.js.map +1 -0
- package/build/react/useGlassesConnection.d.ts +29 -0
- package/build/react/useGlassesConnection.d.ts.map +1 -0
- package/build/react/useGlassesConnection.js +153 -0
- package/build/react/useGlassesConnection.js.map +1 -0
- package/build/types/index.d.ts +3 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/expo-module.config.json +14 -0
- package/ios/BackgroundOtaArtifactDownloader.swift +125 -0
- package/ios/BluetoothSdkModule.swift +1034 -0
- package/ios/GlasslyBluetoothSDK.podspec +106 -0
- package/ios/LocalIPv4.swift +150 -0
- package/ios/LocalOtaServer.swift +309 -0
- package/ios/LocalPhotoUploadServer.swift +754 -0
- package/ios/OtaServerModule.swift +147 -0
- package/ios/Packages/CoreObjC/CoreObjC.xcodeproj/project.pbxproj +213 -0
- package/ios/Packages/CoreObjC/PcmConverter.h +22 -0
- package/ios/Packages/CoreObjC/PcmConverter.m +266 -0
- package/ios/Packages/CoreObjC/attdet.c +92 -0
- package/ios/Packages/CoreObjC/attdet.h +44 -0
- package/ios/Packages/CoreObjC/bits.c +375 -0
- package/ios/Packages/CoreObjC/bits.h +315 -0
- package/ios/Packages/CoreObjC/bwdet.c +129 -0
- package/ios/Packages/CoreObjC/bwdet.h +69 -0
- package/ios/Packages/CoreObjC/common.h +151 -0
- package/ios/Packages/CoreObjC/energy.c +70 -0
- package/ios/Packages/CoreObjC/energy.h +43 -0
- package/ios/Packages/CoreObjC/fastmath.h +158 -0
- package/ios/Packages/CoreObjC/include/PcmConverter.h +22 -0
- package/ios/Packages/CoreObjC/lc3.c +704 -0
- package/ios/Packages/CoreObjC/lc3.h +313 -0
- package/ios/Packages/CoreObjC/lc3_cpp.h +283 -0
- package/ios/Packages/CoreObjC/lc3_private.h +163 -0
- package/ios/Packages/CoreObjC/ltpf.c +905 -0
- package/ios/Packages/CoreObjC/ltpf.h +111 -0
- package/ios/Packages/CoreObjC/ltpf_arm.h +506 -0
- package/ios/Packages/CoreObjC/ltpf_neon.h +281 -0
- package/ios/Packages/CoreObjC/makefile.mk +35 -0
- package/ios/Packages/CoreObjC/mdct.c +469 -0
- package/ios/Packages/CoreObjC/mdct.h +57 -0
- package/ios/Packages/CoreObjC/mdct_neon.h +296 -0
- package/ios/Packages/CoreObjC/meson.build +61 -0
- package/ios/Packages/CoreObjC/plc.c +61 -0
- package/ios/Packages/CoreObjC/plc.h +57 -0
- package/ios/Packages/CoreObjC/rnnoise.h +114 -0
- package/ios/Packages/CoreObjC/sns.c +880 -0
- package/ios/Packages/CoreObjC/sns.h +103 -0
- package/ios/Packages/CoreObjC/spec.c +907 -0
- package/ios/Packages/CoreObjC/spec.h +119 -0
- package/ios/Packages/CoreObjC/tables.c +3457 -0
- package/ios/Packages/CoreObjC/tables.h +94 -0
- package/ios/Packages/CoreObjC/tns.c +457 -0
- package/ios/Packages/CoreObjC/tns.h +99 -0
- package/ios/Packages/SherpaOnnx/Model/joiner.onnx +0 -0
- package/ios/Packages/SherpaOnnx/Model/tokens.txt +502 -0
- package/ios/Packages/SherpaOnnx/SherpaOnnx.swift +2383 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/Info.plist +48 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/c-api.h +4689 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -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 +4689 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/Headers/sherpa-onnx/c-api/cxx-api.h +2036 -0
- package/ios/Packages/SherpaOnnx/sherpa-onnx.xcframework/ios-arm64_x86_64-simulator/libsherpa-onnx.a +0 -0
- package/ios/Packages/libbz2/module.modulemap +5 -0
- package/ios/Packages/libbz2/shim.h +1 -0
- package/ios/PhotoReceiverModule.swift +129 -0
- package/ios/Source/BluetoothSDK.swift +2303 -0
- package/ios/Source/BluetoothSDKDebug.swift +12 -0
- package/ios/Source/BluetoothSdkDefaults.swift +29 -0
- package/ios/Source/Bridge.swift +708 -0
- package/ios/Source/Bridging-Header.h +16 -0
- package/ios/Source/DeviceManager.swift +2109 -0
- package/ios/Source/DeviceStore.swift +336 -0
- package/ios/Source/GeneratedChangelogCatalog.swift +7 -0
- package/ios/Source/GeneratedReleaseMetadata.swift +11 -0
- package/ios/Source/ObservableStore.swift +118 -0
- package/ios/Source/OtaManifest.swift +211 -0
- package/ios/Source/PrivacyInfo.xcprivacy +23 -0
- package/ios/Source/ReleaseChangelog.swift +65 -0
- package/ios/Source/Resources/G2Firmware/README.md +10 -0
- package/ios/Source/audio/AudioModels.swift +178 -0
- package/ios/Source/audio/PcmStreamPlayer.swift +410 -0
- package/ios/Source/camera/CameraModels.swift +866 -0
- package/ios/Source/connection/ScanSession.swift +27 -0
- package/ios/Source/controllers/ControllerManager.swift +184 -0
- package/ios/Source/controllers/R1.swift +829 -0
- package/ios/Source/errors/BluetoothSdkError.swift +19 -0
- package/ios/Source/events/BluetoothEvents.swift +342 -0
- package/ios/Source/internal/BleTraceLogger.swift +192 -0
- package/ios/Source/internal/BluetoothAvailability.swift +78 -0
- package/ios/Source/internal/BluetoothSdkAnalytics.swift +199 -0
- package/ios/Source/internal/ValueParsing.swift +99 -0
- package/ios/Source/requests/DisplayRequests.swift +82 -0
- package/ios/Source/services/PhoneMic.swift +662 -0
- package/ios/Source/sgcs/Ar99.swift +2451 -0
- package/ios/Source/sgcs/Frame.swift +649 -0
- package/ios/Source/sgcs/G1.swift +2554 -0
- package/ios/Source/sgcs/G2.swift +6887 -0
- package/ios/Source/sgcs/G2CfwClassification.swift +43 -0
- package/ios/Source/sgcs/G2CfwRenderer.swift +1279 -0
- package/ios/Source/sgcs/G2CfwTextureCache.swift +233 -0
- package/ios/Source/sgcs/G2FlashProtocol.swift +312 -0
- package/ios/Source/sgcs/G2Flasher.swift +773 -0
- package/ios/Source/sgcs/Mach1.swift +541 -0
- package/ios/Source/sgcs/MentraLive.swift +7011 -0
- package/ios/Source/sgcs/MentraLiveL2capChannel.swift +183 -0
- package/ios/Source/sgcs/MentraLivePairingAdvertisement.swift +64 -0
- package/ios/Source/sgcs/MentraNex.swift +3221 -0
- package/ios/Source/sgcs/Nimo.swift +1886 -0
- package/ios/Source/sgcs/SGCManager.swift +608 -0
- package/ios/Source/sgcs/Simulated.swift +274 -0
- package/ios/Source/sgcs/ar99/ota/Ar99OtaManager.swift +637 -0
- package/ios/Source/sgcs/glassly_ble.pb.swift +4354 -0
- package/ios/Source/speakerid/SpeakerIdEngine.swift +573 -0
- package/ios/Source/status/DeviceStatus.swift +981 -0
- package/ios/Source/status/RuntimeState.swift +359 -0
- package/ios/Source/status/WifiHotspotStatus.swift +345 -0
- package/ios/Source/streaming/StreamModels.swift +693 -0
- package/ios/Source/stt/STTTools.swift +191 -0
- package/ios/Source/stt/SherpaOnnxTranscriber.swift +466 -0
- package/ios/Source/tts/TTSTools.swift +171 -0
- package/ios/Source/types/DeviceModels.swift +177 -0
- package/ios/Source/utils/AudioSessionMonitor.swift +283 -0
- package/ios/Source/utils/BinaryCodec.swift +61 -0
- package/ios/Source/utils/BleJsonCompact.swift +405 -0
- package/ios/Source/utils/BleWireProtocol.swift +92 -0
- package/ios/Source/utils/Constants.swift +78 -0
- package/ios/Source/utils/Enums.swift +95 -0
- package/ios/Source/utils/G1Text.swift +2096 -0
- package/ios/Source/utils/JSCExperiment.swift +241 -0
- package/ios/Source/utils/MemoryMonitor.swift +44 -0
- package/ios/Source/utils/MessageChunkReassembler.swift +190 -0
- package/ios/Source/utils/MessageChunker.swift +294 -0
- package/ios/Source/utils/Models.swift +135 -0
- package/ios/Source/utils/PhoneAudioMonitor.swift +230 -0
- package/ios/Source/utils/TarBz2Extractor.swift +257 -0
- package/ios/Tests/BluetoothSDKTests/G2CfwClassificationTests.swift +78 -0
- package/ios/Tests/BluetoothSDKTests/G2CfwRendererTests.swift +372 -0
- package/ios/Tests/BluetoothSDKTests/G2CfwTextureCacheTests.swift +162 -0
- package/ios/Tests/BluetoothSDKTests/G2FlashProtocolTests.swift +182 -0
- package/ios/Tests/MentraLivePairingAdvertisementTests.swift +160 -0
- package/ios/Tests/ReleaseChangelogTests.swift +13 -0
- package/package.json +129 -0
- package/plugin/build/index.d.ts +10 -0
- package/plugin/build/index.js +12 -0
- package/plugin/build/withAndroid.d.ts +3 -0
- package/plugin/build/withAndroid.js +190 -0
- package/plugin/build/withIos.d.ts +5 -0
- package/plugin/build/withIos.js +108 -0
- package/scripts/inject-ios-sdk-version.mjs +65 -0
- package/scripts/public-ota-api.test.mjs +37 -0
- package/scripts/verify-release-package.mjs +45 -0
- package/scripts/write-release-metadata.mjs +152 -0
- package/scripts/write-release-metadata.test.mjs +37 -0
- package/src/BluetoothSdk.types.ts +1623 -0
- package/src/_internal.ts +16 -0
- package/src/_private/BluetoothSdkModule.ts +684 -0
- package/src/_private/LocalNetworkModule.ts +50 -0
- package/src/_private/cameraRequestPayload.ts +34 -0
- package/src/_private/photoRequestPayload.ts +90 -0
- package/src/_private/sdkOtaManifest.ts +18 -0
- package/src/changelogs.ts +46 -0
- package/src/debug.ts +9 -0
- package/src/generated/changelogCatalog.ts +13 -0
- package/src/generated/releaseMetadata.ts +20 -0
- package/src/index.ts +321 -0
- package/src/ota-server/OtaServer.types.ts +10 -0
- package/src/ota-server/OtaServerModule.ts +23 -0
- package/src/ota-server/OtaServerModule.web.ts +17 -0
- package/src/ota-server/index.ts +2 -0
- package/src/ota-transport/index.ts +116 -0
- package/src/photo-receiver/PhotoReceiver.types.ts +20 -0
- package/src/photo-receiver/PhotoReceiverModule.ts +11 -0
- package/src/photo-receiver/PhotoReceiverModule.web.ts +17 -0
- package/src/photo-receiver/index.ts +2 -0
- package/src/react/index.ts +21 -0
- package/src/react/useBluetooth.ts +309 -0
- package/src/react/useBluetoothEvent.ts +35 -0
- package/src/react/useBluetoothScan.ts +173 -0
- package/src/react/useBluetoothStatus.ts +180 -0
- package/src/react/useGlassesConnection.ts +202 -0
- package/src/types/index.ts +12 -0
|
@@ -0,0 +1,2383 @@
|
|
|
1
|
+
// swift-api-examples/SherpaOnnx.swift
|
|
2
|
+
// Copyright (c) 2023 Xiaomi Corporation
|
|
3
|
+
|
|
4
|
+
import Foundation // For NSString
|
|
5
|
+
|
|
6
|
+
// ⚠️ LOCAL DIVERGENCE FROM UPSTREAM (sherpa-onnx swift-api-examples) ⚠️
|
|
7
|
+
//
|
|
8
|
+
// Do NOT overwrite this block when syncing this file with upstream (see commit
|
|
9
|
+
// 973a4ad180 "Sync SherpaOnnx.swift wrapper with upstream v1.13.2"). Re-applying
|
|
10
|
+
// upstream's `toCPointer` reintroduces a use-after-free that crashes on launch.
|
|
11
|
+
//
|
|
12
|
+
// Upstream implements this as:
|
|
13
|
+
//
|
|
14
|
+
// let cs = (s as NSString).utf8String
|
|
15
|
+
// return UnsafePointer<Int8>(cs)
|
|
16
|
+
//
|
|
17
|
+
// `NSString.utf8String` returns a pointer with "a lifetime shorter than the
|
|
18
|
+
// string" — it is valid only until the surrounding autorelease pool drains. The
|
|
19
|
+
// config builders below (`sherpaOnnxOnlineModelConfig` et al.) bridge a Swift
|
|
20
|
+
// `String` to a temporary `NSString` that is autoreleased the moment the builder
|
|
21
|
+
// returns, so every `const char*` in the resulting config struct dangles before
|
|
22
|
+
// `SherpaOnnxCreate*` ever dereferences it. That surfaced as an EXC_BAD_ACCESS in
|
|
23
|
+
// `SherpaOnnxCreateOnlineRecognizer` (Sentry REACT-NATIVE-G).
|
|
24
|
+
//
|
|
25
|
+
// Instead we hand C a `strdup` copy that we own outright. sherpa-onnx copies
|
|
26
|
+
// every string into a C++ `std::string` during construction, so the copies only
|
|
27
|
+
// need to outlive the `SherpaOnnxCreate*` call. Ownership is tracked by
|
|
28
|
+
// `SherpaOnnxCStringScope` below; call sites that build a config and immediately
|
|
29
|
+
// construct an object should wrap both in `withSherpaOnnxCStrings { ... }` so the
|
|
30
|
+
// copies are freed once construction returns.
|
|
31
|
+
//
|
|
32
|
+
// Copies made outside any scope are intentionally leaked rather than freed early:
|
|
33
|
+
// a small one-time leak is strictly preferable to handing C a freed pointer.
|
|
34
|
+
|
|
35
|
+
/// Tracks `strdup` allocations made by `toCPointer` so they can be freed once the
|
|
36
|
+
/// C object that copied them has been constructed.
|
|
37
|
+
private enum SherpaOnnxCStringScope {
|
|
38
|
+
/// Allocation stack, keyed by thread so concurrent model loads cannot free
|
|
39
|
+
/// each other's strings. Nested scopes push additional frames.
|
|
40
|
+
private static let threadLocalKey = "com.glassly.sherpaonnx.cstrings"
|
|
41
|
+
|
|
42
|
+
private static var stack: [[UnsafeMutablePointer<Int8>]] {
|
|
43
|
+
get { Thread.current.threadDictionary[threadLocalKey] as? [[UnsafeMutablePointer<Int8>]] ?? [] }
|
|
44
|
+
set { Thread.current.threadDictionary[threadLocalKey] = newValue }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static func track(_ pointer: UnsafeMutablePointer<Int8>) {
|
|
48
|
+
var frames = stack
|
|
49
|
+
guard !frames.isEmpty else { return } // no active scope: intentionally leak
|
|
50
|
+
frames[frames.count - 1].append(pointer)
|
|
51
|
+
stack = frames
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static func withScope<T>(_ body: () throws -> T) rethrows -> T {
|
|
55
|
+
stack.append([])
|
|
56
|
+
defer {
|
|
57
|
+
var frames = stack
|
|
58
|
+
let allocations = frames.popLast() ?? []
|
|
59
|
+
stack = frames
|
|
60
|
+
for pointer in allocations {
|
|
61
|
+
free(pointer)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return try body()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// Run `body` with a scope that owns every C string produced by `toCPointer`
|
|
69
|
+
/// inside it, freeing them all when `body` returns.
|
|
70
|
+
///
|
|
71
|
+
/// Wrap config construction *and* the matching `SherpaOnnxCreate*` call together:
|
|
72
|
+
///
|
|
73
|
+
/// let recognizer = withSherpaOnnxCStrings {
|
|
74
|
+
/// var config = sherpaOnnxOnlineRecognizerConfig(...)
|
|
75
|
+
/// return SherpaOnnxRecognizer(config: &config)
|
|
76
|
+
/// }
|
|
77
|
+
///
|
|
78
|
+
/// Do not let a config struct escape the scope — its pointers die with it.
|
|
79
|
+
func withSherpaOnnxCStrings<T>(_ body: () throws -> T) rethrows -> T {
|
|
80
|
+
return try SherpaOnnxCStringScope.withScope(body)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Convert a String from swift to a `const char*` so that we can pass it to
|
|
84
|
+
// the C language.
|
|
85
|
+
//
|
|
86
|
+
// The returned pointer is owned by the innermost enclosing
|
|
87
|
+
// `withSherpaOnnxCStrings` scope and is freed when that scope exits. Outside any
|
|
88
|
+
// scope the allocation is leaked, which keeps the pointer valid indefinitely.
|
|
89
|
+
//
|
|
90
|
+
// - Parameters:
|
|
91
|
+
// - s: The String to convert.
|
|
92
|
+
// - Returns: A pointer that can be passed to C as `const char*`
|
|
93
|
+
|
|
94
|
+
func toCPointer(_ s: String) -> UnsafePointer<Int8>! {
|
|
95
|
+
guard let copy = strdup(s) else { return nil }
|
|
96
|
+
SherpaOnnxCStringScope.track(copy)
|
|
97
|
+
return UnsafePointer<Int8>(copy)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Return an instance of SherpaOnnxOnlineTransducerModelConfig.
|
|
101
|
+
///
|
|
102
|
+
/// Please refer to
|
|
103
|
+
/// https://k2-fsa.github.io/sherpa/onnx/pretrained_models/online-transducer/index.html
|
|
104
|
+
/// to download the required `.onnx` files.
|
|
105
|
+
///
|
|
106
|
+
/// - Parameters:
|
|
107
|
+
/// - encoder: Path to encoder.onnx
|
|
108
|
+
/// - decoder: Path to decoder.onnx
|
|
109
|
+
/// - joiner: Path to joiner.onnx
|
|
110
|
+
///
|
|
111
|
+
/// - Returns: Return an instance of SherpaOnnxOnlineTransducerModelConfig
|
|
112
|
+
func sherpaOnnxOnlineTransducerModelConfig(
|
|
113
|
+
encoder: String = "",
|
|
114
|
+
decoder: String = "",
|
|
115
|
+
joiner: String = ""
|
|
116
|
+
) -> SherpaOnnxOnlineTransducerModelConfig {
|
|
117
|
+
return SherpaOnnxOnlineTransducerModelConfig(
|
|
118
|
+
encoder: toCPointer(encoder),
|
|
119
|
+
decoder: toCPointer(decoder),
|
|
120
|
+
joiner: toCPointer(joiner)
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// Return an instance of SherpaOnnxOnlineParaformerModelConfig.
|
|
125
|
+
///
|
|
126
|
+
/// Please refer to
|
|
127
|
+
/// https://k2-fsa.github.io/sherpa/onnx/pretrained_models/online-paraformer/index.html
|
|
128
|
+
/// to download the required `.onnx` files.
|
|
129
|
+
///
|
|
130
|
+
/// - Parameters:
|
|
131
|
+
/// - encoder: Path to encoder.onnx
|
|
132
|
+
/// - decoder: Path to decoder.onnx
|
|
133
|
+
///
|
|
134
|
+
/// - Returns: Return an instance of SherpaOnnxOnlineParaformerModelConfig
|
|
135
|
+
func sherpaOnnxOnlineParaformerModelConfig(
|
|
136
|
+
encoder: String = "",
|
|
137
|
+
decoder: String = ""
|
|
138
|
+
) -> SherpaOnnxOnlineParaformerModelConfig {
|
|
139
|
+
return SherpaOnnxOnlineParaformerModelConfig(
|
|
140
|
+
encoder: toCPointer(encoder),
|
|
141
|
+
decoder: toCPointer(decoder)
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func sherpaOnnxOnlineZipformer2CtcModelConfig(
|
|
146
|
+
model: String = ""
|
|
147
|
+
) -> SherpaOnnxOnlineZipformer2CtcModelConfig {
|
|
148
|
+
return SherpaOnnxOnlineZipformer2CtcModelConfig(
|
|
149
|
+
model: toCPointer(model)
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
func sherpaOnnxOnlineNemoCtcModelConfig(
|
|
154
|
+
model: String = ""
|
|
155
|
+
) -> SherpaOnnxOnlineNemoCtcModelConfig {
|
|
156
|
+
return SherpaOnnxOnlineNemoCtcModelConfig(
|
|
157
|
+
model: toCPointer(model)
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
func sherpaOnnxOnlineToneCtcModelConfig(
|
|
162
|
+
model: String = ""
|
|
163
|
+
) -> SherpaOnnxOnlineToneCtcModelConfig {
|
|
164
|
+
return SherpaOnnxOnlineToneCtcModelConfig(
|
|
165
|
+
model: toCPointer(model)
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/// Return an instance of SherpaOnnxOnlineModelConfig.
|
|
170
|
+
///
|
|
171
|
+
/// Please refer to
|
|
172
|
+
/// https://k2-fsa.github.io/sherpa/onnx/pretrained_models/index.html
|
|
173
|
+
/// to download the required `.onnx` files.
|
|
174
|
+
///
|
|
175
|
+
/// - Parameters:
|
|
176
|
+
/// - tokens: Path to tokens.txt
|
|
177
|
+
/// - numThreads: Number of threads to use for neural network computation.
|
|
178
|
+
///
|
|
179
|
+
/// - Returns: Return an instance of SherpaOnnxOnlineTransducerModelConfig
|
|
180
|
+
func sherpaOnnxOnlineModelConfig(
|
|
181
|
+
tokens: String,
|
|
182
|
+
transducer: SherpaOnnxOnlineTransducerModelConfig = sherpaOnnxOnlineTransducerModelConfig(),
|
|
183
|
+
paraformer: SherpaOnnxOnlineParaformerModelConfig = sherpaOnnxOnlineParaformerModelConfig(),
|
|
184
|
+
zipformer2Ctc: SherpaOnnxOnlineZipformer2CtcModelConfig =
|
|
185
|
+
sherpaOnnxOnlineZipformer2CtcModelConfig(),
|
|
186
|
+
numThreads: Int = 1,
|
|
187
|
+
provider: String = "cpu",
|
|
188
|
+
debug: Int = 0,
|
|
189
|
+
modelType: String = "",
|
|
190
|
+
modelingUnit: String = "cjkchar",
|
|
191
|
+
bpeVocab: String = "",
|
|
192
|
+
tokensBuf: String = "",
|
|
193
|
+
tokensBufSize: Int = 0,
|
|
194
|
+
nemoCtc: SherpaOnnxOnlineNemoCtcModelConfig = sherpaOnnxOnlineNemoCtcModelConfig(),
|
|
195
|
+
toneCtc: SherpaOnnxOnlineToneCtcModelConfig = sherpaOnnxOnlineToneCtcModelConfig()
|
|
196
|
+
) -> SherpaOnnxOnlineModelConfig {
|
|
197
|
+
return SherpaOnnxOnlineModelConfig(
|
|
198
|
+
transducer: transducer,
|
|
199
|
+
paraformer: paraformer,
|
|
200
|
+
zipformer2_ctc: zipformer2Ctc,
|
|
201
|
+
tokens: toCPointer(tokens),
|
|
202
|
+
num_threads: Int32(numThreads),
|
|
203
|
+
provider: toCPointer(provider),
|
|
204
|
+
debug: Int32(debug),
|
|
205
|
+
model_type: toCPointer(modelType),
|
|
206
|
+
modeling_unit: toCPointer(modelingUnit),
|
|
207
|
+
bpe_vocab: toCPointer(bpeVocab),
|
|
208
|
+
tokens_buf: toCPointer(tokensBuf),
|
|
209
|
+
tokens_buf_size: Int32(tokensBufSize),
|
|
210
|
+
nemo_ctc: nemoCtc,
|
|
211
|
+
t_one_ctc: toneCtc
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
func sherpaOnnxFeatureConfig(
|
|
216
|
+
sampleRate: Int = 16000,
|
|
217
|
+
featureDim: Int = 80
|
|
218
|
+
) -> SherpaOnnxFeatureConfig {
|
|
219
|
+
return SherpaOnnxFeatureConfig(
|
|
220
|
+
sample_rate: Int32(sampleRate),
|
|
221
|
+
feature_dim: Int32(featureDim)
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
func sherpaOnnxOnlineCtcFstDecoderConfig(
|
|
226
|
+
graph: String = "",
|
|
227
|
+
maxActive: Int = 3000
|
|
228
|
+
) -> SherpaOnnxOnlineCtcFstDecoderConfig {
|
|
229
|
+
return SherpaOnnxOnlineCtcFstDecoderConfig(
|
|
230
|
+
graph: toCPointer(graph),
|
|
231
|
+
max_active: Int32(maxActive)
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func sherpaOnnxHomophoneReplacerConfig(
|
|
236
|
+
dictDir: String = "",
|
|
237
|
+
lexicon: String = "",
|
|
238
|
+
ruleFsts: String = ""
|
|
239
|
+
) -> SherpaOnnxHomophoneReplacerConfig {
|
|
240
|
+
return SherpaOnnxHomophoneReplacerConfig(
|
|
241
|
+
dict_dir: toCPointer(dictDir),
|
|
242
|
+
lexicon: toCPointer(lexicon),
|
|
243
|
+
rule_fsts: toCPointer(ruleFsts)
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
func sherpaOnnxOnlineRecognizerConfig(
|
|
248
|
+
featConfig: SherpaOnnxFeatureConfig,
|
|
249
|
+
modelConfig: SherpaOnnxOnlineModelConfig,
|
|
250
|
+
enableEndpoint: Bool = false,
|
|
251
|
+
rule1MinTrailingSilence: Float = 2.4,
|
|
252
|
+
rule2MinTrailingSilence: Float = 1.2,
|
|
253
|
+
rule3MinUtteranceLength: Float = 30,
|
|
254
|
+
decodingMethod: String = "greedy_search",
|
|
255
|
+
maxActivePaths: Int = 4,
|
|
256
|
+
hotwordsFile: String = "",
|
|
257
|
+
hotwordsScore: Float = 1.5,
|
|
258
|
+
ctcFstDecoderConfig: SherpaOnnxOnlineCtcFstDecoderConfig = sherpaOnnxOnlineCtcFstDecoderConfig(),
|
|
259
|
+
ruleFsts: String = "",
|
|
260
|
+
ruleFars: String = "",
|
|
261
|
+
blankPenalty: Float = 0.0,
|
|
262
|
+
hotwordsBuf: String = "",
|
|
263
|
+
hotwordsBufSize: Int = 0,
|
|
264
|
+
hr: SherpaOnnxHomophoneReplacerConfig = sherpaOnnxHomophoneReplacerConfig()
|
|
265
|
+
) -> SherpaOnnxOnlineRecognizerConfig {
|
|
266
|
+
return SherpaOnnxOnlineRecognizerConfig(
|
|
267
|
+
feat_config: featConfig,
|
|
268
|
+
model_config: modelConfig,
|
|
269
|
+
decoding_method: toCPointer(decodingMethod),
|
|
270
|
+
max_active_paths: Int32(maxActivePaths),
|
|
271
|
+
enable_endpoint: enableEndpoint ? 1 : 0,
|
|
272
|
+
rule1_min_trailing_silence: rule1MinTrailingSilence,
|
|
273
|
+
rule2_min_trailing_silence: rule2MinTrailingSilence,
|
|
274
|
+
rule3_min_utterance_length: rule3MinUtteranceLength,
|
|
275
|
+
hotwords_file: toCPointer(hotwordsFile),
|
|
276
|
+
hotwords_score: hotwordsScore,
|
|
277
|
+
ctc_fst_decoder_config: ctcFstDecoderConfig,
|
|
278
|
+
rule_fsts: toCPointer(ruleFsts),
|
|
279
|
+
rule_fars: toCPointer(ruleFars),
|
|
280
|
+
blank_penalty: blankPenalty,
|
|
281
|
+
hotwords_buf: toCPointer(hotwordsBuf),
|
|
282
|
+
hotwords_buf_size: Int32(hotwordsBufSize),
|
|
283
|
+
hr: hr
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// Wrapper for recognition result.
|
|
288
|
+
///
|
|
289
|
+
/// Usage:
|
|
290
|
+
///
|
|
291
|
+
/// let result = recognizer.getResult()
|
|
292
|
+
/// print("text: \(result.text)")
|
|
293
|
+
///
|
|
294
|
+
class SherpaOnnxOnlineRecongitionResult {
|
|
295
|
+
/// A pointer to the underlying counterpart in C
|
|
296
|
+
private let result: UnsafePointer<SherpaOnnxOnlineRecognizerResult>
|
|
297
|
+
|
|
298
|
+
private lazy var _text: String = {
|
|
299
|
+
guard let cstr = result.pointee.text else { return "" }
|
|
300
|
+
return String(cString: cstr)
|
|
301
|
+
}()
|
|
302
|
+
|
|
303
|
+
private lazy var _tokens: [String] = {
|
|
304
|
+
guard let tokensPointer = result.pointee.tokens_arr else { return [] }
|
|
305
|
+
return (0 ..< count).compactMap { index in
|
|
306
|
+
guard let ptr = tokensPointer[index] else { return nil }
|
|
307
|
+
return String(cString: ptr)
|
|
308
|
+
}
|
|
309
|
+
}()
|
|
310
|
+
|
|
311
|
+
private lazy var _timestamps: [Float] = {
|
|
312
|
+
guard let timestampsPointer = result.pointee.timestamps else { return [] }
|
|
313
|
+
return (0 ..< count).map { index in timestampsPointer[index] }
|
|
314
|
+
}()
|
|
315
|
+
|
|
316
|
+
init(result: UnsafePointer<SherpaOnnxOnlineRecognizerResult>) {
|
|
317
|
+
self.result = result
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
deinit {
|
|
321
|
+
SherpaOnnxDestroyOnlineRecognizerResult(result)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/// Return the actual recognition result.
|
|
325
|
+
/// For English models, it contains words separated by spaces.
|
|
326
|
+
/// For Chinese models, it contains Chinese words.
|
|
327
|
+
var text: String {
|
|
328
|
+
_text
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
var count: Int {
|
|
332
|
+
Int(result.pointee.count)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
var tokens: [String] {
|
|
336
|
+
_tokens
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
var timestamps: [Float] {
|
|
340
|
+
_timestamps
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
class SherpaOnnxRecognizer {
|
|
345
|
+
/// A pointer to the underlying counterpart in C
|
|
346
|
+
private let recognizer: OpaquePointer
|
|
347
|
+
private var stream: OpaquePointer
|
|
348
|
+
private let lock = NSLock() // for thread-safe stream replacement
|
|
349
|
+
|
|
350
|
+
/// Constructor taking a model config
|
|
351
|
+
init(
|
|
352
|
+
config: UnsafePointer<SherpaOnnxOnlineRecognizerConfig>
|
|
353
|
+
) {
|
|
354
|
+
recognizer = SherpaOnnxCreateOnlineRecognizer(config)
|
|
355
|
+
stream = SherpaOnnxCreateOnlineStream(recognizer)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
deinit {
|
|
359
|
+
SherpaOnnxDestroyOnlineStream(stream)
|
|
360
|
+
SherpaOnnxDestroyOnlineRecognizer(recognizer)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/// Decode wave samples.
|
|
364
|
+
///
|
|
365
|
+
/// - Parameters:
|
|
366
|
+
/// - samples: Audio samples normalized to the range [-1, 1]
|
|
367
|
+
/// - sampleRate: Sample rate of the input audio samples. Must match
|
|
368
|
+
/// the one expected by the model.
|
|
369
|
+
func acceptWaveform(samples: [Float], sampleRate: Int = 16000) {
|
|
370
|
+
SherpaOnnxOnlineStreamAcceptWaveform(stream, Int32(sampleRate), samples, Int32(samples.count))
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
func isReady() -> Bool {
|
|
374
|
+
return SherpaOnnxIsOnlineStreamReady(recognizer, stream) != 0
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/// If there are enough number of feature frames, it invokes the neural
|
|
378
|
+
/// network computation and decoding. Otherwise, it is a no-op.
|
|
379
|
+
func decode() {
|
|
380
|
+
SherpaOnnxDecodeOnlineStream(recognizer, stream)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/// Get the decoding results so far
|
|
384
|
+
func getResult() -> SherpaOnnxOnlineRecongitionResult {
|
|
385
|
+
guard let result = SherpaOnnxGetOnlineStreamResult(recognizer, stream) else {
|
|
386
|
+
fatalError("SherpaOnnxGetOnlineStreamResult returned nil")
|
|
387
|
+
}
|
|
388
|
+
return SherpaOnnxOnlineRecongitionResult(result: result)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/// Reset the recognizer, which clears the neural network model state
|
|
392
|
+
/// and the state for decoding.
|
|
393
|
+
/// If hotwords is an empty string, it just recreates the decoding stream
|
|
394
|
+
/// If hotwords is not empty, it will create a new decoding stream with
|
|
395
|
+
/// the given hotWords appended to the default hotwords.
|
|
396
|
+
func reset(hotwords: String? = nil) {
|
|
397
|
+
guard let words = hotwords, !words.isEmpty else {
|
|
398
|
+
SherpaOnnxOnlineStreamReset(recognizer, stream)
|
|
399
|
+
return
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
words.withCString { cString in
|
|
403
|
+
guard let newStream = SherpaOnnxCreateOnlineStreamWithHotwords(recognizer, cString) else {
|
|
404
|
+
fatalError("SherpaOnnxCreateOnlineStreamWithHotwords returned nil")
|
|
405
|
+
}
|
|
406
|
+
lock.lock()
|
|
407
|
+
// lock while release and replace stream
|
|
408
|
+
SherpaOnnxDestroyOnlineStream(stream)
|
|
409
|
+
stream = newStream
|
|
410
|
+
lock.unlock()
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/// Signal that no more audio samples would be available.
|
|
415
|
+
/// After this call, you cannot call acceptWaveform() any more.
|
|
416
|
+
func inputFinished() {
|
|
417
|
+
SherpaOnnxOnlineStreamInputFinished(stream)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/// Return true is an endpoint has been detected.
|
|
421
|
+
func isEndpoint() -> Bool {
|
|
422
|
+
return SherpaOnnxOnlineStreamIsEndpoint(recognizer, stream) != 0
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// For offline APIs
|
|
427
|
+
|
|
428
|
+
func sherpaOnnxOfflineTransducerModelConfig(
|
|
429
|
+
encoder: String = "",
|
|
430
|
+
decoder: String = "",
|
|
431
|
+
joiner: String = ""
|
|
432
|
+
) -> SherpaOnnxOfflineTransducerModelConfig {
|
|
433
|
+
return SherpaOnnxOfflineTransducerModelConfig(
|
|
434
|
+
encoder: toCPointer(encoder),
|
|
435
|
+
decoder: toCPointer(decoder),
|
|
436
|
+
joiner: toCPointer(joiner)
|
|
437
|
+
)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
func sherpaOnnxOfflineParaformerModelConfig(
|
|
441
|
+
model: String = ""
|
|
442
|
+
) -> SherpaOnnxOfflineParaformerModelConfig {
|
|
443
|
+
return SherpaOnnxOfflineParaformerModelConfig(
|
|
444
|
+
model: toCPointer(model)
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
func sherpaOnnxOfflineZipformerCtcModelConfig(
|
|
449
|
+
model: String = ""
|
|
450
|
+
) -> SherpaOnnxOfflineZipformerCtcModelConfig {
|
|
451
|
+
return SherpaOnnxOfflineZipformerCtcModelConfig(
|
|
452
|
+
model: toCPointer(model)
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
func sherpaOnnxOfflineWenetCtcModelConfig(
|
|
457
|
+
model: String = ""
|
|
458
|
+
) -> SherpaOnnxOfflineWenetCtcModelConfig {
|
|
459
|
+
return SherpaOnnxOfflineWenetCtcModelConfig(
|
|
460
|
+
model: toCPointer(model)
|
|
461
|
+
)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
func sherpaOnnxOfflineOmnilingualAsrCtcModelConfig(
|
|
465
|
+
model: String = ""
|
|
466
|
+
) -> SherpaOnnxOfflineOmnilingualAsrCtcModelConfig {
|
|
467
|
+
return SherpaOnnxOfflineOmnilingualAsrCtcModelConfig(
|
|
468
|
+
model: toCPointer(model)
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
func sherpaOnnxOfflineMedAsrCtcModelConfig(
|
|
473
|
+
model: String = ""
|
|
474
|
+
) -> SherpaOnnxOfflineMedAsrCtcModelConfig {
|
|
475
|
+
return SherpaOnnxOfflineMedAsrCtcModelConfig(
|
|
476
|
+
model: toCPointer(model)
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
func sherpaOnnxOfflineFireRedAsrCtcModelConfig(
|
|
481
|
+
model: String = ""
|
|
482
|
+
) -> SherpaOnnxOfflineFireRedAsrCtcModelConfig {
|
|
483
|
+
return SherpaOnnxOfflineFireRedAsrCtcModelConfig(
|
|
484
|
+
model: toCPointer(model)
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
func sherpaOnnxOfflineNemoEncDecCtcModelConfig(
|
|
489
|
+
model: String = ""
|
|
490
|
+
) -> SherpaOnnxOfflineNemoEncDecCtcModelConfig {
|
|
491
|
+
return SherpaOnnxOfflineNemoEncDecCtcModelConfig(
|
|
492
|
+
model: toCPointer(model)
|
|
493
|
+
)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
func sherpaOnnxOfflineDolphinModelConfig(
|
|
497
|
+
model: String = ""
|
|
498
|
+
) -> SherpaOnnxOfflineDolphinModelConfig {
|
|
499
|
+
return SherpaOnnxOfflineDolphinModelConfig(
|
|
500
|
+
model: toCPointer(model)
|
|
501
|
+
)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
func sherpaOnnxOfflineWhisperModelConfig(
|
|
505
|
+
encoder: String = "",
|
|
506
|
+
decoder: String = "",
|
|
507
|
+
language: String = "",
|
|
508
|
+
task: String = "transcribe",
|
|
509
|
+
tailPaddings: Int = -1,
|
|
510
|
+
enableTokenTimestamps: Bool = false,
|
|
511
|
+
enableSegmentTimestamps: Bool = false
|
|
512
|
+
) -> SherpaOnnxOfflineWhisperModelConfig {
|
|
513
|
+
return SherpaOnnxOfflineWhisperModelConfig(
|
|
514
|
+
encoder: toCPointer(encoder),
|
|
515
|
+
decoder: toCPointer(decoder),
|
|
516
|
+
language: toCPointer(language),
|
|
517
|
+
task: toCPointer(task),
|
|
518
|
+
tail_paddings: Int32(tailPaddings),
|
|
519
|
+
enable_token_timestamps: enableTokenTimestamps ? 1 : 0,
|
|
520
|
+
enable_segment_timestamps: enableSegmentTimestamps ? 1 : 0
|
|
521
|
+
)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
func sherpaOnnxOfflineCanaryModelConfig(
|
|
525
|
+
encoder: String = "",
|
|
526
|
+
decoder: String = "",
|
|
527
|
+
srcLang: String = "en",
|
|
528
|
+
tgtLang: String = "en",
|
|
529
|
+
usePnc: Bool = true
|
|
530
|
+
) -> SherpaOnnxOfflineCanaryModelConfig {
|
|
531
|
+
return SherpaOnnxOfflineCanaryModelConfig(
|
|
532
|
+
encoder: toCPointer(encoder),
|
|
533
|
+
decoder: toCPointer(decoder),
|
|
534
|
+
src_lang: toCPointer(srcLang),
|
|
535
|
+
tgt_lang: toCPointer(tgtLang),
|
|
536
|
+
use_pnc: usePnc ? 1 : 0
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
func sherpaOnnxOfflineCohereTranscribeModelConfig(
|
|
541
|
+
encoder: String = "",
|
|
542
|
+
decoder: String = "",
|
|
543
|
+
language: String = "",
|
|
544
|
+
usePunct: Bool = true,
|
|
545
|
+
useInverseTextNormalization: Bool = true
|
|
546
|
+
) -> SherpaOnnxOfflineCohereTranscribeModelConfig {
|
|
547
|
+
return SherpaOnnxOfflineCohereTranscribeModelConfig(
|
|
548
|
+
encoder: toCPointer(encoder),
|
|
549
|
+
decoder: toCPointer(decoder),
|
|
550
|
+
language: toCPointer(language),
|
|
551
|
+
use_punct: usePunct ? 1 : 0,
|
|
552
|
+
use_itn: useInverseTextNormalization ? 1 : 0
|
|
553
|
+
)
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
func sherpaOnnxOfflineFireRedAsrModelConfig(
|
|
557
|
+
encoder: String = "",
|
|
558
|
+
decoder: String = ""
|
|
559
|
+
) -> SherpaOnnxOfflineFireRedAsrModelConfig {
|
|
560
|
+
return SherpaOnnxOfflineFireRedAsrModelConfig(
|
|
561
|
+
encoder: toCPointer(encoder),
|
|
562
|
+
decoder: toCPointer(decoder)
|
|
563
|
+
)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/// there are two versions of Moonshine
|
|
567
|
+
/// For v1, you need four models: preprocessor, encoder, uncachedDecoder, cachedDecoder
|
|
568
|
+
/// For v2, you need two models: encoder, mergedDecoder
|
|
569
|
+
func sherpaOnnxOfflineMoonshineModelConfig(
|
|
570
|
+
preprocessor: String = "",
|
|
571
|
+
encoder: String = "",
|
|
572
|
+
uncachedDecoder: String = "",
|
|
573
|
+
cachedDecoder: String = "",
|
|
574
|
+
mergedDecoder: String = ""
|
|
575
|
+
) -> SherpaOnnxOfflineMoonshineModelConfig {
|
|
576
|
+
return SherpaOnnxOfflineMoonshineModelConfig(
|
|
577
|
+
preprocessor: toCPointer(preprocessor),
|
|
578
|
+
encoder: toCPointer(encoder),
|
|
579
|
+
uncached_decoder: toCPointer(uncachedDecoder),
|
|
580
|
+
cached_decoder: toCPointer(cachedDecoder),
|
|
581
|
+
merged_decoder: toCPointer(mergedDecoder)
|
|
582
|
+
)
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
func sherpaOnnxOfflineQwen3ASRModelConfig(
|
|
586
|
+
convFrontend: String = "",
|
|
587
|
+
encoder: String = "",
|
|
588
|
+
decoder: String = "",
|
|
589
|
+
tokenizer: String = "",
|
|
590
|
+
maxTotalLen: Int = 512,
|
|
591
|
+
maxNewTokens: Int = 128,
|
|
592
|
+
temperature: Float = 1e-6,
|
|
593
|
+
topP: Float = 0.8,
|
|
594
|
+
seed: Int = 42,
|
|
595
|
+
hotwords: String = ""
|
|
596
|
+
) -> SherpaOnnxOfflineQwen3ASRModelConfig {
|
|
597
|
+
return SherpaOnnxOfflineQwen3ASRModelConfig(
|
|
598
|
+
conv_frontend: toCPointer(convFrontend),
|
|
599
|
+
encoder: toCPointer(encoder),
|
|
600
|
+
decoder: toCPointer(decoder),
|
|
601
|
+
tokenizer: toCPointer(tokenizer),
|
|
602
|
+
max_total_len: Int32(maxTotalLen),
|
|
603
|
+
max_new_tokens: Int32(maxNewTokens),
|
|
604
|
+
temperature: temperature,
|
|
605
|
+
top_p: topP,
|
|
606
|
+
seed: Int32(seed),
|
|
607
|
+
hotwords: toCPointer(hotwords)
|
|
608
|
+
)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
func sherpaOnnxOfflineTdnnModelConfig(
|
|
612
|
+
model: String = ""
|
|
613
|
+
) -> SherpaOnnxOfflineTdnnModelConfig {
|
|
614
|
+
return SherpaOnnxOfflineTdnnModelConfig(
|
|
615
|
+
model: toCPointer(model)
|
|
616
|
+
)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
func sherpaOnnxOfflineSenseVoiceModelConfig(
|
|
620
|
+
model: String = "",
|
|
621
|
+
language: String = "",
|
|
622
|
+
useInverseTextNormalization: Bool = false
|
|
623
|
+
) -> SherpaOnnxOfflineSenseVoiceModelConfig {
|
|
624
|
+
return SherpaOnnxOfflineSenseVoiceModelConfig(
|
|
625
|
+
model: toCPointer(model),
|
|
626
|
+
language: toCPointer(language),
|
|
627
|
+
use_itn: useInverseTextNormalization ? 1 : 0
|
|
628
|
+
)
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
func sherpaOnnxOfflineLMConfig(
|
|
632
|
+
model: String = "",
|
|
633
|
+
scale: Float = 1.0
|
|
634
|
+
) -> SherpaOnnxOfflineLMConfig {
|
|
635
|
+
return SherpaOnnxOfflineLMConfig(
|
|
636
|
+
model: toCPointer(model),
|
|
637
|
+
scale: scale
|
|
638
|
+
)
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
func sherpaOnnxOfflineFunASRNanoModelConfig(
|
|
642
|
+
encoderAdaptor: String = "",
|
|
643
|
+
llm: String = "",
|
|
644
|
+
embedding: String = "",
|
|
645
|
+
tokenizer: String = "",
|
|
646
|
+
systemPrompt: String = "You are a helpful assistant.",
|
|
647
|
+
userPrompt: String = "语音转写:",
|
|
648
|
+
maxNewTokens: Int = 512,
|
|
649
|
+
temperature: Float = 1e-6,
|
|
650
|
+
topP: Float = 0.8,
|
|
651
|
+
seed: Int = 42,
|
|
652
|
+
language: String = "",
|
|
653
|
+
itn: Bool = true,
|
|
654
|
+
hotwords: String = ""
|
|
655
|
+
) -> SherpaOnnxOfflineFunASRNanoModelConfig {
|
|
656
|
+
return SherpaOnnxOfflineFunASRNanoModelConfig(
|
|
657
|
+
encoder_adaptor: toCPointer(encoderAdaptor),
|
|
658
|
+
llm: toCPointer(llm),
|
|
659
|
+
embedding: toCPointer(embedding),
|
|
660
|
+
tokenizer: toCPointer(tokenizer),
|
|
661
|
+
system_prompt: toCPointer(systemPrompt),
|
|
662
|
+
user_prompt: toCPointer(userPrompt),
|
|
663
|
+
max_new_tokens: Int32(maxNewTokens),
|
|
664
|
+
temperature: temperature,
|
|
665
|
+
top_p: topP,
|
|
666
|
+
seed: Int32(seed),
|
|
667
|
+
language: toCPointer(language),
|
|
668
|
+
itn: itn ? 1 : 0,
|
|
669
|
+
hotwords: toCPointer(hotwords)
|
|
670
|
+
)
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
func sherpaOnnxOfflineModelConfig(
|
|
674
|
+
tokens: String,
|
|
675
|
+
transducer: SherpaOnnxOfflineTransducerModelConfig = sherpaOnnxOfflineTransducerModelConfig(),
|
|
676
|
+
paraformer: SherpaOnnxOfflineParaformerModelConfig = sherpaOnnxOfflineParaformerModelConfig(),
|
|
677
|
+
nemoCtc: SherpaOnnxOfflineNemoEncDecCtcModelConfig = sherpaOnnxOfflineNemoEncDecCtcModelConfig(),
|
|
678
|
+
whisper: SherpaOnnxOfflineWhisperModelConfig = sherpaOnnxOfflineWhisperModelConfig(),
|
|
679
|
+
tdnn: SherpaOnnxOfflineTdnnModelConfig = sherpaOnnxOfflineTdnnModelConfig(),
|
|
680
|
+
numThreads: Int = 1,
|
|
681
|
+
provider: String = "cpu",
|
|
682
|
+
debug: Int = 0,
|
|
683
|
+
modelType: String = "",
|
|
684
|
+
modelingUnit: String = "cjkchar",
|
|
685
|
+
bpeVocab: String = "",
|
|
686
|
+
teleSpeechCtc: String = "",
|
|
687
|
+
senseVoice: SherpaOnnxOfflineSenseVoiceModelConfig = sherpaOnnxOfflineSenseVoiceModelConfig(),
|
|
688
|
+
moonshine: SherpaOnnxOfflineMoonshineModelConfig = sherpaOnnxOfflineMoonshineModelConfig(),
|
|
689
|
+
fireRedAsr: SherpaOnnxOfflineFireRedAsrModelConfig = sherpaOnnxOfflineFireRedAsrModelConfig(),
|
|
690
|
+
dolphin: SherpaOnnxOfflineDolphinModelConfig = sherpaOnnxOfflineDolphinModelConfig(),
|
|
691
|
+
zipformerCtc: SherpaOnnxOfflineZipformerCtcModelConfig =
|
|
692
|
+
sherpaOnnxOfflineZipformerCtcModelConfig(),
|
|
693
|
+
canary: SherpaOnnxOfflineCanaryModelConfig = sherpaOnnxOfflineCanaryModelConfig(),
|
|
694
|
+
wenetCtc: SherpaOnnxOfflineWenetCtcModelConfig =
|
|
695
|
+
sherpaOnnxOfflineWenetCtcModelConfig(),
|
|
696
|
+
omnilingual: SherpaOnnxOfflineOmnilingualAsrCtcModelConfig =
|
|
697
|
+
sherpaOnnxOfflineOmnilingualAsrCtcModelConfig(),
|
|
698
|
+
medasr: SherpaOnnxOfflineMedAsrCtcModelConfig =
|
|
699
|
+
sherpaOnnxOfflineMedAsrCtcModelConfig(),
|
|
700
|
+
funasrNano: SherpaOnnxOfflineFunASRNanoModelConfig =
|
|
701
|
+
sherpaOnnxOfflineFunASRNanoModelConfig(),
|
|
702
|
+
fireRedAsrCtc: SherpaOnnxOfflineFireRedAsrCtcModelConfig =
|
|
703
|
+
sherpaOnnxOfflineFireRedAsrCtcModelConfig(),
|
|
704
|
+
qwen3Asr: SherpaOnnxOfflineQwen3ASRModelConfig =
|
|
705
|
+
sherpaOnnxOfflineQwen3ASRModelConfig(),
|
|
706
|
+
cohereTranscribe: SherpaOnnxOfflineCohereTranscribeModelConfig =
|
|
707
|
+
sherpaOnnxOfflineCohereTranscribeModelConfig()
|
|
708
|
+
) -> SherpaOnnxOfflineModelConfig {
|
|
709
|
+
return SherpaOnnxOfflineModelConfig(
|
|
710
|
+
transducer: transducer,
|
|
711
|
+
paraformer: paraformer,
|
|
712
|
+
nemo_ctc: nemoCtc,
|
|
713
|
+
whisper: whisper,
|
|
714
|
+
tdnn: tdnn,
|
|
715
|
+
tokens: toCPointer(tokens),
|
|
716
|
+
num_threads: Int32(numThreads),
|
|
717
|
+
debug: Int32(debug),
|
|
718
|
+
provider: toCPointer(provider),
|
|
719
|
+
model_type: toCPointer(modelType),
|
|
720
|
+
modeling_unit: toCPointer(modelingUnit),
|
|
721
|
+
bpe_vocab: toCPointer(bpeVocab),
|
|
722
|
+
telespeech_ctc: toCPointer(teleSpeechCtc),
|
|
723
|
+
sense_voice: senseVoice,
|
|
724
|
+
moonshine: moonshine,
|
|
725
|
+
fire_red_asr: fireRedAsr,
|
|
726
|
+
dolphin: dolphin,
|
|
727
|
+
zipformer_ctc: zipformerCtc,
|
|
728
|
+
canary: canary,
|
|
729
|
+
wenet_ctc: wenetCtc,
|
|
730
|
+
omnilingual: omnilingual,
|
|
731
|
+
medasr: medasr,
|
|
732
|
+
funasr_nano: funasrNano,
|
|
733
|
+
fire_red_asr_ctc: fireRedAsrCtc,
|
|
734
|
+
qwen3_asr: qwen3Asr,
|
|
735
|
+
cohere_transcribe: cohereTranscribe
|
|
736
|
+
)
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
func sherpaOnnxOfflineRecognizerConfig(
|
|
740
|
+
featConfig: SherpaOnnxFeatureConfig,
|
|
741
|
+
modelConfig: SherpaOnnxOfflineModelConfig,
|
|
742
|
+
lmConfig: SherpaOnnxOfflineLMConfig = sherpaOnnxOfflineLMConfig(),
|
|
743
|
+
decodingMethod: String = "greedy_search",
|
|
744
|
+
maxActivePaths: Int = 4,
|
|
745
|
+
hotwordsFile: String = "",
|
|
746
|
+
hotwordsScore: Float = 1.5,
|
|
747
|
+
ruleFsts: String = "",
|
|
748
|
+
ruleFars: String = "",
|
|
749
|
+
blankPenalty: Float = 0.0,
|
|
750
|
+
hr: SherpaOnnxHomophoneReplacerConfig = sherpaOnnxHomophoneReplacerConfig()
|
|
751
|
+
) -> SherpaOnnxOfflineRecognizerConfig {
|
|
752
|
+
return SherpaOnnxOfflineRecognizerConfig(
|
|
753
|
+
feat_config: featConfig,
|
|
754
|
+
model_config: modelConfig,
|
|
755
|
+
lm_config: lmConfig,
|
|
756
|
+
decoding_method: toCPointer(decodingMethod),
|
|
757
|
+
max_active_paths: Int32(maxActivePaths),
|
|
758
|
+
hotwords_file: toCPointer(hotwordsFile),
|
|
759
|
+
hotwords_score: hotwordsScore,
|
|
760
|
+
rule_fsts: toCPointer(ruleFsts),
|
|
761
|
+
rule_fars: toCPointer(ruleFars),
|
|
762
|
+
blank_penalty: blankPenalty,
|
|
763
|
+
hr: hr
|
|
764
|
+
)
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
class SherpaOnnxOfflineRecongitionResult {
|
|
768
|
+
/// A pointer to the underlying counterpart in C
|
|
769
|
+
let result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>
|
|
770
|
+
|
|
771
|
+
private lazy var _text: String = {
|
|
772
|
+
guard let cstr = result.pointee.text else { return "" }
|
|
773
|
+
return String(cString: cstr)
|
|
774
|
+
}()
|
|
775
|
+
|
|
776
|
+
private lazy var _timestamps: [Float] = {
|
|
777
|
+
guard let p = result.pointee.timestamps else { return [] }
|
|
778
|
+
return (0 ..< result.pointee.count).map { p[Int($0)] }
|
|
779
|
+
}()
|
|
780
|
+
|
|
781
|
+
private lazy var _durations: [Float] = {
|
|
782
|
+
guard let p = result.pointee.durations else { return [] }
|
|
783
|
+
return (0 ..< result.pointee.count).map { p[Int($0)] }
|
|
784
|
+
}()
|
|
785
|
+
|
|
786
|
+
private lazy var _lang: String = {
|
|
787
|
+
guard let cstr = result.pointee.lang else { return "" }
|
|
788
|
+
return String(cString: cstr)
|
|
789
|
+
}()
|
|
790
|
+
|
|
791
|
+
private lazy var _emotion: String = {
|
|
792
|
+
guard let cstr = result.pointee.emotion else { return "" }
|
|
793
|
+
return String(cString: cstr)
|
|
794
|
+
}()
|
|
795
|
+
|
|
796
|
+
private lazy var _event: String = {
|
|
797
|
+
guard let cstr = result.pointee.event else { return "" }
|
|
798
|
+
return String(cString: cstr)
|
|
799
|
+
}()
|
|
800
|
+
|
|
801
|
+
private lazy var _segmentTimestamps: [Float] = {
|
|
802
|
+
guard let p = result.pointee.segment_timestamps else { return [] }
|
|
803
|
+
return (0 ..< result.pointee.segment_count).map { p[Int($0)] }
|
|
804
|
+
}()
|
|
805
|
+
|
|
806
|
+
private lazy var _segmentDurations: [Float] = {
|
|
807
|
+
guard let p = result.pointee.segment_durations else { return [] }
|
|
808
|
+
return (0 ..< result.pointee.segment_count).map { p[Int($0)] }
|
|
809
|
+
}()
|
|
810
|
+
|
|
811
|
+
private lazy var _segmentTexts: [String] = {
|
|
812
|
+
guard let arr = result.pointee.segment_texts_arr else { return [] }
|
|
813
|
+
return (0 ..< result.pointee.segment_count).compactMap { idx -> String? in
|
|
814
|
+
guard let ptr = arr[Int(idx)] else { return nil }
|
|
815
|
+
return String(cString: ptr)
|
|
816
|
+
}
|
|
817
|
+
}()
|
|
818
|
+
|
|
819
|
+
/// Return the actual recognition result.
|
|
820
|
+
/// For English models, it contains words separated by spaces.
|
|
821
|
+
/// For Chinese models, it contains Chinese words.
|
|
822
|
+
var text: String {
|
|
823
|
+
_text
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
var count: Int {
|
|
827
|
+
Int(result.pointee.count)
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
var timestamps: [Float] {
|
|
831
|
+
_timestamps
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/// Non-empty for TDT models. Empty for all other non-TDT models
|
|
835
|
+
var durations: [Float] {
|
|
836
|
+
_durations
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/// For SenseVoice models, it can be zh, en, ja, yue, ko
|
|
840
|
+
/// where zh is for Chinese
|
|
841
|
+
/// en is for English
|
|
842
|
+
/// ja is for Japanese
|
|
843
|
+
/// yue is for Cantonese
|
|
844
|
+
/// ko is for Korean
|
|
845
|
+
var lang: String {
|
|
846
|
+
_lang
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/// for SenseVoice models
|
|
850
|
+
var emotion: String {
|
|
851
|
+
_emotion
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/// for SenseVoice models
|
|
855
|
+
var event: String {
|
|
856
|
+
_event
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/// Segment-level timestamps (for Whisper with segment timestamps enabled)
|
|
860
|
+
var segmentCount: Int {
|
|
861
|
+
Int(result.pointee.segment_count)
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
var segmentTimestamps: [Float] {
|
|
865
|
+
_segmentTimestamps
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
var segmentDurations: [Float] {
|
|
869
|
+
_segmentDurations
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
var segmentTexts: [String] {
|
|
873
|
+
_segmentTexts
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
init(result: UnsafePointer<SherpaOnnxOfflineRecognizerResult>) {
|
|
877
|
+
self.result = result
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
deinit {
|
|
881
|
+
SherpaOnnxDestroyOfflineRecognizerResult(result)
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
class SherpaOnnxOfflineRecognizer {
|
|
886
|
+
/// A pointer to the underlying counterpart in C
|
|
887
|
+
private let recognizer: OpaquePointer
|
|
888
|
+
|
|
889
|
+
init(
|
|
890
|
+
config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig>
|
|
891
|
+
) {
|
|
892
|
+
guard let ptr = SherpaOnnxCreateOfflineRecognizer(config) else {
|
|
893
|
+
fatalError("Failed to create SherpaOnnxOfflineRecognizer")
|
|
894
|
+
}
|
|
895
|
+
recognizer = ptr
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
deinit {
|
|
899
|
+
SherpaOnnxDestroyOfflineRecognizer(recognizer)
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/// Decode wave samples.
|
|
903
|
+
///
|
|
904
|
+
/// - Parameters:
|
|
905
|
+
/// - samples: Audio samples normalized to the range [-1, 1]
|
|
906
|
+
/// - sampleRate: Sample rate of the input audio samples. Must match
|
|
907
|
+
/// the one expected by the model.
|
|
908
|
+
func decode(samples: [Float], sampleRate: Int = 16000) -> SherpaOnnxOfflineRecongitionResult {
|
|
909
|
+
let stream = createStream()
|
|
910
|
+
stream.acceptWaveform(samples: samples, sampleRate: sampleRate)
|
|
911
|
+
decode(stream: stream)
|
|
912
|
+
return getResult(stream: stream)
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
func setConfig(config: UnsafePointer<SherpaOnnxOfflineRecognizerConfig>) {
|
|
916
|
+
SherpaOnnxOfflineRecognizerSetConfig(recognizer, config)
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
func createStream() -> SherpaOnnxOfflineStreamWrapper {
|
|
920
|
+
guard let stream = SherpaOnnxCreateOfflineStream(recognizer) else {
|
|
921
|
+
fatalError("Failed to create offline stream")
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return SherpaOnnxOfflineStreamWrapper(stream: stream)
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
func decode(stream: SherpaOnnxOfflineStreamWrapper) {
|
|
928
|
+
SherpaOnnxDecodeOfflineStream(recognizer, stream.stream)
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
func getResult(stream: SherpaOnnxOfflineStreamWrapper) -> SherpaOnnxOfflineRecongitionResult {
|
|
932
|
+
guard let resultPtr = SherpaOnnxGetOfflineStreamResult(stream.stream) else {
|
|
933
|
+
fatalError("Failed to get offline recognition result")
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return SherpaOnnxOfflineRecongitionResult(result: resultPtr)
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
class SherpaOnnxOfflineStreamWrapper {
|
|
941
|
+
let stream: OpaquePointer
|
|
942
|
+
|
|
943
|
+
init(stream: OpaquePointer) {
|
|
944
|
+
self.stream = stream
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
deinit {
|
|
948
|
+
SherpaOnnxDestroyOfflineStream(stream)
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
func setOption(key: String, value: String) {
|
|
952
|
+
SherpaOnnxOfflineStreamSetOption(stream, toCPointer(key), toCPointer(value))
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
func acceptWaveform(samples: [Float], sampleRate: Int = 16000) {
|
|
956
|
+
SherpaOnnxAcceptWaveformOffline(stream, Int32(sampleRate), samples, Int32(samples.count))
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
func sherpaOnnxSileroVadModelConfig(
|
|
961
|
+
model: String = "",
|
|
962
|
+
threshold: Float = 0.5,
|
|
963
|
+
minSilenceDuration: Float = 0.25,
|
|
964
|
+
minSpeechDuration: Float = 0.5,
|
|
965
|
+
windowSize: Int = 512,
|
|
966
|
+
maxSpeechDuration: Float = 5.0
|
|
967
|
+
) -> SherpaOnnxSileroVadModelConfig {
|
|
968
|
+
return SherpaOnnxSileroVadModelConfig(
|
|
969
|
+
model: toCPointer(model),
|
|
970
|
+
threshold: threshold,
|
|
971
|
+
min_silence_duration: minSilenceDuration,
|
|
972
|
+
min_speech_duration: minSpeechDuration,
|
|
973
|
+
window_size: Int32(windowSize),
|
|
974
|
+
max_speech_duration: maxSpeechDuration
|
|
975
|
+
)
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
func sherpaOnnxTenVadModelConfig(
|
|
979
|
+
model: String = "",
|
|
980
|
+
threshold: Float = 0.5,
|
|
981
|
+
minSilenceDuration: Float = 0.25,
|
|
982
|
+
minSpeechDuration: Float = 0.5,
|
|
983
|
+
windowSize: Int = 256,
|
|
984
|
+
maxSpeechDuration: Float = 5.0
|
|
985
|
+
) -> SherpaOnnxTenVadModelConfig {
|
|
986
|
+
return SherpaOnnxTenVadModelConfig(
|
|
987
|
+
model: toCPointer(model),
|
|
988
|
+
threshold: threshold,
|
|
989
|
+
min_silence_duration: minSilenceDuration,
|
|
990
|
+
min_speech_duration: minSpeechDuration,
|
|
991
|
+
window_size: Int32(windowSize),
|
|
992
|
+
max_speech_duration: maxSpeechDuration
|
|
993
|
+
)
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
func sherpaOnnxVadModelConfig(
|
|
997
|
+
sileroVad: SherpaOnnxSileroVadModelConfig = sherpaOnnxSileroVadModelConfig(),
|
|
998
|
+
sampleRate: Int32 = 16000,
|
|
999
|
+
numThreads: Int = 1,
|
|
1000
|
+
provider: String = "cpu",
|
|
1001
|
+
debug: Int = 0,
|
|
1002
|
+
tenVad: SherpaOnnxTenVadModelConfig = sherpaOnnxTenVadModelConfig()
|
|
1003
|
+
) -> SherpaOnnxVadModelConfig {
|
|
1004
|
+
return SherpaOnnxVadModelConfig(
|
|
1005
|
+
silero_vad: sileroVad,
|
|
1006
|
+
sample_rate: sampleRate,
|
|
1007
|
+
num_threads: Int32(numThreads),
|
|
1008
|
+
provider: toCPointer(provider),
|
|
1009
|
+
debug: Int32(debug),
|
|
1010
|
+
ten_vad: tenVad
|
|
1011
|
+
)
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
class SherpaOnnxCircularBufferWrapper {
|
|
1015
|
+
private let buffer: OpaquePointer
|
|
1016
|
+
|
|
1017
|
+
init(capacity: Int) {
|
|
1018
|
+
guard let ptr = SherpaOnnxCreateCircularBuffer(Int32(capacity)) else {
|
|
1019
|
+
fatalError("Failed to create SherpaOnnxCircularBuffer")
|
|
1020
|
+
}
|
|
1021
|
+
buffer = ptr
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
deinit {
|
|
1025
|
+
SherpaOnnxDestroyCircularBuffer(buffer)
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
func push(samples: [Float]) {
|
|
1029
|
+
guard !samples.isEmpty else { return }
|
|
1030
|
+
SherpaOnnxCircularBufferPush(buffer, samples, Int32(samples.count))
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
func get(startIndex: Int, n: Int) -> [Float] {
|
|
1034
|
+
guard startIndex >= 0 else { return [] }
|
|
1035
|
+
guard n > 0 else { return [] }
|
|
1036
|
+
|
|
1037
|
+
guard let ptr = SherpaOnnxCircularBufferGet(buffer, Int32(startIndex), Int32(n)) else {
|
|
1038
|
+
return []
|
|
1039
|
+
}
|
|
1040
|
+
defer { SherpaOnnxCircularBufferFree(ptr) }
|
|
1041
|
+
|
|
1042
|
+
return Array(UnsafeBufferPointer(start: ptr, count: n))
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
func pop(n: Int) {
|
|
1046
|
+
guard n > 0 else { return }
|
|
1047
|
+
SherpaOnnxCircularBufferPop(buffer, Int32(n))
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
func size() -> Int {
|
|
1051
|
+
return Int(SherpaOnnxCircularBufferSize(buffer))
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
func reset() {
|
|
1055
|
+
SherpaOnnxCircularBufferReset(buffer)
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
class SherpaOnnxSpeechSegmentWrapper {
|
|
1060
|
+
private let p: UnsafePointer<SherpaOnnxSpeechSegment>
|
|
1061
|
+
|
|
1062
|
+
init(p: UnsafePointer<SherpaOnnxSpeechSegment>) {
|
|
1063
|
+
self.p = p
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
deinit {
|
|
1067
|
+
SherpaOnnxDestroySpeechSegment(p)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
var start: Int {
|
|
1071
|
+
Int(p.pointee.start)
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
var n: Int {
|
|
1075
|
+
Int(p.pointee.n)
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
lazy var samples: [Float] = Array(UnsafeBufferPointer(start: p.pointee.samples, count: n))
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
class SherpaOnnxVoiceActivityDetectorWrapper {
|
|
1082
|
+
/// A pointer to the underlying counterpart in C
|
|
1083
|
+
private let vad: OpaquePointer
|
|
1084
|
+
|
|
1085
|
+
init(config: UnsafePointer<SherpaOnnxVadModelConfig>, buffer_size_in_seconds: Float) {
|
|
1086
|
+
guard let vad = SherpaOnnxCreateVoiceActivityDetector(config, buffer_size_in_seconds) else {
|
|
1087
|
+
fatalError("SherpaOnnxCreateVoiceActivityDetector returned nil")
|
|
1088
|
+
}
|
|
1089
|
+
self.vad = vad
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
deinit {
|
|
1093
|
+
SherpaOnnxDestroyVoiceActivityDetector(vad)
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
func acceptWaveform(samples: [Float]) {
|
|
1097
|
+
SherpaOnnxVoiceActivityDetectorAcceptWaveform(vad, samples, Int32(samples.count))
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
func isEmpty() -> Bool {
|
|
1101
|
+
return SherpaOnnxVoiceActivityDetectorEmpty(vad) == 1
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
func isSpeechDetected() -> Bool {
|
|
1105
|
+
return SherpaOnnxVoiceActivityDetectorDetected(vad) == 1
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
func pop() {
|
|
1109
|
+
SherpaOnnxVoiceActivityDetectorPop(vad)
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
func clear() {
|
|
1113
|
+
SherpaOnnxVoiceActivityDetectorClear(vad)
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
func front() -> SherpaOnnxSpeechSegmentWrapper {
|
|
1117
|
+
guard let p = SherpaOnnxVoiceActivityDetectorFront(vad) else {
|
|
1118
|
+
fatalError("SherpaOnnxVoiceActivityDetectorFront returned nil")
|
|
1119
|
+
}
|
|
1120
|
+
return SherpaOnnxSpeechSegmentWrapper(p: p)
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
func reset() {
|
|
1124
|
+
SherpaOnnxVoiceActivityDetectorReset(vad)
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
func flush() {
|
|
1128
|
+
SherpaOnnxVoiceActivityDetectorFlush(vad)
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/// offline tts
|
|
1133
|
+
func sherpaOnnxOfflineTtsVitsModelConfig(
|
|
1134
|
+
model: String = "",
|
|
1135
|
+
lexicon: String = "",
|
|
1136
|
+
tokens: String = "",
|
|
1137
|
+
dataDir: String = "",
|
|
1138
|
+
noiseScale: Float = 0.667,
|
|
1139
|
+
noiseScaleW: Float = 0.8,
|
|
1140
|
+
lengthScale: Float = 1.0,
|
|
1141
|
+
dictDir: String = ""
|
|
1142
|
+
) -> SherpaOnnxOfflineTtsVitsModelConfig {
|
|
1143
|
+
return SherpaOnnxOfflineTtsVitsModelConfig(
|
|
1144
|
+
model: toCPointer(model),
|
|
1145
|
+
lexicon: toCPointer(lexicon),
|
|
1146
|
+
tokens: toCPointer(tokens),
|
|
1147
|
+
data_dir: toCPointer(dataDir),
|
|
1148
|
+
noise_scale: noiseScale,
|
|
1149
|
+
noise_scale_w: noiseScaleW,
|
|
1150
|
+
length_scale: lengthScale,
|
|
1151
|
+
dict_dir: toCPointer(dictDir)
|
|
1152
|
+
)
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
func sherpaOnnxOfflineTtsMatchaModelConfig(
|
|
1156
|
+
acousticModel: String = "",
|
|
1157
|
+
vocoder: String = "",
|
|
1158
|
+
lexicon: String = "",
|
|
1159
|
+
tokens: String = "",
|
|
1160
|
+
dataDir: String = "",
|
|
1161
|
+
noiseScale: Float = 0.667,
|
|
1162
|
+
lengthScale: Float = 1.0,
|
|
1163
|
+
dictDir: String = ""
|
|
1164
|
+
) -> SherpaOnnxOfflineTtsMatchaModelConfig {
|
|
1165
|
+
return SherpaOnnxOfflineTtsMatchaModelConfig(
|
|
1166
|
+
acoustic_model: toCPointer(acousticModel),
|
|
1167
|
+
vocoder: toCPointer(vocoder),
|
|
1168
|
+
lexicon: toCPointer(lexicon),
|
|
1169
|
+
tokens: toCPointer(tokens),
|
|
1170
|
+
data_dir: toCPointer(dataDir),
|
|
1171
|
+
noise_scale: noiseScale,
|
|
1172
|
+
length_scale: lengthScale,
|
|
1173
|
+
dict_dir: toCPointer(dictDir)
|
|
1174
|
+
)
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
func sherpaOnnxOfflineTtsKokoroModelConfig(
|
|
1178
|
+
model: String = "",
|
|
1179
|
+
voices: String = "",
|
|
1180
|
+
tokens: String = "",
|
|
1181
|
+
dataDir: String = "",
|
|
1182
|
+
lengthScale: Float = 1.0,
|
|
1183
|
+
dictDir: String = "",
|
|
1184
|
+
lexicon: String = "",
|
|
1185
|
+
lang: String = ""
|
|
1186
|
+
) -> SherpaOnnxOfflineTtsKokoroModelConfig {
|
|
1187
|
+
return SherpaOnnxOfflineTtsKokoroModelConfig(
|
|
1188
|
+
model: toCPointer(model),
|
|
1189
|
+
voices: toCPointer(voices),
|
|
1190
|
+
tokens: toCPointer(tokens),
|
|
1191
|
+
data_dir: toCPointer(dataDir),
|
|
1192
|
+
length_scale: lengthScale,
|
|
1193
|
+
dict_dir: toCPointer(dictDir),
|
|
1194
|
+
lexicon: toCPointer(lexicon),
|
|
1195
|
+
lang: toCPointer(lang)
|
|
1196
|
+
)
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
func sherpaOnnxOfflineTtsKittenModelConfig(
|
|
1200
|
+
model: String = "",
|
|
1201
|
+
voices: String = "",
|
|
1202
|
+
tokens: String = "",
|
|
1203
|
+
dataDir: String = "",
|
|
1204
|
+
lengthScale: Float = 1.0
|
|
1205
|
+
) -> SherpaOnnxOfflineTtsKittenModelConfig {
|
|
1206
|
+
return SherpaOnnxOfflineTtsKittenModelConfig(
|
|
1207
|
+
model: toCPointer(model),
|
|
1208
|
+
voices: toCPointer(voices),
|
|
1209
|
+
tokens: toCPointer(tokens),
|
|
1210
|
+
data_dir: toCPointer(dataDir),
|
|
1211
|
+
length_scale: lengthScale
|
|
1212
|
+
)
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
func sherpaOnnxOfflineTtsZipvoiceModelConfig(
|
|
1216
|
+
tokens: String = "",
|
|
1217
|
+
encoder: String = "",
|
|
1218
|
+
decoder: String = "",
|
|
1219
|
+
vocoder: String = "",
|
|
1220
|
+
dataDir: String = "",
|
|
1221
|
+
lexicon: String = "",
|
|
1222
|
+
featScale: Float = 0.1,
|
|
1223
|
+
tShift: Float = 0.5,
|
|
1224
|
+
targetRms: Float = 0.1,
|
|
1225
|
+
guidanceScale: Float = 1.0
|
|
1226
|
+
) -> SherpaOnnxOfflineTtsZipvoiceModelConfig {
|
|
1227
|
+
return SherpaOnnxOfflineTtsZipvoiceModelConfig(
|
|
1228
|
+
tokens: toCPointer(tokens),
|
|
1229
|
+
encoder: toCPointer(encoder),
|
|
1230
|
+
decoder: toCPointer(decoder),
|
|
1231
|
+
vocoder: toCPointer(vocoder),
|
|
1232
|
+
data_dir: toCPointer(dataDir),
|
|
1233
|
+
lexicon: toCPointer(lexicon),
|
|
1234
|
+
feat_scale: featScale,
|
|
1235
|
+
t_shift: tShift,
|
|
1236
|
+
target_rms: targetRms,
|
|
1237
|
+
guidance_scale: guidanceScale
|
|
1238
|
+
)
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
func sherpaOnnxOfflineTtsPocketModelConfig(
|
|
1242
|
+
lmFlow: String = "",
|
|
1243
|
+
lmMain: String = "",
|
|
1244
|
+
encoder: String = "",
|
|
1245
|
+
decoder: String = "",
|
|
1246
|
+
textConditioner: String = "",
|
|
1247
|
+
vocabJson: String = "",
|
|
1248
|
+
tokenScoresJson: String = "",
|
|
1249
|
+
voiceEmbeddingCacheCapacity: Int = 50
|
|
1250
|
+
) -> SherpaOnnxOfflineTtsPocketModelConfig {
|
|
1251
|
+
return SherpaOnnxOfflineTtsPocketModelConfig(
|
|
1252
|
+
lm_flow: toCPointer(lmFlow),
|
|
1253
|
+
lm_main: toCPointer(lmMain),
|
|
1254
|
+
encoder: toCPointer(encoder),
|
|
1255
|
+
decoder: toCPointer(decoder),
|
|
1256
|
+
text_conditioner: toCPointer(textConditioner),
|
|
1257
|
+
vocab_json: toCPointer(vocabJson),
|
|
1258
|
+
token_scores_json: toCPointer(tokenScoresJson),
|
|
1259
|
+
voice_embedding_cache_capacity: Int32(voiceEmbeddingCacheCapacity)
|
|
1260
|
+
)
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
func sherpaOnnxOfflineTtsSupertonicModelConfig(
|
|
1264
|
+
durationPredictor: String = "",
|
|
1265
|
+
textEncoder: String = "",
|
|
1266
|
+
vectorEstimator: String = "",
|
|
1267
|
+
vocoder: String = "",
|
|
1268
|
+
ttsJson: String = "",
|
|
1269
|
+
unicodeIndexer: String = "",
|
|
1270
|
+
voiceStyle: String = ""
|
|
1271
|
+
) -> SherpaOnnxOfflineTtsSupertonicModelConfig {
|
|
1272
|
+
return SherpaOnnxOfflineTtsSupertonicModelConfig(
|
|
1273
|
+
duration_predictor: toCPointer(durationPredictor),
|
|
1274
|
+
text_encoder: toCPointer(textEncoder),
|
|
1275
|
+
vector_estimator: toCPointer(vectorEstimator),
|
|
1276
|
+
vocoder: toCPointer(vocoder),
|
|
1277
|
+
tts_json: toCPointer(ttsJson),
|
|
1278
|
+
unicode_indexer: toCPointer(unicodeIndexer),
|
|
1279
|
+
voice_style: toCPointer(voiceStyle)
|
|
1280
|
+
)
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
func sherpaOnnxOfflineTtsModelConfig(
|
|
1284
|
+
vits: SherpaOnnxOfflineTtsVitsModelConfig = sherpaOnnxOfflineTtsVitsModelConfig(),
|
|
1285
|
+
matcha: SherpaOnnxOfflineTtsMatchaModelConfig = sherpaOnnxOfflineTtsMatchaModelConfig(),
|
|
1286
|
+
kokoro: SherpaOnnxOfflineTtsKokoroModelConfig = sherpaOnnxOfflineTtsKokoroModelConfig(),
|
|
1287
|
+
numThreads: Int = 1,
|
|
1288
|
+
debug: Int = 0,
|
|
1289
|
+
provider: String = "cpu",
|
|
1290
|
+
kitten: SherpaOnnxOfflineTtsKittenModelConfig = sherpaOnnxOfflineTtsKittenModelConfig(),
|
|
1291
|
+
zipvoice: SherpaOnnxOfflineTtsZipvoiceModelConfig = sherpaOnnxOfflineTtsZipvoiceModelConfig(),
|
|
1292
|
+
pocket: SherpaOnnxOfflineTtsPocketModelConfig = sherpaOnnxOfflineTtsPocketModelConfig(),
|
|
1293
|
+
supertonic: SherpaOnnxOfflineTtsSupertonicModelConfig =
|
|
1294
|
+
sherpaOnnxOfflineTtsSupertonicModelConfig()
|
|
1295
|
+
) -> SherpaOnnxOfflineTtsModelConfig {
|
|
1296
|
+
return SherpaOnnxOfflineTtsModelConfig(
|
|
1297
|
+
vits: vits,
|
|
1298
|
+
num_threads: Int32(numThreads),
|
|
1299
|
+
debug: Int32(debug),
|
|
1300
|
+
provider: toCPointer(provider),
|
|
1301
|
+
matcha: matcha,
|
|
1302
|
+
kokoro: kokoro,
|
|
1303
|
+
kitten: kitten,
|
|
1304
|
+
zipvoice: zipvoice,
|
|
1305
|
+
pocket: pocket,
|
|
1306
|
+
supertonic: supertonic
|
|
1307
|
+
)
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
func sherpaOnnxOfflineTtsConfig(
|
|
1311
|
+
model: SherpaOnnxOfflineTtsModelConfig,
|
|
1312
|
+
ruleFsts: String = "",
|
|
1313
|
+
ruleFars: String = "",
|
|
1314
|
+
maxNumSentences: Int = 1,
|
|
1315
|
+
silenceScale: Float = 0.2
|
|
1316
|
+
) -> SherpaOnnxOfflineTtsConfig {
|
|
1317
|
+
return SherpaOnnxOfflineTtsConfig(
|
|
1318
|
+
model: model,
|
|
1319
|
+
rule_fsts: toCPointer(ruleFsts),
|
|
1320
|
+
max_num_sentences: Int32(maxNumSentences),
|
|
1321
|
+
rule_fars: toCPointer(ruleFars),
|
|
1322
|
+
silence_scale: silenceScale
|
|
1323
|
+
)
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
class SherpaOnnxWaveWrapper {
|
|
1327
|
+
let wave: UnsafePointer<SherpaOnnxWave>!
|
|
1328
|
+
|
|
1329
|
+
class func readWave(filename: String) -> SherpaOnnxWaveWrapper {
|
|
1330
|
+
let wave = SherpaOnnxReadWave(toCPointer(filename))
|
|
1331
|
+
return SherpaOnnxWaveWrapper(wave: wave)
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
init(wave: UnsafePointer<SherpaOnnxWave>!) {
|
|
1335
|
+
self.wave = wave
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
deinit {
|
|
1339
|
+
if let wave {
|
|
1340
|
+
SherpaOnnxFreeWave(wave)
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
var numSamples: Int {
|
|
1345
|
+
return Int(wave.pointee.num_samples)
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
var sampleRate: Int {
|
|
1349
|
+
return Int(wave.pointee.sample_rate)
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
var samples: [Float] {
|
|
1353
|
+
if numSamples == 0 {
|
|
1354
|
+
return []
|
|
1355
|
+
} else {
|
|
1356
|
+
return [Float](UnsafeBufferPointer(start: wave.pointee.samples, count: numSamples))
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
class SherpaOnnxGeneratedAudioWrapper {
|
|
1362
|
+
/// A pointer to the underlying counterpart in C
|
|
1363
|
+
let audio: UnsafePointer<SherpaOnnxGeneratedAudio>!
|
|
1364
|
+
|
|
1365
|
+
init(audio: UnsafePointer<SherpaOnnxGeneratedAudio>!) {
|
|
1366
|
+
self.audio = audio
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
deinit {
|
|
1370
|
+
if let audio {
|
|
1371
|
+
SherpaOnnxDestroyOfflineTtsGeneratedAudio(audio)
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
var n: Int32 {
|
|
1376
|
+
return audio.pointee.n
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
var sampleRate: Int32 {
|
|
1380
|
+
return audio.pointee.sample_rate
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
var samples: [Float] {
|
|
1384
|
+
if let p = audio.pointee.samples {
|
|
1385
|
+
return [Float](UnsafeBufferPointer(start: p, count: Int(n)))
|
|
1386
|
+
} else {
|
|
1387
|
+
return []
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
func save(filename: String) -> Int32 {
|
|
1392
|
+
return SherpaOnnxWriteWave(audio.pointee.samples, n, sampleRate, toCPointer(filename))
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
typealias TtsCallbackWithArg = (
|
|
1397
|
+
@convention(c) (
|
|
1398
|
+
UnsafePointer<Float>?, // const float* samples
|
|
1399
|
+
Int32, // int32_t n
|
|
1400
|
+
UnsafeMutableRawPointer? // void *arg
|
|
1401
|
+
) -> Int32
|
|
1402
|
+
)?
|
|
1403
|
+
|
|
1404
|
+
class SherpaOnnxCallbackPair {
|
|
1405
|
+
var cb: TtsCallbackWithArg
|
|
1406
|
+
var arg: UnsafeMutableRawPointer?
|
|
1407
|
+
init(cb: TtsCallbackWithArg, arg: UnsafeMutableRawPointer?) {
|
|
1408
|
+
self.cb = cb
|
|
1409
|
+
self.arg = arg
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
typealias TtsProgressCallbackWithArg =
|
|
1414
|
+
@convention(c) (
|
|
1415
|
+
UnsafePointer<Float>?, Int32, Float, UnsafeMutableRawPointer?
|
|
1416
|
+
) -> Int32
|
|
1417
|
+
|
|
1418
|
+
struct SherpaOnnxGenerationConfigSwift {
|
|
1419
|
+
var silenceScale: Float = 0.2
|
|
1420
|
+
var speed: Float = 1.0
|
|
1421
|
+
var sid: Int = 0
|
|
1422
|
+
var referenceAudio: [Float] = []
|
|
1423
|
+
var referenceSampleRate: Int = 16000
|
|
1424
|
+
var referenceText: String = ""
|
|
1425
|
+
var numSteps: Int = 1
|
|
1426
|
+
var extra: [String: Any] = [:] // Any can be String, Int, Float, Double
|
|
1427
|
+
|
|
1428
|
+
/// Convert the extra dictionary into a JSON string
|
|
1429
|
+
func extraJsonString() -> String {
|
|
1430
|
+
var jsonCompatible: [String: Any] = [:]
|
|
1431
|
+
|
|
1432
|
+
for (key, value) in extra {
|
|
1433
|
+
switch value {
|
|
1434
|
+
case let v as String:
|
|
1435
|
+
jsonCompatible[key] = v
|
|
1436
|
+
case let v as Int:
|
|
1437
|
+
jsonCompatible[key] = v
|
|
1438
|
+
case let v as Float:
|
|
1439
|
+
jsonCompatible[key] = v
|
|
1440
|
+
case let v as Double:
|
|
1441
|
+
jsonCompatible[key] = v
|
|
1442
|
+
default:
|
|
1443
|
+
// ignore unsupported types
|
|
1444
|
+
print("Warning: unsupported type for key '\(key)' in extra")
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
guard let data = try? JSONSerialization.data(withJSONObject: jsonCompatible, options: []),
|
|
1449
|
+
let json = String(data: data, encoding: .utf8)
|
|
1450
|
+
else {
|
|
1451
|
+
return "{}"
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
return json
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
final class SherpaOnnxGenerationConfigC {
|
|
1459
|
+
/// The underlying C struct
|
|
1460
|
+
var cConfig: SherpaOnnxGenerationConfig
|
|
1461
|
+
|
|
1462
|
+
/// Storage for reference audio so the pointer stays valid during the C call
|
|
1463
|
+
private let referenceAudioStorage: [Float]
|
|
1464
|
+
|
|
1465
|
+
/// Extra JSON string for C API
|
|
1466
|
+
let extraJson: String
|
|
1467
|
+
|
|
1468
|
+
init(_ swiftConfig: SherpaOnnxGenerationConfigSwift) {
|
|
1469
|
+
let referenceAudio = swiftConfig.referenceAudio
|
|
1470
|
+
|
|
1471
|
+
let extraJson = swiftConfig.extraJsonString()
|
|
1472
|
+
self.extraJson = extraJson
|
|
1473
|
+
|
|
1474
|
+
referenceAudioStorage = referenceAudio
|
|
1475
|
+
|
|
1476
|
+
cConfig = referenceAudioStorage.withUnsafeBufferPointer { buffer in
|
|
1477
|
+
SherpaOnnxGenerationConfig(
|
|
1478
|
+
silence_scale: swiftConfig.silenceScale,
|
|
1479
|
+
speed: swiftConfig.speed,
|
|
1480
|
+
sid: Int32(swiftConfig.sid),
|
|
1481
|
+
reference_audio: buffer.count > 0 ? buffer.baseAddress : nil,
|
|
1482
|
+
reference_audio_len: Int32(buffer.count),
|
|
1483
|
+
reference_sample_rate: Int32(swiftConfig.referenceSampleRate),
|
|
1484
|
+
reference_text: toCPointer(swiftConfig.referenceText),
|
|
1485
|
+
num_steps: Int32(swiftConfig.numSteps),
|
|
1486
|
+
extra: toCPointer(extraJson)
|
|
1487
|
+
)
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
class SherpaOnnxOfflineTtsWrapper {
|
|
1493
|
+
/// A pointer to the underlying counterpart in C
|
|
1494
|
+
let tts: OpaquePointer!
|
|
1495
|
+
|
|
1496
|
+
/// Constructor taking a model config
|
|
1497
|
+
init(
|
|
1498
|
+
config: UnsafePointer<SherpaOnnxOfflineTtsConfig>!
|
|
1499
|
+
) {
|
|
1500
|
+
tts = SherpaOnnxCreateOfflineTts(config)
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
deinit {
|
|
1504
|
+
if let tts {
|
|
1505
|
+
SherpaOnnxDestroyOfflineTts(tts)
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
func generate(text: String, sid: Int = 0, speed: Float = 1.0) -> SherpaOnnxGeneratedAudioWrapper {
|
|
1510
|
+
let config = SherpaOnnxGenerationConfigSwift(speed: speed, sid: sid)
|
|
1511
|
+
return generateWithConfig(text: text, config: config, callback: nil, arg: nil)
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
func generateWithCallbackWithArg(
|
|
1515
|
+
text: String, callback: TtsCallbackWithArg, arg: UnsafeMutableRawPointer, sid: Int = 0,
|
|
1516
|
+
speed: Float = 1.0
|
|
1517
|
+
) -> SherpaOnnxGeneratedAudioWrapper {
|
|
1518
|
+
let config = SherpaOnnxGenerationConfigSwift(speed: speed, sid: sid)
|
|
1519
|
+
|
|
1520
|
+
let pair = SherpaOnnxCallbackPair(cb: callback, arg: arg)
|
|
1521
|
+
let unmanaged = Unmanaged.passRetained(pair)
|
|
1522
|
+
let wrapper: TtsProgressCallbackWithArg = { samples, n, _, rawArg in
|
|
1523
|
+
let p = Unmanaged<SherpaOnnxCallbackPair>.fromOpaque(rawArg!).takeUnretainedValue()
|
|
1524
|
+
return p.cb!(samples, n, p.arg)
|
|
1525
|
+
}
|
|
1526
|
+
let result = generateWithConfig(
|
|
1527
|
+
text: text, config: config, callback: wrapper, arg: unmanaged.toOpaque()
|
|
1528
|
+
)
|
|
1529
|
+
unmanaged.release()
|
|
1530
|
+
return result
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
func generateWithConfig(
|
|
1534
|
+
text: String,
|
|
1535
|
+
config: SherpaOnnxGenerationConfigSwift,
|
|
1536
|
+
callback: TtsProgressCallbackWithArg?,
|
|
1537
|
+
arg: UnsafeMutableRawPointer?
|
|
1538
|
+
) -> SherpaOnnxGeneratedAudioWrapper {
|
|
1539
|
+
let bridge = SherpaOnnxGenerationConfigC(config)
|
|
1540
|
+
|
|
1541
|
+
let audio: UnsafePointer<SherpaOnnxGeneratedAudio>? =
|
|
1542
|
+
withUnsafePointer(to: &bridge.cConfig) { configPtr in
|
|
1543
|
+
SherpaOnnxOfflineTtsGenerateWithConfig(
|
|
1544
|
+
tts,
|
|
1545
|
+
toCPointer(text),
|
|
1546
|
+
configPtr,
|
|
1547
|
+
callback,
|
|
1548
|
+
arg
|
|
1549
|
+
)
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
return SherpaOnnxGeneratedAudioWrapper(audio: audio)
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// spoken language identification
|
|
1557
|
+
|
|
1558
|
+
func sherpaOnnxSpokenLanguageIdentificationWhisperConfig(
|
|
1559
|
+
encoder: String,
|
|
1560
|
+
decoder: String,
|
|
1561
|
+
tailPaddings: Int = -1
|
|
1562
|
+
) -> SherpaOnnxSpokenLanguageIdentificationWhisperConfig {
|
|
1563
|
+
return SherpaOnnxSpokenLanguageIdentificationWhisperConfig(
|
|
1564
|
+
encoder: toCPointer(encoder),
|
|
1565
|
+
decoder: toCPointer(decoder),
|
|
1566
|
+
tail_paddings: Int32(tailPaddings)
|
|
1567
|
+
)
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
func sherpaOnnxSpokenLanguageIdentificationConfig(
|
|
1571
|
+
whisper: SherpaOnnxSpokenLanguageIdentificationWhisperConfig,
|
|
1572
|
+
numThreads: Int = 1,
|
|
1573
|
+
debug: Int = 0,
|
|
1574
|
+
provider: String = "cpu"
|
|
1575
|
+
) -> SherpaOnnxSpokenLanguageIdentificationConfig {
|
|
1576
|
+
return SherpaOnnxSpokenLanguageIdentificationConfig(
|
|
1577
|
+
whisper: whisper,
|
|
1578
|
+
num_threads: Int32(numThreads),
|
|
1579
|
+
debug: Int32(debug),
|
|
1580
|
+
provider: toCPointer(provider)
|
|
1581
|
+
)
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
class SherpaOnnxSpokenLanguageIdentificationResultWrapper {
|
|
1585
|
+
/// A pointer to the underlying counterpart in C
|
|
1586
|
+
let result: UnsafePointer<SherpaOnnxSpokenLanguageIdentificationResult>!
|
|
1587
|
+
|
|
1588
|
+
/// Return the detected language.
|
|
1589
|
+
/// en for English
|
|
1590
|
+
/// zh for Chinese
|
|
1591
|
+
/// es for Spanish
|
|
1592
|
+
/// de for German
|
|
1593
|
+
/// etc.
|
|
1594
|
+
var lang: String {
|
|
1595
|
+
return String(cString: result.pointee.lang)
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
init(result: UnsafePointer<SherpaOnnxSpokenLanguageIdentificationResult>!) {
|
|
1599
|
+
self.result = result
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
deinit {
|
|
1603
|
+
if let result {
|
|
1604
|
+
SherpaOnnxDestroySpokenLanguageIdentificationResult(result)
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
class SherpaOnnxSpokenLanguageIdentificationWrapper {
|
|
1610
|
+
/// A pointer to the underlying counterpart in C
|
|
1611
|
+
let slid: OpaquePointer!
|
|
1612
|
+
|
|
1613
|
+
init(
|
|
1614
|
+
config: UnsafePointer<SherpaOnnxSpokenLanguageIdentificationConfig>!
|
|
1615
|
+
) {
|
|
1616
|
+
slid = SherpaOnnxCreateSpokenLanguageIdentification(config)
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
deinit {
|
|
1620
|
+
if let slid {
|
|
1621
|
+
SherpaOnnxDestroySpokenLanguageIdentification(slid)
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
func decode(samples: [Float], sampleRate: Int = 16000)
|
|
1626
|
+
-> SherpaOnnxSpokenLanguageIdentificationResultWrapper
|
|
1627
|
+
{
|
|
1628
|
+
let stream: OpaquePointer! = SherpaOnnxSpokenLanguageIdentificationCreateOfflineStream(slid)
|
|
1629
|
+
SherpaOnnxAcceptWaveformOffline(stream, Int32(sampleRate), samples, Int32(samples.count))
|
|
1630
|
+
|
|
1631
|
+
let result: UnsafePointer<SherpaOnnxSpokenLanguageIdentificationResult>? =
|
|
1632
|
+
SherpaOnnxSpokenLanguageIdentificationCompute(
|
|
1633
|
+
slid,
|
|
1634
|
+
stream
|
|
1635
|
+
)
|
|
1636
|
+
|
|
1637
|
+
SherpaOnnxDestroyOfflineStream(stream)
|
|
1638
|
+
return SherpaOnnxSpokenLanguageIdentificationResultWrapper(result: result)
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// keyword spotting
|
|
1643
|
+
|
|
1644
|
+
class SherpaOnnxKeywordResultWrapper {
|
|
1645
|
+
/// A pointer to the underlying counterpart in C
|
|
1646
|
+
let result: UnsafePointer<SherpaOnnxKeywordResult>!
|
|
1647
|
+
|
|
1648
|
+
var keyword: String {
|
|
1649
|
+
return String(cString: result.pointee.keyword)
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
var count: Int32 {
|
|
1653
|
+
return result.pointee.count
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
var tokens: [String] {
|
|
1657
|
+
if let tokensPointer = result.pointee.tokens_arr {
|
|
1658
|
+
var tokens: [String] = []
|
|
1659
|
+
for index in 0 ..< count {
|
|
1660
|
+
if let tokenPointer = tokensPointer[Int(index)] {
|
|
1661
|
+
let token = String(cString: tokenPointer)
|
|
1662
|
+
tokens.append(token)
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return tokens
|
|
1666
|
+
} else {
|
|
1667
|
+
return []
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
init(result: UnsafePointer<SherpaOnnxKeywordResult>!) {
|
|
1672
|
+
self.result = result
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
deinit {
|
|
1676
|
+
if let result {
|
|
1677
|
+
SherpaOnnxDestroyKeywordResult(result)
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
func sherpaOnnxKeywordSpotterConfig(
|
|
1683
|
+
featConfig: SherpaOnnxFeatureConfig,
|
|
1684
|
+
modelConfig: SherpaOnnxOnlineModelConfig,
|
|
1685
|
+
keywordsFile: String,
|
|
1686
|
+
maxActivePaths: Int = 4,
|
|
1687
|
+
numTrailingBlanks: Int = 1,
|
|
1688
|
+
keywordsScore: Float = 1.0,
|
|
1689
|
+
keywordsThreshold: Float = 0.25,
|
|
1690
|
+
keywordsBuf: String = "",
|
|
1691
|
+
keywordsBufSize: Int = 0
|
|
1692
|
+
) -> SherpaOnnxKeywordSpotterConfig {
|
|
1693
|
+
return SherpaOnnxKeywordSpotterConfig(
|
|
1694
|
+
feat_config: featConfig,
|
|
1695
|
+
model_config: modelConfig,
|
|
1696
|
+
max_active_paths: Int32(maxActivePaths),
|
|
1697
|
+
num_trailing_blanks: Int32(numTrailingBlanks),
|
|
1698
|
+
keywords_score: keywordsScore,
|
|
1699
|
+
keywords_threshold: keywordsThreshold,
|
|
1700
|
+
keywords_file: toCPointer(keywordsFile),
|
|
1701
|
+
keywords_buf: toCPointer(keywordsBuf),
|
|
1702
|
+
keywords_buf_size: Int32(keywordsBufSize)
|
|
1703
|
+
)
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
class SherpaOnnxKeywordSpotterWrapper {
|
|
1707
|
+
/// A pointer to the underlying counterpart in C
|
|
1708
|
+
let spotter: OpaquePointer!
|
|
1709
|
+
var stream: OpaquePointer!
|
|
1710
|
+
|
|
1711
|
+
init(
|
|
1712
|
+
config: UnsafePointer<SherpaOnnxKeywordSpotterConfig>!
|
|
1713
|
+
) {
|
|
1714
|
+
spotter = SherpaOnnxCreateKeywordSpotter(config)
|
|
1715
|
+
stream = SherpaOnnxCreateKeywordStream(spotter)
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
deinit {
|
|
1719
|
+
if let stream {
|
|
1720
|
+
SherpaOnnxDestroyOnlineStream(stream)
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
if let spotter {
|
|
1724
|
+
SherpaOnnxDestroyKeywordSpotter(spotter)
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
func acceptWaveform(samples: [Float], sampleRate: Int = 16000) {
|
|
1729
|
+
SherpaOnnxOnlineStreamAcceptWaveform(stream, Int32(sampleRate), samples, Int32(samples.count))
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
func isReady() -> Bool {
|
|
1733
|
+
return SherpaOnnxIsKeywordStreamReady(spotter, stream) == 1 ? true : false
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
func decode() {
|
|
1737
|
+
SherpaOnnxDecodeKeywordStream(spotter, stream)
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
func reset() {
|
|
1741
|
+
SherpaOnnxResetKeywordStream(spotter, stream)
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
func getResult() -> SherpaOnnxKeywordResultWrapper {
|
|
1745
|
+
let result: UnsafePointer<SherpaOnnxKeywordResult>? = SherpaOnnxGetKeywordResult(
|
|
1746
|
+
spotter, stream
|
|
1747
|
+
)
|
|
1748
|
+
return SherpaOnnxKeywordResultWrapper(result: result)
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
/// Signal that no more audio samples would be available.
|
|
1752
|
+
/// After this call, you cannot call acceptWaveform() any more.
|
|
1753
|
+
func inputFinished() {
|
|
1754
|
+
SherpaOnnxOnlineStreamInputFinished(stream)
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
// Punctuation
|
|
1759
|
+
|
|
1760
|
+
func sherpaOnnxOfflinePunctuationModelConfig(
|
|
1761
|
+
ctTransformer: String,
|
|
1762
|
+
numThreads: Int = 1,
|
|
1763
|
+
debug: Int = 0,
|
|
1764
|
+
provider: String = "cpu"
|
|
1765
|
+
) -> SherpaOnnxOfflinePunctuationModelConfig {
|
|
1766
|
+
return SherpaOnnxOfflinePunctuationModelConfig(
|
|
1767
|
+
ct_transformer: toCPointer(ctTransformer),
|
|
1768
|
+
num_threads: Int32(numThreads),
|
|
1769
|
+
debug: Int32(debug),
|
|
1770
|
+
provider: toCPointer(provider)
|
|
1771
|
+
)
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
func sherpaOnnxOfflinePunctuationConfig(
|
|
1775
|
+
model: SherpaOnnxOfflinePunctuationModelConfig
|
|
1776
|
+
) -> SherpaOnnxOfflinePunctuationConfig {
|
|
1777
|
+
return SherpaOnnxOfflinePunctuationConfig(
|
|
1778
|
+
model: model
|
|
1779
|
+
)
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
class SherpaOnnxOfflinePunctuationWrapper {
|
|
1783
|
+
/// A pointer to the underlying counterpart in C
|
|
1784
|
+
let ptr: OpaquePointer!
|
|
1785
|
+
|
|
1786
|
+
/// Constructor taking a model config
|
|
1787
|
+
init(
|
|
1788
|
+
config: UnsafePointer<SherpaOnnxOfflinePunctuationConfig>!
|
|
1789
|
+
) {
|
|
1790
|
+
ptr = SherpaOnnxCreateOfflinePunctuation(config)
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
deinit {
|
|
1794
|
+
if let ptr {
|
|
1795
|
+
SherpaOnnxDestroyOfflinePunctuation(ptr)
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
func addPunct(text: String) -> String {
|
|
1800
|
+
let cText = SherpaOfflinePunctuationAddPunct(ptr, toCPointer(text))
|
|
1801
|
+
let ans = String(cString: cText!)
|
|
1802
|
+
SherpaOfflinePunctuationFreeText(cText)
|
|
1803
|
+
return ans
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
func sherpaOnnxOnlinePunctuationModelConfig(
|
|
1808
|
+
cnnBiLstm: String,
|
|
1809
|
+
bpeVocab: String,
|
|
1810
|
+
numThreads: Int = 1,
|
|
1811
|
+
debug: Int = 0,
|
|
1812
|
+
provider: String = "cpu"
|
|
1813
|
+
) -> SherpaOnnxOnlinePunctuationModelConfig {
|
|
1814
|
+
return SherpaOnnxOnlinePunctuationModelConfig(
|
|
1815
|
+
cnn_bilstm: toCPointer(cnnBiLstm),
|
|
1816
|
+
bpe_vocab: toCPointer(bpeVocab),
|
|
1817
|
+
num_threads: Int32(numThreads),
|
|
1818
|
+
debug: Int32(debug),
|
|
1819
|
+
provider: toCPointer(provider)
|
|
1820
|
+
)
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
func sherpaOnnxOnlinePunctuationConfig(
|
|
1824
|
+
model: SherpaOnnxOnlinePunctuationModelConfig
|
|
1825
|
+
) -> SherpaOnnxOnlinePunctuationConfig {
|
|
1826
|
+
return SherpaOnnxOnlinePunctuationConfig(model: model)
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
class SherpaOnnxOnlinePunctuationWrapper {
|
|
1830
|
+
/// A pointer to the underlying counterpart in C
|
|
1831
|
+
let ptr: OpaquePointer!
|
|
1832
|
+
|
|
1833
|
+
/// Constructor taking a model config
|
|
1834
|
+
init(
|
|
1835
|
+
config: UnsafePointer<SherpaOnnxOnlinePunctuationConfig>!
|
|
1836
|
+
) {
|
|
1837
|
+
ptr = SherpaOnnxCreateOnlinePunctuation(config)
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
deinit {
|
|
1841
|
+
if let ptr {
|
|
1842
|
+
SherpaOnnxDestroyOnlinePunctuation(ptr)
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
func addPunct(text: String) -> String {
|
|
1847
|
+
let cText = SherpaOnnxOnlinePunctuationAddPunct(ptr, toCPointer(text))
|
|
1848
|
+
let ans = String(cString: cText!)
|
|
1849
|
+
SherpaOnnxOnlinePunctuationFreeText(cText)
|
|
1850
|
+
return ans
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
func sherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig(model: String)
|
|
1855
|
+
-> SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig
|
|
1856
|
+
{
|
|
1857
|
+
return SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig(model: toCPointer(model))
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
func sherpaOnnxOfflineSpeakerSegmentationModelConfig(
|
|
1861
|
+
pyannote: SherpaOnnxOfflineSpeakerSegmentationPyannoteModelConfig,
|
|
1862
|
+
numThreads: Int = 1,
|
|
1863
|
+
debug: Int = 0,
|
|
1864
|
+
provider: String = "cpu"
|
|
1865
|
+
) -> SherpaOnnxOfflineSpeakerSegmentationModelConfig {
|
|
1866
|
+
return SherpaOnnxOfflineSpeakerSegmentationModelConfig(
|
|
1867
|
+
pyannote: pyannote,
|
|
1868
|
+
num_threads: Int32(numThreads),
|
|
1869
|
+
debug: Int32(debug),
|
|
1870
|
+
provider: toCPointer(provider)
|
|
1871
|
+
)
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
func sherpaOnnxFastClusteringConfig(numClusters: Int = -1, threshold: Float = 0.5)
|
|
1875
|
+
-> SherpaOnnxFastClusteringConfig
|
|
1876
|
+
{
|
|
1877
|
+
return SherpaOnnxFastClusteringConfig(num_clusters: Int32(numClusters), threshold: threshold)
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
func sherpaOnnxSpeakerEmbeddingExtractorConfig(
|
|
1881
|
+
model: String,
|
|
1882
|
+
numThreads: Int = 1,
|
|
1883
|
+
debug: Int = 0,
|
|
1884
|
+
provider: String = "cpu"
|
|
1885
|
+
) -> SherpaOnnxSpeakerEmbeddingExtractorConfig {
|
|
1886
|
+
return SherpaOnnxSpeakerEmbeddingExtractorConfig(
|
|
1887
|
+
model: toCPointer(model),
|
|
1888
|
+
num_threads: Int32(numThreads),
|
|
1889
|
+
debug: Int32(debug),
|
|
1890
|
+
provider: toCPointer(provider)
|
|
1891
|
+
)
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
func sherpaOnnxOfflineSpeakerDiarizationConfig(
|
|
1895
|
+
segmentation: SherpaOnnxOfflineSpeakerSegmentationModelConfig,
|
|
1896
|
+
embedding: SherpaOnnxSpeakerEmbeddingExtractorConfig,
|
|
1897
|
+
clustering: SherpaOnnxFastClusteringConfig,
|
|
1898
|
+
minDurationOn: Float = 0.3,
|
|
1899
|
+
minDurationOff: Float = 0.5
|
|
1900
|
+
) -> SherpaOnnxOfflineSpeakerDiarizationConfig {
|
|
1901
|
+
return SherpaOnnxOfflineSpeakerDiarizationConfig(
|
|
1902
|
+
segmentation: segmentation,
|
|
1903
|
+
embedding: embedding,
|
|
1904
|
+
clustering: clustering,
|
|
1905
|
+
min_duration_on: minDurationOn,
|
|
1906
|
+
min_duration_off: minDurationOff
|
|
1907
|
+
)
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
struct SherpaOnnxOfflineSpeakerDiarizationSegmentWrapper {
|
|
1911
|
+
var start: Float = 0
|
|
1912
|
+
var end: Float = 0
|
|
1913
|
+
var speaker: Int = 0
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
class SherpaOnnxOfflineSpeakerDiarizationWrapper {
|
|
1917
|
+
/// A pointer to the underlying counterpart in C
|
|
1918
|
+
let impl: OpaquePointer!
|
|
1919
|
+
|
|
1920
|
+
init(
|
|
1921
|
+
config: UnsafePointer<SherpaOnnxOfflineSpeakerDiarizationConfig>!
|
|
1922
|
+
) {
|
|
1923
|
+
impl = SherpaOnnxCreateOfflineSpeakerDiarization(config)
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
deinit {
|
|
1927
|
+
if let impl {
|
|
1928
|
+
SherpaOnnxDestroyOfflineSpeakerDiarization(impl)
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
var sampleRate: Int {
|
|
1933
|
+
return Int(SherpaOnnxOfflineSpeakerDiarizationGetSampleRate(impl))
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
/// only config.clustering is used. All other fields are ignored
|
|
1937
|
+
func setConfig(config: UnsafePointer<SherpaOnnxOfflineSpeakerDiarizationConfig>!) {
|
|
1938
|
+
SherpaOnnxOfflineSpeakerDiarizationSetConfig(impl, config)
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
func process(samples: [Float]) -> [SherpaOnnxOfflineSpeakerDiarizationSegmentWrapper] {
|
|
1942
|
+
let result = SherpaOnnxOfflineSpeakerDiarizationProcess(
|
|
1943
|
+
impl, samples, Int32(samples.count)
|
|
1944
|
+
)
|
|
1945
|
+
|
|
1946
|
+
if result == nil {
|
|
1947
|
+
return []
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
let numSegments = Int(SherpaOnnxOfflineSpeakerDiarizationResultGetNumSegments(result))
|
|
1951
|
+
|
|
1952
|
+
let p: UnsafePointer<SherpaOnnxOfflineSpeakerDiarizationSegment>? =
|
|
1953
|
+
SherpaOnnxOfflineSpeakerDiarizationResultSortByStartTime(result)
|
|
1954
|
+
|
|
1955
|
+
if p == nil {
|
|
1956
|
+
return []
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
var ans: [SherpaOnnxOfflineSpeakerDiarizationSegmentWrapper] = []
|
|
1960
|
+
for i in 0 ..< numSegments {
|
|
1961
|
+
ans.append(
|
|
1962
|
+
SherpaOnnxOfflineSpeakerDiarizationSegmentWrapper(
|
|
1963
|
+
start: p![i].start, end: p![i].end, speaker: Int(p![i].speaker)
|
|
1964
|
+
)
|
|
1965
|
+
)
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
SherpaOnnxOfflineSpeakerDiarizationDestroySegment(p)
|
|
1969
|
+
SherpaOnnxOfflineSpeakerDiarizationDestroyResult(result)
|
|
1970
|
+
|
|
1971
|
+
return ans
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
class SherpaOnnxOnlineStreamWrapper {
|
|
1976
|
+
/// A pointer to the underlying counterpart in C
|
|
1977
|
+
let impl: OpaquePointer!
|
|
1978
|
+
init(impl: OpaquePointer!) {
|
|
1979
|
+
self.impl = impl
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
deinit {
|
|
1983
|
+
if let impl {
|
|
1984
|
+
SherpaOnnxDestroyOnlineStream(impl)
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
func acceptWaveform(samples: [Float], sampleRate: Int = 16000) {
|
|
1989
|
+
SherpaOnnxOnlineStreamAcceptWaveform(impl, Int32(sampleRate), samples, Int32(samples.count))
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
func inputFinished() {
|
|
1993
|
+
SherpaOnnxOnlineStreamInputFinished(impl)
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
class SherpaOnnxSpeakerEmbeddingExtractorWrapper {
|
|
1998
|
+
/// A pointer to the underlying counterpart in C
|
|
1999
|
+
let impl: OpaquePointer!
|
|
2000
|
+
|
|
2001
|
+
init(
|
|
2002
|
+
config: UnsafePointer<SherpaOnnxSpeakerEmbeddingExtractorConfig>!
|
|
2003
|
+
) {
|
|
2004
|
+
impl = SherpaOnnxCreateSpeakerEmbeddingExtractor(config)
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
deinit {
|
|
2008
|
+
if let impl {
|
|
2009
|
+
SherpaOnnxDestroySpeakerEmbeddingExtractor(impl)
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
var dim: Int {
|
|
2014
|
+
return Int(SherpaOnnxSpeakerEmbeddingExtractorDim(impl))
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
func createStream() -> SherpaOnnxOnlineStreamWrapper {
|
|
2018
|
+
let newStream = SherpaOnnxSpeakerEmbeddingExtractorCreateStream(impl)
|
|
2019
|
+
return SherpaOnnxOnlineStreamWrapper(impl: newStream)
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
func isReady(stream: SherpaOnnxOnlineStreamWrapper) -> Bool {
|
|
2023
|
+
return SherpaOnnxSpeakerEmbeddingExtractorIsReady(impl, stream.impl) == 1 ? true : false
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
func compute(stream: SherpaOnnxOnlineStreamWrapper) -> [Float] {
|
|
2027
|
+
if !isReady(stream: stream) {
|
|
2028
|
+
return []
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
let p = SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding(impl, stream.impl)
|
|
2032
|
+
|
|
2033
|
+
defer {
|
|
2034
|
+
SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding(p)
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
return [Float](UnsafeBufferPointer(start: p, count: dim))
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
func sherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig(model: String = "")
|
|
2042
|
+
-> SherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig
|
|
2043
|
+
{
|
|
2044
|
+
return SherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig(model: toCPointer(model))
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
func sherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig(model: String = "")
|
|
2048
|
+
-> SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig
|
|
2049
|
+
{
|
|
2050
|
+
return SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig(model: toCPointer(model))
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
func sherpaOnnxOfflineSpeechDenoiserModelConfig(
|
|
2054
|
+
gtcrn: SherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig =
|
|
2055
|
+
sherpaOnnxOfflineSpeechDenoiserGtcrnModelConfig(),
|
|
2056
|
+
dpdfnet: SherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig =
|
|
2057
|
+
sherpaOnnxOfflineSpeechDenoiserDpdfNetModelConfig(),
|
|
2058
|
+
numThreads: Int = 1,
|
|
2059
|
+
provider: String = "cpu",
|
|
2060
|
+
debug: Int = 0
|
|
2061
|
+
) -> SherpaOnnxOfflineSpeechDenoiserModelConfig {
|
|
2062
|
+
return SherpaOnnxOfflineSpeechDenoiserModelConfig(
|
|
2063
|
+
gtcrn: gtcrn,
|
|
2064
|
+
num_threads: Int32(numThreads),
|
|
2065
|
+
debug: Int32(debug),
|
|
2066
|
+
provider: toCPointer(provider),
|
|
2067
|
+
dpdfnet: dpdfnet
|
|
2068
|
+
)
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
func sherpaOnnxOfflineSpeechDenoiserConfig(
|
|
2072
|
+
model: SherpaOnnxOfflineSpeechDenoiserModelConfig =
|
|
2073
|
+
sherpaOnnxOfflineSpeechDenoiserModelConfig()
|
|
2074
|
+
) -> SherpaOnnxOfflineSpeechDenoiserConfig {
|
|
2075
|
+
return SherpaOnnxOfflineSpeechDenoiserConfig(
|
|
2076
|
+
model: model
|
|
2077
|
+
)
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
class SherpaOnnxDenoisedAudioWrapper {
|
|
2081
|
+
/// A pointer to the underlying counterpart in C
|
|
2082
|
+
let audio: UnsafePointer<SherpaOnnxDenoisedAudio>!
|
|
2083
|
+
|
|
2084
|
+
init(audio: UnsafePointer<SherpaOnnxDenoisedAudio>!) {
|
|
2085
|
+
self.audio = audio
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
deinit {
|
|
2089
|
+
if let audio {
|
|
2090
|
+
SherpaOnnxDestroyDenoisedAudio(audio)
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
var n: Int32 {
|
|
2095
|
+
guard let audio else {
|
|
2096
|
+
return 0
|
|
2097
|
+
}
|
|
2098
|
+
return audio.pointee.n
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
var sampleRate: Int32 {
|
|
2102
|
+
guard let audio else {
|
|
2103
|
+
return 0
|
|
2104
|
+
}
|
|
2105
|
+
return audio.pointee.sample_rate
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
var samples: [Float] {
|
|
2109
|
+
guard let audio else {
|
|
2110
|
+
return []
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
if let p = audio.pointee.samples {
|
|
2114
|
+
var samples: [Float] = []
|
|
2115
|
+
for index in 0 ..< n {
|
|
2116
|
+
samples.append(p[Int(index)])
|
|
2117
|
+
}
|
|
2118
|
+
return samples
|
|
2119
|
+
} else {
|
|
2120
|
+
return []
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
func save(filename: String) -> Int32 {
|
|
2125
|
+
guard let audio else {
|
|
2126
|
+
return 0
|
|
2127
|
+
}
|
|
2128
|
+
return SherpaOnnxWriteWave(audio.pointee.samples, n, sampleRate, toCPointer(filename))
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
class SherpaOnnxOfflineSpeechDenoiserWrapper {
|
|
2133
|
+
/// A pointer to the underlying counterpart in C
|
|
2134
|
+
let impl: OpaquePointer!
|
|
2135
|
+
|
|
2136
|
+
/// Constructor taking a model config
|
|
2137
|
+
init(
|
|
2138
|
+
config: UnsafePointer<SherpaOnnxOfflineSpeechDenoiserConfig>!
|
|
2139
|
+
) {
|
|
2140
|
+
impl = SherpaOnnxCreateOfflineSpeechDenoiser(config)
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
deinit {
|
|
2144
|
+
if let impl {
|
|
2145
|
+
SherpaOnnxDestroyOfflineSpeechDenoiser(impl)
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
func run(samples: [Float], sampleRate: Int) -> SherpaOnnxDenoisedAudioWrapper {
|
|
2150
|
+
let audio: UnsafePointer<SherpaOnnxDenoisedAudio>? = SherpaOnnxOfflineSpeechDenoiserRun(
|
|
2151
|
+
impl, samples, Int32(samples.count), Int32(sampleRate)
|
|
2152
|
+
)
|
|
2153
|
+
|
|
2154
|
+
return SherpaOnnxDenoisedAudioWrapper(audio: audio)
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
var sampleRate: Int {
|
|
2158
|
+
return Int(SherpaOnnxOfflineSpeechDenoiserGetSampleRate(impl))
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
func sherpaOnnxOnlineSpeechDenoiserConfig(
|
|
2163
|
+
model: SherpaOnnxOfflineSpeechDenoiserModelConfig =
|
|
2164
|
+
sherpaOnnxOfflineSpeechDenoiserModelConfig()
|
|
2165
|
+
) -> SherpaOnnxOnlineSpeechDenoiserConfig {
|
|
2166
|
+
return SherpaOnnxOnlineSpeechDenoiserConfig(model: model)
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
class SherpaOnnxOnlineSpeechDenoiserWrapper {
|
|
2170
|
+
let impl: OpaquePointer!
|
|
2171
|
+
|
|
2172
|
+
init(
|
|
2173
|
+
config: UnsafePointer<SherpaOnnxOnlineSpeechDenoiserConfig>!
|
|
2174
|
+
) {
|
|
2175
|
+
impl = SherpaOnnxCreateOnlineSpeechDenoiser(config)
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
deinit {
|
|
2179
|
+
if let impl {
|
|
2180
|
+
SherpaOnnxDestroyOnlineSpeechDenoiser(impl)
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
func run(samples: [Float], sampleRate: Int) -> SherpaOnnxDenoisedAudioWrapper {
|
|
2185
|
+
let audio: UnsafePointer<SherpaOnnxDenoisedAudio>? = SherpaOnnxOnlineSpeechDenoiserRun(
|
|
2186
|
+
impl, samples, Int32(samples.count), Int32(sampleRate)
|
|
2187
|
+
)
|
|
2188
|
+
return SherpaOnnxDenoisedAudioWrapper(audio: audio)
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
func flush() -> SherpaOnnxDenoisedAudioWrapper {
|
|
2192
|
+
let audio: UnsafePointer<SherpaOnnxDenoisedAudio>? = SherpaOnnxOnlineSpeechDenoiserFlush(impl)
|
|
2193
|
+
return SherpaOnnxDenoisedAudioWrapper(audio: audio)
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
func reset() {
|
|
2197
|
+
SherpaOnnxOnlineSpeechDenoiserReset(impl)
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
var sampleRate: Int {
|
|
2201
|
+
return Int(SherpaOnnxOnlineSpeechDenoiserGetSampleRate(impl))
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
var frameShiftInSamples: Int {
|
|
2205
|
+
return Int(SherpaOnnxOnlineSpeechDenoiserGetFrameShiftInSamples(impl))
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
func getSherpaOnnxVersion() -> String {
|
|
2210
|
+
return String(cString: SherpaOnnxGetVersionStr())
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
func getSherpaOnnxGitSha1() -> String {
|
|
2214
|
+
return String(cString: SherpaOnnxGetGitSha1())
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
func getSherpaOnnxGitDate() -> String {
|
|
2218
|
+
return String(cString: SherpaOnnxGetGitDate())
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
// ---------------------------
|
|
2222
|
+
// Source separation
|
|
2223
|
+
// ---------------------------
|
|
2224
|
+
|
|
2225
|
+
struct AudioData {
|
|
2226
|
+
private enum Storage {
|
|
2227
|
+
case owned([Float])
|
|
2228
|
+
case wrapped(ManagedWave)
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
private class ManagedWave {
|
|
2232
|
+
let pointer: UnsafePointer<SherpaOnnxMultiChannelWave>
|
|
2233
|
+
init(_ p: UnsafePointer<SherpaOnnxMultiChannelWave>) {
|
|
2234
|
+
pointer = p
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
deinit { SherpaOnnxFreeMultiChannelWave(pointer) }
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
private let storage: Storage
|
|
2241
|
+
let channelCount: Int
|
|
2242
|
+
let samplesPerChannel: Int
|
|
2243
|
+
let sampleRate: Int
|
|
2244
|
+
|
|
2245
|
+
init(samples: [Float], channelCount: Int, sampleRate: Int) {
|
|
2246
|
+
storage = .owned(samples)
|
|
2247
|
+
self.channelCount = channelCount
|
|
2248
|
+
self.sampleRate = sampleRate
|
|
2249
|
+
samplesPerChannel = channelCount > 0 ? samples.count / channelCount : 0
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
init?(filename: String) {
|
|
2253
|
+
guard let ptr = SherpaOnnxReadWaveMultiChannel(filename) else { return nil }
|
|
2254
|
+
storage = .wrapped(ManagedWave(ptr))
|
|
2255
|
+
channelCount = Int(ptr.pointee.num_channels)
|
|
2256
|
+
samplesPerChannel = Int(ptr.pointee.num_samples)
|
|
2257
|
+
sampleRate = Int(ptr.pointee.sample_rate)
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Float>) -> R) -> R {
|
|
2261
|
+
switch storage {
|
|
2262
|
+
case let .owned(array):
|
|
2263
|
+
return array.withUnsafeBufferPointer(body)
|
|
2264
|
+
case let .wrapped(managed):
|
|
2265
|
+
let total = Int(managed.pointer.pointee.num_channels * managed.pointer.pointee.num_samples)
|
|
2266
|
+
// Ensure we start from the first channel's pointer
|
|
2267
|
+
return body(UnsafeBufferPointer(start: managed.pointer.pointee.samples[0], count: total))
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
@discardableResult
|
|
2272
|
+
func save(to filename: String) -> Bool {
|
|
2273
|
+
return withUnsafeBufferPointer { buf in
|
|
2274
|
+
guard let base = buf.baseAddress else { return false }
|
|
2275
|
+
// FIX: Explicitly type the array as Optional pointers to match C 'float* const*'
|
|
2276
|
+
var ptrs: [UnsafePointer<Float>?] = (0 ..< channelCount).map { base + ($0 * samplesPerChannel) }
|
|
2277
|
+
|
|
2278
|
+
return SherpaOnnxWriteWaveMultiChannel(
|
|
2279
|
+
&ptrs,
|
|
2280
|
+
Int32(samplesPerChannel),
|
|
2281
|
+
Int32(sampleRate),
|
|
2282
|
+
Int32(channelCount),
|
|
2283
|
+
filename
|
|
2284
|
+
) == 1
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
struct SourceSeparationConfig {
|
|
2290
|
+
struct Spleeter {
|
|
2291
|
+
var vocals: String
|
|
2292
|
+
var accompaniment: String
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
struct Uvr { var model: String }
|
|
2296
|
+
|
|
2297
|
+
var spleeter: Spleeter?
|
|
2298
|
+
var uvr: Uvr?
|
|
2299
|
+
var numThreads: Int = 1
|
|
2300
|
+
var debug: Bool = false
|
|
2301
|
+
var provider: String = "cpu"
|
|
2302
|
+
|
|
2303
|
+
func withCConfig<R>(_ body: (UnsafePointer<SherpaOnnxOfflineSourceSeparationConfig>) -> R) -> R {
|
|
2304
|
+
var cConfig = SherpaOnnxOfflineSourceSeparationConfig()
|
|
2305
|
+
cConfig.model.num_threads = Int32(numThreads)
|
|
2306
|
+
cConfig.model.debug = debug ? 1 : 0
|
|
2307
|
+
|
|
2308
|
+
var s: [String: [Int8]] = [:]
|
|
2309
|
+
func b(_ k: String, _ v: String?) -> UnsafePointer<Int8>? {
|
|
2310
|
+
guard let v = v else { return nil }
|
|
2311
|
+
s[k] = Array(v.utf8CString)
|
|
2312
|
+
return s[k]!.withUnsafeBufferPointer { $0.baseAddress }
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
cConfig.model.provider = b("provider", provider)
|
|
2316
|
+
cConfig.model.spleeter.vocals = b("spleeter.vocals", spleeter?.vocals)
|
|
2317
|
+
cConfig.model.spleeter.accompaniment = b("spleeter.accompaniment", spleeter?.accompaniment)
|
|
2318
|
+
cConfig.model.uvr.model = b("uvr.model", uvr?.model)
|
|
2319
|
+
|
|
2320
|
+
return body(&cConfig)
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
class SourceSeparator {
|
|
2325
|
+
private var engine: OpaquePointer?
|
|
2326
|
+
|
|
2327
|
+
init?(config: SourceSeparationConfig) {
|
|
2328
|
+
engine = config.withCConfig { SherpaOnnxCreateOfflineSourceSeparation($0) }
|
|
2329
|
+
|
|
2330
|
+
if engine == nil { return nil }
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
deinit {
|
|
2334
|
+
if let e = engine {
|
|
2335
|
+
SherpaOnnxDestroyOfflineSourceSeparation(e)
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
func process(buffer: AudioData) -> [AudioData]? {
|
|
2340
|
+
guard let engine = engine else { return nil }
|
|
2341
|
+
|
|
2342
|
+
return buffer.withUnsafeBufferPointer { flatBuf in
|
|
2343
|
+
guard let base = flatBuf.baseAddress else { return nil }
|
|
2344
|
+
var ptrs: [UnsafePointer<Float>?] = (0 ..< buffer.channelCount).map {
|
|
2345
|
+
base + ($0 * buffer.samplesPerChannel)
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
guard
|
|
2349
|
+
let raw = SherpaOnnxOfflineSourceSeparationProcess(
|
|
2350
|
+
engine,
|
|
2351
|
+
&ptrs,
|
|
2352
|
+
Int32(buffer.channelCount),
|
|
2353
|
+
Int32(buffer.samplesPerChannel),
|
|
2354
|
+
Int32(buffer.sampleRate)
|
|
2355
|
+
)
|
|
2356
|
+
else { return nil }
|
|
2357
|
+
|
|
2358
|
+
let stemCount = Int(raw.pointee.num_stems)
|
|
2359
|
+
let result = (0 ..< stemCount).map { i in
|
|
2360
|
+
let stem = raw.pointee.stems[i]
|
|
2361
|
+
let chs = Int(stem.num_channels)
|
|
2362
|
+
let n = Int(stem.n)
|
|
2363
|
+
var flat = [Float](repeating: 0, count: chs * n)
|
|
2364
|
+
|
|
2365
|
+
for c in 0 ..< chs {
|
|
2366
|
+
if let src = stem.samples[c] {
|
|
2367
|
+
let offset = c * n
|
|
2368
|
+
flat.withUnsafeMutableBufferPointer { dest in
|
|
2369
|
+
let destPtr = dest.baseAddress!.advanced(by: offset)
|
|
2370
|
+
destPtr.initialize(from: src, count: n)
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
return AudioData(
|
|
2375
|
+
samples: flat, channelCount: chs, sampleRate: Int(raw.pointee.sample_rate)
|
|
2376
|
+
)
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
SherpaOnnxDestroySourceSeparationOutput(raw)
|
|
2380
|
+
return result
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
}
|