1use sva_ast::{CHANNEL, FILTERS, JOIN, SERIES};
4use sva_formula::filter::{ALL_SHAPES, Shape};
5
6pub const MAX_WIDTH: usize = 8;
8
9pub fn shape(name: &str) -> Option<Shape> {
11 FILTERS
12 .iter()
13 .position(|held| *held == name)
14 .map(|at| ALL_SHAPES[at])
15}
16
17const _: () = assert!(FILTERS.len() == ALL_SHAPES.len());
18
19pub fn shape_name(shape: Shape) -> &'static str {
20 let at = ALL_SHAPES.iter().position(|held| *held == shape);
21 FILTERS[at.expect("ALL_SHAPES holds every shape")]
22}
23
24const NO_NAMED: &[&str] = &[];
26const WAVE_NAMED: &[&str] = &["tol"];
27const SAT_NAMED: &[&str] = &["drive"];
28const CROP_NAMED: &[&str] = &["start", "end", "rise", "fall"];
29const RAND_NAMED: &[&str] = &["seed"];
30const DELTA_NAMED: &[&str] = &["k"];
31const STFT_NAMED: &[&str] = &["window", "hop"];
32const NOISE_NAMED: &[&str] = &["period", "color"];
33macro_rules! modal_named {
36 (one_mode $($own:literal),+ $(,)?) => {
37 &[$($own,)+ "damp_dc", "damp_freq", "vel", "at", "contact", "p", "force"]
38 };
39 ($($own:literal),+ $(,)?) => {
40 &[$($own,)+ "damp_dc", "damp_freq", "modes", "vel", "at", "contact", "p", "force"]
41 };
42}
43
44const STRING_NAMED: &[&str] = modal_named!("inharmonicity", "strike");
45const MEMBRANE_NAMED: &[&str] = modal_named!("tension", "density", "strike_x", "strike_y");
46const BAR_NAMED: &[&str] = modal_named!("thickness", "young", "density");
47const BORE_NAMED: &[&str] = modal_named!("radius", "speed", "closed");
48const ROOM_NAMED: &[&str] = modal_named!("speed");
49const HELMHOLTZ_NAMED: &[&str] =
50 modal_named!(one_mode "neck_area", "neck_length", "radius", "speed");
51const HAMMER_NAMED: &[&str] = &["at", "contact", "p", "force"];
52const FILTER_NAMED: &[&str] = &["cutoff", "q", "gain"];
53const CHAIGNE_ASKENFELT_NAMED: &[&str] = &[
54 "b",
55 "strike_pos",
56 "vel",
57 "hammer_mass",
58 "hammer_k",
59 "hammer_p",
60 "damp_dc",
61 "damp_freq",
62 "unison_count",
63 "detune",
64 "bridge_coupling",
65 "bridge_mass",
66 "string1_cents",
67 "string2_cents",
68 "string3_cents",
69 "string1_hammer_k_ratio",
70 "string2_hammer_k_ratio",
71 "string3_hammer_k_ratio",
72 "damper_pos",
73 "damper_r",
74 "damper_k",
75];
76const WILLEMSEN_BILBAO_SERAFIN_NAMED: &[&str] = &[
77 "b",
78 "bow_pos",
79 "bow_vel",
80 "bow_force",
81 "mu_s",
82 "mu_c",
83 "stribeck_vel",
84 "bristle_stiffness",
85 "bristle_damping",
86 "viscous_friction",
87 "damp_dc",
88 "damp_freq",
89];
90const DARABUNDIT_SCAVONE_NAMED: &[&str] = &[
92 "radius_in",
93 "radius_out",
94 "excite_pos",
95 "pulse_amp",
96 "pulse_width",
97 "damp_dc",
98 "damp_freq",
99 "hole1_pos",
100 "hole1_open",
101 "hole1_radius",
102 "hole1_height",
103 "hole2_pos",
104 "hole2_open",
105 "hole2_radius",
106 "hole2_height",
107 "hole3_pos",
108 "hole3_open",
109 "hole3_radius",
110 "hole3_height",
111 "hole4_pos",
112 "hole4_open",
113 "hole4_radius",
114 "hole4_height",
115 "hole5_pos",
116 "hole5_open",
117 "hole5_radius",
118 "hole5_height",
119 "hole6_pos",
120 "hole6_open",
121 "hole6_radius",
122 "hole6_height",
123];
124const RHAOUTI_CHAIGNE_JOLY_NAMED: &[&str] = &[
125 "aspect_ratio",
126 "strike_x",
127 "strike_y",
128 "vel",
129 "hammer_mass",
130 "hammer_k",
131 "hammer_p",
132 "damp_dc",
133 "damp_freq",
134];
135const CHAIGNE_DOUTAUT_NAMED: &[&str] = &[
136 "strike_pos",
137 "vel",
138 "hammer_mass",
139 "hammer_k",
140 "hammer_p",
141 "damp_dc",
142 "damp_freq",
143];
144const BOTTELDOOREN_NAMED: &[&str] = &[
145 "aspect_y",
146 "aspect_z",
147 "listener_x",
148 "listener_y",
149 "listener_z",
150 "pulse_amp",
151 "pulse_width",
152 "damp_dc",
153 "damp_freq",
154];
155
156pub fn named_may_move(name: &str, key: &str) -> bool {
159 (shape(name).is_some() && FILTER_NAMED.contains(&key))
160 || sva_samples::physics::varying(name)
161 .iter()
162 .any(|(k, _)| *k == key)
163}
164
165pub fn recognized_named(name: &str) -> Option<&'static [&'static str]> {
167 if shape(name).is_some() {
168 return Some(FILTER_NAMED);
169 }
170 Some(match name {
171 "sin" | "cos" | "exp" | "sqrt" | "abs" | "tanh" | "step" | "max" | "min" | "pow"
172 | "log" => NO_NAMED,
173 "saw" | "square" | "triangle" => WAVE_NAMED,
174 "sat" => SAT_NAMED,
175 SERIES | "pv" => NO_NAMED,
176 "crop" => CROP_NAMED,
177 "rand" => RAND_NAMED,
178 "delta" => DELTA_NAMED,
179 "chaigne_askenfelt" => CHAIGNE_ASKENFELT_NAMED,
180 "willemsen_bilbao_serafin" => WILLEMSEN_BILBAO_SERAFIN_NAMED,
181 "darabundit_scavone" => DARABUNDIT_SCAVONE_NAMED,
182 "rhaouti_chaigne_joly" => RHAOUTI_CHAIGNE_JOLY_NAMED,
183 "chaigne_doutaut" => CHAIGNE_DOUTAUT_NAMED,
184 "botteldooren" => BOTTELDOOREN_NAMED,
185 JOIN | CHANNEL => NO_NAMED,
186 "stft" => STFT_NAMED,
187 "sample" | "fourier" | "ifourier" | "istft" => NO_NAMED,
188 "noise" => NOISE_NAMED,
189 "string" => STRING_NAMED,
190 "membrane" => MEMBRANE_NAMED,
191 "bar" => BAR_NAMED,
192 "bore" => BORE_NAMED,
193 "room" => ROOM_NAMED,
194 "helmholtz" => HELMHOLTZ_NAMED,
195 "hammer_pulse" => HAMMER_NAMED,
196 _ => return None,
197 })
198}