1use crate::enums::{State, Tone};
2
3use core::iter::Iterator;
4use goertzel_nostd::Parameters;
5
6const TONE_TABLE: [[Tone; 4]; 4] = [
7 [Tone::One, Tone::Two, Tone::Three, Tone::A],
8 [Tone::Four, Tone::Five, Tone::Six, Tone::B],
9 [Tone::Seven, Tone::Eight, Tone::Nine, Tone::C],
10 [Tone::Asterisk, Tone::Zero, Tone::Pound, Tone::D],
11];
12
13const SAMPLE_RATE: u32 = 8000;
14const NUM_SAMPLES: usize = 200;
15const STATE_DURATION: u32 = 2;
17
18const LOW_FREQS: [f32; 4] = [697.0, 770.0, 852.0, 941.0];
19const HIGH_FREQS: [f32; 4] = [1209.0, 1336.0, 1477.0, 1633.0];
20
21pub struct Decoder<F: FnMut(Tone, State)> {
22 lows: [Parameters; 4],
23 highs: [Parameters; 4],
24 low_harms: [Parameters; 4],
25 high_harms: [Parameters; 4],
26
27 sample_rate: u32,
28 tone_change: F,
29 cur_tone: Option<Tone>,
30 old_tone: Option<Tone>,
31 old_old_tone: Option<Tone>,
33
34 state_duration: u32,
36
37 samples: [f32; NUM_SAMPLES],
39 sample_len: usize,
40 downsample_phase: f32,
42}
43
44impl<F: FnMut(Tone, State)> Decoder<F> {
45 pub fn new(sample_rate: u32, tone_change: F) -> Self {
46 let lows = [
47 Parameters::new(LOW_FREQS[0], SAMPLE_RATE, NUM_SAMPLES),
48 Parameters::new(LOW_FREQS[1], SAMPLE_RATE, NUM_SAMPLES),
49 Parameters::new(LOW_FREQS[2], SAMPLE_RATE, NUM_SAMPLES),
50 Parameters::new(LOW_FREQS[3], SAMPLE_RATE, NUM_SAMPLES),
51 ];
52
53 let highs = [
54 Parameters::new(HIGH_FREQS[0], SAMPLE_RATE, NUM_SAMPLES),
55 Parameters::new(HIGH_FREQS[1], SAMPLE_RATE, NUM_SAMPLES),
56 Parameters::new(HIGH_FREQS[2], SAMPLE_RATE, NUM_SAMPLES),
57 Parameters::new(HIGH_FREQS[3], SAMPLE_RATE, NUM_SAMPLES),
58 ];
59
60 let low_harms = [
61 Parameters::new(LOW_FREQS[0] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
62 Parameters::new(LOW_FREQS[1] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
63 Parameters::new(LOW_FREQS[2] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
64 Parameters::new(LOW_FREQS[3] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
65 ];
66
67 let high_harms = [
68 Parameters::new(HIGH_FREQS[0] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
69 Parameters::new(HIGH_FREQS[1] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
70 Parameters::new(HIGH_FREQS[2] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
71 Parameters::new(HIGH_FREQS[3] * 2.0, SAMPLE_RATE, NUM_SAMPLES),
72 ];
73
74 Self {
75 lows,
76 highs,
77
78 low_harms,
79 high_harms,
80
81 sample_rate,
82 tone_change,
83
84 cur_tone: None,
85 old_tone: None,
86 old_old_tone: None,
87
88 state_duration: STATE_DURATION,
89
90 samples: [0.0; NUM_SAMPLES],
91 sample_len: 0,
92
93 downsample_phase: 0.0,
94 }
95 }
96
97 pub fn process(&mut self, samples: &[f32]) {
100 self.downsample(samples, |decoder, sample| {
101 decoder.samples[decoder.sample_len] = sample;
102 decoder.sample_len += 1;
103 if decoder.sample_len == NUM_SAMPLES {
104 decoder.process_chunk();
105 decoder.sample_len = 0;
106 }
107 });
108 }
109
110 fn process_chunk(&mut self) {
111 let mut low_powers = [0.0; 4];
112 for (i, lp) in low_powers.iter_mut().enumerate() {
113 *lp = self.lows[i].mag_squared(&self.samples);
114 }
115
116 let mut high_powers = [0.0; 4];
117 for (i, hp) in high_powers.iter_mut().enumerate() {
118 *hp = self.highs[i].mag_squared(&self.samples);
119 }
120
121 let low = main_freq(&low_powers);
122 let high = main_freq(&high_powers);
123
124 match (low, high) {
125 (Some(l), Some(h)) => {
126 let l2 = self.low_harms[l].mag_squared(&self.samples);
129
130 if l2 > (low_powers[l] / 8.0) {
132 self.no_tone();
133 } else {
134 let h2 = self.high_harms[h].mag_squared(&self.samples);
135
136 if h2 > (high_powers[h] / 8.0) {
137 self.no_tone();
138 } else {
139 self.tone(l, h);
140 }
141 }
142 }
143 _ => {
144 self.no_tone();
145 }
146 }
147 }
148
149 fn tone(&mut self, low: usize, high: usize) {
150 let tone = TONE_TABLE[low][high];
151
152 if self.cur_tone != Some(tone) {
153 self.old_tone = self.cur_tone;
154 self.cur_tone = Some(tone);
155 self.state_duration = 0;
156 }
157
158 if self.state_duration < STATE_DURATION {
159 self.state_duration += 1;
160
161 if self.state_duration == STATE_DURATION && self.cur_tone != self.old_old_tone {
162 if let Some(old) = self.old_tone {
163 (self.tone_change)(old, State::Off);
164 }
165
166 (self.tone_change)(tone, State::On);
167 self.old_old_tone = self.cur_tone;
168 }
169 }
170 }
171
172 fn no_tone(&mut self) {
173 if let Some(tone) = self.cur_tone {
174 self.old_tone = Some(tone);
175 self.cur_tone = None;
176 self.state_duration = 0;
177 }
178
179 if self.state_duration < STATE_DURATION {
180 self.state_duration += 1;
181
182 if self.state_duration == STATE_DURATION && self.cur_tone != self.old_old_tone {
183 (self.tone_change)(self.old_tone.unwrap(), State::Off);
185 self.old_old_tone = self.cur_tone;
186 }
187 }
188 }
189
190 fn downsample<T: Copy, C: Fn(&mut Self, T)>(&mut self, samples: &[T], func: C) {
193 let scale = self.sample_rate as f32 / SAMPLE_RATE as f32;
194
195 let len = samples.len();
196 let mut i = 0;
197 while i < len {
198 if self.downsample_phase > scale {
199 self.downsample_phase -= scale;
200
201 func(self, samples[i]);
202 }
203
204 let dist = ((scale - self.downsample_phase) as usize)
205 .max(1)
206 .min(len - i);
207
208 self.downsample_phase += dist as f32;
209 i += dist;
210 }
211 }
212}
213
214fn main_freq(freqs: &[f32]) -> Option<usize> {
216 let mut idx = 0;
217 for i in 1..freqs.len() {
218 if freqs[i] > freqs[idx] {
219 idx = i;
220 }
221 }
222
223 let mut sum_others = 0.0;
224 for (i, v) in freqs.iter().enumerate() {
225 if i != idx {
226 sum_others += v;
227 }
228 }
229
230 if sum_others * 8.0 < freqs[idx] {
232 Some(idx)
233 } else {
234 None
235 }
236}