From 8c6ff651ee3a6e95dda93f6dba2d219bcc9ee9ad Mon Sep 17 00:00:00 2001 From: Mason Bourgeois Date: Wed, 30 Jun 2021 11:07:58 -0500 Subject: [PATCH] Optimize asset loading & caching only fetch each resource from the network once, and only compile each wasm module once --- package.json | 2 +- src/loadProcessor.ts | 59 +++++++++++++++++++++++++++++--------------- test/index.js | 9 ++++--- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 2299fa3..6f50c1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "faust-loader", - "version": "1.1.1", + "version": "1.2.0", "main": "dist/faustLoader.js", "types": "dist/faustLoader.d.ts", "scripts": { diff --git a/src/loadProcessor.ts b/src/loadProcessor.ts index e2e1fc9..1a06b9a 100644 --- a/src/loadProcessor.ts +++ b/src/loadProcessor.ts @@ -10,7 +10,39 @@ function heap2Str(buf: Uint8Array) { return str; } -const loadedProcessors: string[] = []; +const processorModules: Record> = {}; +async function loadProcessorModule(context: IAudioContext, url: string) { + if (!context.audioWorklet) { + console.error( + "Error loading FaustAudioProcessorNode: standardized-audio-context AudioWorklet isn't supported in this environment." + ); + return null; + } + + const existing = processorModules[url]; + + if (existing) { + return existing; + } + + processorModules[url] = context.audioWorklet.addModule(url); + return processorModules[url]; +} + +const wasmModules: Record> = {}; +async function getWasmModule(url: string) { + 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, @@ -81,10 +113,12 @@ export default async function loadProcessor( baseURL: string ) { const cleanedBaseURL = baseURL.endsWith("/") ? baseURL : `${baseURL}/`; - // Load DSP wasm - const dspFile = await fetch(`${cleanedBaseURL}${name}.wasm`); - const dspBuffer = await dspFile.arrayBuffer(); - const dspModule = await WebAssembly.compile(dspBuffer); + + const [dspModule] = await Promise.all([ + getWasmModule(`${cleanedBaseURL}${name}.wasm`), + loadProcessorModule(context, `${cleanedBaseURL}${name}-processor.js`), + ]); + const dspInstance = await WebAssembly.instantiate(dspModule, importObject); const HEAPU8 = new Uint8Array(dspInstance.exports.memory.buffer); @@ -92,21 +126,6 @@ export default async function loadProcessor( const json_object = JSON.parse(json); const processorOptions = { wasm_module: dspModule, json: json }; - if (!context.audioWorklet) { - console.error( - "Error loading FaustAudioProcessorNode: standardized-audio-context AudioWorklet isn't supported in this environment." - ); - return null; - } - - // Load processor script, if necessary - if (!loadedProcessors.includes(name)) { - await context.audioWorklet.addModule( - `${cleanedBaseURL}${name}-processor.js` - ); - loadedProcessors.push(name); - } - const nodeOptions = { numberOfInputs: parseInt(json_object.inputs) > 0 ? 1 : 0, numberOfOutputs: parseInt(json_object.outputs) > 0 ? 1 : 0, diff --git a/test/index.js b/test/index.js index 976d5c9..bed7739 100644 --- a/test/index.js +++ b/test/index.js @@ -2,7 +2,10 @@ import { AudioContext } from "standardized-audio-context"; import createCompressor from "./Compressor.dsp"; const ctx = new AudioContext(); -createCompressor(ctx).then((node) => { - console.log(node); - console.log(node.getParams()); +Promise.all([ + createCompressor(ctx), + createCompressor(ctx), + createCompressor(ctx), +]).then((nodes) => { + console.log(nodes); });