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