commit ad431becdd17df5a1f5afd0405e431be35131591
parent a1608ff5dd04a4e657e7a0ddb3b0df371b7e7d6e
Author: massi <mdsiboldi@gmail.com>
Date: Thu, 6 Jul 2023 10:04:41 -0700
units can eventually have multiple outputs, so wrap input in obj
Diffstat:
4 files changed, 77 insertions(+), 78 deletions(-)
diff --git a/src/lib/Slider.svelte b/src/lib/Slider.svelte
@@ -1,22 +1,22 @@
<script lang="ts">
import type { Unit, UnitId, UnitMap } from '$lib/types';
- import { INPUT_RANGE, getUnit as _getUnit } from '$lib/types';
+ import { INPUT_RANGE, getUnit as _getUnit, is } from '$lib/types';
export let id: UnitId;
export let units: UnitMap;
export let handleInput: (id: string, coarseVal: number | null, fineVal: number | null) => void;
export let handleChange: () => void;
$: props = { units, handleInput, handleChange };
+
+ $: getUnit = _getUnit.bind(null, units);
$: unit = getUnit(id);
+ $: coarseUnit = !is.unit.const(unit) ? 0 : Math.floor(unit.value / 100_000) * 100_000;
+ $: fineUnit = !is.unit.const(unit) ? 0 : unit.value % 100_000;
const _handleInput = (...args) => {
handleInput(...args);
unit = unit;
};
-
- $: getUnit = _getUnit.bind(null, units);
- $: coarseUnit = Math.floor(unit.value / 100_000) * 100_000;
- $: fineUnit = unit.value % 100_000;
</script>
<div class="unit-container">
@@ -28,40 +28,40 @@
<input
name={id}
type="range"
- min="0"
- max={INPUT_RANGE}
+ min={(-1 * INPUT_RANGE) / 2}
+ max={INPUT_RANGE / 2}
step={100_000}
value={coarseUnit}
- on:input={(e) => _handleInput(id, Number(e.target.value), null)}
+ on:input={(e) => _handleInput(id, Number(e.target?.value), null)}
on:change={handleChange}
/>
<input
type="range"
min={0}
- max={100_000}
+ max={100_000 - 1}
step={1}
value={fineUnit}
- on:input={(e) => _handleInput(id, null, Number(e.target.value))}
+ on:input={(e) => _handleInput(id, null, Number(e.target?.value))}
on:change={handleChange}
/>
{:else if unit.kind === 'combinator'}
<h3>{unit.kind}</h3>
<div class="combinator-container">
- {#each unit.sources as sourceId}
- <svelte:self id={sourceId} {...props} />
+ {#each unit.sources as input}
+ <svelte:self id={input.id} {...props} />
{/each}
</div>
{:else if unit.kind === 'rescale'}
- <svelte:self id={unit.input} {...props} />
+ <svelte:self id={unit.input.id} {...props} />
{:else if unit.kind === 'noise'}
<h3>{unit.kind}</h3>
- <svelte:self id={unit.amount} {...props} />
+ <svelte:self id={unit.amount.id} {...props} />
{:else if unit.kind === 'osc'}
<h3>{unit.kind}</h3>
<h4>rate</h4>
- <svelte:self id={unit.rate} {...props} />
+ <svelte:self id={unit.rate.id} {...props} />
<h4>amount</h4>
- <svelte:self id={unit.amount} {...props} />
+ <svelte:self id={unit.amount.id} {...props} />
{:else}
<h3>{unit.kind} nyi</h3>
{/if}
diff --git a/src/lib/engine.worker.ts b/src/lib/engine.worker.ts
@@ -1,5 +1,6 @@
import type {
EngineMessage,
+ Input,
SynthConfig,
Unit,
UnitId,
@@ -60,13 +61,14 @@ function setUnitState(id: UnitId, state: UnitState) {
unitState.set(id, state);
}
-function v(id: UnitId): number {
+function v(input: Input): number {
+ const { id } = input;
const unit: Unit = getUnit(config.units, id);
switch (unit.kind) {
case "osc": {
const position = getUnitState(id);
- return (Math.sin(2 * Math.PI * (position / LOOP_CYCLES)) - 0.5) *
- v(unit.amount);
+ return Math.sin(2 * Math.PI * (position / LOOP_CYCLES)) *
+ v(unit.amount) - 0.5;
}
case "const": {
return unit.value;
@@ -109,13 +111,13 @@ function update() {
function drawSquares() {
if (config && canvas) {
const ctx = canvas.getContext("2d");
- const cols = 300;
- const rows = 100;
- let color = [0, 0, 0];
- let width = canvas.width;
- let height = canvas.height;
- let paneWidth = Math.ceil(width / cols);
- let paneHeight = Math.ceil(height / rows);
+ const cols = 100;
+ const rows = 50;
+ const color = [0, 0, 0];
+ const width = canvas.width;
+ const height = canvas.height;
+ const paneWidth = Math.ceil(width / cols);
+ const paneHeight = Math.ceil(height / rows);
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
@@ -132,6 +134,7 @@ function drawSquares() {
}
requestAnimationFrame(drawSquares);
}
+
drawSquares();
export {};
diff --git a/src/lib/types.ts b/src/lib/types.ts
@@ -1,3 +1,6 @@
+export const LOOP_CYCLES = 100_000_000;
+export const INPUT_RANGE = 100_000_000;
+
export type SynthConfig = {
sinks: Sinks;
units: UnitMap;
@@ -25,23 +28,26 @@ export type Unit =
export type UnitId = string;
+// To support units with multiple outputs.
+export type Input = { id: UnitId };
+
export type RescaleUnit = {
kind: "rescale";
- input: UnitId;
- min: UnitId;
- max: UnitId;
+ input: Input;
+ min: Input;
+ max: Input;
};
// uses rate and amount to output a sine wave going that fast and loud. TBD: what units the values are, etc.
export type OscUnit = {
kind: "osc";
- rate: UnitId;
- amount: UnitId;
+ rate: Input;
+ amount: Input;
};
export type NoiseUnit = {
kind: "noise";
- amount: UnitId;
+ amount: Input;
};
// outputs number as it is
@@ -52,16 +58,16 @@ export type ConstUnit = {
export type CombinatorUnit = {
kind: "combinator";
- sources: UnitId[];
+ sources: Input[];
};
export type UnitMap = Map<UnitId, Unit>;
export type UnitStateMap = Map<UnitId, UnitState>;
export type UnitState = any;
export type Sinks = {
- red?: UnitId;
- green?: UnitId;
- blue?: UnitId;
+ red?: Input;
+ green?: Input;
+ blue?: Input;
};
export function getUnit(units: UnitMap, id: UnitId): Unit {
@@ -70,5 +76,13 @@ export function getUnit(units: UnitMap, id: UnitId): Unit {
return result;
}
-export const LOOP_CYCLES = 100_000_000;
-export const INPUT_RANGE = 100_000_000;
+export const is = {
+ input: (i: any): i is Input => {
+ return i === Object(i) && i.id;
+ },
+ unit: {
+ const: (u: Unit): u is ConstUnit => {
+ return u.kind === "const";
+ },
+ },
+};
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
@@ -2,21 +2,8 @@
import { onMount } from 'svelte';
import { debounce } from 'lodash';
import Slider from '$lib/Slider.svelte';
- import { getUnit as _getUnit, LOOP_CYCLES, INPUT_RANGE } from '$lib/types';
- import type {
- Unit,
- UnitId,
- RescaleUnit,
- OscUnit,
- NoiseUnit,
- ConstUnit,
- CombinatorUnit,
- PageMessage,
- UnitMap,
- UnitStateMap,
- UnitState,
- Sinks
- } from '$lib/types';
+ import { is, getUnit as _getUnit, INPUT_RANGE } from '$lib/types';
+ import type { Input, Unit, UnitId, ConstUnit, UnitMap, Sinks } from '$lib/types';
let cvs: HTMLCanvasElement | undefined;
let offscreenCanvas: OffscreenCanvas | undefined;
@@ -60,7 +47,7 @@
});
$: getUnit = _getUnit.bind(null, units);
- let id = 0;
+ let uid = 0;
let units: UnitMap = new Map();
let sinks: Sinks = {};
@@ -101,22 +88,22 @@
console.log(fromUrl());
}
- function addUnit(unit: Unit) {
- const _id = String(id++);
- units.set(_id, unit);
+ function addUnit(unit: Unit): Input {
+ const id = String(uid++);
+ units.set(id, unit);
units = units;
- return _id;
+ return { id };
}
- type EzUnit = UnitId | number | undefined;
+ type EzUnit = Input | number | undefined;
// make a const unit or use the supplied one
- function ez(input: EzUnit): UnitId {
- return typeof input === 'string' ? input : mk.c(input || 0);
+ function ez(input: EzUnit): Input {
+ return is.input(input) ? input : mk.c(input || 0);
}
- function gatherControls(accum: Set<UnitId>, ...ids: UnitId[]) {
- for (let id of ids) {
- const unit = getUnit(id);
+ function gatherControls(accum: Set<Input>, ...ins: Input[]) {
+ for (let input of ins) {
+ const unit = getUnit(input.id);
switch (unit.kind) {
case 'osc': {
gatherControls(accum, unit.rate, unit.amount);
@@ -131,7 +118,7 @@
break;
}
case 'const': {
- accum.add(id);
+ accum.add(input);
break;
}
case 'combinator': {
@@ -145,13 +132,13 @@
$: unitsToControl = gatherControls(new Set(), ...Object.values(sinks));
const mk = {
- c: function mkConst(value: number): UnitId {
+ c: function mkConst(value?: number): Input {
return addUnit({
kind: 'const',
- value
+ value: value || 0
});
},
- osc: function mkOsc(rate?: EzUnit, amount?: EzUnit): UnitId {
+ osc: function mkOsc(rate?: EzUnit, amount?: EzUnit): Input {
return addUnit({
kind: 'osc',
rate: mk.re(0, INPUT_RANGE / 10, ez(rate)),
@@ -188,16 +175,11 @@
}
};
- const CELLS = 5000;
-
const red = mk.re_color(
mk.add(
mk.c(INPUT_RANGE / 2), //
- mk.n(INPUT_RANGE / 2),
- mk.osc(
- mk.add(mk.c(0), mk.osc(CELLS * 4 * 10), mk.osc(CELLS * 2 * 10, INPUT_RANGE / 2)),
- INPUT_RANGE / 2
- ) //
+ mk.n(0),
+ mk.osc(mk.add(mk.c(0), mk.osc(), mk.osc(mk.c(), mk.osc())), INPUT_RANGE / 2) //
)
);
const green = mk.re_color();
@@ -215,7 +197,7 @@
if (vCoarse !== null) {
unit.value = (oldVal % 100_000) + vCoarse;
} else if (vFine !== null) {
- unit.value = Math.floor(oldVal / 100_000) * 100_000 + vFine;
+ unit.value = Math.floor(oldVal / 100_000) * 100_000 + Math.abs(vFine);
}
console.log({ value: unit.value });
units = units;
@@ -225,10 +207,10 @@
<canvas bind:this={cvs} />
<div id="sliders">
- {#each [...Object.entries(sinks)] as [label, unitId]}
+ {#each [...Object.entries(sinks)] as [label, input]}
<div>
<h2>{label}</h2>
- <Slider id={unitId} {units} handleInput={updateUnit} handleChange={updateUrl} />
+ <Slider id={input.id} {units} handleInput={updateUnit} handleChange={updateUrl} />
</div>
{/each}
</div>