commit 5e6139f8e0eabb75dee9d65edf842d9939f5fd92
parent b1a7aa45fd457a8f8efcf6e94cb112a7b4f939b8
Author: massi <mdsiboldi@gmail.com>
Date: Wed, 19 Jul 2023 00:43:19 -0700
get back in sync with ts
Diffstat:
8 files changed, 86 insertions(+), 61 deletions(-)
diff --git a/package-lock.json b/package-lock.json
@@ -9,12 +9,13 @@
"version": "0.0.1",
"dependencies": {
"@sveltejs/adapter-static": "^2.0.2",
- "@types/offscreencanvas": "^2019.7.0",
"lodash": "^4.17.21"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.5.0",
+ "@types/lodash": "^4.14.195",
+ "@types/offscreencanvas": "^2019.7.0",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
@@ -616,10 +617,17 @@
"integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
"dev": true
},
+ "node_modules/@types/lodash": {
+ "version": "4.14.195",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
+ "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==",
+ "dev": true
+ },
"node_modules/@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
- "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
+ "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==",
+ "dev": true
},
"node_modules/@types/pug": {
"version": "2.0.6",
@@ -3305,10 +3313,17 @@
"integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
"dev": true
},
+ "@types/lodash": {
+ "version": "4.14.195",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz",
+ "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==",
+ "dev": true
+ },
"@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
- "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
+ "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==",
+ "dev": true
},
"@types/pug": {
"version": "2.0.6",
diff --git a/package.json b/package.json
@@ -14,6 +14,8 @@
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.5.0",
+ "@types/lodash": "^4.14.195",
+ "@types/offscreencanvas": "^2019.7.0",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
@@ -30,7 +32,6 @@
"type": "module",
"dependencies": {
"@sveltejs/adapter-static": "^2.0.2",
- "@types/offscreencanvas": "^2019.7.0",
"lodash": "^4.17.21"
}
}
diff --git a/src/lib/Sink.svelte b/src/lib/Sink.svelte
@@ -1,8 +1,6 @@
<script lang="ts">
- import type { UnitId } from '$lib/types';
- export let id: UnitId;
export let channel: 'l' | 'c' | 'h';
- export let onSinkConnect: null | ((ch: string) => void);
+ export let onSinkConnect: null | ((ch: 'l' | 'c' | 'h') => void);
let _onSinkConnect: null | (() => void) = null;
$: _onSinkConnect = onSinkConnect ? () => onSinkConnect && onSinkConnect(channel) : null;
diff --git a/src/lib/Slider.svelte b/src/lib/Slider.svelte
@@ -1,6 +1,6 @@
<script lang="ts">
- import type { Unit, UnitId, UnitMap } from '$lib/types';
- import { rescale, range, INPUT_RANGE, getUnit as _getUnit, is } from '$lib/types';
+ import type { WithTarget, UnitId, UnitMap } from '$lib/types';
+ import { rescale, range, getUnit as _getUnit } from '$lib/types';
import NumberSelector from '$lib/NumberSelector.svelte';
export let id: UnitId;
@@ -12,12 +12,18 @@
$: getUnit = _getUnit.bind(null, units);
$: unit = getUnit(id);
- $: sliderValue = Math.round(rescale(unit.value, range.signal, range.slider));
+ $: sliderValue =
+ unit.kind === 'const' ? Math.round(rescale(unit.value, range.signal, range.slider)) : 0;
const _handleInput = (val: number) => {
handleInput(id, Math.round(rescale(val, range.slider, range.signal)));
unit = unit;
};
+
+ const onInput = (e: WithTarget<Event, HTMLInputElement>) => {
+ console.log(e.currentTarget);
+ _handleInput(Number(e.currentTarget?.value));
+ };
</script>
<div class="unit-container">
@@ -31,7 +37,7 @@
max={range.slider.max}
step={1}
value={sliderValue}
- on:input={(e) => _handleInput(Number(e.target?.value))}
+ on:input={onInput}
on:change={handleChange}
/>
{:else if unit.kind === 'combinator'}
@@ -41,8 +47,6 @@
<svelte:self id={input.id} {...props} />
{/each}
</div>
- {:else if unit.kind === 'rescale'}
- <svelte:self id={unit.input.id} {...props} />
{:else if unit.kind === 'noise'}
<h3>{unit.kind}</h3>
<svelte:self id={unit.amount.id} {...props} />
@@ -50,15 +54,13 @@
<h3>{unit.kind}</h3>
<h4>rate</h4>
coarse
- <svelte:self id={unit.coarse.id} {...props} />
+ <svelte:self id={unit.coarse[0].id} {...props} />
fine
<svelte:self id={unit.fine.id} {...props} />
superfine
<svelte:self id={unit.superfine.id} {...props} />
<h4>amount</h4>
<svelte:self id={unit.amount.id} {...props} />
- {:else}
- <h3>{unit.kind} nyi</h3>
{/if}
</div>
@@ -72,14 +74,9 @@
padding: 10px;
display: flexbox;
}
- h1,
- h2,
h3,
h4 {
padding: 0;
margin: 0;
}
- .val {
- height: 16px;
- }
</style>
diff --git a/src/lib/engine.worker.ts b/src/lib/engine.worker.ts
@@ -8,10 +8,7 @@ import type {
UnitStateMap,
} from "$lib/types";
import {
- CELLS,
- clamp,
getUnit,
- INPUT_RANGE,
LOOP_CYCLES,
range,
rescale,
@@ -22,23 +19,29 @@ let config: SynthConfig | undefined = undefined;
let unitState: UnitStateMap = new Map();
+// @ts-ignore dunno how to get OffscreenCanvas working
let canvas: OffscreenCanvas = new OffscreenCanvas(1, 1);
+// @ts-ignore dunno how to get message working
onmessage = (message: { data: EngineMessage }) => {
- const { data, data: { kind, content } } = message;
- switch (kind) {
+ const { data } = message;
+ switch (data.kind) {
case "config": {
- config = content;
+ config = data.content;
break;
}
case "window": {
- console.log(content);
+ console.log(data.content);
+ // @ts-ignore dunno how to get OffscreenCanvas working
canvas = new OffscreenCanvas(content.width, content.height);
}
}
};
function getUnitState(id: UnitId): UnitState {
+ if (!config) {
+ throw new Error("no config, can't get unit state.")
+ }
const unit = getUnit(config.units, id);
const theState = unitState.get(id);
switch (unit.kind) {
@@ -63,8 +66,17 @@ function setUnitState(id: UnitId, state: UnitState) {
unitState.set(id, state);
}
-function v(input: Input): number {
- const { id } = input;
+function v(inOrIns: Input | Input[]): number {
+ if (!config) {
+ throw new Error("no config, can't get unit value.")
+ }
+
+ if (Array.isArray(inOrIns)) {
+ return inOrIns.reduce((a, b) => a + v(b), 0);
+ }
+
+
+ const { id } = inOrIns;
const unit: Unit = getUnit(config.units, id);
switch (unit.kind) {
case "osc": {
@@ -90,14 +102,14 @@ function v(input: Input): number {
case "noise": {
return Math.random() * v(unit.amount);
}
- default: {
- throw new Error(`${unit.kind} unsupported`);
- }
}
}
function update() {
// update all unit states
+ if (!config) {
+ throw new Error("no config, can't update unit state.")
+ }
const ids = config.units.keys();
for (let id of ids) {
const unit = getUnit(config.units, id);
@@ -115,7 +127,7 @@ function update() {
id,
(position + coarse * LOOP_CYCLES / 100 + fine * 20000 +
superfine * 10) %
- LOOP_CYCLES,
+ LOOP_CYCLES,
);
break;
}
@@ -126,6 +138,7 @@ function update() {
function drawSquares() {
if (config) {
const ctx = canvas.getContext("2d");
+ if (!ctx) throw new Error("could not get 2d rendering context...")
const cols = 100;
const rows = 50;
const color = [0, 0, 0];
@@ -136,9 +149,9 @@ function drawSquares() {
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
- const l = config.sinks.l == null ? 0 : v({ id: config.sinks.l });
- const c = config.sinks.c == null ? 0 : v({ id: config.sinks.c });
- const h = config.sinks.h == null ? 0 : v({ id: config.sinks.h });
+ const l = config.sinks.l == null ? 0 : v(config.sinks.l);
+ const c = config.sinks.c == null ? 0 : v(config.sinks.c);
+ const h = config.sinks.h == null ? 0 : v(config.sinks.h);
color[0] = wrangle(l, range.signal, {
min: 0,
max: 100,
diff --git a/src/lib/types.ts b/src/lib/types.ts
@@ -1,10 +1,11 @@
-import type { OffscreenCavas } from "@types/offscreencanvas";
export const LOOP_CYCLES = 100_000_000;
export const INPUT_RANGE = 100;
export const ROWS = 100;
export const COLS = 50;
export const CELLS = ROWS * COLS;
+export type WithTarget<E, T> = E & { currentTarget: T };
+
export type SynthConfig = {
sinks: Sinks;
units: UnitMap;
@@ -26,7 +27,6 @@ export type EngineMessage = {
export type HigherUnit =
| OscUnit
| CombinatorUnit
- | RescaleUnit
| NoiseUnit;
export type Unit =
@@ -39,16 +39,9 @@ export type Input = { id: UnitId };
export type Pos = { x: number; y: number };
-export type RescaleUnit = {
- kind: "rescale";
- input: Input;
- min: Input;
- max: Input;
-};
-
export type OscUnit = {
kind: "osc";
- coarse: Input;
+ coarse: Input[];
fine: Input;
superfine: Input;
amount: Input;
@@ -174,7 +167,7 @@ export function clamp(n: number, range: Range) {
}
export function rescale(n: number, origin: Range, dest: Range) {
return ((n - origin.min) / (origin.max - origin.min)) *
- (dest.max - dest.min) + dest.min;
+ (dest.max - dest.min) + dest.min;
}
export function wrangle(n: number, origin: Range, dest: Range) {
return rescale(clamp(n, origin), origin, dest);
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
@@ -3,7 +3,7 @@
import { debounce } from 'lodash';
import Sink from '$lib/Sink.svelte';
import Slider from '$lib/Slider.svelte';
- import { ensure, rescale, range, is, getUnit as _getUnit, INPUT_RANGE } from '$lib/types';
+ import { ensure, rescale, range, is, getUnit as _getUnit } from '$lib/types';
import type { Input, Unit, UnitId, ConstUnit, UnitMap, Sinks } from '$lib/types';
let cvs: HTMLCanvasElement | undefined;
@@ -61,7 +61,7 @@
$: getUnit = _getUnit.bind(null, units);
let uid = 0;
let units: UnitMap = new Map();
- let sinks: Sinks = {};
+ let sinks: Sinks = { l: null, c: null, h: null };
onMount(() => {
const doc: SerializedState = fromUrl();
@@ -118,7 +118,8 @@
c: function mkConst(value?: number): Input {
return addUnit({
kind: 'const',
- value: value == null ? randConst() : value
+ value: value == null ? randConst() : value,
+ pos: { x: 0, y: 0 }
});
},
osc: function mkOsc(
@@ -129,7 +130,7 @@
): Input {
return addUnit({
kind: 'osc',
- coarse: ez(coarse),
+ coarse: [ez(coarse)],
fine: ez(fine),
superfine: superfine ? ez(superfine) : mk.c(0),
amount: ez(amount)
@@ -169,7 +170,7 @@
let dragging: false | UnitId = false;
- const handleMouseMove = (e) => {
+ const handleMouseMove = (e: MouseEvent) => {
if (!dragging) return;
ensure.unit.const(getUnit(dragging)).pos = {
x: e.clientX,
@@ -210,7 +211,7 @@
if (!signalDragging) {
throw new Error('cant connect sink to nonexistant signal');
}
- sinks[ch] = signalDragging.id;
+ sinks[ch] = { id: signalDragging.id };
engineWorker && engineWorker.postMessage({ kind: 'config', content: { sinks, units } });
console.log(sinks);
signalDragging = false;
@@ -219,25 +220,31 @@
$: onSinkConnect = signalDragging ? _onSinkConnect : null;
$: unitEntries = units.entries();
- $: sinkEntries = Object.entries(sinks);
+ type SinkEntries = [keyof Sinks, Input | null][];
+ // Object.entries COULD have extra stuff, so it doesn't assume keys are keyof Sinks exactly.
+ // see https://stackoverflow.com/questions/60141960/typescript-key-value-relation-preserving-object-entries-type
+ $: sinkEntries = [...Object.entries(sinks)] as SinkEntries;
</script>
<canvas bind:this={cvs} />
<div id="buttons">
- <button on:click={(e) => addConst()}>add const</button>
+ <button on:click={addConst}>add const</button>
</div>
<h1>HI {unitEntries}</h1>
<div id="sinks">
- {#each [...sinkEntries] as [channel, id]}
- <Sink {id} {channel} {onSinkConnect} />
+ {#each sinkEntries as [channel]}
+ <Sink {channel} {onSinkConnect} />
{/each}
</div>
<div id="units">
{#each [...unitEntries] as [id, unit]}
- <div class="unit" style={`top: ${unit.pos.y}px; left: ${unit.pos.x}px`}>
- <h2 on:mousedown={(e) => handleMouseDown(id)}>{id} {unit.kind}</h2>
+ <div
+ class="unit"
+ style={unit.kind === 'const' ? `top: ${unit.pos.y}px; left: ${unit.pos.x}px` : ''}
+ >
+ <h2 on:mousedown={handleMouseDown.bind(null, id)}>{id} {unit.kind}</h2>
<Slider {id} {units} handleInput={updateUnit} handleChange={updateUrl} />
<div
class="output-dragger"
diff --git a/tsconfig.json b/tsconfig.json
@@ -8,7 +8,8 @@
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
- "strict": true
+ "strict": true,
+ "lib": ["webworker", "es2019"]
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//