From d9fbcb154d99aece97abf23e86d13bac9c9d1f3d Mon Sep 17 00:00:00 2001 From: Fr0stbyteR Date: Mon, 29 Apr 2024 21:17:27 +0800 Subject: [PATCH] adapt addSoundfiles method, bug fixes and optimizations --- package-lock.json | 8 ++++---- package.json | 2 +- src/FileManager.ts | 4 ++-- src/index.ts | 46 ++++++++++++++++++++++++++-------------------- webpack.config.js | 2 +- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index ffee1fd..7b8dffa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@babel/preset-typescript": "^7.18.6", "@babel/runtime": "^7.18.9", "@fortawesome/fontawesome-free": "^5.15.3", - "@grame/faustwasm": "^0.2.0", + "@grame/faustwasm": "^0.2.1", "@shren/faust-ui": "^1.1.9", "@types/bootstrap": "^4.6.0", "@types/jquery": "^3.5.5", @@ -1965,9 +1965,9 @@ } }, "node_modules/@grame/faustwasm": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@grame/faustwasm/-/faustwasm-0.2.0.tgz", - "integrity": "sha512-sikXJsvJK+YnijsorlfXICSic0kBh/Oxvpzi66zdHvK6FGMJXBjhMqg6uimP98HrQ33F79ADHnbdVha8hNp5uA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@grame/faustwasm/-/faustwasm-0.2.1.tgz", + "integrity": "sha512-46PyFhBYQJPr9P+fgXB3el4TP/L4zhSR5zC4xoVxWBsSTG5napVR4VIdHDmX0Ua9PSzpK7qww5PATLgG3gkYvA==", "dev": true, "dependencies": { "@types/emscripten": "^1.39.10" diff --git a/package.json b/package.json index 79d24a3..53ed348 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@babel/preset-typescript": "^7.18.6", "@babel/runtime": "^7.18.9", "@fortawesome/fontawesome-free": "^5.15.3", - "@grame/faustwasm": "^0.2.0", + "@grame/faustwasm": "^0.2.1", "@shren/faust-ui": "^1.1.9", "@types/bootstrap": "^4.6.0", "@types/jquery": "^3.5.5", diff --git a/src/FileManager.ts b/src/FileManager.ts index 6ecb046..bf5e3e8 100644 --- a/src/FileManager.ts +++ b/src/FileManager.ts @@ -6,7 +6,7 @@ type TOptions = { path?: string; mainFile?: string; selectHandler?: (name: string, content: string, mainCode: string) => any; - saveHandler?: (name: string, content: string, mainCode: string) => any; + saveHandler?: (name: string, content: string | Uint8Array, mainCode: string) => any; deleteHandler?: (name: string, mainCode: string) => any; mainFileChangeHandler?: (name: string, mainCode: string) => any; }; @@ -202,7 +202,7 @@ export class FileManager { const file = e.dataTransfer.files[0]; const reader = new FileReader(); reader.onload = () => { - const content = reader.result instanceof ArrayBuffer ? new Uint8Array(reader.result) : reader.result.toString(); + const content = typeof reader.result === "string" ? reader.result.toString() : new Uint8Array(reader.result); const fileName = this.newFile(file.name, content); this.select(fileName); }; diff --git a/src/index.ts b/src/index.ts index a61b43a..10396ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,15 +13,11 @@ // snippets // indexDB -import * as monaco from "monaco-editor"; -import { initVimMode, VimMode } from "monaco-vim"; +import type * as monaco from "monaco-editor"; +import type { VimMode } from "monaco-vim"; import webmidi, { Input, WebMidiEventConnected, WebMidiEventDisconnected } from "webmidi"; -import * as QRCode from "qrcode"; -import * as WaveSurfer from "wavesurfer.js"; -import * as JSZip from "jszip"; -import * as BrowserFS from "browserfs"; -import { FSModule } from "browserfs/dist/node/core/FS"; -import { FaustAudioWorkletNode, FaustCompiler, FaustMonoDspGenerator, FaustScriptProcessorNode, FaustSvgDiagrams, LibFaust, instantiateFaustModuleFromFile, FaustPolyDspGenerator, AudioData } from "@grame/faustwasm"; +import type { FSModule } from "browserfs/dist/node/core/FS"; +import type { FaustAudioWorkletNode, FaustCompiler, FaustScriptProcessorNode, LibFaust, AudioData } from "@grame/faustwasm"; import { Key2Midi } from "./Key2Midi"; import { Scope } from "./Scope"; import "bootstrap/js/dist/dropdown"; @@ -103,6 +99,7 @@ let server = "https://faustservicecloud.grame.fr"; const PROJECT_DIR = "/usr/share/project/"; $(async () => { + const { instantiateFaustModuleFromFile, LibFaust, FaustCompiler, FaustSvgDiagrams, FaustMonoDspGenerator, FaustPolyDspGenerator } = await import("@grame/faustwasm"); const faustModule = await instantiateFaustModuleFromFile("faustwasm/libfaust-wasm.js"); const libFaust = new LibFaust(faustModule); const faustCompiler = new FaustCompiler(libFaust); @@ -110,6 +107,9 @@ $(async () => { const faustPrimitiveLibFile = await fetch("primitives.lib"); const faustPrimitiveLib = await faustPrimitiveLibFile.text(); libFaust.fs().writeFile("/usr/share/faust/primitives.lib", faustPrimitiveLib); + + const BrowserFS = await import("browserfs"); + const { Buffer } = BrowserFS.BFSRequire("buffer"); const bfs = await new Promise((resolve, reject) => BrowserFS.configure({ fs: "IndexedDB", options: { storeName: "FaustIDE" } @@ -118,11 +118,12 @@ $(async () => { reject(e); } else { resolve(BrowserFS.BFSRequire("fs")); - // libFaust.fs().mkdir(PROJECT_DIR); - // libFaust.fs().mount(fs, { root: "/" }, PROJECT_DIR); - // resolve(bfs); } })); + + const JSZip = (await import("jszip") as any).default as import("jszip"); + const WaveSurfer = (await import("wavesurfer.js") as any).default as import("wavesurfer.js"); + const QRCode = await import("qrcode"); // TODO(ijc): This previously set `window.faust`; what depends on that being set? window.faustCompiler = faustCompiler; /** @@ -212,10 +213,10 @@ $(async () => { })); } }; - const loadSoundfiles = async (audioCtx: BaseAudioContext): Promise> => { + const loadSoundfiles = async (audioCtx: BaseAudioContext, soundfileList: string[]): Promise> => { const map = {} as Record; const files = libFaust.fs().readdir(PROJECT_DIR) as string[]; - await Promise.all(files.filter(n => n.match(/\.(wav|mp3|ogg|flac|aac)$/)).map(async (filename) => { + await Promise.all(files.filter(n => soundfileList.indexOf(n) !== -1).map(async (filename) => { const ui8Array = libFaust.fs().readFile(PROJECT_DIR + filename); try { const audioBuffer = await audioCtx.decodeAudioData(ui8Array.buffer); @@ -332,17 +333,20 @@ $(async () => { if (mediaLengthRaf) cancelAnimationFrame(mediaLengthRaf); mediaLengthRaf = requestAnimationFrame(() => mediaLengthDisplay(t)); }; - const soundfiles = await loadSoundfiles(audioCtx); try { // const getDiagramResult = getDiagram(code); // if (!getDiagramResult.success) throw getDiagramResult.error; if (voices) { const factory = await new FaustPolyDspGenerator().compile(faustCompiler, "main", code, args.join(" ")); - factory.voiceFactory.soundfiles = soundfiles; + const soundfileList = factory.getSoundfileList(); + const soundfiles = await loadSoundfiles(audioCtx, soundfileList); + factory.addSoundfiles(soundfiles); node = await factory.createNode(audioCtx, voices, "main", undefined, undefined, undefined, !useWorklet, bufferSize); } else { const factory = await new FaustMonoDspGenerator().compile(faustCompiler, "main", code, args.join(" ")); - factory.factory.soundfiles = soundfiles; + const soundfileList = factory.getSoundfileList(); + const soundfiles = await loadSoundfiles(audioCtx, soundfileList); + factory.addSoundfiles(soundfiles); node = await factory.createNode(audioCtx, "main", undefined, !useWorklet, bufferSize); } node.setPlotHandler(plotHandler); @@ -546,7 +550,7 @@ $(async () => { path: PROJECT_DIR, mainFile: compileOptions.mainFile, selectHandler: (fileName, content) => editor.setValue(content), - saveHandler: async (fileName: string, content: string, mainCode: string) => { + saveHandler: async (fileName: string, content: string | Uint8Array, mainCode: string) => { /* let project: { [name: string]: string }; try { @@ -569,7 +573,7 @@ $(async () => { else resolve(); })); } - await new Promise((resolve, reject) => bfs.writeFile(fileName, content, { encoding: "utf8" }, (e) => { + await new Promise((resolve, reject) => bfs.writeFile(fileName, typeof content === "string" ? content : Buffer.from(content), typeof content === "string" ? { encoding: "utf8" } : {}, (e) => { if (e) reject(e); else resolve(); })); @@ -728,10 +732,11 @@ $(async () => { if (compileOptions.plotMode === "offline") { const code = uiEnv.fileManager.mainCode; const { args, plot, plotSR } = compileOptions; - const soundfiles = await loadSoundfiles(new OfflineAudioContext({ sampleRate: plotSR, length: 0 })); const generator = new FaustMonoDspGenerator(); await generator.compile(faustCompiler, "main", code, args.join(" ")); - generator.factory.soundfiles = soundfiles; + const soundfileList = generator.getSoundfileList(); + const soundfiles = await loadSoundfiles(new OfflineAudioContext({ sampleRate: plotSR, length: 0 }), soundfileList); + generator.addSoundfiles(soundfiles); const processor = await generator.createOfflineProcessor(plotSR, 128); const output = processor.render([], plot); uiEnv.analyser.plotHandler(output, 0, undefined, true); @@ -1924,6 +1929,7 @@ process = ba.pulsen(1, ba.hz2midikey(freq) * 1000) : pm.marimba(freq, 0, 7000, 0 }; effect = dm.freeverb_demo;`; const monaco = await import("monaco-editor"); + const { initVimMode } = await import("monaco-vim"); const { faustLang, providers } = await faustLangRegister(monaco, libFaust); let saveCode = false; try { diff --git a/webpack.config.js b/webpack.config.js index 9bbb901..537e9bf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -87,7 +87,7 @@ const config = { cleanupOutdatedCaches: true, clientsClaim: true, skipWaiting: true, - maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, + maximumFileSizeToCacheInBytes: 16 * 1024 * 1024, }) ] };