5778036cymbalsim: scripted plate and cymbal designer with a modal linear model and a von Karman GPU modelJeremy Magland 1// The only .m file the simulator puts in scope of a design script. It is not
2// a design helper: the trailer that evaluatePlate appends calls it to sample
3// a field (a number or a function handle) on the grid matrices, or the decay
4// time on a row of frequencies, and to report a bad return value in the
5// script's own terms. Design scripts define whatever shape functions they
6// need themselves, at the bottom of the script.
8import type { WorkspaceFile } from "numbl";
10const SAMPLE = `function v = cymbalsim_field(f, what, x, y, r, theta)
11% Samples a design field (a number or a function handle) on the grid matrices.
12if isa(f, 'function_handle')
13 try
14 v = f(x, y, r, theta);
15 catch e
16 error('%s: %s', what, e.message);
17 end
18elseif isnumeric(f) || islogical(f)
19 v = f;
20else
21 error('%s must be a number or a function handle @(x, y, r, theta)', what);
22end
23if isscalar(v)
24 v = double(v) * ones(size(x));
25elseif ~isequal(size(v), size(x))
26 error('%s returned a %d x %d array for a %d x %d grid; use elementwise operators (.*, ./, .^)', what, size(v, 1), size(v, 2), size(x, 1), size(x, 2));
27else
28 v = double(v);
29end
30end
31`;
33const T60 = `function v = cymbalsim_t60(f, freqs)
34% Samples the decay time on a row of frequencies when it is a function handle.
35try
36 v = f(freqs);
37catch e
38 error('design.loss.T60: %s', e.message);
39end
40if isscalar(v)
41 v = double(v) * ones(size(freqs));
42elseif numel(v) ~= numel(freqs)
43 error('design.loss.T60 returned %d values for %d frequencies; use elementwise operators (./, .^)', numel(v), numel(freqs));
44else
45 v = double(v);
46end
47end
48`;
50export const RUNTIME_FILES: WorkspaceFile[] = [
51 { name: "cymbalsim_field.m", source: SAMPLE },
52 { name: "cymbalsim_t60.m", source: T60 },
53];