From 932799092b9713e3c7e82777fa94681b5411fb79 Mon Sep 17 00:00:00 2001 From: terry feng Date: Sat, 24 Aug 2024 23:20:57 -0700 Subject: [PATCH 01/13] create rainfly directory --- src/rainfly/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/rainfly/README.md diff --git a/src/rainfly/README.md b/src/rainfly/README.md new file mode 100644 index 000000000..96fe6c33f --- /dev/null +++ b/src/rainfly/README.md @@ -0,0 +1,5 @@ +# Rainfly + +WIP + +This is the directory for Rainfly - An AudioWorklet DSP Playground for Chromium Web Audio API Project (2024) From dd4ffa7075df762dc03d48f446dd7d2be7a1dfa9 Mon Sep 17 00:00:00 2001 From: Tristan <24882191+Kizjkre@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:16:41 -0700 Subject: [PATCH 02/13] Add rainfly code from https://github.com/Kizjkre/rainfly --- .eleventyignore | 3 +- src/rainfly/.eslintrc.json | 27 ++ src/rainfly/.gitignore | 29 ++ src/rainfly/.npmrc | 1 + src/rainfly/README.md | 25 +- src/rainfly/jsconfig.json | 19 ++ src/rainfly/package.json | 36 +++ src/rainfly/postcss.config.js | 7 + src/rainfly/src/app.css | 173 ++++++++++++ src/rainfly/src/app.d.ts | 13 + src/rainfly/src/app.html | 12 + src/rainfly/src/lib/actions/click-outside.js | 13 + src/rainfly/src/lib/actions/portal.js | 46 +++ src/rainfly/src/lib/assets/logo.svg | 7 + src/rainfly/src/lib/assets/player-pause.svg | 1 + src/rainfly/src/lib/assets/player-play.svg | 1 + src/rainfly/src/lib/assets/player-stop.svg | 1 + src/rainfly/src/lib/assets/splash.svg | 46 +++ .../src/lib/components/ActionButton.svelte | 71 +++++ src/rainfly/src/lib/components/Editor.svelte | 264 ++++++++++++++++++ src/rainfly/src/lib/components/Modal.svelte | 35 +++ src/rainfly/src/lib/components/Toast.svelte | 20 ++ src/rainfly/src/lib/components/Tooltip.svelte | 91 ++++++ .../src/lib/components/Visualizer.svelte | 230 +++++++++++++++ src/rainfly/src/lib/components/nav/Nav.svelte | 16 ++ .../lib/components/nav/NavDropdownItem.svelte | 8 + .../src/lib/components/nav/NavItem.svelte | 46 +++ .../components/nav/items/NavExamples.svelte | 39 +++ .../lib/components/nav/items/NavFile.svelte | 80 ++++++ .../lib/components/nav/items/NavHelp.svelte | 45 +++ src/rainfly/src/lib/stores/status.js | 13 + src/rainfly/src/lib/stores/vim-status.js | 8 + .../src/lib/utils/audio-buffer-to-wav.js | 152 ++++++++++ src/rainfly/src/lib/utils/audio-host.js | 145 ++++++++++ src/rainfly/src/lib/utils/click-outside.js | 11 + src/rainfly/src/lib/utils/file-utils.js | 35 +++ src/rainfly/src/lib/utils/monaco.js | 24 ++ src/rainfly/src/routes/+layout.js | 1 + src/rainfly/src/routes/+layout.svelte | 9 + src/rainfly/src/routes/+page.svelte | 81 ++++++ src/rainfly/static/examples/bypass/main.js | 9 + .../static/examples/bypass/processor.js | 15 + src/rainfly/static/examples/sine/main.js | 7 + src/rainfly/static/examples/sine/processor.js | 31 ++ src/rainfly/static/favicon.svg | 5 + .../static/processor/recorder-processor.js | 18 ++ src/rainfly/svelte.config.js | 18 ++ src/rainfly/tailwind.config.js | 22 ++ src/rainfly/vite.config.js | 11 + 49 files changed, 2017 insertions(+), 3 deletions(-) create mode 100644 src/rainfly/.eslintrc.json create mode 100644 src/rainfly/.gitignore create mode 100644 src/rainfly/.npmrc create mode 100644 src/rainfly/jsconfig.json create mode 100644 src/rainfly/package.json create mode 100644 src/rainfly/postcss.config.js create mode 100644 src/rainfly/src/app.css create mode 100644 src/rainfly/src/app.d.ts create mode 100644 src/rainfly/src/app.html create mode 100644 src/rainfly/src/lib/actions/click-outside.js create mode 100644 src/rainfly/src/lib/actions/portal.js create mode 100644 src/rainfly/src/lib/assets/logo.svg create mode 100644 src/rainfly/src/lib/assets/player-pause.svg create mode 100644 src/rainfly/src/lib/assets/player-play.svg create mode 100644 src/rainfly/src/lib/assets/player-stop.svg create mode 100644 src/rainfly/src/lib/assets/splash.svg create mode 100644 src/rainfly/src/lib/components/ActionButton.svelte create mode 100644 src/rainfly/src/lib/components/Editor.svelte create mode 100644 src/rainfly/src/lib/components/Modal.svelte create mode 100644 src/rainfly/src/lib/components/Toast.svelte create mode 100644 src/rainfly/src/lib/components/Tooltip.svelte create mode 100644 src/rainfly/src/lib/components/Visualizer.svelte create mode 100644 src/rainfly/src/lib/components/nav/Nav.svelte create mode 100644 src/rainfly/src/lib/components/nav/NavDropdownItem.svelte create mode 100644 src/rainfly/src/lib/components/nav/NavItem.svelte create mode 100644 src/rainfly/src/lib/components/nav/items/NavExamples.svelte create mode 100644 src/rainfly/src/lib/components/nav/items/NavFile.svelte create mode 100644 src/rainfly/src/lib/components/nav/items/NavHelp.svelte create mode 100644 src/rainfly/src/lib/stores/status.js create mode 100644 src/rainfly/src/lib/stores/vim-status.js create mode 100644 src/rainfly/src/lib/utils/audio-buffer-to-wav.js create mode 100644 src/rainfly/src/lib/utils/audio-host.js create mode 100644 src/rainfly/src/lib/utils/click-outside.js create mode 100644 src/rainfly/src/lib/utils/file-utils.js create mode 100644 src/rainfly/src/lib/utils/monaco.js create mode 100644 src/rainfly/src/routes/+layout.js create mode 100644 src/rainfly/src/routes/+layout.svelte create mode 100644 src/rainfly/src/routes/+page.svelte create mode 100644 src/rainfly/static/examples/bypass/main.js create mode 100644 src/rainfly/static/examples/bypass/processor.js create mode 100644 src/rainfly/static/examples/sine/main.js create mode 100644 src/rainfly/static/examples/sine/processor.js create mode 100644 src/rainfly/static/favicon.svg create mode 100644 src/rainfly/static/processor/recorder-processor.js create mode 100644 src/rainfly/svelte.config.js create mode 100644 src/rainfly/tailwind.config.js create mode 100644 src/rainfly/vite.config.js diff --git a/.eleventyignore b/.eleventyignore index 1f9e52b62..7f9ef4297 100644 --- a/.eleventyignore +++ b/.eleventyignore @@ -1,3 +1,4 @@ node_modules/ ./src/archive/ -**/README.md \ No newline at end of file +.src/rainfly/ +**/README.md diff --git a/src/rainfly/.eslintrc.json b/src/rainfly/.eslintrc.json new file mode 100644 index 000000000..29f9114dd --- /dev/null +++ b/src/rainfly/.eslintrc.json @@ -0,0 +1,27 @@ +{ + "env": { + "es6": true, + "browser": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "plugin:svelte/recommended", + "google" + ], + "ignorePatterns": [ + "build/", + ".svelte-kit/", + "dist/", + "static/" + ], + "globals": { + "window": "readonly", + "document": "readonly" + }, + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "rules": {} +} \ No newline at end of file diff --git a/src/rainfly/.gitignore b/src/rainfly/.gitignore new file mode 100644 index 000000000..1fd341645 --- /dev/null +++ b/src/rainfly/.gitignore @@ -0,0 +1,29 @@ +node_modules + +# Output +.output +.vercel +/.svelte-kit +/build + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.* +!.env.example +!.env.test + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +# IDE +.idea +.vscode + +# Lockfiles +package-lock.json +bun.lockb diff --git a/src/rainfly/.npmrc b/src/rainfly/.npmrc new file mode 100644 index 000000000..b6f27f135 --- /dev/null +++ b/src/rainfly/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/src/rainfly/README.md b/src/rainfly/README.md index 96fe6c33f..522a1b63e 100644 --- a/src/rainfly/README.md +++ b/src/rainfly/README.md @@ -1,5 +1,26 @@ # Rainfly +
+ Rainfly logo +
-WIP +**An AudioWorklet DSP Playground for Chromium Web Audio API Project (2024)** -This is the directory for Rainfly - An AudioWorklet DSP Playground for Chromium Web Audio API Project (2024) +## Developing +Install dependencies with `npm install` (or `pnpm install` or `yarn`), and then start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of Rainfly: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. diff --git a/src/rainfly/jsconfig.json b/src/rainfly/jsconfig.json new file mode 100644 index 000000000..fc93cbd94 --- /dev/null +++ b/src/rainfly/jsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/src/rainfly/package.json b/src/rainfly/package.json new file mode 100644 index 000000000..37703ebf9 --- /dev/null +++ b/src/rainfly/package.json @@ -0,0 +1,36 @@ +{ + "name": "rainfly", + "version": "1.0.0-beta", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", + "lint": "eslint --fix ." + }, + "devDependencies": { + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@types/eslint": "^9.6.0", + "autoprefixer": "^10.4.19", + "eslint": "^8.57.0", + "eslint-config-google": "^0.14.0", + "eslint-plugin-svelte": "^2.36.0", + "globals": "^15.0.0", + "monaco-editor": "^0.50.0", + "postcss": "^8.4.40", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "tailwindcss": "^3.4.7", + "typescript": "^5.0.0", + "vite": "^5.0.3" + }, + "type": "module", + "dependencies": { + "@sveltejs/adapter-static": "^3.0.4", + "jszip": "^3.10.1", + "monaco-vim": "^0.4.1" + } +} diff --git a/src/rainfly/postcss.config.js b/src/rainfly/postcss.config.js new file mode 100644 index 000000000..ab16b20e1 --- /dev/null +++ b/src/rainfly/postcss.config.js @@ -0,0 +1,7 @@ +// noinspection JSUnusedGlobalSymbols +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/src/rainfly/src/app.css b/src/rainfly/src/app.css new file mode 100644 index 000000000..f069c597f --- /dev/null +++ b/src/rainfly/src/app.css @@ -0,0 +1,173 @@ +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&family=Anonymous+Pro:ital,wght@0,400;0,700;1,400;1,700&display=swap'); + +@tailwind base; +@tailwind components; +@tailwind utilities; + +@keyframes left-bounce-expand-in { + 0% { + transform: translateX(-100%) scaleY(0.5); + opacity: 0; + } + + 80% { + transform: translateX(40%) scaleY(1); + opacity: 1; + } + + 100% { + transform: translateX(0.25rem); + } +} + +@keyframes left-bounce-shrink-out { + 0% { + transform: translateX(0.25rem); + } + + 20% { + transform: translateX(40%) scaleY(1); + opacity: 1; + } + + 100% { + transform: translateX(-100%) scaleY(0.5); + opacity: 0; + } +} + +@keyframes right-bounce-in { + 0% { + transform: translateX(100%) scaleY(0.5); + opacity: 0; + } + + 80% { + transform: translateX(-5rem) scaleY(1); + opacity: 1; + } + + 100% { + transform: translateX(0); + } +} + +@keyframes right-bounce-out { + 0% { + transform: translateX(0); + } + + 20% { + transform: translateX(-5rem) scaleY(1); + opacity: 1; + } + + 100% { + transform: translateX(100%) scaleY(0.5); + opacity: 0; + } +} + +@keyframes unfold { + 0% { + max-height: 0; + opacity: 0; + } + + 50% { + opacity: 1; + } + + 100% { + max-height: 10rem; + } +} + +@keyframes fold { + 0% { + max-height: 10rem; + } + + 50% { + opacity: 1; + } + + 100% { + max-height: 0; + opacity: 0; + } +} + +@keyframes appear { + 0% { + opacity: 0; + transform: scale(.9); + } + + 100% { + opacity: 1; + transform: scale(1); + } +} + +@keyframes disappear { + 0% { + opacity: 1; + transform: scale(1); + } + + 100% { + opacity: 0; + transform: scale(0.9); + } +} + +body, html { + height: 100vh; + margin: 0; + overflow: hidden; + width: 100vw; +} + +.fab-in { + animation: left-bounce-expand-in 0.25s ease-in-out forwards; +} + +.fab-out { + animation: left-bounce-shrink-out 0.25s ease-in-out forwards; +} + +.fold { + @apply overflow-hidden; + animation: fold 0.2s ease-in-out forwards; +} + +.unfold { + @apply overflow-hidden; + animation: unfold 0.2s ease-in-out forwards; +} + +.toast-in { + animation: right-bounce-in 0.25s ease-in-out forwards; +} + +.toast-out { + animation: right-bounce-out 0.25s ease-in-out forwards; +} + +.tooltip-in { + animation: appear 0.05s ease-in-out forwards; +} + +.tooltip-out { + animation: disappear 0.05s ease-in-out forwards; +} + +.vimBar { + @apply w-full h-6 px-1 border-none bg-gray-200 text-sm items-center; + display: flex !important; +} + +.vimBar input { + @apply outline-none bg-transparent border-none; +} diff --git a/src/rainfly/src/app.d.ts b/src/rainfly/src/app.d.ts new file mode 100644 index 000000000..743f07b2e --- /dev/null +++ b/src/rainfly/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/src/rainfly/src/app.html b/src/rainfly/src/app.html new file mode 100644 index 000000000..1391f8848 --- /dev/null +++ b/src/rainfly/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/rainfly/src/lib/actions/click-outside.js b/src/rainfly/src/lib/actions/click-outside.js new file mode 100644 index 000000000..522008dad --- /dev/null +++ b/src/rainfly/src/lib/actions/click-outside.js @@ -0,0 +1,13 @@ +export const nodes = new Map(); + +/** + * Listen for clicks outside of the node and call the callback. + * @param {HTMLElement} node - The node to listen for clicks outside of + * @param {Function} callback - callback when click outside occurs + * @return {Object.} Object with destroy method to remove + */ +export const clickOutside = (node, callback) => { + nodes.set(node, callback); + + return {destroy: () => nodes.delete(node)}; +}; diff --git a/src/rainfly/src/lib/actions/portal.js b/src/rainfly/src/lib/actions/portal.js new file mode 100644 index 000000000..2630f6823 --- /dev/null +++ b/src/rainfly/src/lib/actions/portal.js @@ -0,0 +1,46 @@ +// REF: https://github.com/romkor/svelte-portal/blob/a650e7b762344a1bb0ad9e218660ed1ee66e3f90/src/Portal.svelte + +import {tick} from 'svelte'; + +/** + * Creates a portal to render an element at a target location. + * + * @param {HTMLElement} el - The element to render in the portal. + * @param {string|HTMLElement} target - The target location where the element + * ``will be rendered. Can be a CSS selector string or an HTMLElement. + * @return {Object} An object containing the update and destroy methods for + * ``the portal. + */ +export const portal = (el, target = 'div') => { + let targetEl; + const update = async (/** @type {string|HTMLElement} */ newTarget) => { + target = newTarget; + if (typeof target === 'string') { + targetEl = document.querySelector(target); + if (targetEl === null) { + await tick(); + targetEl = document.querySelector(target); + } + if (targetEl === null) { + throw new Error(`No element found matching css selector: "${target}"`); + } + } else if (target instanceof HTMLElement) { + targetEl = target; + } else { + // eslint-disable-next-line max-len + throw new TypeError(`Unknown portal target type: ${target === null ? 'null' : typeof target}. Allowed types: string (CSS selector) or HTMLElement.`); + } + targetEl.appendChild(el); + el.hidden = false; + }; + + const destroy = () => el.parentNode && el.parentNode.removeChild(el); + + // noinspection JSIgnoredPromiseFromCall + update(target); + + return { + update, + destroy, + }; +}; diff --git a/src/rainfly/src/lib/assets/logo.svg b/src/rainfly/src/lib/assets/logo.svg new file mode 100644 index 000000000..9982303b6 --- /dev/null +++ b/src/rainfly/src/lib/assets/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/rainfly/src/lib/assets/player-pause.svg b/src/rainfly/src/lib/assets/player-pause.svg new file mode 100644 index 000000000..7f0cfffe9 --- /dev/null +++ b/src/rainfly/src/lib/assets/player-pause.svg @@ -0,0 +1 @@ + diff --git a/src/rainfly/src/lib/assets/player-play.svg b/src/rainfly/src/lib/assets/player-play.svg new file mode 100644 index 000000000..51f12e460 --- /dev/null +++ b/src/rainfly/src/lib/assets/player-play.svg @@ -0,0 +1 @@ + diff --git a/src/rainfly/src/lib/assets/player-stop.svg b/src/rainfly/src/lib/assets/player-stop.svg new file mode 100644 index 000000000..b9b29d292 --- /dev/null +++ b/src/rainfly/src/lib/assets/player-stop.svg @@ -0,0 +1 @@ + diff --git a/src/rainfly/src/lib/assets/splash.svg b/src/rainfly/src/lib/assets/splash.svg new file mode 100644 index 000000000..ef86e5c99 --- /dev/null +++ b/src/rainfly/src/lib/assets/splash.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/rainfly/src/lib/components/ActionButton.svelte b/src/rainfly/src/lib/components/ActionButton.svelte new file mode 100644 index 000000000..36e46db60 --- /dev/null +++ b/src/rainfly/src/lib/components/ActionButton.svelte @@ -0,0 +1,71 @@ + + +
+ + +
+ + diff --git a/src/rainfly/src/lib/components/Editor.svelte b/src/rainfly/src/lib/components/Editor.svelte new file mode 100644 index 000000000..42825e967 --- /dev/null +++ b/src/rainfly/src/lib/components/Editor.svelte @@ -0,0 +1,264 @@ + + + +
+
+
+ {editorType === EditorTypes.processor ? 'AudioWorkletProcessor' : 'Main'} +
+ {#if editorType === EditorTypes.main} + + {/if} +
+
+
+
+
+
+ +{errorMsg} + +{#if editorType === EditorTypes.main} + + Toggle Vim mode + +{/if} + + diff --git a/src/rainfly/src/lib/components/Modal.svelte b/src/rainfly/src/lib/components/Modal.svelte new file mode 100644 index 000000000..2b43c6e90 --- /dev/null +++ b/src/rainfly/src/lib/components/Modal.svelte @@ -0,0 +1,35 @@ + + + + + + + diff --git a/src/rainfly/src/lib/components/Toast.svelte b/src/rainfly/src/lib/components/Toast.svelte new file mode 100644 index 000000000..6d4ddcd68 --- /dev/null +++ b/src/rainfly/src/lib/components/Toast.svelte @@ -0,0 +1,20 @@ + + + + + diff --git a/src/rainfly/src/lib/components/Tooltip.svelte b/src/rainfly/src/lib/components/Tooltip.svelte new file mode 100644 index 000000000..66f009c6c --- /dev/null +++ b/src/rainfly/src/lib/components/Tooltip.svelte @@ -0,0 +1,91 @@ + + +
+ +
+ diff --git a/src/rainfly/src/lib/components/Visualizer.svelte b/src/rainfly/src/lib/components/Visualizer.svelte new file mode 100644 index 000000000..980fb67f6 --- /dev/null +++ b/src/rainfly/src/lib/components/Visualizer.svelte @@ -0,0 +1,230 @@ + + + + +
+ + +
+ +
+
+ + diff --git a/src/rainfly/src/lib/components/nav/Nav.svelte b/src/rainfly/src/lib/components/nav/Nav.svelte new file mode 100644 index 000000000..9f441bcbd --- /dev/null +++ b/src/rainfly/src/lib/components/nav/Nav.svelte @@ -0,0 +1,16 @@ + + + + +rainfly logo diff --git a/src/rainfly/src/lib/components/nav/NavDropdownItem.svelte b/src/rainfly/src/lib/components/nav/NavDropdownItem.svelte new file mode 100644 index 000000000..47feab2d7 --- /dev/null +++ b/src/rainfly/src/lib/components/nav/NavDropdownItem.svelte @@ -0,0 +1,8 @@ + diff --git a/src/rainfly/src/lib/components/nav/NavItem.svelte b/src/rainfly/src/lib/components/nav/NavItem.svelte new file mode 100644 index 000000000..46dad1fb4 --- /dev/null +++ b/src/rainfly/src/lib/components/nav/NavItem.svelte @@ -0,0 +1,46 @@ + + +
+ { name } + + + +
+ + diff --git a/src/rainfly/src/lib/components/nav/items/NavExamples.svelte b/src/rainfly/src/lib/components/nav/items/NavExamples.svelte new file mode 100644 index 000000000..20c6e4c69 --- /dev/null +++ b/src/rainfly/src/lib/components/nav/items/NavExamples.svelte @@ -0,0 +1,39 @@ + + + + { + loadExample('examples/bypass/main.js', 'examples/bypass/processor.js'); + }} + > + Hello Bypass + + { + loadExample('examples/sine/main.js', 'examples/sine/processor.js'); + }} + > + Hello Sine + + diff --git a/src/rainfly/src/lib/components/nav/items/NavFile.svelte b/src/rainfly/src/lib/components/nav/items/NavFile.svelte new file mode 100644 index 000000000..68bbc25ef --- /dev/null +++ b/src/rainfly/src/lib/components/nav/items/NavFile.svelte @@ -0,0 +1,80 @@ + + + + + Save code + + + Export to .wav + + + +{errorMsg} diff --git a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte new file mode 100644 index 000000000..6b92eddef --- /dev/null +++ b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte @@ -0,0 +1,45 @@ + + + + showAbout(true)}>About + + + +
+
+
+

Rainfly

+

An AudioWorklet DSP Playground for Chromium Web Audio API Project + (2024)

+
+

Created by @terryzfeng and @kizjkre

+
+ +

See + GitHub + for more information or to submit an issue

+
+
+ Rainfly logo +
+
+
+ +

ver {meta.version}

+
+
+
+ + diff --git a/src/rainfly/src/lib/stores/status.js b/src/rainfly/src/lib/stores/status.js new file mode 100644 index 000000000..6acf0d662 --- /dev/null +++ b/src/rainfly/src/lib/stores/status.js @@ -0,0 +1,13 @@ +import {writable} from 'svelte/store'; + +export const Status = Object.freeze({ + stop: 0, + play: 1, + running: 2, + pause: 3, +}); + +/** + * @type {import('svelte/store').Writable} + */ +export const status = writable(Status.stop); diff --git a/src/rainfly/src/lib/stores/vim-status.js b/src/rainfly/src/lib/stores/vim-status.js new file mode 100644 index 000000000..e090013ff --- /dev/null +++ b/src/rainfly/src/lib/stores/vim-status.js @@ -0,0 +1,8 @@ +import {writable} from 'svelte/store'; + +const defaultVim = false; // TODO: load from local storage + +/** + * @type {import('svelte/store').Writable} + */ +export const vimStatus = writable(defaultVim); diff --git a/src/rainfly/src/lib/utils/audio-buffer-to-wav.js b/src/rainfly/src/lib/utils/audio-buffer-to-wav.js new file mode 100644 index 000000000..9d35d43ea --- /dev/null +++ b/src/rainfly/src/lib/utils/audio-buffer-to-wav.js @@ -0,0 +1,152 @@ +/* eslint-disable */ +// REF: https://github.com/hoch/canopy/blob/master/docs/js/canopy-exporter.js + +/** + * Writes a string to an array starting at a specified offset. + * + * @param {string} aString - The string to write to the array. + * @param {Uint8Array} targetArray - The array to write to. + * @param {number} offset - The offset in the array to start writing at. + */ +const _writeStringToArray = (aString, targetArray, offset) => { + for (let i = 0; i < aString.length; ++i) targetArray[offset + i] = aString.charCodeAt(i); +}; + +/** + * Writes a 16-bit integer to an array at the specified offset. + * + * @param {number} aNumber - The 16-bit integer to be written. + * @param {Uint8Array} targetArray - The array to write the integer to. + * @param {number} offset - The offset at which to write the integer in the array. + */ +const _writeInt16ToArray = (aNumber, targetArray, offset) => { + aNumber = Math.floor(aNumber); + targetArray[offset] = aNumber & 255; // byte 1 + targetArray[offset + 1] = (aNumber >> 8) & 255; // byte 2 +}; + +/** + * Writes a 32-bit integer to a target array at the specified offset. + * + * @param {number} aNumber - The number to be written. + * @param {Uint8Array} targetArray - The array to write the number to. + * @param {number} offset - The offset at which to start writing. + */ +const _writeInt32ToArray = (aNumber, targetArray, offset) => { + aNumber = Math.floor(aNumber); + targetArray[offset] = aNumber & 255; // byte 1 + targetArray[offset + 1] = (aNumber >> 8) & 255; // byte 2 + targetArray[offset + 2] = (aNumber >> 16) & 255; // byte 3 + targetArray[offset + 3] = (aNumber >> 24) & 255; // byte 4 +}; + +// Return the bits of the float as a 32-bit integer value. This +// produces the raw bits; no intepretation of the value is done. +const _floatBits = (f) => { + const buf = new ArrayBuffer(4); + (new Float32Array(buf))[0] = f; + const bits = (new Uint32Array(buf))[0]; + // Return as a signed integer. + return bits | 0; +}; + +/** + * Converts an audio buffer to an array with the specified bit depth. + * + * @param {AudioBuffer} audioBuffer - The audio buffer to convert. + * @param {Uint8Array} targetArray - The array to store the converted samples. + * @param {number} offset - The offset in the targetArray to start writing the converted samples. + * @param {number} bitDepth - The desired bit depth of the converted samples (16 or 32). + */ +const _writeAudioBufferToArray = (audioBuffer, targetArray, offset, bitDepth) => { + let index; let channel = 0; + const length = audioBuffer.length; + const channels = audioBuffer.numberOfChannels; + let channelData; let sample; + + // Clamping samples onto the 16-bit resolution. + for (index = 0; index < length; ++index) { + for (channel = 0; channel < channels; ++channel) { + channelData = audioBuffer.getChannelData(channel); + + // Branches upon the requested bit depth + if (bitDepth === 16) { + sample = channelData[index] * 32768.0; + if (sample < -32768) { + sample = -32768; + } else if (sample > 32767) { + sample = 32767; + } + _writeInt16ToArray(sample, targetArray, offset); + offset += 2; + } else if (bitDepth === 32) { + // This assumes we're going to out 32-float, not 32-bit linear. + sample = _floatBits(channelData[index]); + _writeInt32ToArray(sample, targetArray, offset); + offset += 4; + } else { + console.error('Invalid bit depth for PCM encoding.'); + return; + } + } + } +}; + +/** + * Converts an AudioBuffer object into a WAV file in the form of a binary blob.The resulting WAV file can be used for + * audio playback or further processing. The function takes two parameters: audioBuffer which represents the audio data, + * and as32BitFloat which indicates whether the WAV file should be encoded as 32-bit float or 16-bit integer PCM. The + * function performs various calculations and writes the necessary headers and data to create the WAV file. Finally, it + * returns the WAV file as a Blob object with the MIME type audio/wave. + * + * @param {AudioBuffer} audioBuffer + * @param {Boolean} as32BitFloat + * @return {Blob} Resulting binary blob. + */ +export const audioBufferToWav = (audioBuffer, as32BitFloat) => { + // Encoding setup. + const frameLength = audioBuffer.length; + const numberOfChannels = audioBuffer.numberOfChannels; + const sampleRate = audioBuffer.sampleRate; + const bitsPerSample = as32BitFloat ? 32 : 16; + const bytesPerSample = bitsPerSample / 8; + const byteRate = sampleRate * numberOfChannels * bitsPerSample / 8; + const blockAlign = numberOfChannels * bitsPerSample / 8; + const wavDataByteLength = frameLength * numberOfChannels * bytesPerSample; + const headerByteLength = 44; + const totalLength = headerByteLength + wavDataByteLength; + const waveFileData = new Uint8Array(totalLength); + const subChunk1Size = 16; + const subChunk2Size = wavDataByteLength; + const chunkSize = 4 + (8 + subChunk1Size) + (8 + subChunk2Size); + + _writeStringToArray('RIFF', waveFileData, 0); + _writeInt32ToArray(chunkSize, waveFileData, 4); + _writeStringToArray('WAVE', waveFileData, 8); + _writeStringToArray('fmt ', waveFileData, 12); + + // SubChunk1Size (4) + _writeInt32ToArray(subChunk1Size, waveFileData, 16); + // AudioFormat (2): 3 means 32-bit float, 1 means integer PCM. + _writeInt16ToArray(as32BitFloat ? 3 : 1, waveFileData, 20); + // NumChannels (2) + _writeInt16ToArray(numberOfChannels, waveFileData, 22); + // SampleRate (4) + _writeInt32ToArray(sampleRate, waveFileData, 24); + // ByteRate (4) + _writeInt32ToArray(byteRate, waveFileData, 28); + // BlockAlign (2) + _writeInt16ToArray(blockAlign, waveFileData, 32); + // BitsPerSample (4) + _writeInt32ToArray(bitsPerSample, waveFileData, 34); + _writeStringToArray('data', waveFileData, 36); + // SubChunk2Size (4) + _writeInt32ToArray(subChunk2Size, waveFileData, 40); + + // Write actual audio data starting at offset 44. + _writeAudioBufferToArray(audioBuffer, waveFileData, 44, bitsPerSample); + + return new Blob([waveFileData], { + type: 'audio/wav', + }); +}; diff --git a/src/rainfly/src/lib/utils/audio-host.js b/src/rainfly/src/lib/utils/audio-host.js new file mode 100644 index 000000000..5f7efc675 --- /dev/null +++ b/src/rainfly/src/lib/utils/audio-host.js @@ -0,0 +1,145 @@ +// import AsyncFunction +const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor; + +/** @type {Array>} */ +export let recordedSamples = [[]]; + +/** @type {AudioContext | undefined} */ +let context; +/** @type {AudioWorkletNode | undefined} */ +let recorder; +let sampleRate = 48000; +let _blobUrl = ''; + +// ----------------------------------------------------------------------------- +// EDITOR CODE HANDLING +// ----------------------------------------------------------------------------- +/** + * Replace addModule url to be blobUrl for AudioWorkletNode + * @param {string} code - code containing addModule function + * @return {string} code with addModule url replaced to blobUrl + */ +function transformWorkletModuleUrl(code) { + if (_blobUrl === '') { + return code; + } + return code.replace(/addModule\(["'].*?["']\)/, `addModule('${_blobUrl}')`); +} + +/** + * Find and replace all instances of a string in a code block + * @param {string} code - code block to search + * @param {string} find - string to find + * @param {string} replace - string to replace + * @return {string} transformed code block + */ +function findReplace(code, find, replace) { + return code.replace(new RegExp(find, 'g'), replace); +} + +/** + * Parse parameter from header code comments + * @param {string} code - code to parse + * @param {string} paramName - syntax: // @paramName = value + * @return {number | null} parsed value or null + */ +function parseParam(code, paramName) { + const regex = new RegExp(`@${paramName}\\s*=\\s*(\\d+)`); + const match = code.match(regex); + return match ? parseInt(match[1], 10) : null; +} + +/** + * Run AudioWorkletProcessor code to build an AudioWorkletNode + * @param {string} code - Processor code to run + */ +export function runProcessorCode(code) { + _blobUrl = window.URL.createObjectURL( + new Blob([code], {type: 'text/javascript'}), + ); +} + +/** + * Run AudioContext code to execute Web Audio Code. If this code contains + * AudioWorklet instantiation, `runProcessorCode` must be run first. + * @param {string} code - AudioContext Graph code to run + */ +export async function runMainCode(code) { + await context?.close(); + + const tryParseSampleRate = parseParam(code, 'sampleRate'); + sampleRate = tryParseSampleRate ? tryParseSampleRate : sampleRate; + + await createContext(); + + let transformCode = transformWorkletModuleUrl(code); + transformCode = findReplace(transformCode, + 'context.destination', + 'recorder).connect(context.destination'); + + const evalFunction = new AsyncFunction('context', 'sampleRate', 'recorder', + transformCode); + await evalFunction(context, sampleRate, recorder); +} + +// ----------------------------------------------------------------------------- +// AUDIO CONTEXT +// ----------------------------------------------------------------------------- +/** + * Create an AudioContext and all the essentials for Rainfly audio processing + */ +async function createContext() { + context = new AudioContext({sampleRate}); + await context.audioWorklet.addModule('processor/recorder-processor.js'); + recorder = new AudioWorkletNode(context, 'recorder-processor'); + recorder.port.onmessage = (event) => { + // if channel doesn't exist, create it with empty array + if (!(event.data.channel in recordedSamples)) { + recordedSamples[event.data.channel] = []; + } + recordedSamples[event.data.channel].push(...event.data.data); + }; +} + +/** + * Resume the AudioContext + */ +export function resumeContext() { + context?.resume(); +} + +/** + * Suspend the AudioContext + */ +export function suspendContext() { + context?.suspend(); +} + +/** + * Destroy the AudioContext + */ +export function stopContext() { + context?.close(); + context = undefined; + recorder = undefined; + recordedSamples = [[]]; +} + +// ----------------------------------------------------------------------------- +// RECORDER +// ----------------------------------------------------------------------------- +/** + * Get current recorded samples + * @return {Array>} - The recorded samples + */ +export function getRecordedSamples() { + return recordedSamples; +} + +/** + * Returns the current sample rate of the AudioContext + * @return {number} - The current sample rate + */ +export function getSampleRate() { + return sampleRate; +} diff --git a/src/rainfly/src/lib/utils/click-outside.js b/src/rainfly/src/lib/utils/click-outside.js new file mode 100644 index 000000000..4fb6a888b --- /dev/null +++ b/src/rainfly/src/lib/utils/click-outside.js @@ -0,0 +1,11 @@ +import {nodes} from '$lib/actions/click-outside'; + +const clickOutsideListener = (/** @type {Event} */ e) => + [...nodes.entries()].forEach(([node, callback]) => + node !== e.target && callback({ + ...e, + currentTarget: node, + }), + ); + +export default clickOutsideListener; diff --git a/src/rainfly/src/lib/utils/file-utils.js b/src/rainfly/src/lib/utils/file-utils.js new file mode 100644 index 000000000..939da7e4f --- /dev/null +++ b/src/rainfly/src/lib/utils/file-utils.js @@ -0,0 +1,35 @@ +/** + * @fileoverview Common utility function for working with files + */ + +import JSZip from 'jszip'; + +/** + * Fetch a file from the given URL and return name and text data + * @param {string} url - URL of the file to fetch + * @return {Promise<{name: string, data: string}>} - Promise that resolves to + * an object with the name and data of the file + */ +export async function fetchTextFile(url) { + let filename = url.split('/').pop(); + if (filename === undefined) { + filename = url; + } + const response = await fetch(url); + const text = await response.text(); + return {name: filename, data: text}; +} + +/** + * Zip multiple text files into a single blob + * @param {Object.} files - JSON object of + * filenames and data + * @return {Promise} - Promise to blob of zipped files + */ +export async function zipTextFiles(files) { + const zip = new JSZip(); + for (const [filename, data] of Object.entries(files)) { + zip.file(filename, data); + } + return zip.generateAsync({type: 'blob'}); +} diff --git a/src/rainfly/src/lib/utils/monaco.js b/src/rainfly/src/lib/utils/monaco.js new file mode 100644 index 000000000..bc0659fca --- /dev/null +++ b/src/rainfly/src/lib/utils/monaco.js @@ -0,0 +1,24 @@ +/** + * @fileoverview Prepare Monaco Editor API for Vite usage + */ +import * as monaco from 'monaco-editor'; + +import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; +import tsWorker + from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; + +self.MonacoEnvironment = { + getWorker: function(_id, label) { + switch (label) { + case 'typescript': + case 'javascript': + // eslint-disable-next-line new-cap + return new tsWorker(); + default: + // eslint-disable-next-line new-cap + return new editorWorker(); + } + }, +}; + +export default monaco; diff --git a/src/rainfly/src/routes/+layout.js b/src/rainfly/src/routes/+layout.js new file mode 100644 index 000000000..189f71e2e --- /dev/null +++ b/src/rainfly/src/routes/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/src/rainfly/src/routes/+layout.svelte b/src/rainfly/src/routes/+layout.svelte new file mode 100644 index 000000000..fbe5576ff --- /dev/null +++ b/src/rainfly/src/routes/+layout.svelte @@ -0,0 +1,9 @@ + + + + Rainfly + + + diff --git a/src/rainfly/src/routes/+page.svelte b/src/rainfly/src/routes/+page.svelte new file mode 100644 index 000000000..f893769e6 --- /dev/null +++ b/src/rainfly/src/routes/+page.svelte @@ -0,0 +1,81 @@ + + + + + +
+
diff --git a/src/rainfly/static/examples/bypass/main.js b/src/rainfly/static/examples/bypass/main.js new file mode 100644 index 000000000..1ce274dcd --- /dev/null +++ b/src/rainfly/static/examples/bypass/main.js @@ -0,0 +1,9 @@ +// Use `context` as the AudioContext +// @sampleRate = 48000 + +const oscillator = new OscillatorNode(context); +await context.audioWorklet.addModule('processor.js'); +const workletNode = new AudioWorkletNode(context, 'bypass-processor'); + +oscillator.connect(workletNode).connect(context.destination); +oscillator.start(); diff --git a/src/rainfly/static/examples/bypass/processor.js b/src/rainfly/static/examples/bypass/processor.js new file mode 100644 index 000000000..ec91dd34d --- /dev/null +++ b/src/rainfly/static/examples/bypass/processor.js @@ -0,0 +1,15 @@ +class BypassProcessor extends AudioWorkletProcessor { + process(inputs, outputs) { + const input = inputs[0]; + const output = outputs[0]; + for (let channel = 0; channel < input.length; ++channel) { + for (let i = 0; i < input[0].length; ++i) { + output[channel][i] = input[channel][i]; + } + } + + return true; + } +} + +registerProcessor('bypass-processor', BypassProcessor); diff --git a/src/rainfly/static/examples/sine/main.js b/src/rainfly/static/examples/sine/main.js new file mode 100644 index 000000000..9bfe14358 --- /dev/null +++ b/src/rainfly/static/examples/sine/main.js @@ -0,0 +1,7 @@ +// Use `context` as the AudioContext +// @sampleRate = 48000 + +await context.audioWorklet.addModule('processor.js'); +const sineWorkletNode = new AudioWorkletNode(context, 'sine-processor'); +sineWorkletNode.parameters.get('frequency').value = 440; +sineWorkletNode.connect(context.destination); diff --git a/src/rainfly/static/examples/sine/processor.js b/src/rainfly/static/examples/sine/processor.js new file mode 100644 index 000000000..1dd79ecad --- /dev/null +++ b/src/rainfly/static/examples/sine/processor.js @@ -0,0 +1,31 @@ +class SineProcessor extends AudioWorkletProcessor { + static get parameterDescriptors() { + return [ + { name: 'frequency', defaultValue: 440, }, + ]; + } + + constructor() { + super(); + this.phase = 0; + this.inverseSampleRate = 1 / sampleRate; + } + + process(inputs, outputs, parameters) { + const output = outputs[0]; + const frequency = parameters.frequency[0]; + + for (let i = 0; i < output[0].length; ++i) { + output[0][i] = Math.sin(2 * Math.PI * frequency * this.phase); + this.phase += this.inverseSampleRate; + } + + for (let channel = 1; channel < output.length; ++channel) { + output[channel].set(output[0]); + } + + return true; + } +} + +registerProcessor('sine-processor', SineProcessor); diff --git a/src/rainfly/static/favicon.svg b/src/rainfly/static/favicon.svg new file mode 100644 index 000000000..b7794c8d5 --- /dev/null +++ b/src/rainfly/static/favicon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/rainfly/static/processor/recorder-processor.js b/src/rainfly/static/processor/recorder-processor.js new file mode 100644 index 000000000..d61693915 --- /dev/null +++ b/src/rainfly/static/processor/recorder-processor.js @@ -0,0 +1,18 @@ +/** + * RecorderProcessor records samples on the fly and streams them to the main thread. + */ +class RecorderProcessor extends AudioWorkletProcessor { + process(inputs, outputs) { + const input = inputs[0]; + const output = outputs[0]; + + for (let channel = 0; channel < input.length; channel++) { + output[channel].set(input[channel]); + this.port.postMessage({ channel, data: input[channel] }); + } + + return true; + } +} + +registerProcessor('recorder-processor', RecorderProcessor); \ No newline at end of file diff --git a/src/rainfly/svelte.config.js b/src/rainfly/svelte.config.js new file mode 100644 index 000000000..e5487abda --- /dev/null +++ b/src/rainfly/svelte.config.js @@ -0,0 +1,18 @@ +import adapter from '@sveltejs/adapter-static'; +import {vitePreprocess} from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + // adapter-auto only supports some environments, see + // https://kit.svelte.dev/docs/adapter-auto for a list. + // If your environment is not supported, or you settled + // on a specific environment, switch out the adapter. See + // https://kit.svelte.dev/docs/adapters for more information + // about adapters. + adapter: adapter(), + }, + preprocess: vitePreprocess(), +}; + +export default config; diff --git a/src/rainfly/tailwind.config.js b/src/rainfly/tailwind.config.js new file mode 100644 index 000000000..3c2b13439 --- /dev/null +++ b/src/rainfly/tailwind.config.js @@ -0,0 +1,22 @@ +// noinspection JSUnusedGlobalSymbols +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{html,js,svelte,ts}'], + theme: { + extend: { + colors: { + primary: '#94E170', + secondary: '#FFFBD3', + accent: '#FD9494', + }, + fontFamily: { + sans: ['"Outfit"', 'sans-serif'], + mono: ['"Anonymous Pro"', 'monospace'], + }, + gridTemplateRows: { + main: '3rem minmax(0, 4fr) minmax(0, 6fr)', + }, + }, + }, + plugins: [], +}; diff --git a/src/rainfly/vite.config.js b/src/rainfly/vite.config.js new file mode 100644 index 000000000..8aa53da74 --- /dev/null +++ b/src/rainfly/vite.config.js @@ -0,0 +1,11 @@ +import {sveltekit} from '@sveltejs/kit/vite'; +import {defineConfig} from 'vite'; +import {readFileSync} from 'node:fs'; + +export default defineConfig({ + plugins: [sveltekit()], + // REF: https://stackoverflow.com/a/72141502 + define: { + meta: {version: JSON.parse(readFileSync('package.json', 'utf8')).version}, + }, +}); From 8c37dc40662df3e81a6a8b2c8e18d7a46e20689d Mon Sep 17 00:00:00 2001 From: Tristan <24882191+Kizjkre@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:38:54 -0700 Subject: [PATCH 03/13] [Untested] Add build script --- package.json | 1 + src/_data/build_info.json | 2 +- src/rainfly/package.json | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ad4bad2bc..6f3f85677 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "build": "npm run clean && run-p build:*", "build:eleventy": "ELEVENTY_ENV=production eleventy", "build:postcss": "ELEVENTY_ENV=production postcss src/styles/*.css --dir _site", + "build:rainfly": "cd src/rainfly && npm run build", "start": "run-p start:*", "start:eleventy": "eleventy --serve", "start:postcss": "postcss src/styles/*.css --dir _site --watch", diff --git a/src/_data/build_info.json b/src/_data/build_info.json index a90588ff9..f1dd865f0 100644 --- a/src/_data/build_info.json +++ b/src/_data/build_info.json @@ -1 +1 @@ -{"version":"3.2.0","revision":"e45e5d0","lastUpdated":"2024-08-07","copyrightYear":2024} \ No newline at end of file +{"version":"3.2.0","revision":"dd4ffa7","lastUpdated":"2024-09-30","copyrightYear":2024} \ No newline at end of file diff --git a/src/rainfly/package.json b/src/rainfly/package.json index 37703ebf9..8b2cabe93 100644 --- a/src/rainfly/package.json +++ b/src/rainfly/package.json @@ -5,6 +5,7 @@ "scripts": { "dev": "vite dev", "build": "vite build", + "postbuild": "rm -rf ../../_site/rainfly/* && cp -r build/* ../../_site/rainfly/ && rm -rf build/", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", From d4a7fab324070dc5fa35224c563cb878d9949cd0 Mon Sep 17 00:00:00 2001 From: Tristan <24882191+Kizjkre@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:50:21 -0700 Subject: [PATCH 04/13] [Untested] Add install script before building rainfly --- src/_data/build_info.json | 2 +- src/rainfly/package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_data/build_info.json b/src/_data/build_info.json index f1dd865f0..872925444 100644 --- a/src/_data/build_info.json +++ b/src/_data/build_info.json @@ -1 +1 @@ -{"version":"3.2.0","revision":"dd4ffa7","lastUpdated":"2024-09-30","copyrightYear":2024} \ No newline at end of file +{"version":"3.2.0","revision":"8c37dc4","lastUpdated":"2024-09-30","copyrightYear":2024} \ No newline at end of file diff --git a/src/rainfly/package.json b/src/rainfly/package.json index 8b2cabe93..d525dfd9f 100644 --- a/src/rainfly/package.json +++ b/src/rainfly/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "dev": "vite dev", + "prebuild": "npm ci", "build": "vite build", "postbuild": "rm -rf ../../_site/rainfly/* && cp -r build/* ../../_site/rainfly/ && rm -rf build/", "preview": "vite preview", From b16168820d0773637d18e876d831897a45e8269f Mon Sep 17 00:00:00 2001 From: Tristan <24882191+Kizjkre@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:52:06 -0700 Subject: [PATCH 05/13] [Untested] Use install instead of a clean install --- src/rainfly/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rainfly/package.json b/src/rainfly/package.json index d525dfd9f..367e75630 100644 --- a/src/rainfly/package.json +++ b/src/rainfly/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "dev": "vite dev", - "prebuild": "npm ci", + "prebuild": "npm i", "build": "vite build", "postbuild": "rm -rf ../../_site/rainfly/* && cp -r build/* ../../_site/rainfly/ && rm -rf build/", "preview": "vite preview", From 12cf38256bc436334bb27f9d3b916df43a5373dc Mon Sep 17 00:00:00 2001 From: Tristan <24882191+Kizjkre@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:54:54 -0700 Subject: [PATCH 06/13] [Untested] Update node version --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6db7f3114..a1aa2f8b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - name: npm install and build run: | npm install From 393c9a3ecba48ab073a6b8d3dfc78b919b936e72 Mon Sep 17 00:00:00 2001 From: terry feng Date: Mon, 30 Sep 2024 23:59:22 -0700 Subject: [PATCH 07/13] add rainfly link to audioworklet page eleventy --- src/_data/audioworklet_data.yaml | 3 +++ src/_data/landing_data.yaml | 3 --- src/rainfly/src/lib/components/nav/items/NavHelp.svelte | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/_data/audioworklet_data.yaml b/src/_data/audioworklet_data.yaml index 9bdcb3194..689071c36 100644 --- a/src/_data/audioworklet_data.yaml +++ b/src/_data/audioworklet_data.yaml @@ -42,6 +42,9 @@ - title: Audio Worklet, SharedArrayBuffer, and Worker description: For high performance large-scale audio applications href: design-pattern/shared-buffer/ + - title: Rainfly + description: AudioWorklet DSP Playground and Visualizer + href: ../rainfly - title: FreeQueue entries: diff --git a/src/_data/landing_data.yaml b/src/_data/landing_data.yaml index a97ab75e7..3afed5fbf 100644 --- a/src/_data/landing_data.yaml +++ b/src/_data/landing_data.yaml @@ -18,9 +18,6 @@ - title: Canopy description: Web Audio code editor and visual debugger href: https://hoch.github.io/canopy/ -# - title: Audio Worklets Playground -# description: Audio Worklet playground -# href: \# - title: Demos entries: diff --git a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte index 6b92eddef..4df9cd34d 100644 --- a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte +++ b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte @@ -33,6 +33,7 @@
+

ver {meta.version}

From 9b8ed08683e68b4c3e0df7cacc848b48351dd293 Mon Sep 17 00:00:00 2001 From: terry feng Date: Tue, 1 Oct 2024 12:45:12 -0700 Subject: [PATCH 08/13] fix svelte output paths --- src/rainfly/svelte.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rainfly/svelte.config.js b/src/rainfly/svelte.config.js index e5487abda..3b353f900 100644 --- a/src/rainfly/svelte.config.js +++ b/src/rainfly/svelte.config.js @@ -1,6 +1,8 @@ import adapter from '@sveltejs/adapter-static'; import {vitePreprocess} from '@sveltejs/vite-plugin-svelte'; +const BUILD_DIR = '/rainfly'; + /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { @@ -11,6 +13,10 @@ const config = { // https://kit.svelte.dev/docs/adapters for more information // about adapters. adapter: adapter(), + appDir: 'app', + paths: { + base: process.argv.includes('dev') ? '' : BUILD_DIR, + }, }, preprocess: vitePreprocess(), }; From 4a8c6206075be7f50f3ceafe205f1ee9aa3f9855 Mon Sep 17 00:00:00 2001 From: terry feng Date: Tue, 1 Oct 2024 13:41:09 -0700 Subject: [PATCH 09/13] add compile run button and mouse scroll hack --- .../src/lib/assets/player-run-play.svg | 58 +++++++++++++++++++ .../src/lib/components/ActionButton.svelte | 5 +- .../src/lib/components/Visualizer.svelte | 9 ++- 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/rainfly/src/lib/assets/player-run-play.svg diff --git a/src/rainfly/src/lib/assets/player-run-play.svg b/src/rainfly/src/lib/assets/player-run-play.svg new file mode 100644 index 000000000..719c4a09e --- /dev/null +++ b/src/rainfly/src/lib/assets/player-run-play.svg @@ -0,0 +1,58 @@ + + + + + + + + + diff --git a/src/rainfly/src/lib/components/ActionButton.svelte b/src/rainfly/src/lib/components/ActionButton.svelte index 36e46db60..0c70644bd 100644 --- a/src/rainfly/src/lib/components/ActionButton.svelte +++ b/src/rainfly/src/lib/components/ActionButton.svelte @@ -3,6 +3,7 @@ import playerPlay from '$lib/assets/player-play.svg'; import playerStop from '$lib/assets/player-stop.svg'; import playerPause from '$lib/assets/player-pause.svg'; + import playerRunPlay from '$lib/assets/player-run-play.svg'; let showStop = false; let playButtonText = 'Play'; @@ -46,9 +47,9 @@ break; default: case Status.stop: - playButtonText = 'Run'; - icon = playerPlay; showStop = false; + playButtonText = 'Run'; + icon = playerRunPlay; } } diff --git a/src/rainfly/src/lib/components/Visualizer.svelte b/src/rainfly/src/lib/components/Visualizer.svelte index 980fb67f6..9208d6c89 100644 --- a/src/rainfly/src/lib/components/Visualizer.svelte +++ b/src/rainfly/src/lib/components/Visualizer.svelte @@ -183,7 +183,14 @@ const samples = getRecordedSamples(); if (samples && samples[0].length === 0) return; - zoom = Math.max(0, Math.min(zoom + event.deltaY, MAX_ZOOM)); + let scrollY = event.deltaY; + // hack: convert mouse scroll to trackpad scroll amount + if (Math.abs(scrollY) > 40) { + scrollY /= 40; + } + + zoom = Math.max(0, Math.min(zoom + scrollY, MAX_ZOOM)); + console.log("zoom", zoom); slice.full = zoom === 0; const max = getRecordedSamples()[0].length; const position = event.clientX / window.innerWidth * From e6f49ec2afe0d9ca8114741ffb5e4124c2f50084 Mon Sep 17 00:00:00 2001 From: terry feng Date: Thu, 17 Oct 2024 11:58:07 -0700 Subject: [PATCH 10/13] add PR fixes and code health improvements --- .eleventyignore | 1 - src/_data/audioworklet_data.yaml | 4 +- src/_data/landing_data.yaml | 3 + src/rainfly/src/lib/assets/vim.svg | 8 ++ src/rainfly/src/lib/components/Editor.svelte | 14 +--- .../src/lib/components/Visualizer.svelte | 31 ++++--- .../components/nav/items/NavExamples.svelte | 61 +++++++++----- .../lib/components/nav/items/NavFile.svelte | 16 +++- .../lib/components/nav/items/NavHelp.svelte | 2 +- .../src/lib/utils/audio-buffer-to-wav.js | 84 ++++++++++--------- src/rainfly/src/lib/utils/file-utils.js | 16 +++- src/rainfly/static/examples/examples.json | 14 ++++ 12 files changed, 159 insertions(+), 95 deletions(-) create mode 100644 src/rainfly/src/lib/assets/vim.svg create mode 100644 src/rainfly/static/examples/examples.json diff --git a/.eleventyignore b/.eleventyignore index 7f9ef4297..f733f1a87 100644 --- a/.eleventyignore +++ b/.eleventyignore @@ -1,4 +1,3 @@ node_modules/ ./src/archive/ -.src/rainfly/ **/README.md diff --git a/src/_data/audioworklet_data.yaml b/src/_data/audioworklet_data.yaml index 689071c36..f0d44078f 100644 --- a/src/_data/audioworklet_data.yaml +++ b/src/_data/audioworklet_data.yaml @@ -42,9 +42,7 @@ - title: Audio Worklet, SharedArrayBuffer, and Worker description: For high performance large-scale audio applications href: design-pattern/shared-buffer/ - - title: Rainfly - description: AudioWorklet DSP Playground and Visualizer - href: ../rainfly + - title: FreeQueue entries: diff --git a/src/_data/landing_data.yaml b/src/_data/landing_data.yaml index 3afed5fbf..78800b349 100644 --- a/src/_data/landing_data.yaml +++ b/src/_data/landing_data.yaml @@ -18,6 +18,9 @@ - title: Canopy description: Web Audio code editor and visual debugger href: https://hoch.github.io/canopy/ + - title: Rainfly + description: AudioWorklet DSP Playground and Visualizer + href: rainfly/ - title: Demos entries: diff --git a/src/rainfly/src/lib/assets/vim.svg b/src/rainfly/src/lib/assets/vim.svg new file mode 100644 index 000000000..4e8730f97 --- /dev/null +++ b/src/rainfly/src/lib/assets/vim.svg @@ -0,0 +1,8 @@ + + + + + VIm + + + \ No newline at end of file diff --git a/src/rainfly/src/lib/components/Editor.svelte b/src/rainfly/src/lib/components/Editor.svelte index 42825e967..598108c2c 100644 --- a/src/rainfly/src/lib/components/Editor.svelte +++ b/src/rainfly/src/lib/components/Editor.svelte @@ -6,6 +6,7 @@ import {vimStatus} from '$lib/stores/vim-status.js'; import {status, Status} from '$lib/stores/status.js'; import {fetchTextFile} from '$lib/utils/file-utils.js'; + import vimIcon from '$lib/assets/vim.svg'; /** * @type {string} - "processor" | "main" @@ -74,7 +75,7 @@ ); editor.setModel(model); - // temp testing + // TODO: Add ability for autosave on change to LocalStorage editor.onDidChangeModelContent(() => { // console.log(getEditorCode()) }); @@ -220,16 +221,7 @@ class:bg-accent={$vimStatus} bind:this={anchor} > - - - - - - VIm - - - - + Vim {/if} diff --git a/src/rainfly/src/lib/components/Visualizer.svelte b/src/rainfly/src/lib/components/Visualizer.svelte index 9208d6c89..d812f6436 100644 --- a/src/rainfly/src/lib/components/Visualizer.svelte +++ b/src/rainfly/src/lib/components/Visualizer.svelte @@ -8,7 +8,10 @@ let canvas; /** @type {CanvasRenderingContext2D | null} */ let context; - /** @type {number} */ + /** + * Ratio of canvas size to device pixels, for retina displays + * @type {number} + */ let RATIO; /** @type {number} */ const BAR_THRESHOLD = 250; @@ -46,7 +49,6 @@ if (context === null) return; context.clearRect(0, 0, canvas.width, canvas.height); - // visualizer width and height const width = canvas.width; const height = canvas.height; const padding = 0.8; @@ -57,12 +59,10 @@ slice.full && (slice.end = samples[0]?.length || Infinity); const displaySamples = samples[0]?.slice(slice.start, slice.end) || []; - // visualize the samples + // Visualize the samples if (displaySamples.length > BAR_THRESHOLD) { - // display whole sine wav + // Display sine wave samples as a continuous line const size = displaySamples.length; - - // const downsampleHop = Math.floor(size / width / 10); const downsampleHop = 1; const increment = width / (size / downsampleHop); @@ -75,19 +75,16 @@ height / 2 - (displaySamples[i] * height / 2 * padding)); } context.strokeStyle = PRIMARY_COLOR; - // stroke thickness context.lineWidth = 1.5 * RATIO; context.stroke(); context.closePath(); } else { - // display sin wave as bars like audacity + // Display sine wave samples as bars like Audacity const size = displaySamples.length; - - // const downsampleHop = Math.floor(size / width / 10); const downsampleHop = 1; - const increment = width / (size / downsampleHop); + // draw each sample as a bar let i = 0; context.beginPath(); for (let x = 0; x < width; x += increment, i += downsampleHop) { @@ -96,7 +93,6 @@ height / 2 - (displaySamples[i] * height / 2 * padding)); } context.strokeStyle = PRIMARY_COLOR; - // stroke thickness context.lineWidth = 1.5 * RATIO; context.stroke(); context.closePath(); @@ -114,7 +110,6 @@ } } - // Request animation frame if ($status === Status.play || $status === Status.running) { requestAnimationFrame(draw); } @@ -159,7 +154,7 @@ } /** - * Clear the canvas and draw the axes + * Clear the canvas and re-draw the axes */ function clearCanvas() { if (!context) return; @@ -179,7 +174,11 @@ draw(); } - const handleWheel = (/** @type {WheelEvent} */ event) => { + /** + * Handle mouse wheel event to zoom in/out of the visualizer + * @param {WheelEvent} event - mouse wheel event + */ + const handleWheel = (event) => { const samples = getRecordedSamples(); if (samples && samples[0].length === 0) return; @@ -190,7 +189,7 @@ } zoom = Math.max(0, Math.min(zoom + scrollY, MAX_ZOOM)); - console.log("zoom", zoom); + console.log('zoom', zoom); slice.full = zoom === 0; const max = getRecordedSamples()[0].length; const position = event.clientX / window.innerWidth * diff --git a/src/rainfly/src/lib/components/nav/items/NavExamples.svelte b/src/rainfly/src/lib/components/nav/items/NavExamples.svelte index 20c6e4c69..f555cad8a 100644 --- a/src/rainfly/src/lib/components/nav/items/NavExamples.svelte +++ b/src/rainfly/src/lib/components/nav/items/NavExamples.svelte @@ -1,39 +1,62 @@ - { - loadExample('examples/bypass/main.js', 'examples/bypass/processor.js'); - }} - > - Hello Bypass - - { - loadExample('examples/sine/main.js', 'examples/sine/processor.js'); - }} - > - Hello Sine - + {#each examples as example} + { + loadExample(example.mainCodeUrl, example.processorCodeUrl); + }} + > + {example.name} + + {/each} diff --git a/src/rainfly/src/lib/components/nav/items/NavFile.svelte b/src/rainfly/src/lib/components/nav/items/NavFile.svelte index 68bbc25ef..568e8eac9 100644 --- a/src/rainfly/src/lib/components/nav/items/NavFile.svelte +++ b/src/rainfly/src/lib/components/nav/items/NavFile.svelte @@ -19,8 +19,20 @@ const mainCode = getEditorMain(); /** @type {Object.}*/ const files = {}; - processorCode && (files['processor.js'] = processorCode); - mainCode && (files['main.js'] = mainCode); + if (processorCode.length == 0 && mainCode.length == 0) { + errorMsg = 'No code to save'; + console.error(errorMsg); + showError(true); + return; + } else { + showError(false); + } + if (processorCode.length > 0) { + files['processor.js'] = processorCode; + } + if (mainCode.length > 0) { + files['main.js'] = mainCode; + } const zipBlob = await zipTextFiles(files); const url = URL.createObjectURL(zipBlob); diff --git a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte index 4df9cd34d..e379b0bc4 100644 --- a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte +++ b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte @@ -32,8 +32,8 @@
- +

ver {meta.version}

diff --git a/src/rainfly/src/lib/utils/audio-buffer-to-wav.js b/src/rainfly/src/lib/utils/audio-buffer-to-wav.js index 9d35d43ea..418bdfcb6 100644 --- a/src/rainfly/src/lib/utils/audio-buffer-to-wav.js +++ b/src/rainfly/src/lib/utils/audio-buffer-to-wav.js @@ -1,4 +1,3 @@ -/* eslint-disable */ // REF: https://github.com/hoch/canopy/blob/master/docs/js/canopy-exporter.js /** @@ -9,7 +8,9 @@ * @param {number} offset - The offset in the array to start writing at. */ const _writeStringToArray = (aString, targetArray, offset) => { - for (let i = 0; i < aString.length; ++i) targetArray[offset + i] = aString.charCodeAt(i); + for (let i = 0; i < aString.length; ++i) { + targetArray[offset + i] = aString.charCodeAt(i); + } }; /** @@ -17,7 +18,8 @@ const _writeStringToArray = (aString, targetArray, offset) => { * * @param {number} aNumber - The 16-bit integer to be written. * @param {Uint8Array} targetArray - The array to write the integer to. - * @param {number} offset - The offset at which to write the integer in the array. + * @param {number} offset - The offset at which to write the integer in the + * array. */ const _writeInt16ToArray = (aNumber, targetArray, offset) => { aNumber = Math.floor(aNumber); @@ -55,49 +57,55 @@ const _floatBits = (f) => { * * @param {AudioBuffer} audioBuffer - The audio buffer to convert. * @param {Uint8Array} targetArray - The array to store the converted samples. - * @param {number} offset - The offset in the targetArray to start writing the converted samples. - * @param {number} bitDepth - The desired bit depth of the converted samples (16 or 32). + * @param {number} offset - The offset in the targetArray to start writing the + * converted samples. + * @param {number} bitDepth - The desired bit depth of the converted samples + * (16 or 32). */ -const _writeAudioBufferToArray = (audioBuffer, targetArray, offset, bitDepth) => { - let index; let channel = 0; - const length = audioBuffer.length; - const channels = audioBuffer.numberOfChannels; - let channelData; let sample; +const _writeAudioBufferToArray = + (audioBuffer, targetArray, offset, bitDepth) => { + let index; let channel = 0; + const length = audioBuffer.length; + const channels = audioBuffer.numberOfChannels; + let channelData; let sample; - // Clamping samples onto the 16-bit resolution. - for (index = 0; index < length; ++index) { - for (channel = 0; channel < channels; ++channel) { - channelData = audioBuffer.getChannelData(channel); + // Clamping samples onto the 16-bit resolution. + for (index = 0; index < length; ++index) { + for (channel = 0; channel < channels; ++channel) { + channelData = audioBuffer.getChannelData(channel); - // Branches upon the requested bit depth - if (bitDepth === 16) { - sample = channelData[index] * 32768.0; - if (sample < -32768) { - sample = -32768; - } else if (sample > 32767) { - sample = 32767; - } - _writeInt16ToArray(sample, targetArray, offset); - offset += 2; - } else if (bitDepth === 32) { + // Branches upon the requested bit depth + if (bitDepth === 16) { + sample = channelData[index] * 32768.0; + if (sample < -32768) { + sample = -32768; + } else if (sample > 32767) { + sample = 32767; + } + _writeInt16ToArray(sample, targetArray, offset); + offset += 2; + } else if (bitDepth === 32) { // This assumes we're going to out 32-float, not 32-bit linear. - sample = _floatBits(channelData[index]); - _writeInt32ToArray(sample, targetArray, offset); - offset += 4; - } else { - console.error('Invalid bit depth for PCM encoding.'); - return; + sample = _floatBits(channelData[index]); + _writeInt32ToArray(sample, targetArray, offset); + offset += 4; + } else { + console.error('Invalid bit depth for PCM encoding.'); + return; + } } } - } -}; + }; /** - * Converts an AudioBuffer object into a WAV file in the form of a binary blob.The resulting WAV file can be used for - * audio playback or further processing. The function takes two parameters: audioBuffer which represents the audio data, - * and as32BitFloat which indicates whether the WAV file should be encoded as 32-bit float or 16-bit integer PCM. The - * function performs various calculations and writes the necessary headers and data to create the WAV file. Finally, it - * returns the WAV file as a Blob object with the MIME type audio/wave. + * Converts an AudioBuffer object into a WAV file in the form of a binary blob. + * The resulting WAV file can be used for audio playback or further processing. + * The function takes two parameters: audioBuffer which represents the audio + * data, and as 32BitFloat which indicates whether the WAV file should be + * encoded as 32-bit float or 16-bit integer PCM. The function performs various + * calculations and writes the necessary headers and data to create the WAV + * file. Finally, it returns the WAV file as a Blob object with the MIME type + * audio/wave. * * @param {AudioBuffer} audioBuffer * @param {Boolean} as32BitFloat diff --git a/src/rainfly/src/lib/utils/file-utils.js b/src/rainfly/src/lib/utils/file-utils.js index 939da7e4f..8d0422afa 100644 --- a/src/rainfly/src/lib/utils/file-utils.js +++ b/src/rainfly/src/lib/utils/file-utils.js @@ -12,12 +12,20 @@ import JSZip from 'jszip'; */ export async function fetchTextFile(url) { let filename = url.split('/').pop(); - if (filename === undefined) { + if (filename === undefined || filename === '') { filename = url; } - const response = await fetch(url); - const text = await response.text(); - return {name: filename, data: text}; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch ${url}`); + } + const data = await response.text(); + return {name: filename, data}; + } catch (/** @type any */ error) { + return {name: filename, data: 'error: '+ error.message}; + } } /** diff --git a/src/rainfly/static/examples/examples.json b/src/rainfly/static/examples/examples.json new file mode 100644 index 000000000..06fb2b58d --- /dev/null +++ b/src/rainfly/static/examples/examples.json @@ -0,0 +1,14 @@ +{ + "examples": [ + { + "name": "Hello Bypass", + "mainCodeUrl": "examples/bypass/main.js", + "processorCodeUrl": "examples/bypass/processor.js" + }, + { + "name": "Hello Sine", + "mainCodeUrl": "examples/sine/main.js", + "processorCodeUrl": "examples/sine/processor.js" + } + ] +} \ No newline at end of file From 7cb0fdfb7e5107a127df362c4ba189578eb79485 Mon Sep 17 00:00:00 2001 From: terry feng Date: Thu, 17 Oct 2024 12:01:06 -0700 Subject: [PATCH 11/13] newline deletion --- src/_data/build_info.json | 2 +- src/rainfly/src/lib/components/ActionButton.svelte | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/_data/build_info.json b/src/_data/build_info.json index 872925444..bbede861b 100644 --- a/src/_data/build_info.json +++ b/src/_data/build_info.json @@ -1 +1 @@ -{"version":"3.2.0","revision":"8c37dc4","lastUpdated":"2024-09-30","copyrightYear":2024} \ No newline at end of file +{"version":"3.2.0","revision":"e6f49ec","lastUpdated":"2024-10-17","copyrightYear":2024} \ No newline at end of file diff --git a/src/rainfly/src/lib/components/ActionButton.svelte b/src/rainfly/src/lib/components/ActionButton.svelte index 0c70644bd..59a0d3d6c 100644 --- a/src/rainfly/src/lib/components/ActionButton.svelte +++ b/src/rainfly/src/lib/components/ActionButton.svelte @@ -52,7 +52,6 @@ icon = playerRunPlay; } } -
From 74d22704097ecf43bdfd57744235dde498485c6d Mon Sep 17 00:00:00 2001 From: terry feng Date: Thu, 17 Oct 2024 16:36:09 -0700 Subject: [PATCH 12/13] fix modal splash.svg --- src/_data/build_info.json | 2 +- src/rainfly/src/lib/components/nav/items/NavHelp.svelte | 3 +-- src/rainfly/{src/lib/assets => static}/splash.svg | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename src/rainfly/{src/lib/assets => static}/splash.svg (100%) diff --git a/src/_data/build_info.json b/src/_data/build_info.json index bbede861b..cd8ea9859 100644 --- a/src/_data/build_info.json +++ b/src/_data/build_info.json @@ -1 +1 @@ -{"version":"3.2.0","revision":"e6f49ec","lastUpdated":"2024-10-17","copyrightYear":2024} \ No newline at end of file +{"version":"3.2.0","revision":"7cb0fdf","lastUpdated":"2024-10-17","copyrightYear":2024} \ No newline at end of file diff --git a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte index e379b0bc4..0478dd9e8 100644 --- a/src/rainfly/src/lib/components/nav/items/NavHelp.svelte +++ b/src/rainfly/src/lib/components/nav/items/NavHelp.svelte @@ -2,7 +2,6 @@ import NavItem from '$lib/components/nav/NavItem.svelte'; import NavDropdownItem from '$lib/components/nav/NavDropdownItem.svelte'; import Modal from '$lib/components/Modal.svelte'; - import splash from '$lib/assets/splash.svg'; /** @type {(state: boolean) => void}*/ let showAbout; @@ -28,7 +27,7 @@ for more information or to submit an issue

- Rainfly logo + Rainfly logo
diff --git a/src/rainfly/src/lib/assets/splash.svg b/src/rainfly/static/splash.svg similarity index 100% rename from src/rainfly/src/lib/assets/splash.svg rename to src/rainfly/static/splash.svg From b36c177593d8395efc3ec0801f5ed1505ba41fe9 Mon Sep 17 00:00:00 2001 From: terry feng Date: Sun, 20 Oct 2024 16:04:41 -0700 Subject: [PATCH 13/13] add license + small changes --- src/_data/audioworklet_data.yaml | 1 - src/rainfly/src/lib/actions/portal.js | 23 +++++++++++++++++++ .../src/lib/components/Visualizer.svelte | 2 -- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/_data/audioworklet_data.yaml b/src/_data/audioworklet_data.yaml index f0d44078f..9bdcb3194 100644 --- a/src/_data/audioworklet_data.yaml +++ b/src/_data/audioworklet_data.yaml @@ -43,7 +43,6 @@ description: For high performance large-scale audio applications href: design-pattern/shared-buffer/ - - title: FreeQueue entries: - title: Simple Passthrough diff --git a/src/rainfly/src/lib/actions/portal.js b/src/rainfly/src/lib/actions/portal.js index 2630f6823..ebe30847a 100644 --- a/src/rainfly/src/lib/actions/portal.js +++ b/src/rainfly/src/lib/actions/portal.js @@ -1,4 +1,27 @@ // REF: https://github.com/romkor/svelte-portal/blob/a650e7b762344a1bb0ad9e218660ed1ee66e3f90/src/Portal.svelte +/** + * MIT License + * + * Copyright (c) 2019 Roman Rodych + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ import {tick} from 'svelte'; diff --git a/src/rainfly/src/lib/components/Visualizer.svelte b/src/rainfly/src/lib/components/Visualizer.svelte index d812f6436..a2f5180b1 100644 --- a/src/rainfly/src/lib/components/Visualizer.svelte +++ b/src/rainfly/src/lib/components/Visualizer.svelte @@ -29,7 +29,6 @@ $: { if ($status === Status.play || $status === Status.running) { - console.log($status); draw(); } else if ($status === Status.stop) { clearCanvas(); @@ -189,7 +188,6 @@ } zoom = Math.max(0, Math.min(zoom + scrollY, MAX_ZOOM)); - console.log('zoom', zoom); slice.full = zoom === 0; const max = getRecordedSamples()[0].length; const position = event.clientX / window.innerWidth *