stores.ts (3215B)
1 import { 2 rescale, 3 type ControlName, 4 type Controls, 5 type Input, 6 type Unit, 7 type UnitId, 8 type UnitKind, 9 type UnitToConnect, 10 type Units, 11 RANGE, 12 wrangle, 13 unitRange, 14 type Pos, 15 type Sinks 16 } from '$lib/types'; 17 import { v4 as uuidv4 } from 'uuid'; 18 19 import { writable } from 'svelte/store'; 20 21 const randNum = () => { 22 const sliderVal = Math.round(rescale(Math.random(), { min: 0, max: 1 }, RANGE.slider)); 23 return rescale(sliderVal, RANGE.slider, RANGE.signal); 24 }; 25 26 const mkInput = (value?: number) => { 27 const ret: Input = { sources: [] }; 28 if (value !== undefined) { 29 ret.value = value; 30 } 31 return ret; 32 }; 33 34 const mkUnitStore = () => { 35 const { subscribe, set, update } = writable<Units>({}); 36 const setControl = <K extends UnitKind>( 37 kind: K, 38 id: UnitId, 39 controlName: ControlName<K>, 40 input: Input 41 ) => { 42 update((units) => { 43 const controls = units[id].controls as Controls<K>; 44 controls[controlName] = input; 45 return units; 46 }); 47 }; 48 return { 49 subscribe, 50 set, 51 setUnit<K extends UnitKind>(id: UnitId, unit: Unit<K>) { 52 update((units) => ({ ...units, [id]: unit })); 53 }, 54 setControl, 55 addUnit<K extends UnitKind>(kind: K): UnitId { 56 let unit: Unit; 57 switch (kind) { 58 case 'number': { 59 unit = { kind: 'number', controls: { value: mkInput(0) }, pos: { x: 0, y: 0 } }; 60 break; 61 } 62 case 'osc': { 63 unit = { 64 kind: 'osc', 65 controls: { 66 coarse: mkInput(wrangle(1, unitRange.osc.coarse, RANGE.signal)), 67 fine: mkInput(wrangle(1, unitRange.osc.fine, RANGE.signal)), 68 superfine: mkInput(0), 69 amount: mkInput(RANGE.signal.max), 70 waveshape: mkInput(RANGE.signal.min) 71 }, 72 pos: { x: 0, y: 0 } 73 }; 74 break; 75 } 76 case 'noise': { 77 unit = { 78 kind: 'noise', 79 controls: { amount: mkInput(RANGE.signal.max / 2) }, 80 pos: { x: 0, y: 0 } 81 }; 82 break; 83 } 84 case 'smooth': { 85 unit = { 86 kind: 'smooth', 87 controls: { 88 frames: mkInput(wrangle(3, unitRange.smooth.frames, RANGE.signal)), 89 signal: mkInput() 90 }, 91 pos: { x: 0, y: 0 } 92 }; 93 break; 94 } 95 case 'math': { 96 unit = { 97 kind: 'math', 98 controls: { 99 a: mkInput(0), 100 op: mkInput(RANGE.signal.min), 101 b: mkInput(0) 102 }, 103 pos: { x: 0, y: 0 } 104 }; 105 break; 106 } 107 case 'lag': { 108 unit = { 109 kind: 'lag', 110 controls: { 111 signal: mkInput(), 112 amount: mkInput(0) 113 }, 114 pos: { x: 0, y: 0 } 115 }; 116 break; 117 } 118 case 'img': { 119 unit = { 120 kind: 'img', 121 controls: { 122 speed: mkInput(rescale(100000, unitRange.img.speed, RANGE.signal)) 123 }, 124 pos: { x: 0, y: 0 } 125 }; 126 } 127 } 128 129 const uuid = uuidv4(); 130 update((units) => { 131 return { ...units, [uuid]: unit }; 132 }); 133 return String(uuid); 134 } 135 }; 136 }; 137 138 export const unitToConnect = writable<UnitToConnect>(false); 139 140 export type UnitDragging = null | { initPos: Pos; pos: Pos; id: UnitId }; 141 export const unitDragging = writable<UnitDragging>(null); 142 143 export const unitStore = mkUnitStore(); 144 export const sinksStore = writable<Sinks>({ 145 l: { value: 0, sources: [] }, 146 c: { value: 0, sources: [] }, 147 h: { value: 0, sources: [] } 148 });