oscillation/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![feature(variant_count)]
3#![feature(let_chains)]
4#![feature(iter_array_chunks)]
5#![feature(specialization)]
6
7use num_traits::Float;
8
9moddef::moddef!(
10    flat(pub) mod {
11        wavetable
12    },
13    pub mod {
14        oscillator,
15        waveform
16    },
17    mod {
18        plot for cfg(test),
19        util
20    }
21);
22
23pub fn duty_cycle_default<F>() -> F
24where
25    F: Float
26{
27    F::from(0.5).unwrap()
28}
29
30#[cfg(test)]
31mod tests
32{
33    use core::{
34        error::Error,
35        f32::consts::{FRAC_PI_2, TAU},
36        ops::RangeInclusive
37    };
38
39    use linspace::{Linspace, LinspaceArray};
40
41    use crate::{
42        oscillator::{Direct, Oscillator},
43        waveform::Waveform
44    };
45
46    use super::*;
47
48    const PLOT_TARGET: &str = "plots";
49
50    #[test]
51    fn it_works() {}
52
53    fn name(type_name: &str) -> (&str, String)
54    {
55        let name = {
56            let mut k = 0;
57            let mut i = 0;
58            loop
59            {
60                if i >= type_name.len()
61                {
62                    break &type_name[k..];
63                }
64                else if type_name[i..].starts_with("::")
65                {
66                    i += "::".len();
67                    k = i;
68                }
69                else if type_name[i..].starts_with("<")
70                {
71                    break &type_name[k..i];
72                }
73                else
74                {
75                    i += 1;
76                }
77            }
78        };
79        let mut first = true;
80        let file_name: String = name
81            .chars()
82            .flat_map(|c| {
83                if c.is_ascii_uppercase()
84                {
85                    if first
86                    {
87                        first = false;
88                        vec![c.to_ascii_lowercase()]
89                    }
90                    else
91                    {
92                        vec!['_', c.to_ascii_lowercase()]
93                    }
94                }
95                else
96                {
97                    vec![c]
98                }
99            })
100            .collect();
101        (name, file_name)
102    }
103
104    pub(crate) fn print_waveform<W>(waveform: W) -> Result<(), Box<dyn Error>>
105    where
106        W: Waveform<f32> + Copy
107    {
108        const N: usize = 128;
109        const M: usize = 32;
110        const MM: usize = M + 1;
111        const MC: usize = MM / 2;
112        const MORE: f32 = FRAC_PI_2;
113        const RANGE: RangeInclusive<f32> = -MORE..=(TAU + MORE);
114        const RATE: f32 = N as f32 * TAU / (*RANGE.end() - *RANGE.start());
115        const L: usize = 1024;
116        const TIME: f32 = 1.0;
117
118        const OMEGA: f32 = TAU;
119        const PHI: f32 = *RANGE.start();
120
121        let theta = RANGE.linspace(N);
122
123        let dtc: [_; M] = (0.0..=1.0).linspace_array();
124
125        let assert_finite = |x: f32| {
126            assert!(x.is_finite(), "Not finite!");
127            x
128        };
129
130        let y = core::array::from_fn::<_, MM, _>(|i| {
131            let mut osc1 = Oscillator::new(OMEGA, PHI, Direct::from(waveform));
132            let mut osc2 = osc1.with_wavetable::<L>();
133
134            if i == MC
135            {
136                [
137                    (0..N).map(|_| osc1.next(RATE)).map(assert_finite).collect::<Vec<_>>(),
138                    (0..N).map(|_| osc2.next(RATE)).map(assert_finite).collect::<Vec<_>>()
139                ]
140            }
141            else
142            {
143                let duty_cycle = dtc[i - (i >= MC) as usize];
144                let mut osc1 = osc1.with_dtc(duty_cycle);
145                let mut osc2 = osc2.with_dtc(duty_cycle);
146                [
147                    (0..N).map(|_| osc1.next(RATE)).map(assert_finite).collect::<Vec<_>>(),
148                    (0..N).map(|_| osc2.next(RATE)).map(assert_finite).collect::<Vec<_>>()
149                ]
150            }
151        });
152
153        let (name, file_name) = name(core::any::type_name::<W>());
154
155        plot::plot_curves_anim(
156            &format!("Waveform of '{}'", name),
157            &format!("{}/{}.gif", PLOT_TARGET, file_name),
158            [[&theta; 2]; MM],
159            y.each_ref().map(|y| y.each_ref().map(|y| y.as_slice())),
160            TIME
161        )
162    }
163}