4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 1import { simulate } from './solver';
a78afe0Add WebGPU solver with a toggle; faster CPU solverJeremy Magland 2import { simulateGPU } from './gpu';
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 3import { decimateResult, oversampledOptions, oversampling } from './antialias';
a78afe0Add WebGPU solver with a toggle; faster CPU solverJeremy Magland 4import type { BeadSystem, Excitation, SimOptions, SimResult } from './types';
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 5
6export interface WorkerRequest {
7 sys: BeadSystem;
8 exc: Excitation;
9 opt: SimOptions;
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 11}
87d896eShow partial results while a run is in progress: plots, replay and audio update every 2 s (CPU and WebGPU); a cancelled run keeps its last partial resultJeremy Magland 13const buffers = (r: SimResult) =>
14 [r.audio, r.frames, r.frameTimes, r.energy, r.balance, r.contactForce, r.malletPos].filter((a) => a).map((a) => a!.buffer) as ArrayBuffer[];
a78afe0Add WebGPU solver with a toggle; faster CPU solverJeremy Magland 16self.onmessage = async (ev: MessageEvent<WorkerRequest>) => {
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 17 const { sys, exc, gpu } = ev.data;
18 const out = ev.data.opt;
19 // solve at R times the sample rate; the pickup is filtered back down to fs (antialias.ts)
20 const R = oversampling(sys, exc, out);
21 const opt = oversampledOptions(out, R);
a78afe0Add WebGPU solver with a toggle; faster CPU solverJeremy Magland 22 const progress = (f: number) => self.postMessage({ type: 'progress', fraction: f });
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 23 const partial = (r: SimResult) => {
24 const result = decimateResult(r, R, false);
25 self.postMessage({ type: 'partial', result }, { transfer: buffers(result) });
26 };
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 27 try {
a78afe0Add WebGPU solver with a toggle; faster CPU solverJeremy Magland 28 let result: SimResult | undefined;
29 let fallback: string | undefined;
30 if (gpu) {
31 try {
87d896eShow partial results while a run is in progress: plots, replay and audio update every 2 s (CPU and WebGPU); a cancelled run keeps its last partial resultJeremy Magland 32 const r = await simulateGPU(sys, exc, opt, progress, (p) => partial({ ...p, backend: `WebGPU (${(p as SimResult & { device: string }).device})` }));
a78afe0Add WebGPU solver with a toggle; faster CPU solverJeremy Magland 33 result = { ...r, backend: `WebGPU (${r.device})` };
34 } catch (e) {
35 fallback = (e as Error).message ?? String(e);
36 }
37 }
87d896eShow partial results while a run is in progress: plots, replay and audio update every 2 s (CPU and WebGPU); a cancelled run keeps its last partial resultJeremy Magland 38 result ??= { ...simulate(sys, exc, opt, progress, (p) => partial({ ...p, backend: 'CPU', fallback })), backend: 'CPU', fallback };
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 39 result = decimateResult(result, R, true);
87d896eShow partial results while a run is in progress: plots, replay and audio update every 2 s (CPU and WebGPU); a cancelled run keeps its last partial resultJeremy Magland 40 self.postMessage({ type: 'done', result }, { transfer: buffers(result) });
4a8abcfString of beads: 3D bead-spring solver, control panel, waveform, spectrogram, wav, displacement viewerJeremy Magland 41 } catch (e) {
42 self.postMessage({ type: 'error', message: String(e) });
43 }
44};