Instructions to use Sky-Kim/moonshine-tiny-ko-unity with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- unity-sentis
How to use Sky-Kim/moonshine-tiny-ko-unity with unity-sentis:
string modelName = "[Your model name here].sentis"; Model model = ModelLoader.Load(Application.streamingAssetsPath + "/" + modelName); IWorker engine = WorkerFactory.CreateWorker(BackendType.GPUCompute, model); // Please see provided C# file for more details
- Notebooks
- Google Colab
- Kaggle
Download Assets/Scripts/TenVADRunner.cs from Sky-Kim/moonshine-tiny-ko-unity: direct link, hf CLI and curl.
- Browser
- Download file 8.31 kB
-
https://huggingface.co/Sky-Kim/moonshine-tiny-ko-unity/resolve/main/Assets/Scripts/TenVADRunner.cs
- Command line
-
hf download hf://Sky-Kim/moonshine-tiny-ko-unity/Assets/Scripts/TenVADRunner.cs
-
curl -L -o TenVADRunner.cs https://huggingface.co/Sky-Kim/moonshine-tiny-ko-unity/resolve/main/Assets/Scripts/TenVADRunner.cs
8.31 kB
| using System; | |
| using System.Runtime.InteropServices; | |
| using UnityEngine; | |
| public class TenVADRunner : IDisposable | |
| { | |
| [] | |
| private static extern int WebGLTenVad_Create(int hopSize, float threshold); | |
| [] | |
| private static extern int WebGLTenVad_Process(int instanceId, short[] audioData, int audioDataLength, out float outProbability, out int outFlag); | |
| [] | |
| private static extern int WebGLTenVad_Destroy(int instanceId); | |
| [] | |
| private static extern int WebGLTenVad_GetState(); | |
| private const int WebGlStateLoading = 0; | |
| private const int WebGlStateError = -1; | |
| private const int WebGlPending = -2; | |
| private int webGlInstanceId; | |
| private readonly int webGlHopSize; | |
| private readonly float webGlThreshold; | |
| private const string DllName = "ten_vad"; | |
| [] | |
| private static extern int ten_vad_create(out IntPtr handle, UIntPtr hop_size, float threshold); | |
| [] | |
| private static extern int ten_vad_process(IntPtr handle, short[] audio_data, UIntPtr audio_data_length, out float out_probability, out int out_flag); | |
| [] | |
| private static extern int ten_vad_destroy(ref IntPtr handle); | |
| private IntPtr vadHandle = IntPtr.Zero; | |
| private bool isDisposed = false; | |
| private bool useFallbackVad = false; | |
| private readonly float fallbackThreshold; | |
| private float fallbackSmoothedProbability; | |
| private const float FallbackRmsScale = 140f; | |
| private const float FallbackRmsScale = 20f; | |
| private const float FallbackSmoothing = 0.35f; | |
| public TenVADRunner(UIntPtr hopSize, float threshold) | |
| { | |
| fallbackThreshold = Mathf.Clamp01(threshold); | |
| fallbackSmoothedProbability = 0f; | |
| webGlHopSize = Math.Max(1, (int)hopSize.ToUInt64()); | |
| webGlThreshold = threshold; | |
| TryInitializeWebGlVad(); | |
| try | |
| { | |
| int result = ten_vad_create(out vadHandle, hopSize, threshold); | |
| if (result != 0 || vadHandle == IntPtr.Zero) | |
| { | |
| EnableFallback($"Failed to create VAD Handle. (Error Code: {result})"); | |
| return; | |
| } | |
| } | |
| catch (DllNotFoundException ex) | |
| { | |
| EnableFallback($"Native VAD library '{DllName}' was not found. {ex.Message}"); | |
| } | |
| catch (EntryPointNotFoundException ex) | |
| { | |
| EnableFallback($"Native VAD entry point was not found. {ex.Message}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| EnableFallback($"Native VAD initialization failed. {ex.Message}"); | |
| } | |
| } | |
| public int Process(short[] audioData, out float probability, out int flag) | |
| { | |
| if (isDisposed) | |
| { | |
| throw new ObjectDisposedException(nameof(TenVADRunner), "The VAD instance has already been disposed."); | |
| } | |
| if (audioData == null || audioData.Length == 0) | |
| { | |
| probability = 0; | |
| flag = 0; | |
| return -1; | |
| } | |
| if (!useFallbackVad) | |
| { | |
| if (webGlInstanceId <= 0) | |
| { | |
| if (!TryInitializeWebGlVad()) | |
| return ProcessWithFallback(audioData, out probability, out flag); | |
| } | |
| try | |
| { | |
| int result = WebGLTenVad_Process(webGlInstanceId, audioData, audioData.Length, out probability, out flag); | |
| if (result == 0) | |
| return result; | |
| if (result == WebGlPending) | |
| return ProcessWithFallback(audioData, out probability, out flag); | |
| int state = SafeGetWebGlState(); | |
| EnableFallback($"WebGL ten_vad processing failed. result={result}, state={state}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| EnableFallback($"WebGL ten_vad processing bridge failed. {ex.Message}"); | |
| } | |
| if (vadHandle != IntPtr.Zero) | |
| { | |
| try | |
| { | |
| int result = ten_vad_process(vadHandle, audioData, (UIntPtr)audioData.Length, out probability, out flag); | |
| return result; | |
| } | |
| catch (DllNotFoundException ex) | |
| { | |
| EnableFallback($"Native VAD library '{DllName}' disappeared at runtime. {ex.Message}"); | |
| } | |
| catch (EntryPointNotFoundException ex) | |
| { | |
| EnableFallback($"Native VAD entry point missing at runtime. {ex.Message}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| EnableFallback($"Native VAD processing failed. {ex.Message}"); | |
| } | |
| } | |
| } | |
| return ProcessWithFallback(audioData, out probability, out flag); | |
| } | |
| public void Dispose() | |
| { | |
| if (isDisposed) | |
| return; | |
| if (!useFallbackVad && webGlInstanceId > 0) | |
| { | |
| try | |
| { | |
| WebGLTenVad_Destroy(webGlInstanceId); | |
| } | |
| catch (Exception) | |
| { | |
| // Ignore disposal failures for browser teardown. | |
| } | |
| webGlInstanceId = 0; | |
| } | |
| if (!useFallbackVad && vadHandle != IntPtr.Zero) | |
| { | |
| try | |
| { | |
| ten_vad_destroy(ref vadHandle); | |
| } | |
| catch (Exception) | |
| { | |
| // Ignore disposal failures for native plugin teardown. | |
| } | |
| vadHandle = IntPtr.Zero; | |
| } | |
| isDisposed = true; | |
| } | |
| private void EnableFallback(string reason) | |
| { | |
| if (useFallbackVad) | |
| return; | |
| useFallbackVad = true; | |
| webGlInstanceId = 0; | |
| Debug.LogWarning($"[TenVADRunner] Falling back to RMS VAD on WebGL. Reason: {reason}"); | |
| vadHandle = IntPtr.Zero; | |
| Debug.LogWarning($"[TenVADRunner] Falling back to simple RMS VAD. Reason: {reason}"); | |
| } | |
| private bool TryInitializeWebGlVad() | |
| { | |
| if (webGlInstanceId > 0) | |
| return true; | |
| int createResult; | |
| try | |
| { | |
| createResult = WebGLTenVad_Create(webGlHopSize, webGlThreshold); | |
| } | |
| catch (Exception ex) | |
| { | |
| EnableFallback($"WebGL ten_vad bridge is unavailable. {ex.Message}"); | |
| return false; | |
| } | |
| if (createResult > 0) | |
| { | |
| webGlInstanceId = createResult; | |
| return true; | |
| } | |
| if (createResult == WebGlPending || createResult == WebGlStateLoading) | |
| { | |
| return false; | |
| } | |
| int state = SafeGetWebGlState(); | |
| if (state == WebGlStateError || createResult < 0) | |
| { | |
| EnableFallback($"WebGL ten_vad initialization failed. createResult={createResult}, state={state}"); | |
| } | |
| return false; | |
| } | |
| private int SafeGetWebGlState() | |
| { | |
| try | |
| { | |
| return WebGLTenVad_GetState(); | |
| } | |
| catch | |
| { | |
| return WebGlStateError; | |
| } | |
| } | |
| private int ProcessWithFallback(short[] audioData, out float probability, out int flag) | |
| { | |
| double sumSquares = 0d; | |
| for (int i = 0; i < audioData.Length; i++) | |
| { | |
| float sample = audioData[i] / 32768f; | |
| sumSquares += sample * sample; | |
| } | |
| float rms = (float)Math.Sqrt(sumSquares / audioData.Length); | |
| float rawProbability = Mathf.Clamp01(rms * FallbackRmsScale); | |
| fallbackSmoothedProbability = Mathf.Lerp(fallbackSmoothedProbability, rawProbability, FallbackSmoothing); | |
| probability = fallbackSmoothedProbability; | |
| flag = probability >= fallbackThreshold ? 1 : 0; | |
| return 0; | |
| } | |
| } | |