/ proof-of-concept / toy-instruments
Sign in
proof-of-concept / toy-instruments
toy-instruments / src / ui / settings.ts
63 lines · 3.0 KBCodeBlameHistory
4import type { Built, InstrumentConfig, SimParams } from './instrumentPage';
6// Settings in a shared link (#/<instrument>?<param>=<value>&…&preset=<i>&gpu=<0|1>),
7// read by the instrument page and by the embedded widget.
9export interface Settings<P> {
10 params: P;
11 preset: number;
12 gpu?: boolean;
15// Settings p as a query string: every parameter, the preset they started from
16// (for its description) and the WebGPU toggle (CPU and WebGPU results are cached separately).
17export function settingsQuery<P extends SimParams>(p: P, preset: number, gpu: boolean): string {
18 const qs = new URLSearchParams();
19 for (const [k, v] of Object.entries(p)) qs.set(k, String(v));
20 qs.set('preset', String(preset));
21 qs.set('gpu', gpu ? '1' : '0');
22 return qs.toString();
25// Parameters missing from the query (or invalid) keep the values of its preset;
26// unknown ones are ignored, so old links still open.
27export function parseSettings<P extends SimParams>(cfg: InstrumentConfig<P>, query: string): Settings<P> {
28 const qs = new URLSearchParams(query);
29 const n = Number(qs.get('preset'));
30 const preset = Number.isInteger(n) && n >= 0 && n < cfg.presets.length ? n : 0;
31 const base = cfg.presets[preset].params;
32 const params = { ...base } as Record<string, unknown>;
33 const options = new Map<string, string[]>();
34 for (const sec of cfg.sections) for (const s of sec.params) if (s.options) options.set(s.key, s.options.map(([v]) => v));
35 for (const [k, v0] of Object.entries(base)) {
36 const v = qs.get(k);
37 if (v === null) continue;
38 if (typeof v0 === 'number') {
39 const x = Number(v);
40 if (v.trim() !== '' && Number.isFinite(x) && (!options.has(k) || options.get(k)!.includes(String(x)))) params[k] = x;
41 } else if (typeof v0 === 'string' && (!options.has(k) || options.get(k)!.includes(v))) params[k] = v;
42 }
43 const gpu = qs.get('gpu');
44 return { params: params as P, preset, gpu: gpu === null ? undefined : gpu === '1' };
47// The solver options for parameters p of a built instrument.
48export function simOptions(p: SimParams, built: Built): SimOptions {
49 return { duration: p.duration, fs: p.fs, cfl: p.cfl, frameRate: p.frameRate, pickup: built.pickup, pickupDelay: built.pickupDelay };
ae42884Anti-aliased pickup: solve at R fs and low-pass filter the pickup down to fs (both solvers); CACHE_VERSION 3; chaos-check analysis scriptsJeremy Magland 52// Size of a run: time step (the solver runs at R times fs, see antialias.ts),
53// steps per output sample and element updates (a bending hinge costs about four
55export const CPU_RATE = 2.2e7;
56export function runCost(p: SimParams, built: Built) {
58 const R = oversampling(built.sys, built.exc, opt);
59 const { omegaMax, stepsPerSample: inner } = timeStep(built.sys, built.exc.mallet, p.fs * R, p.cfl);
60 const stepsPerSample = inner * R;
ae42884Anti-aliased pickup: solve at R fs and low-pass filter the pickup down to fs (both solvers); CACHE_VERSION 3; chaos-check analysis scriptsJeremy Magland 62 return { omegaMax, stepsPerSample, oversampling: R, work: stepsPerSample * p.fs * p.duration * elements };
↑↓ move↵openescclose