commit f4a5f72284046c308acb7aad7c5109d8a05e8677
parent e8cdcb3c25d66e3a0744509c6d36d14e275a6012
Author: massi <mdsiboldi@gmail.com>
Date: Wed, 21 Jun 2023 17:49:35 -0700
first stab at typing
Diffstat:
1 file changed, 167 insertions(+), 35 deletions(-)
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
@@ -20,62 +20,187 @@
let t = 0;
+ const DELTA = 0.00001;
function step() {
- t = (t + 1) % 1000000000000; // lol
+ t = (t + DELTA) % 100; // lol
}
- type Binding = () => number;
+ enum BindingKind {
+ OscBinding
+ }
+
+ type UnitMap = Map<UnitId, Unit>;
+ type UnitStateMap = Map<UnitId, UnitState>;
+ type UnitState = any;
+
+ type UnitId = string;
+
+ // uses rate and amount to output a sine wave going that fast and loud. TBD: what units the values are, etc.
+ type OscUnit = {
+ kind: 'osc';
+ rate: Binding[];
+ amount: Binding[];
+ };
+
+ // outputs number as it is
+ type ConstUnit = {
+ kind: 'const';
+ value: number;
+ };
+
+ type Unit = OscUnit | ConstUnit;
+
+ type Binding = {
+ scale: number;
+ source: UnitId;
+ };
- function mkOsc(inputs: { rate: Binding; amount: Binding }): Binding {
- let { rate, amount } = inputs;
- return () => (Math.sin(2 * Math.PI * t * rate()) - 0.5) * amount();
+ type Grid = {
+ rows: Binding[];
+ cols: Binding[];
+ };
+
+ type OldBinding = () => number;
+
+ let id = 1;
+ let units: UnitMap = new Map();
+ let unitState: UnitStateMap = new Map();
+ function addUnit(unit: Unit) {
+ const _id = String(id++);
+ units.set(_id, unit);
+ switch (unit.kind) {
+ case 'osc': {
+ unitState.set(_id, 0);
+ }
+ }
+ return _id;
}
- function combinatorBinding(...bindings: Binding[]): Binding {
- return () => bindings.reduce((a, b) => a + b(), 0);
+ function getUnit(id: UnitId): Unit {
+ let goal = units.get(id);
+ if (!goal) throw new Error('invalid id for unit: ' + id);
+ return goal;
+ }
+
+ function getUnitState(id: UnitId): UnitState {
+ let unit = getUnit(id);
+ let goal = unitState.get(id);
+ switch (unit.kind) {
+ case 'osc': {
+ if (typeof goal !== 'number') {
+ throw new Error('invalid state for osc unit: ' + id);
+ }
+ break;
+ }
+ default: {
+ throw new Error('state for this invalid or NYI');
+ }
+ }
+ return goal;
+ }
+
+ function setUnitState(id: UnitId, state: UnitState) {
+ // TODO: type safety
+ unitState.set(id, state);
+ }
+
+ function v(id: UnitId): number {
+ const unit: Unit = getUnit(id);
+ switch (unit.kind) {
+ case 'osc': {
+ const position = getUnitState(id);
+ return (Math.sin(2 * Math.PI * position) - 0.5) * r(unit.amount);
+ }
+ case 'const': {
+ return unit.value;
+ }
+ }
+ }
+
+ function r(bindings: Binding[]): number {
+ return bindings.reduce((a, b) => a + b.scale * v(b.source), 0);
}
- function constBinding(value: number): Binding {
- return () => value;
+ function update(...ids: UnitId[]) {
+ // update all unit states
+ ids = ids || units.keys();
+ for (let id of ids) {
+ const unit = getUnit(id);
+ switch (unit.kind) {
+ case 'osc':
+ const position = getUnitState(id);
+ const rate = r(unit.rate);
+ setUnitState(id, position + rate);
+ }
+ }
+ }
+
+ function mkConst(value: number): UnitId {
+ return addUnit({
+ kind: 'const',
+ value
+ });
+ }
+
+ function mkOsc(rate: Binding[], amount: Binding[]): UnitId {
+ return addUnit({
+ kind: 'osc',
+ rate,
+ amount
+ });
+ }
+
+ function c(value: number): Binding {
+ return { scale: 1, source: mkConst(value) };
+ }
+
+ function mkBinding(source: UnitId): Binding {
+ return {
+ scale: 1,
+ source
+ };
+ }
+
+ function o(rate: Binding[], amount: Binding[]): Binding {
+ return mkBinding(mkOsc(rate, amount));
+ }
+
+ //const red = mkOsc([c(0.1), o([c(0.1)], [c(0.01)])], [c(100)]);
+ const red = mkOsc([c(189)], [c(50)]);
+ const green = mkConst(20);
+ const blue = mkOsc([c(0.01)], [c(100)]);
+
+ console.log(units.get(red));
+
+ //function mkOsc(inputs: { rate: OldBinding; amount: OldBinding }): OldBinding {
+ // let { rate, amount } = inputs;
+ // return () => (Math.sin(2 * Math.PI * t * rate()) - 0.5 + Math.random() / 20) * amount();
+ //}
+
+ function combinatorBinding(...bindings: OldBinding[]): OldBinding {
+ return () => bindings.reduce((a, b) => a + b(), 0);
}
+ let nextT = null;
+
function drawSquares(ctx: CanvasRenderingContext2D) {
if (!cvs) {
return;
}
- const cols = 100;
- const rows = 200;
- let color = [128, 128, 128];
+ const cols = 50;
+ const rows = 50;
+ let color = [50, 0, 100];
let width = cvs.width;
let height = cvs.height;
let paneWidth = Math.ceil(width / cols);
let paneHeight = Math.ceil(height / rows);
- let osc1 = mkOsc({
- rate: combinatorBinding(
- constBinding(0.761243),
- mkOsc({ rate: () => 0.0001, amount: () => 0.01 })
- ),
- amount: constBinding(30)
- });
- let osc2 = mkOsc({
- rate: combinatorBinding(
- mkOsc({ rate: () => 0.00001, amount: () => 1 }),
- constBinding(0.881242)
- ),
- amount: constBinding(55)
- });
- let osc3 = mkOsc({ rate: constBinding(0.000001), amount: constBinding(255) });
-
- const red = combinatorBinding(constBinding(128), osc1);
- const green = combinatorBinding(constBinding(128), osc2);
- const blue = combinatorBinding(constBinding(128), osc3);
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
- step();
- color[0] = red();
- color[1] = green();
- color[2] = blue();
+ color[0] = v(red);
+ color[1] = v(green);
+ color[2] = v(blue);
+ update(red, green, blue);
ctx.fillStyle = `rgb(${color.join(', ')})`;
let x = col * paneWidth;
let y = row * paneHeight;
@@ -97,10 +222,17 @@
<canvas bind:this={cvs} />
+<button on:click={run}>step </button>
+
<style>
canvas {
width: 100vw;
height: 100vh;
background: salmon;
}
+ button {
+ position: absolute;
+ left: 10px;
+ top: 10px;
+ }
</style>