1use caw_builder_proc_macros::builder;
2use caw_core::{Buf, Sig, SigCtx, SigT};
3
4pub mod waveform {
5 use std::f32::consts::PI;
6
7 pub trait Waveform: Copy {
8 fn sample(&self, state_01: f32, pulse_width_01: f32) -> f32;
9
10 const PULSE: bool = false;
11 }
12
13 #[derive(Clone, Copy)]
14 pub struct Sine;
15 impl Waveform for Sine {
16 fn sample(&self, state_01: f32, _pulse_width_01: f32) -> f32 {
17 (state_01 * PI * 2.0).sin()
18 }
19 }
20
21 #[derive(Clone, Copy)]
22 pub struct Triangle;
23 impl Waveform for Triangle {
24 fn sample(&self, state_01: f32, _pulse_width_01: f32) -> f32 {
25 (((state_01 * 2.0) - 1.0).abs() * 2.0) - 1.0
26 }
27 }
28
29 #[derive(Clone, Copy)]
30 pub struct Saw;
31 impl Waveform for Saw {
32 fn sample(&self, state_01: f32, _pulse_width_01: f32) -> f32 {
33 (state_01 * 2.0) - 1.0
34 }
35 }
36
37 #[derive(Clone, Copy)]
38 pub struct Pulse;
39 impl Waveform for Pulse {
40 fn sample(&self, state_01: f32, pulse_width_01: f32) -> f32 {
41 if state_01 < pulse_width_01 { -1.0 } else { 1.0 }
42 }
43
44 const PULSE: bool = true;
45 }
46}
47
48use crate::{Pulse, Saw, Sine, Triangle};
49pub use waveform::Waveform;
50
51pub struct Oscillator<W, F, P, R, T>
52where
53 W: Waveform,
54 F: SigT<Item = f32>,
55 P: SigT<Item = f32>,
56 R: SigT<Item = f32>,
57 T: SigT<Item = bool>,
58{
59 first_frame: bool,
60 state_01: f32,
61 waveform: W,
62 freq_hz: F,
63 pulse_width_01: P,
64 reset_offset_01: R,
65 reset_trig: T,
66 buf: Vec<f32>,
67}
68
69impl<W, F, P, R, T> SigT for Oscillator<W, F, P, R, T>
70where
71 W: Waveform,
72 F: SigT<Item = f32>,
73 P: SigT<Item = f32>,
74 R: SigT<Item = f32>,
75 T: SigT<Item = bool>,
76{
77 type Item = f32;
78
79 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
80 if W::PULSE {
81 self.sample_pulse(ctx);
82 } else {
83 self.sample_non_pulse(ctx);
84 }
85 &self.buf
86 }
87}
88
89impl<W, F, P, R, T> Oscillator<W, F, P, R, T>
90where
91 W: Waveform,
92 F: SigT<Item = f32>,
93 P: SigT<Item = f32>,
94 R: SigT<Item = f32>,
95 T: SigT<Item = bool>,
96{
97 fn new(
98 waveform: W,
99 freq_hz: F,
100 pulse_width_01: P,
101 reset_offset_01: R,
102 reset_trig: T,
103 ) -> Sig<Self> {
104 Sig(Self {
105 first_frame: true,
106 state_01: 0.0,
107 waveform,
108 freq_hz,
109 pulse_width_01,
110 reset_offset_01,
111 reset_trig,
112 buf: Vec::new(),
113 })
114 }
115
116 fn sample_non_pulse(&mut self, ctx: &SigCtx) {
117 let buf_freq_hz = self.freq_hz.sample(ctx);
118 let buf_reset_trig = self.reset_trig.sample(ctx);
119 let buf_reset_offset_01 = self.reset_offset_01.sample(ctx);
120 self.buf.clear();
121 for ((freq_hz, reset_trig), reset_offset_01) in buf_freq_hz
122 .iter()
123 .zip(buf_reset_trig.iter())
124 .zip(buf_reset_offset_01.iter())
125 {
126 if reset_trig || self.first_frame {
127 self.first_frame = false;
128 self.state_01 = reset_offset_01;
129 } else {
130 let state_delta = freq_hz / ctx.sample_rate_hz;
131 self.state_01 += state_delta;
132 self.state_01 = self.state_01 - (self.state_01 - 0.5).round();
133 }
134 let sample = self.waveform.sample(self.state_01, 0.0);
135 self.buf.push(sample);
136 }
137 }
138
139 fn sample_pulse(&mut self, ctx: &SigCtx) {
142 let buf_freq_hz = self.freq_hz.sample(ctx);
143 let buf_reset_trig = self.reset_trig.sample(ctx);
144 let buf_reset_offset_01 = self.reset_offset_01.sample(ctx);
145 let buf_pulse_width_01 = self.pulse_width_01.sample(ctx);
146 self.buf.clear();
147 for (((freq_hz, reset_trig), reset_offset_01), pulse_width_01) in
148 buf_freq_hz
149 .iter()
150 .zip(buf_reset_trig.iter())
151 .zip(buf_reset_offset_01.iter())
152 .zip(buf_pulse_width_01.iter())
153 {
154 if reset_trig || self.first_frame {
155 self.first_frame = false;
156 self.state_01 = reset_offset_01;
157 } else {
158 let state_delta = freq_hz / ctx.sample_rate_hz;
159 self.state_01 = (self.state_01 + state_delta).rem_euclid(1.0);
160 }
161 let sample = self.waveform.sample(self.state_01, pulse_width_01);
162 self.buf.push(sample);
163 }
164 }
165}
166
167builder! {
168 #[constructor = "oscillator"]
169 #[constructor_doc = "A signal which oscillates with a given waveform at a given freq_hzuency."]
170 #[build_fn = "Oscillator::new"]
171 #[build_ty = "Sig<Oscillator<W, F, P, R, T>>"]
172 #[generic_setter_type_name = "X"]
173 pub struct OscillatorBuilder {
174 #[generic_with_constraint = "Waveform"]
175 #[generic_name = "W"]
176 waveform: _,
177 #[generic_with_constraint = "SigT<Item = f32>"]
178 #[generic_name = "F"]
179 freq_hz: _,
180 #[generic_with_constraint = "SigT<Item = f32>"]
181 #[default = 0.5]
182 #[generic_name = "P"]
183 pulse_width_01: f32,
184 #[generic_with_constraint = "SigT<Item = f32>"]
185 #[default = 0.0]
186 #[generic_name = "R"]
187 reset_offset_01: f32,
188 #[generic_with_constraint = "SigT<Item = bool>"]
189 #[default = false]
190 #[generic_name = "T"]
191 reset_trig: bool,
192 }
193}
194
195pub struct OscillatorSaw<F, R, T>(Oscillator<Saw, F, f32, R, T>)
196where
197 F: SigT<Item = f32>,
198 R: SigT<Item = f32>,
199 T: SigT<Item = bool>;
200
201impl<F, R, T> SigT for OscillatorSaw<F, R, T>
202where
203 F: SigT<Item = f32>,
204 R: SigT<Item = f32>,
205 T: SigT<Item = bool>,
206{
207 type Item = f32;
208
209 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
210 self.0.sample_non_pulse(ctx);
211 &self.0.buf
212 }
213}
214
215impl<F, R, T> OscillatorSaw<F, R, T>
216where
217 F: SigT<Item = f32>,
218 R: SigT<Item = f32>,
219 T: SigT<Item = bool>,
220{
221 fn new(freq_hz: F, reset_offset_01: R, reset_trig: T) -> Sig<Self> {
222 Sig(Self(
223 Oscillator::new(Saw, freq_hz, 0., reset_offset_01, reset_trig).0,
224 ))
225 }
226}
227
228builder! {
229 #[constructor = "saw"]
230 #[constructor_doc = "A signal which oscillates with a saw wave at a given freq_hzuency."]
231 #[build_fn = "OscillatorSaw::new"]
232 #[build_ty = "Sig<OscillatorSaw<F, R, T>>"]
233 #[generic_setter_type_name = "X"]
234 pub struct OscillatorSawBuilder {
235 #[generic_with_constraint = "SigT<Item = f32>"]
236 #[generic_name = "F"]
237 freq_hz: _,
238 #[generic_with_constraint = "SigT<Item = f32>"]
239 #[default = 0.0]
240 #[generic_name = "R"]
241 reset_offset_01: f32,
242 #[generic_with_constraint = "SigT<Item = bool>"]
243 #[default = false]
244 #[generic_name = "T"]
245 reset_trig: bool,
246 }
247}
248
249pub struct OscillatorSine<F, R, T>(Oscillator<Sine, F, f32, R, T>)
250where
251 F: SigT<Item = f32>,
252 R: SigT<Item = f32>,
253 T: SigT<Item = bool>;
254
255impl<F, R, T> SigT for OscillatorSine<F, R, T>
256where
257 F: SigT<Item = f32>,
258 R: SigT<Item = f32>,
259 T: SigT<Item = bool>,
260{
261 type Item = f32;
262
263 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
264 self.0.sample_non_pulse(ctx);
265 &self.0.buf
266 }
267}
268
269impl<F, R, T> OscillatorSine<F, R, T>
270where
271 F: SigT<Item = f32>,
272 R: SigT<Item = f32>,
273 T: SigT<Item = bool>,
274{
275 fn new(freq_hz: F, reset_offset_01: R, reset_trig: T) -> Sig<Self> {
276 Sig(Self(
277 Oscillator::new(Sine, freq_hz, 0., reset_offset_01, reset_trig).0,
278 ))
279 }
280}
281
282builder! {
283 #[constructor = "sine"]
284 #[constructor_doc = "A signal which oscillates with a sine wave at a given freq_hzuency."]
285 #[build_fn = "OscillatorSine::new"]
286 #[build_ty = "Sig<OscillatorSine<F, R, T>>"]
287 #[generic_setter_type_name = "X"]
288 pub struct OscillatorSineBuilder {
289 #[generic_with_constraint = "SigT<Item = f32>"]
290 #[generic_name = "F"]
291 freq_hz: _,
292 #[generic_with_constraint = "SigT<Item = f32>"]
293 #[default = 0.0]
294 #[generic_name = "R"]
295 reset_offset_01: f32,
296 #[generic_with_constraint = "SigT<Item = bool>"]
297 #[default = false]
298 #[generic_name = "T"]
299 reset_trig: bool,
300 }
301}
302
303pub struct OscillatorTriangle<F, R, T>(Oscillator<Triangle, F, f32, R, T>)
304where
305 F: SigT<Item = f32>,
306 R: SigT<Item = f32>,
307 T: SigT<Item = bool>;
308
309impl<F, R, T> SigT for OscillatorTriangle<F, R, T>
310where
311 F: SigT<Item = f32>,
312 R: SigT<Item = f32>,
313 T: SigT<Item = bool>,
314{
315 type Item = f32;
316
317 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
318 self.0.sample_non_pulse(ctx);
319 &self.0.buf
320 }
321}
322
323impl<F, R, T> OscillatorTriangle<F, R, T>
324where
325 F: SigT<Item = f32>,
326 R: SigT<Item = f32>,
327 T: SigT<Item = bool>,
328{
329 fn new(freq_hz: F, reset_offset_01: R, reset_trig: T) -> Sig<Self> {
330 Sig(Self(
331 Oscillator::new(Triangle, freq_hz, 0., reset_offset_01, reset_trig)
332 .0,
333 ))
334 }
335}
336
337builder! {
338 #[constructor = "triangle"]
339 #[constructor_doc = "A signal which oscillates with a triangle wave at a given freq_hzuency."]
340 #[build_fn = "OscillatorTriangle::new"]
341 #[build_ty = "Sig<OscillatorTriangle<F, R, T>>"]
342 #[generic_setter_type_name = "X"]
343 pub struct OscillatorTriangleBuilder {
344 #[generic_with_constraint = "SigT<Item = f32>"]
345 #[generic_name = "F"]
346 freq_hz: _,
347 #[generic_with_constraint = "SigT<Item = f32>"]
348 #[default = 0.0]
349 #[generic_name = "R"]
350 reset_offset_01: f32,
351 #[generic_with_constraint = "SigT<Item = bool>"]
352 #[default = false]
353 #[generic_name = "T"]
354 reset_trig: bool,
355 }
356}
357
358pub struct OscillatorPulse<F, P, R, T>(Oscillator<Pulse, F, P, R, T>)
359where
360 F: SigT<Item = f32>,
361 P: SigT<Item = f32>,
362 R: SigT<Item = f32>,
363 T: SigT<Item = bool>;
364
365impl<F, P, R, T> SigT for OscillatorPulse<F, P, R, T>
366where
367 F: SigT<Item = f32>,
368 P: SigT<Item = f32>,
369 R: SigT<Item = f32>,
370 T: SigT<Item = bool>,
371{
372 type Item = f32;
373
374 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
375 self.0.sample_pulse(ctx);
376 &self.0.buf
377 }
378}
379
380impl<F, P, R, T> OscillatorPulse<F, P, R, T>
381where
382 F: SigT<Item = f32>,
383 P: SigT<Item = f32>,
384 R: SigT<Item = f32>,
385 T: SigT<Item = bool>,
386{
387 fn new(
388 freq_hz: F,
389 pulse_width_01: P,
390 reset_offset_01: R,
391 reset_trig: T,
392 ) -> Sig<Self> {
393 Sig(Self(
394 Oscillator::new(
395 Pulse,
396 freq_hz,
397 pulse_width_01,
398 reset_offset_01,
399 reset_trig,
400 )
401 .0,
402 ))
403 }
404}
405
406builder! {
407 #[constructor = "pulse"]
408 #[constructor_doc = "A signal which oscillates with a pulse wave at a given freq_hzuency."]
409 #[build_fn = "OscillatorPulse::new"]
410 #[build_ty = "Sig<OscillatorPulse<F, P, R, T>>"]
411 #[generic_setter_type_name = "X"]
412 pub struct OscillatorPulseBuilder {
413 #[generic_with_constraint = "SigT<Item = f32>"]
414 #[generic_name = "F"]
415 freq_hz: _,
416 #[generic_with_constraint = "SigT<Item = f32>"]
417 #[default = 0.5]
418 #[generic_name = "P"]
419 pulse_width_01: f32,
420 #[generic_with_constraint = "SigT<Item = f32>"]
421 #[default = 0.0]
422 #[generic_name = "R"]
423 reset_offset_01: f32,
424 #[generic_with_constraint = "SigT<Item = bool>"]
425 #[default = false]
426 #[generic_name = "T"]
427 reset_trig: bool,
428 }
429}