1#[derive(Clone, Debug, PartialEq, Eq)]
4pub enum SampleError {
5 HopOutsideCola {
6 window: usize,
7 hop: usize,
8 },
9 WindowNotPowerOfTwo {
10 window: usize,
11 },
12 WidthMismatch {
13 left: usize,
14 right: usize,
15 },
16 ChannelOutOfRange {
17 k: usize,
18 width: usize,
19 },
20 GridTooLarge {
22 model: &'static str,
23 nodes: usize,
24 ceiling: usize,
25 },
26 StringPastRate {
28 model: &'static str,
29 },
30 BridgeUnstable {
32 model: &'static str,
33 },
34 ContactUnsettled {
36 model: &'static str,
37 sample: usize,
38 },
39 StateMismatch,
41}
42
43#[derive(Clone, Debug, PartialEq)]
45pub enum CollapseError {
46 NoHorizon,
47 EmptyBand {
48 ceiling: f64,
49 lowest: f64,
50 },
51 SingularInCt {
52 at: f64,
53 order: i32,
54 },
55 NotEvaluable(&'static str),
56 NestedSeries {
57 depth: usize,
58 terms: usize,
59 bound: usize,
60 },
61 LeftAlgebra(&'static str),
62 NoBlockRow,
64}
65
66impl CollapseError {
67 pub fn code(&self) -> &'static str {
68 match self {
69 CollapseError::NoHorizon => "collapse.no_horizon",
70 CollapseError::EmptyBand { .. } => "collapse.empty_band",
71 CollapseError::SingularInCt { .. } => "collapse.singular_in_ct",
72 CollapseError::NotEvaluable(_) => "collapse.not_evaluable",
73 CollapseError::NestedSeries { .. } => "collapse.series_nesting",
74 CollapseError::LeftAlgebra(_) => "cast.left_algebra",
75 CollapseError::NoBlockRow => "collapse.no_block_row",
76 }
77 }
78}
79
80impl CollapseError {
83 pub fn help(&self) -> &'static str {
84 match self {
85 CollapseError::NoHorizon => "give the observation a window with --from and --to",
86 CollapseError::EmptyBand { ceiling, .. }
87 if *ceiling < sva_formula::AUDIBLE_CEILING_HZ =>
88 {
89 "this rate's own half is the ceiling: raise --sample-rate past twice the \
90 lowest line"
91 }
92 CollapseError::EmptyBand { .. } => {
93 "the profile's 20 kHz ceiling is what no rate raises; read it with \
94 `--as lines`, or bring the line into the band"
95 }
96 CollapseError::SingularInCt { .. } => {
97 "write it inside a convolution, or sample the closed form it multiplies"
98 }
99 CollapseError::NestedSeries { .. } => {
100 "write fewer levels, or a narrower band for the terms to clear"
101 }
102 CollapseError::NotEvaluable(_) | CollapseError::LeftAlgebra(_) => {
103 "write the subterm inside sample(...) to leave A deliberately"
104 }
105 CollapseError::NoBlockRow => {
106 "render it to a stated end instead of streaming it, or write it in t"
107 }
108 }
109 }
110}
111
112impl std::fmt::Display for CollapseError {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 match self {
115 CollapseError::NoHorizon => {
116 write!(
117 f,
118 "a closed form collapses against a horizon. give --from and --to"
119 )
120 }
121 CollapseError::EmptyBand { ceiling, lowest } => write!(
122 f,
123 "every line is at or above the {ceiling} Hz ceiling, the lowest at {lowest} Hz"
124 ),
125 CollapseError::SingularInCt { at, order } => write!(
126 f,
127 "a singularity of order {order} at t = {at} has no value on the grid"
128 ),
129 CollapseError::NotEvaluable(what) => {
130 write!(f, "{what} has no value at a point")
131 }
132 CollapseError::NestedSeries {
133 depth,
134 terms,
135 bound,
136 } => write!(
137 f,
138 "a series nested {depth} deep takes {terms} terms at one instant, past the \
139 {bound} one expansion holds"
140 ),
141 CollapseError::LeftAlgebra(clause) => write!(f, "the closed form left A. {clause}"),
142 CollapseError::NoBlockRow => write!(
143 f,
144 "a closed form in f reaches the grid by one transform over a whole horizon, \
145 so no block of it is read alone"
146 ),
147 }
148 }
149}
150
151impl SampleError {
152 pub fn code(&self) -> &'static str {
153 match self {
154 SampleError::HopOutsideCola { .. } => "samples.hop_outside_cola",
155 SampleError::WindowNotPowerOfTwo { .. } => "samples.window_not_power_of_two",
156 SampleError::WidthMismatch { .. } => "type.width_mismatch",
157 SampleError::ChannelOutOfRange { .. } => "samples.channel_out_of_range",
158 SampleError::GridTooLarge { .. } => "samples.grid_too_large",
159 SampleError::StringPastRate { .. } => "samples.string_past_rate",
160 SampleError::BridgeUnstable { .. } => "samples.bridge_unstable",
161 SampleError::ContactUnsettled { .. } => "samples.contact_unsettled",
162 SampleError::StateMismatch => "samples.state_mismatch",
163 }
164 }
165}
166
167impl std::fmt::Display for SampleError {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 match self {
170 SampleError::HopOutsideCola { window, hop } => write!(
171 f,
172 "a window of {window} at a hop of {hop} does not overlap-add to a constant. \
173 write a hop that divides the window"
174 ),
175 SampleError::WindowNotPowerOfTwo { window } => {
176 write!(f, "a window of {window} is not a power of two")
177 }
178 SampleError::WidthMismatch { left, right } => write!(
179 f,
180 "{left} components meet {right}; an elementwise operation needs equal widths, \
181 or one side mono"
182 ),
183 SampleError::ChannelOutOfRange { k, width } => {
184 write!(f, "component {k} of a value {width} wide")
185 }
186 SampleError::GridTooLarge {
187 model,
188 nodes,
189 ceiling,
190 } => write!(
191 f,
192 "`{model}` sizes a {nodes}-node grid at this rate, past the {ceiling} one \
193 call may hold. ask for a higher fundamental, or a lower --sample-rate"
194 ),
195 SampleError::StringPastRate { model } => write!(
196 f,
197 "`{model}` has no stable grid at this rate whose first two partials ring where \
198 asked. ask for a lower fundamental or `b`, or a higher --sample-rate"
199 ),
200 SampleError::BridgeUnstable { model } => write!(
201 f,
202 "`{model}`'s unison is not proven stable on its bridge at this rate: the mass \
203 form its bridge row leaves is not provably positive. ask for a heavier bridge, \
204 less frequency-dependent loss, or a higher --sample-rate"
205 ),
206 SampleError::ContactUnsettled { model, sample } => write!(
207 f,
208 "`{model}`'s contact force settled on no value at sample {sample}. ask for a \
209 lower bow velocity or force, or a higher --sample-rate"
210 ),
211 SampleError::StateMismatch => write!(
212 f,
213 "the state held is for other call sites than these: a site that moved takes \
214 only a chaigne_askenfelt string's motion, and only across a new release"
215 ),
216 }
217 }
218}