1use std::str::FromStr;
2
3use crate::{Error, Result};
4
5#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
7pub enum Duty {
8 Eighth,
10 Quarter,
12 #[default]
14 Half,
15 ThreeQuarters,
17}
18impl Duty {
19 pub fn fraction(self) -> f64 {
20 match self {
21 Self::Eighth => 0.125,
22 Self::Quarter => 0.25,
23 Self::Half => 0.5,
24 Self::ThreeQuarters => 0.75,
25 }
26 }
27}
28impl FromStr for Duty {
29 type Err = Error;
30 fn from_str(s: &str) -> Result<Self> {
32 match s {
33 "12.5" | "12" => Ok(Self::Eighth),
34 "25" => Ok(Self::Quarter),
35 "50" => Ok(Self::Half),
36 "75" => Ok(Self::ThreeQuarters),
37 _ => Err(Error::invalid(format!(
38 "Duty must be 12.5, 25, 50 or 75, not {s}"
39 ))),
40 }
41 }
42}
43
44#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
46pub enum NoiseMode {
47 #[default]
49 Long,
50 Short,
52}
53
54#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
55pub enum Waveform {
56 Pulse(Duty),
57 Triangle,
58 Sawtooth,
59 Noise(NoiseMode),
62}
63impl Default for Waveform {
64 fn default() -> Self {
65 Self::Pulse(Duty::Half)
66 }
67}
68
69#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
71pub enum Aliasing {
72 #[default]
75 BandLimited,
76 Naive,
78}
79
80#[derive(Clone, Copy, Debug, Eq, PartialEq)]
82pub struct Lfsr {
83 state: u16,
84 mode: NoiseMode,
85}
86impl Lfsr {
87 pub fn new(mode: NoiseMode) -> Self {
88 Self { state: 1, mode }
89 }
90 pub fn mode(&self) -> NoiseMode {
91 self.mode
92 }
93 pub fn set_mode(&mut self, mode: NoiseMode) {
95 if mode != self.mode {
96 *self = Self::new(mode);
97 }
98 }
99 pub fn state(&self) -> u16 {
100 self.state
101 }
102 pub fn output(&self) -> f64 {
104 if self.state & 1 == 0 { 1.0 } else { -1.0 }
105 }
106 pub fn step(&mut self) {
107 let tap = match self.mode {
108 NoiseMode::Long => 1,
109 NoiseMode::Short => 6,
110 };
111 let feedback = (self.state ^ (self.state >> tap)) & 1;
112 self.state = (self.state >> 1) | (feedback << 14);
113 }
114}
115
116const ONE: u64 = 1 << 32;
117const FRACTION: u64 = ONE - 1;
118
119#[derive(Clone, Debug)]
125pub struct Oscillator {
126 phase: u64,
127 lfsr: Lfsr,
128 aliasing: Aliasing,
129}
130impl Oscillator {
131 pub(super) fn phase_offset(&mut self, turns: f64) {
132 self.phase = ((turns - turns.floor()) * ONE as f64).round() as u64 & FRACTION;
133 }
134 pub fn new(aliasing: Aliasing) -> Self {
135 Self {
136 phase: 0,
137 lfsr: Lfsr::new(NoiseMode::Long),
138 aliasing,
139 }
140 }
141 pub fn next(&mut self, waveform: Waveform, frequency: f64, sample_rate: u32) -> f64 {
144 match waveform {
145 Waveform::Pulse(duty) => {
146 self.tone(Shape::Pulse(duty.fraction()), frequency, sample_rate)
147 }
148 Waveform::Triangle => self.tone(Shape::Triangle, frequency, sample_rate),
149 Waveform::Sawtooth => self.tone(Shape::Sawtooth, frequency, sample_rate),
150 Waveform::Noise(mode) => {
151 let rate = sample_rate.max(1) as f64;
152 self.lfsr.set_mode(mode);
153 let increment =
154 (clamp_frequency(frequency, rate) * 93.0 / rate * ONE as f64).round() as u64;
155 self.noise(increment)
156 }
157 }
158 }
159 pub fn next_pulse(&mut self, duty: f64, frequency: f64, sample_rate: u32) -> f64 {
162 let duty = if duty.is_finite() {
163 duty.clamp(0.01, 0.99)
164 } else {
165 0.5
166 };
167 self.tone(Shape::Pulse(duty), frequency, sample_rate)
168 }
169 pub(super) fn clocked_noise(&mut self, mode: NoiseMode, clock: f64, sample_rate: u32) -> f64 {
171 self.lfsr.set_mode(mode);
172 let increment = (clock / sample_rate as f64 * ONE as f64).round() as u64;
173 self.noise(increment)
174 }
175 fn tone(&mut self, shape: Shape, frequency: f64, sample_rate: u32) -> f64 {
176 let rate = sample_rate.max(1) as f64;
177 let increment = (clamp_frequency(frequency, rate) / rate * ONE as f64).round() as u64;
178 let t = (self.phase & FRACTION) as f64 / ONE as f64;
179 let dt = increment as f64 / ONE as f64;
180 self.phase = (self.phase & FRACTION) + increment;
181 let band_limited = self.aliasing == Aliasing::BandLimited && dt > 0.0;
182 match shape {
183 Shape::Pulse(d) => {
184 let mut value = if t < d { 1.0 } else { -1.0 };
185 if band_limited {
186 value += poly_blep(t, dt) - poly_blep(wrap(t - d), dt);
187 }
188 value
189 }
190 Shape::Sawtooth => {
191 let mut value = 2.0 * t - 1.0;
192 if band_limited {
193 value -= poly_blep(t, dt);
194 }
195 value
196 }
197 Shape::Triangle => {
198 let mut value = if t < 0.5 {
199 4.0 * t - 1.0
200 } else {
201 3.0 - 4.0 * t
202 };
203 if band_limited {
204 value += 8.0 * dt * (poly_blamp(t, dt) - poly_blamp(wrap(t - 0.5), dt));
205 }
206 value
207 }
208 }
209 }
210 fn noise(&mut self, increment: u64) -> f64 {
211 let start = self.phase & FRACTION;
212 let end = start + increment;
213 let steps = end >> 32;
214 let value = if self.aliasing == Aliasing::Naive || increment == 0 {
215 let value = self.lfsr.output();
216 for _ in 0..steps {
217 self.lfsr.step();
218 }
219 value
220 } else {
221 let mut sum = self.lfsr.output() * (end.min(ONE) - start) as f64;
222 for k in 1..=steps {
223 self.lfsr.step();
224 let from = k * ONE;
225 sum += self.lfsr.output() * (end.min(from + ONE) - from) as f64;
226 }
227 sum / increment as f64
228 };
229 self.phase = end & FRACTION;
230 value
231 }
232}
233
234#[derive(Clone, Copy)]
235enum Shape {
236 Pulse(f64),
237 Triangle,
238 Sawtooth,
239}
240
241fn clamp_frequency(frequency: f64, rate: f64) -> f64 {
242 if frequency.is_finite() {
243 frequency.clamp(0.0, rate / 2.0)
244 } else {
245 0.0
246 }
247}
248
249fn wrap(t: f64) -> f64 {
250 if t < 0.0 { t + 1.0 } else { t }
251}
252
253fn poly_blep(t: f64, dt: f64) -> f64 {
255 if t < dt {
256 let x = t / dt;
257 2.0 * x - x * x - 1.0
258 } else if t > 1.0 - dt {
259 let x = (t - 1.0) / dt;
260 x * x + 2.0 * x + 1.0
261 } else {
262 0.0
263 }
264}
265
266fn poly_blamp(t: f64, dt: f64) -> f64 {
269 let x = if t < dt {
270 1.0 - t / dt
271 } else if t > 1.0 - dt {
272 1.0 - (1.0 - t) / dt
273 } else {
274 return 0.0;
275 };
276 x * x * x / 6.0
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 #[test]
283 fn lfsr_periods() {
284 for (mode, period) in [(NoiseMode::Long, 32767), (NoiseMode::Short, 93)] {
285 let mut lfsr = Lfsr::new(mode);
286 let mut n = 0;
287 loop {
288 lfsr.step();
289 n += 1;
290 if lfsr.state() == 1 {
291 break;
292 }
293 }
294 assert_eq!(n, period);
295 }
296 }
297}