UNPKG

faust-loader

Version:

Webpack loader for Faust .dsp files

150 lines (149 loc) 5.77 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const FaustAudioProcessorNode_1 = __importDefault(require("./FaustAudioProcessorNode")); function heap2Str(buf) { let str = ""; let i = 0; while (buf[i] !== 0) { str += String.fromCharCode(buf[i++]); } return str; } function loadProcessorModule(context, url) { return __awaiter(this, void 0, void 0, function* () { if (!context.audioWorklet) { console.error("Error loading FaustAudioProcessorNode: standardized-audio-context AudioWorklet isn't supported in this environment."); return null; } const processorBlob = yield (yield fetch(url)).blob(); const processorURL = URL.createObjectURL(processorBlob); // The audio worklet handles caching of modules by URL in the same context. // Adding an already-loaded module to a different context will trigger another // network request, but the browser cache should catch it. return context.audioWorklet.addModule(processorURL); }); } const wasmModules = {}; function getWasmModule(url) { return __awaiter(this, void 0, void 0, function* () { const existing = wasmModules[url]; if (existing) { return existing; } wasmModules[url] = fetch(url) .then((response) => response.arrayBuffer()) .then((dspBuffer) => WebAssembly.compile(dspBuffer)); return wasmModules[url]; }); } const importObject = { env: { memoryBase: 0, tableBase: 0, _abs: Math.abs, // Float version _acosf: Math.acos, _asinf: Math.asin, _atanf: Math.atan, _atan2f: Math.atan2, _ceilf: Math.ceil, _cosf: Math.cos, _expf: Math.exp, _floorf: Math.floor, _fmodf: (x, y) => x % y, _logf: Math.log, _log10f: Math.log10, _max_f: Math.max, _min_f: Math.min, _remainderf: (x, y) => x - Math.round(x / y) * y, _powf: Math.pow, _roundf: Math.fround, _sinf: Math.sin, _sqrtf: Math.sqrt, _tanf: Math.tan, _acoshf: Math.acosh, _asinhf: Math.asinh, _atanhf: Math.atanh, _coshf: Math.cosh, _sinhf: Math.sinh, _tanhf: Math.tanh, // Double version _acos: Math.acos, _asin: Math.asin, _atan: Math.atan, _atan2: Math.atan2, _ceil: Math.ceil, _cos: Math.cos, _exp: Math.exp, _floor: Math.floor, _fmod: (x, y) => x % y, _log: Math.log, _log10: Math.log10, _max_: Math.max, _min_: Math.min, _remainder: (x, y) => x - Math.round(x / y) * y, _pow: Math.pow, _round: Math.fround, _sin: Math.sin, _sqrt: Math.sqrt, _tan: Math.tan, _acosh: Math.acosh, _asinh: Math.asinh, _atanh: Math.atanh, _cosh: Math.cosh, _sinh: Math.sinh, _tanh: Math.tanh, table: new WebAssembly.Table({ initial: 0, element: "anyfunc" }), }, }; function loadProcessor(context, name, wasmUrl, processorUrl) { return __awaiter(this, void 0, void 0, function* () { const [dspModule] = yield Promise.all([ getWasmModule(wasmUrl), loadProcessorModule(context, processorUrl), ]); const dspInstance = yield WebAssembly.instantiate(dspModule, importObject); const HEAPU8 = new Uint8Array(dspInstance.exports.memory.buffer); const json = heap2Str(HEAPU8); const json_object = JSON.parse(json); const processorOptions = { wasm_module: dspModule, json: json }; const nodeOptions = { numberOfInputs: parseInt(json_object.inputs) > 0 ? 1 : 0, numberOfOutputs: parseInt(json_object.outputs) > 0 ? 1 : 0, channelCount: Math.max(1, parseInt(json_object.inputs)), outputChannelCount: [parseInt(json_object.outputs)], channelCountMode: "explicit", channelInterpretation: "speakers", processorOptions, }; const FaustAudioProcessorNode = FaustAudioProcessorNode_1.default(); if (!FaustAudioProcessorNode) { console.error("Error loading FaustAudioProcessorNode: Web audio API isn't supported in this environment."); return null; } try { const node = new FaustAudioProcessorNode(context, name, nodeOptions); node.onprocessorerror = () => { console.log(`An error from ${name}-processor was detected.`); }; return node; } catch (e) { console.error("FaustAudioProcessorNode initialization failed: make sure you are passing a standardized-audio-context AudioContext."); console.error(e); } }); } exports.default = loadProcessor;