Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rainfly - An AudioWorklet DSP Playground [MVP] #395

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 0 additions & 1 deletion .eleventyignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
node_modules/
./src/archive/
.src/rainfly/
**/README.md
4 changes: 1 addition & 3 deletions src/_data/audioworklet_data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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


terryzfeng marked this conversation as resolved.
Show resolved Hide resolved
- title: FreeQueue
entries:
Expand Down
3 changes: 3 additions & 0 deletions src/_data/landing_data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions src/rainfly/src/lib/assets/vim.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 3 additions & 11 deletions src/rainfly/src/lib/components/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -74,7 +75,7 @@
);
editor.setModel(model);

// temp testing
// TODO: Add ability for autosave on change to LocalStorage
editor.onDidChangeModelContent(() => {
// console.log(getEditorCode())
});
Expand Down Expand Up @@ -220,16 +221,7 @@
class:bg-accent={$vimStatus}
bind:this={anchor}
>
<svg fill="#000000" width="20" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<!-- eslint-disable-next-line max-len -->
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
<g id="SVGRepo_iconCarrier">
<title>VIm</title>
<!-- eslint-disable-next-line max-len -->
<path d="M26.445 22.095l0.592-0.649h1.667l0.386 0.519-1.581 5.132h0.616l-0.1 0.261h-2.228l1.405-4.454h-2.518l-1.346 4.238h0.53l-0.091 0.217h-2.006l1.383-4.434h-2.619l-1.327 4.172h0.545l-0.090 0.261h-2.076l1.892-5.573h-0.732l0.114-0.339h2.062l0.649 0.671h1.132l0.614-0.692h1.326l0.611 0.669zM7.99 27.033h-2.141l-0.327-0.187v-21.979h-1.545l-0.125-0.125v-1.47l0.179-0.192h9.211l0.266 0.267v1.385l-0.177 0.216h-1.348v10.857l11.006-10.857h-2.607l-0.219-0.235v-1.453l0.151-0.139h9.36l0.165 0.166v1.337l-12.615 12.937h-0.466c-0.005-0-0.011-0-0.018-0-0.012 0-0.024 0.001-0.036 0.002l0.002-0-0.025 0.004c-0.058 0.012-0.108 0.039-0.149 0.075l0-0-0.429 0.369-0.005 0.004c-0.040 0.037-0.072 0.084-0.090 0.136l-0.001 0.002-0.37 1.037zM17.916 18.028l0.187 0.189-0.336 1.152-0.281 0.282h-1.211l-0.226-0.226 0.389-1.088 0.36-0.309zM13.298 27.42l1.973-5.635h-0.626l0.371-0.38h2.073l-1.953 5.692h0.779l-0.099 0.322zM30.996 15.982h-0.034l-5.396-5.396 5.377-5.516v-2.24l-0.811-0.81h-10.245l-0.825 0.756v1.306l-3.044-3.044v-0.034l-0.019 0.018-0.018-0.018v0.034l-1.612 1.613-0.672-0.673h-10.151l-0.797 0.865v2.356l0.77 0.77h0.9v6.636l-3.382 3.38h-0.034l0.018 0.016-0.018 0.017h0.034l3.382 3.382v8.081l1.133 0.654h2.902l2.321-2.379 5.206 5.206v0.035l0.019-0.017 0.017 0.017v-0.035l3.136-3.135h0.606c0.144-0.001 0.266-0.093 0.312-0.221l0.001-0.002 0.182-0.532c0.011-0.031 0.017-0.067 0.017-0.105 0-0.073-0.024-0.14-0.064-0.195l0.001 0.001 1.827-1.827-0.765 2.452c-0.009 0.029-0.015 0.063-0.015 0.097 0 0.149 0.098 0.275 0.233 0.317l0.002 0.001c0.029 0.009 0.063 0.015 0.097 0.015 0 0 0 0 0 0h2.279c0.136-0.001 0.252-0.084 0.303-0.201l0.001-0.002 0.206-0.492c0.014-0.036 0.022-0.077 0.022-0.121 0-0.048-0.010-0.094-0.028-0.135l0.001 0.002c-0.035-0.082-0.1-0.145-0.18-0.177l-0.002-0.001c-0.036-0.015-0.077-0.024-0.121-0.025h-0.094l1.050-3.304h1.54l-1.27 4.025c-0.009 0.029-0.015 0.063-0.015 0.097 0 0.149 0.098 0.274 0.232 0.317l0.002 0.001c0.029 0.009 0.063 0.015 0.098 0.015 0 0 0.001 0 0.001 0h2.502c0 0 0.001 0 0.001 0 0.14 0 0.26-0.087 0.308-0.21l0.001-0.002 0.205-0.535c0.013-0.034 0.020-0.073 0.020-0.114 0-0.142-0.090-0.264-0.215-0.311l-0.002-0.001c-0.034-0.013-0.073-0.021-0.114-0.021h-0.181l1.413-4.59c0.011-0.031 0.017-0.066 0.017-0.103 0-0.074-0.025-0.143-0.066-0.198l0.001 0.001-0.469-0.63-0.004-0.006c-0.061-0.078-0.156-0.127-0.261-0.127h-1.795c-0.093 0-0.177 0.039-0.237 0.101l-0 0-0.5 0.549h-0.78l-0.052-0.057 5.555-5.555h0.035l-0.017-0.014z"></path>
</g>
</svg>
<img src={vimIcon} alt="Vim" />
</button>
{/if}
</div>
Expand Down
31 changes: 15 additions & 16 deletions src/rainfly/src/lib/components/Visualizer.svelte
terryzfeng marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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) {
Expand All @@ -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();
Expand All @@ -114,7 +110,6 @@
}
}

// Request animation frame
if ($status === Status.play || $status === Status.running) {
requestAnimationFrame(draw);
}
Expand Down Expand Up @@ -159,7 +154,7 @@
}

/**
* Clear the canvas and draw the axes
* Clear the canvas and re-draw the axes
*/
function clearCanvas() {
if (!context) return;
Expand All @@ -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;

Expand All @@ -190,7 +189,7 @@
}

zoom = Math.max(0, Math.min(zoom + scrollY, MAX_ZOOM));
console.log("zoom", zoom);
console.log('zoom', zoom);
terryzfeng marked this conversation as resolved.
Show resolved Hide resolved
slice.full = zoom === 0;
const max = getRecordedSamples()[0].length;
const position = event.clientX / window.innerWidth *
Expand Down
61 changes: 42 additions & 19 deletions src/rainfly/src/lib/components/nav/items/NavExamples.svelte
Original file line number Diff line number Diff line change
@@ -1,39 +1,62 @@
<script>
import NavItem from '$lib/components/nav/NavItem.svelte';
import NavDropdownItem from '$lib/components/nav/NavDropdownItem.svelte';
import {onMount} from 'svelte';
import {fetchTextFile} from '$lib/utils/file-utils.js';
import {
loadEditorProcessor,
loadEditorMain,
} from '$lib/../routes/+page.svelte';

/**
* @typedef {Object} Example
* @property {string} name - The name of the example
* @property {string} mainCodeUrl - URL to the AudioWorkletNode code
* @property {string} processorCodeUrl - URL to the AudioWorkletProcessor code
*/

/** @type Example[] */
let examples = [];

onMount(async () => {
buildExamples();
});

/**
* Load processor and main code from URL to Editor
* @param {string} mainCodeUrl - URL to main code
* @param {string} processorCodeUrl - URL to processor code
*/
async function loadExample(mainCodeUrl, processorCodeUrl) {
loadEditorMain((await fetchTextFile(mainCodeUrl)).data, 'main');
loadEditorProcessor(
(await fetchTextFile(processorCodeUrl)).data,
'processor',
);
try {
loadEditorMain((await fetchTextFile(mainCodeUrl)).data, 'main');
loadEditorProcessor(
(await fetchTextFile(processorCodeUrl)).data,
'processor',
);
} catch (/** @type any */ e) {
loadEditorProcessor(`${e.message}`, 'processor');
}
}

/**
* Build examples dropdown from examples.json
*/
async function buildExamples() {
const response = await fetch('examples/examples.json');
const data = await response.json();
examples = data.examples;
}
</script>

<NavItem name="Examples">
terryzfeng marked this conversation as resolved.
Show resolved Hide resolved
<NavDropdownItem
on:click={() => {
loadExample('examples/bypass/main.js', 'examples/bypass/processor.js');
}}
>
Hello Bypass
</NavDropdownItem>
<NavDropdownItem
on:click={() => {
loadExample('examples/sine/main.js', 'examples/sine/processor.js');
}}
>
Hello Sine
</NavDropdownItem>
{#each examples as example}
<NavDropdownItem
on:click={() => {
loadExample(example.mainCodeUrl, example.processorCodeUrl);
}}
>
{example.name}
</NavDropdownItem>
{/each}
</NavItem>
16 changes: 14 additions & 2 deletions src/rainfly/src/lib/components/nav/items/NavFile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,20 @@
const mainCode = getEditorMain();
/** @type {Object.<string, string>}*/
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);
Expand Down
2 changes: 1 addition & 1 deletion src/rainfly/src/lib/components/nav/items/NavHelp.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
</div>
</div>
<div class="text-center text-sm">
<!-- eslint-disable-next-line no-undef -->
<!-- svelte-ignore missing-declaration -->
<!-- eslint-disable-next-line no-undef -->
<p>ver {meta.version}</p>
</div>
</div>
Expand Down
Loading
Loading