color-synth

a synth that generates colors instead of sounds
Log | Files | Refs | README

commit 0b6136b99e5974b174908de9a3bd00a8948bca23
parent df9fd70e935d842b8da4b8910bfc577e99df8fd5
Author: massi <mdsiboldi@gmail.com>
Date:   Wed, 19 Jul 2023 03:43:45 -0700

add osc unit UI

Diffstat:
Asrc/lib/Osc.svelte | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/types.ts | 9+++++----
Msrc/routes/+page.svelte | 76+++++++++++++++++++++++++++++++++-------------------------------------------
3 files changed, 105 insertions(+), 47 deletions(-)

diff --git a/src/lib/Osc.svelte b/src/lib/Osc.svelte @@ -0,0 +1,67 @@ +<script lang="ts"> + import type { OscUnit, WithTarget } from '$lib/types'; + import { wrangle, rescale, range } from '$lib/types'; + import NumberSelector from '$lib/NumberSelector.svelte'; + + export let unit: OscUnit; + export let updateOsc: (osc: OscUnit) => void; + + $: vals = { + coarse: + typeof unit.coarse === 'number' ? wrangle(unit.coarse, range.signal, range.osc.coarse) : null, + fine: typeof unit.fine === 'number' ? wrangle(unit.fine, range.signal, range.osc.fine) : null, + superfine: + typeof unit.superfine === 'number' + ? wrangle(unit.superfine, range.signal, range.osc.superfine) + : null, + amount: + typeof unit.amount === 'number' ? wrangle(unit.amount, range.signal, range.osc.amount) : null + }; + + console.log({ vals }); + + const updateValue = (k: string, n: number) => { + updateOsc({ ...unit, [k]: Math.round(rescale(n, range.osc[k], range.signal)) }); + }; +</script> + +<div class="unit-container"> + <h3>{unit.kind}</h3> + {#each [...Object.entries(vals)] as [k, v]} + <div class="sect"> + {#if v !== null} + <h3>{k}</h3> + <NumberSelector value={v} updateValue={updateValue.bind(undefined, k)} /> + <input + name={unit.id} + type="range" + min={range.osc[k].min} + max={range.osc[k].max} + step={1} + value={v} + on:input={(e) => updateValue(k, Number(e.currentTarget?.value))} + /> + {/if} + </div> + {/each} +</div> + +<style> + .sect { + width: 100%; + height: 80px; + } + .disabled { + opacity: 0.5; + pointer-events: none; + } + .unit-container { + background: rgba(255, 255, 255, 0.3); + padding: 10px; + display: flexbox; + } + h3 { + padding: 0; + margin: 0; + } +</style> diff --git a/src/lib/types.ts b/src/lib/types.ts @@ -39,7 +39,9 @@ export type Input = number | Output[]; export type Pos = { x: number; y: number }; -export type OscUnit = { +type WithPos = { pos: Pos }; + +export type OscUnit = WithPos & { kind: "osc"; coarse: Input; fine: Input; @@ -47,16 +49,15 @@ export type OscUnit = { amount: Input; }; -export type NoiseUnit = { +export type NoiseUnit = WithPos & { kind: "noise"; amount: Input; }; // outputs number as it is -export type ConstUnit = { +export type ConstUnit = WithPos & { kind: "const"; value: number; - pos: Pos; }; export type UnitMap = Map<UnitId, Unit>; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte @@ -2,6 +2,7 @@ import { onMount } from 'svelte'; import { debounce } from 'lodash'; import Sink from '$lib/Sink.svelte'; + import Osc from '$lib/Osc.svelte'; import Slider from '$lib/Slider.svelte'; import { inp, ensure, rescale, range, is, getUnit as _getUnit } from '$lib/types'; import type { Output, Input, Unit, UnitId, ConstUnit, UnitMap, Sinks } from '$lib/types'; @@ -96,17 +97,11 @@ } const updateUrl = debounce(_updateUrl, 250); - function addUnit(unit: Unit): Input { + function addUnit(unit: Unit): UnitId { const id = String(uid++); units.set(id, unit); units = units; - return [{ id }]; - } - - type EzUnit = Input | number | undefined; - // make a const unit or use the supplied one - function ez(input: EzUnit): Input { - return is.input(input) ? input : mk.c(input || randConst()); + return id; } const randConst = () => { @@ -115,29 +110,25 @@ }; const mk = { - c: function mkConst(value?: number): Input { + c: function mkConst(): UnitId { return addUnit({ kind: 'const', - value: value == null ? randConst() : value, + value: randConst(), pos: { x: 0, y: 0 } }); }, - osc: function mkOsc( - coarse?: EzUnit, - fine?: EzUnit, - superfine?: EzUnit, - amount?: EzUnit - ): Input { + osc: function mkOsc(): UnitId { return addUnit({ kind: 'osc', - coarse: ez(coarse), - fine: ez(fine), - superfine: superfine ? ez(superfine) : mk.c(0), - amount: ez(amount) + coarse: randConst(), + fine: randConst(), + superfine: 0, + amount: randConst(), + pos: { x: 0, y: 0 } }); }, - n: function noise(amt: EzUnit) { - return addUnit({ kind: 'noise', amount: ez(amt) }); + n: function noise(): UnitId { + return addUnit({ kind: 'noise', amount: randConst(), pos: { x: 0, y: 0 } }); } }; @@ -155,16 +146,16 @@ units = units; } - const addConst = () => { - addUnit({ kind: 'const', value: randConst(), pos: { x: 5, y: 5 } }); + function updateEntireUnit(id: UnitId, unit: Unit) { + units.set(id, unit); units = units; - }; + } let dragging: false | UnitId = false; const handleMouseMove = (e: MouseEvent) => { if (!dragging) return; - ensure.unit.const(getUnit(dragging)).pos = { + getUnit(dragging).pos = { x: e.clientX, y: e.clientY }; @@ -186,17 +177,9 @@ let signalDragging: false | Output = false; - const handleSignalStart = (obj: { id: UnitId }) => { + const handleSignalStart = (obj: Output) => { console.log('signal start', obj); - const unit = getUnit(obj.id); - switch (unit.kind) { - case 'const': { - signalDragging = obj; - break; - } - default: - throw new Error('handleSignalStart nyi'); - } + signalDragging = obj; }; const _onSinkConnect = (ch: 'l' | 'c' | 'h'): void => { @@ -209,6 +192,10 @@ signalDragging = false; }; + $: { + console.log(units); + } + $: onSinkConnect = signalDragging ? _onSinkConnect : null; $: unitEntries = units.entries(); @@ -221,7 +208,8 @@ <canvas bind:this={cvs} /> <div id="buttons"> - <button on:click={addConst}>add const</button> + <button on:click={mk.c}>add const</button> + <button on:click={mk.osc}>add osc</button> </div> <h1>HI {unitEntries}</h1> @@ -232,12 +220,13 @@ </div> <div id="units"> {#each [...unitEntries] as [id, unit]} - <div - class="unit" - style={unit.kind === 'const' ? `top: ${unit.pos.y}px; left: ${unit.pos.x}px` : ''} - > + <div class="unit" style={`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} /> + {#if unit.kind === 'const'} + <Slider {id} {units} handleInput={updateUnit} handleChange={updateUrl} /> + {:else if unit.kind === 'osc'} + <Osc {unit} updateOsc={updateEntireUnit.bind(null, id)} /> + {/if} <div class="output-dragger" on:mousedown={(e) => { @@ -254,7 +243,7 @@ position: absolute; top: 0; bottom: 0; - right: 0; + right: -20px; width: 20px; background: purple; } @@ -266,6 +255,7 @@ flex-direction: column; } .unit { + width: 150px; position: absolute; z-index: 1; background: black;