moonshine-tiny-ko-unity / Assets /Plugins /WebGL /webgl_tenvad.jslib
Sky-Kim's picture
Initial commit
6ac63e1
mergeInto(LibraryManager.library, {
$WebGLTenVad: {
module: null,
modulePromise: null,
handles: null,
nextInstanceId: 1,
ready: false,
loading: false,
failed: false,
lastError: "",
ensureHandles: function() {
if (!WebGLTenVad.handles) {
WebGLTenVad.handles = {};
}
},
getStreamingAssetsBaseUrl: function() {
var basePath = "StreamingAssets";
if (typeof Module !== "undefined") {
if (Module.streamingAssetsUrl) {
basePath = Module.streamingAssetsUrl;
} else if (Module.absoluteStreamingAssetsUrl) {
basePath = Module.absoluteStreamingAssetsUrl;
}
}
if (basePath.length > 0 && basePath.charAt(basePath.length - 1) === "/") {
basePath = basePath.substring(0, basePath.length - 1);
}
return basePath;
},
buildStreamingAssetUrl: function(fileName) {
var combinedPath = WebGLTenVad.getStreamingAssetsBaseUrl() + "/" + fileName;
if (typeof URL !== "undefined" && typeof document !== "undefined" && document.baseURI) {
try {
return new URL(combinedPath, document.baseURI).toString();
} catch (err) {
// Fallback to plain path below.
}
}
return combinedPath;
},
ensureModuleLoading: function() {
var vad = WebGLTenVad;
if (vad.ready && vad.module) {
return Promise.resolve(vad.module);
}
if (vad.modulePromise) {
return vad.modulePromise;
}
var moduleUrl = WebGLTenVad.buildStreamingAssetUrl("ten_vad.js");
var wasmUrl = WebGLTenVad.buildStreamingAssetUrl("ten_vad.wasm");
vad.loading = true;
vad.failed = false;
vad.lastError = "";
vad.modulePromise = import(moduleUrl)
.then(function(namespace) {
var createFactory = null;
if (namespace) {
if (typeof namespace.default === "function") {
createFactory = namespace.default;
} else if (typeof namespace.createVADModule === "function") {
createFactory = namespace.createVADModule;
}
}
if (!createFactory) {
throw new Error("ten_vad.js does not export a VAD module factory.");
}
return createFactory({
locateFile: function(path) {
if (path === "ten_vad.wasm") {
return wasmUrl;
}
var slashIndex = wasmUrl.lastIndexOf("/");
if (slashIndex >= 0) {
return wasmUrl.substring(0, slashIndex + 1) + path;
}
return path;
}
});
})
.then(function(moduleInstance) {
if (!moduleInstance || typeof moduleInstance._ten_vad_create !== "function") {
throw new Error("Loaded module is missing ten_vad exports.");
}
vad.module = moduleInstance;
vad.ready = true;
vad.loading = false;
vad.failed = false;
console.log("[WebGLTenVad] ten_vad module loaded.");
return moduleInstance;
})
["catch"](function(err) {
vad.module = null;
vad.ready = false;
vad.loading = false;
vad.failed = true;
vad.lastError = err && err.message ? err.message : String(err);
console.warn("[WebGLTenVad] Failed to load ten_vad module:", err);
return null;
});
return vad.modulePromise;
},
createInstance: function(hopSize, threshold) {
var vad = WebGLTenVad;
if (!vad.ready || !vad.module) {
if (vad.failed) {
return -1;
}
WebGLTenVad.ensureModuleLoading();
return -2;
}
var moduleInstance = vad.module;
var handlePtr = moduleInstance._malloc(4);
if (!handlePtr) {
vad.lastError = "Failed to allocate handle pointer.";
return -1;
}
try {
var result = moduleInstance._ten_vad_create(handlePtr, hopSize, threshold);
if (result !== 0) {
vad.lastError = "ten_vad_create failed: " + result;
return -1;
}
var nativeHandle = moduleInstance.HEAP32[handlePtr >> 2];
if (!nativeHandle) {
vad.lastError = "ten_vad_create returned an invalid handle.";
return -1;
}
WebGLTenVad.ensureHandles();
var instanceId = vad.nextInstanceId++;
vad.handles[instanceId] = {
nativeHandle: nativeHandle,
inputPtr: 0,
inputCapacity: 0,
probPtr: 0,
flagPtr: 0
};
return instanceId;
} catch (err) {
vad.lastError = err && err.message ? err.message : String(err);
console.warn("[WebGLTenVad] createInstance failed:", err);
return -1;
} finally {
moduleInstance._free(handlePtr);
}
},
process: function(instanceId, audioPtr, audioLength, outProbabilityPtr, outFlagPtr) {
var vad = WebGLTenVad;
if (!vad.ready || !vad.module) {
if (vad.failed) {
return -1;
}
WebGLTenVad.ensureModuleLoading();
return -2;
}
WebGLTenVad.ensureHandles();
var instance = vad.handles[instanceId];
if (!instance || !instance.nativeHandle) {
vad.lastError = "Invalid instance id: " + instanceId;
return -1;
}
if (!audioPtr || audioLength <= 0 || !outProbabilityPtr || !outFlagPtr) {
vad.lastError = "Invalid process arguments.";
return -1;
}
var moduleInstance = vad.module;
try {
if (!instance.inputPtr || instance.inputCapacity < audioLength) {
if (instance.inputPtr) {
moduleInstance._free(instance.inputPtr);
}
instance.inputPtr = moduleInstance._malloc(audioLength * 2);
instance.inputCapacity = instance.inputPtr ? audioLength : 0;
if (!instance.inputPtr) {
vad.lastError = "Failed to allocate process input buffer.";
return -1;
}
}
if (!instance.probPtr) {
instance.probPtr = moduleInstance._malloc(4);
if (!instance.probPtr) {
vad.lastError = "Failed to allocate process probability buffer.";
return -1;
}
}
if (!instance.flagPtr) {
instance.flagPtr = moduleInstance._malloc(4);
if (!instance.flagPtr) {
vad.lastError = "Failed to allocate process flag buffer.";
return -1;
}
}
var sourceData = HEAP16.subarray(audioPtr >> 1, (audioPtr >> 1) + audioLength);
moduleInstance.HEAP16.set(sourceData, instance.inputPtr >> 1);
var result = moduleInstance._ten_vad_process(instance.nativeHandle, instance.inputPtr, audioLength, instance.probPtr, instance.flagPtr);
if (result !== 0) {
vad.lastError = "ten_vad_process failed: " + result;
return result;
}
HEAPF32[outProbabilityPtr >> 2] = moduleInstance.HEAPF32[instance.probPtr >> 2];
HEAP32[outFlagPtr >> 2] = moduleInstance.HEAP32[instance.flagPtr >> 2];
return 0;
} catch (err) {
vad.lastError = err && err.message ? err.message : String(err);
console.warn("[WebGLTenVad] process failed:", err);
return -1;
}
},
destroyInstance: function(instanceId) {
var vad = WebGLTenVad;
WebGLTenVad.ensureHandles();
var instance = vad.handles[instanceId];
if (!instance || !instance.nativeHandle) {
return 0;
}
delete vad.handles[instanceId];
if (!vad.ready || !vad.module) {
return 0;
}
var moduleInstance = vad.module;
var handlePtr = moduleInstance._malloc(4);
if (!handlePtr) {
return -1;
}
try {
if (instance.inputPtr) {
moduleInstance._free(instance.inputPtr);
instance.inputPtr = 0;
}
if (instance.probPtr) {
moduleInstance._free(instance.probPtr);
instance.probPtr = 0;
}
if (instance.flagPtr) {
moduleInstance._free(instance.flagPtr);
instance.flagPtr = 0;
}
moduleInstance.HEAP32[handlePtr >> 2] = instance.nativeHandle;
return moduleInstance._ten_vad_destroy(handlePtr);
} catch (err) {
console.warn("[WebGLTenVad] destroyInstance failed:", err);
return -1;
} finally {
moduleInstance._free(handlePtr);
}
},
getState: function() {
var vad = WebGLTenVad;
if (vad.ready && vad.module) {
return 1;
}
if (vad.failed) {
return -1;
}
if (vad.loading || vad.modulePromise) {
return 0;
}
return 0;
}
},
WebGLTenVad_Create__deps: ["$WebGLTenVad"],
WebGLTenVad_Create: function(hopSize, threshold) {
return WebGLTenVad.createInstance(hopSize, threshold);
},
WebGLTenVad_Process__deps: ["$WebGLTenVad"],
WebGLTenVad_Process: function(instanceId, audioPtr, audioLength, outProbabilityPtr, outFlagPtr) {
return WebGLTenVad.process(instanceId, audioPtr, audioLength, outProbabilityPtr, outFlagPtr);
},
WebGLTenVad_Destroy__deps: ["$WebGLTenVad"],
WebGLTenVad_Destroy: function(instanceId) {
return WebGLTenVad.destroyInstance(instanceId);
},
WebGLTenVad_GetState__deps: ["$WebGLTenVad"],
WebGLTenVad_GetState: function() {
return WebGLTenVad.getState();
}
});