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}
31
32#[derive(Clone, Debug, PartialEq)]
34pub enum CollapseError {
35 NoHorizon,
36 EmptyBand {
37 ceiling: f64,
38 lowest: f64,
39 },
40 SingularInCt {
41 at: f64,
42 order: i32,
43 },
44 NotEvaluable(&'static str),
45 NestedSeries {
46 depth: usize,
47 terms: usize,
48 bound: usize,
49 },
50 LeftAlgebra(&'static str),
51}
52
53impl CollapseError {
54 pub fn code(&self) -> &'static str {
55 match self {
56 CollapseError::NoHorizon => "collapse.no_horizon",
57 CollapseError::EmptyBand { .. } => "collapse.empty_band",
58 CollapseError::SingularInCt { .. } => "collapse.singular_in_ct",
59 CollapseError::NotEvaluable(_) => "collapse.not_evaluable",
60 CollapseError::NestedSeries { .. } => "collapse.series_nesting",
61 CollapseError::LeftAlgebra(_) => "cast.left_algebra",
62 }
63 }
64}
65
66impl CollapseError {
69 pub fn help(&self) -> &'static str {
70 match self {
71 CollapseError::NoHorizon => "give the observation a window with --from and --to",
72 CollapseError::EmptyBand { ceiling, .. }
73 if *ceiling < sva_formula::AUDIBLE_CEILING_HZ =>
74 {
75 "this rate's own half is the ceiling: raise --sample-rate past twice the \
76 lowest line"
77 }
78 CollapseError::EmptyBand { .. } => {
79 "the profile's 20 kHz ceiling is what no rate raises; read it with \
80 `--as lines`, or bring the line into the band"
81 }
82 CollapseError::SingularInCt { .. } => {
83 "write it inside a convolution, or sample the closed form it multiplies"
84 }
85 CollapseError::NestedSeries { .. } => {
86 "write fewer levels, or a narrower band for the terms to clear"
87 }
88 CollapseError::NotEvaluable(_) | CollapseError::LeftAlgebra(_) => {
89 "write the subterm inside sample(...) to leave A deliberately"
90 }
91 }
92 }
93}
94
95impl std::fmt::Display for CollapseError {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 CollapseError::NoHorizon => {
99 write!(
100 f,
101 "a closed form collapses against a horizon. give --from and --to"
102 )
103 }
104 CollapseError::EmptyBand { ceiling, lowest } => write!(
105 f,
106 "every line is at or above the {ceiling} Hz ceiling, the lowest at {lowest} Hz"
107 ),
108 CollapseError::SingularInCt { at, order } => write!(
109 f,
110 "a singularity of order {order} at t = {at} has no value on the grid"
111 ),
112 CollapseError::NotEvaluable(what) => {
113 write!(f, "{what} has no value at a point")
114 }
115 CollapseError::NestedSeries {
116 depth,
117 terms,
118 bound,
119 } => write!(
120 f,
121 "a series nested {depth} deep takes {terms} terms at one instant, past the \
122 {bound} one expansion holds"
123 ),
124 CollapseError::LeftAlgebra(clause) => write!(f, "the closed form left A. {clause}"),
125 }
126 }
127}
128
129impl SampleError {
130 pub fn code(&self) -> &'static str {
131 match self {
132 SampleError::HopOutsideCola { .. } => "samples.hop_outside_cola",
133 SampleError::WindowNotPowerOfTwo { .. } => "samples.window_not_power_of_two",
134 SampleError::WidthMismatch { .. } => "type.width_mismatch",
135 SampleError::ChannelOutOfRange { .. } => "samples.channel_out_of_range",
136 SampleError::GridTooLarge { .. } => "samples.grid_too_large",
137 SampleError::StringPastRate { .. } => "samples.string_past_rate",
138 }
139 }
140}
141
142impl std::fmt::Display for SampleError {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 match self {
145 SampleError::HopOutsideCola { window, hop } => write!(
146 f,
147 "a window of {window} at a hop of {hop} does not overlap-add to a constant. \
148 write a hop that divides the window"
149 ),
150 SampleError::WindowNotPowerOfTwo { window } => {
151 write!(f, "a window of {window} is not a power of two")
152 }
153 SampleError::WidthMismatch { left, right } => write!(
154 f,
155 "{left} components meet {right}; an elementwise operation needs equal widths, \
156 or one side mono"
157 ),
158 SampleError::ChannelOutOfRange { k, width } => {
159 write!(f, "component {k} of a value {width} wide")
160 }
161 SampleError::GridTooLarge {
162 model,
163 nodes,
164 ceiling,
165 } => write!(
166 f,
167 "`{model}` sizes a {nodes}-node grid at this rate, past the {ceiling} one \
168 call may hold. ask for a higher fundamental, or a lower --sample-rate"
169 ),
170 SampleError::StringPastRate { model } => write!(
171 f,
172 "`{model}` has no stable grid at this rate whose first two partials ring where \
173 asked. ask for a lower fundamental or `b`, or a higher --sample-rate"
174 ),
175 }
176 }
177}