1#[cfg(feature = "fm")]
2pub mod fm;
3
4#[cfg(feature = "fm")]
5pub use fm::{FmMapper, FmTick};
6
7use crate::fixed::clamp_sample;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum DutyMode {
12 #[default]
14 Linear,
15 SigmaDelta,
17 SigmaDelta2ndOrder,
19}
20
21#[derive(Debug, Clone, Copy, Default)]
23pub struct SigmaDelta {
24 integrator: i32,
25}
26
27impl SigmaDelta {
28 pub const fn new() -> Self {
29 Self { integrator: 0 }
30 }
31
32 pub fn reset(&mut self) {
33 self.integrator = 0;
34 }
35
36 pub fn shape(&mut self, pcm: i8) -> i8 {
38 let input = (pcm as i32) << 8;
39 self.integrator += input;
40 let high = self.integrator >= 0;
41 if high {
42 self.integrator -= 65536;
43 }
44 if high { 127 } else { -127 }
45 }
46}
47
48#[derive(Debug, Clone, Copy, Default)]
50pub struct SigmaDelta2ndOrder {
51 e1: i32,
52 e2: i32,
53}
54
55impl SigmaDelta2ndOrder {
56 pub const fn new() -> Self {
57 Self { e1: 0, e2: 0 }
58 }
59
60 pub fn reset(&mut self) {
61 self.e1 = 0;
62 self.e2 = 0;
63 }
64
65 pub fn shape(&mut self, pcm: i8) -> i8 {
66 let input = (pcm as i32) << 8;
67 self.e1 += input;
68 let y1 = if self.e1 >= 0 { 32767 } else { -32768 };
69 self.e1 -= y1;
70
71 self.e2 += self.e1;
72 let y2 = if self.e2 >= 0 { 32767 } else { -32768 };
73 self.e2 -= y2;
74
75 let out = (y1 + y2) >> 9;
76 out.clamp(-127, 127) as i8
77 }
78}
79
80#[inline]
82pub fn pcm_to_duty(pcm: i8, period: u16) -> u16 {
83 let mid = period as i32 / 2;
84 let swing = mid - 1;
85 let offset = (pcm as i32 * swing) / 127;
86 (mid + offset).clamp(1, period as i32 - 1) as u16
87}
88
89pub struct PwmMapper {
91 pub mode: DutyMode,
92 pub sigma_delta: SigmaDelta,
93 pub sigma_delta_2nd: SigmaDelta2ndOrder,
94}
95
96impl PwmMapper {
97 pub const fn new(mode: DutyMode) -> Self {
98 Self {
99 mode,
100 sigma_delta: SigmaDelta::new(),
101 sigma_delta_2nd: SigmaDelta2ndOrder::new(),
102 }
103 }
104
105 pub fn map(&mut self, pcm: i8, period: u16) -> u16 {
106 let shaped = match self.mode {
107 DutyMode::Linear => pcm,
108 DutyMode::SigmaDelta => self.sigma_delta.shape(pcm),
109 DutyMode::SigmaDelta2ndOrder => self.sigma_delta_2nd.shape(pcm),
110 };
111 pcm_to_duty(shaped, period)
112 }
113
114 pub fn reset(&mut self) {
115 self.sigma_delta.reset();
116 self.sigma_delta_2nd.reset();
117 }
118}
119
120#[inline]
122pub fn limit_bus(sum: i32) -> i8 {
123 clamp_sample(sum)
124}
125
126#[inline]
128pub fn pcm_to_i16(pcm: i8) -> i16 {
129 (pcm as i16) << 8
130}
131
132#[inline]
134pub fn pcm_to_i32(pcm: i8) -> i32 {
135 (pcm as i32) << 24
136}
137
138#[inline]
140pub fn pcm_to_dac_u8(pcm: i8) -> u8 {
141 (pcm as i16 + 128).clamp(0, 255) as u8
142}
143
144#[inline]
146pub fn pcm_to_dac_u12(pcm: i8) -> u16 {
147 ((pcm as i32 + 128) * 4095 / 255).clamp(0, 4095) as u16
148}
149
150#[inline]
152pub fn pcm_to_dac_u16(pcm: i8) -> u16 {
153 ((pcm as i32 + 128) << 8).clamp(0, 65535) as u16
154}