sva_samples/physics/
mod.rs1pub(crate) mod arrow;
4mod ball;
5pub mod botteldooren;
6pub mod bound;
7pub mod chaigne_askenfelt;
8pub mod chaigne_doutaut;
9pub mod darabundit_scavone;
10pub mod hammer;
11pub mod rhaouti_chaigne_joly;
12pub(crate) mod stiff_string;
13pub(crate) mod string_energy;
14pub mod tonehole;
15#[cfg(test)]
16mod twofold;
17mod unison_energy;
18pub mod willemsen_bilbao_serafin;
19
20use std::any::Any;
21
22use crate::error::SampleError;
23
24use botteldooren::{BotteldoorenParams, BotteldoorenSite};
25use chaigne_askenfelt::{ChaigneAskenfeltParams, ChaigneAskenfeltSite};
26use chaigne_doutaut::{ChaigneDoutautParams, ChaigneDoutautSite};
27use darabundit_scavone::{BoreParams, BoreSite};
28use rhaouti_chaigne_joly::{RhaoutiChaigneJolyParams, RhaoutiChaigneJolySite};
29use willemsen_bilbao_serafin::{WillemsenBilbaoSerafinParams, WillemsenBilbaoSerafinSite};
30
31pub trait Solver: Held + Send + Sync {
33 fn step(&mut self, args: &[f64]) -> Result<f64, SampleError>;
34
35 fn bytes(&self) -> usize;
37}
38
39pub trait Held {
40 fn boxed(&self) -> Box<dyn Solver>;
41 fn as_any(&self) -> &dyn Any;
42}
43
44impl<T: Solver + Clone + 'static> Held for T {
45 fn boxed(&self) -> Box<dyn Solver> {
46 Box::new(self.clone())
47 }
48
49 fn as_any(&self) -> &dyn Any {
50 self
51 }
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub enum Varies {
57 PerSample,
58 Piecewise,
60}
61
62pub const MAX_VARYING: usize = 2;
63
64#[derive(Clone, Debug, PartialEq)]
65pub enum Params {
66 ChaigneAskenfelt(ChaigneAskenfeltParams),
67 WillemsenBilbaoSerafin(WillemsenBilbaoSerafinParams),
68 DarabunditScavone(BoreParams),
69 RhaoutiChaigneJoly(RhaoutiChaigneJolyParams),
70 ChaigneDoutaut(ChaigneDoutautParams),
71 Botteldooren(BotteldoorenParams),
72}
73
74impl Params {
75 pub fn name(&self) -> &'static str {
76 match self {
77 Params::ChaigneAskenfelt(_) => "chaigne_askenfelt",
78 Params::WillemsenBilbaoSerafin(_) => "willemsen_bilbao_serafin",
79 Params::DarabunditScavone(_) => "darabundit_scavone",
80 Params::RhaoutiChaigneJoly(_) => "rhaouti_chaigne_joly",
81 Params::ChaigneDoutaut(_) => "chaigne_doutaut",
82 Params::Botteldooren(_) => "botteldooren",
83 }
84 }
85
86 pub fn varying(&self) -> &'static [(&'static str, Varies)] {
88 varying(self.name())
89 }
90
91 pub fn structural(&self) -> Params {
92 match self {
93 Params::ChaigneAskenfelt(p) => Params::ChaigneAskenfelt(ChaigneAskenfeltParams {
94 damper_r: 0.0,
95 damper_k: 0.0,
96 ..p.clone()
97 }),
98 Params::WillemsenBilbaoSerafin(p) => {
99 Params::WillemsenBilbaoSerafin(WillemsenBilbaoSerafinParams {
100 bow_vel: 0.0,
101 bow_force: 1.0,
102 ..p.clone()
103 })
104 }
105 other => other.clone(),
106 }
107 }
108
109 pub fn valid(&self) -> bool {
110 match self {
111 Params::ChaigneAskenfelt(p) => p.valid(),
112 Params::WillemsenBilbaoSerafin(p) => p.valid(),
113 Params::DarabunditScavone(p) => p.valid(),
114 Params::RhaoutiChaigneJoly(p) => p.valid(),
115 Params::ChaigneDoutaut(p) => p.valid(),
116 Params::Botteldooren(p) => p.valid(),
117 }
118 }
119}
120
121pub fn varying(model: &str) -> &'static [(&'static str, Varies)] {
122 match model {
123 "chaigne_askenfelt" => chaigne_askenfelt::VARYING,
124 "willemsen_bilbao_serafin" => willemsen_bilbao_serafin::VARYING,
125 _ => &[],
126 }
127}
128
129pub fn site(p: &Params, sr: f64) -> Result<Box<dyn Solver>, SampleError> {
132 Ok(match p {
133 Params::ChaigneAskenfelt(p) => Box::new(ChaigneAskenfeltSite::new(p, sr)?),
134 Params::WillemsenBilbaoSerafin(p) => Box::new(WillemsenBilbaoSerafinSite::new(p, sr)?),
135 Params::DarabunditScavone(p) => Box::new(BoreSite::new(p, sr)),
136 Params::RhaoutiChaigneJoly(p) => {
137 under_ceiling(
138 "rhaouti_chaigne_joly",
139 rhaouti_chaigne_joly::node_count(p, sr),
140 rhaouti_chaigne_joly::NODE_COUNT_CEILING,
141 )?;
142 Box::new(RhaoutiChaigneJolySite::new(p, sr))
143 }
144 Params::ChaigneDoutaut(p) => Box::new(ChaigneDoutautSite::new(p, sr)),
145 Params::Botteldooren(p) => {
146 under_ceiling(
147 "botteldooren",
148 botteldooren::node_count(p.f0, p.aspect_y, p.aspect_z, sr),
149 botteldooren::NODE_COUNT_CEILING,
150 )?;
151 Box::new(BotteldoorenSite::new(p, sr))
152 }
153 })
154}
155
156pub(crate) fn floats(held: &[f64]) -> usize {
158 std::mem::size_of_val(held)
159}
160
161fn under_ceiling(model: &'static str, nodes: f64, ceiling: usize) -> Result<(), SampleError> {
162 match nodes > ceiling as f64 {
163 true => Err(SampleError::GridTooLarge {
164 model,
165 nodes: nodes as usize,
166 ceiling,
167 }),
168 false => Ok(()),
169 }
170}
171
172pub(crate) fn raised_cosine_pulse(t: f64, amp: f64, width: f64) -> f64 {
175 match t < width {
176 true => amp * 0.5 * (1.0 - (std::f64::consts::TAU * t / width).cos()),
177 false => 0.0,
178 }
179}