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 [[θ 2]; MM],
159 y.each_ref().map(|y| y.each_ref().map(|y| y.as_slice())),
160 TIME
161 )
162 }
163}