1#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
7
8use super::external_filter::ExternalFilter;
9use super::filter::Filter;
10use super::sid::reg;
11use super::voice::Voice;
12use super::wave::Syncable;
13use super::ChipModel;
14
15const OUTPUT_RANGE: u32 = 1 << 16;
16const OUTPUT_HALF: i32 = (OUTPUT_RANGE >> 1) as i32;
17const SAMPLES_PER_OUTPUT: u32 = ((4095 * 255) >> 7) * 3 * 15 * 2 / OUTPUT_RANGE;
18
19#[derive(Clone, Copy)]
20pub struct Synth {
21 pub ext_filter: ExternalFilter,
22 pub filter: Filter,
23 pub voices: [Voice; 3],
24 pub ext_in: i32,
25}
26
27fn rotate3<T>([a, b, c]: [T; 3], i: usize) -> [T; 3] {
30 match i {
31 0 => [a, b, c],
32 1 => [b, c, a],
33 2 => [c, a, b],
34 _ => panic!("index out of bounds"),
35 }
36}
37
38impl Synth {
39 pub fn new(chip_model: ChipModel) -> Self {
40 Synth {
41 ext_filter: ExternalFilter::new(chip_model),
42 filter: Filter::new(chip_model),
43 voices: [Voice::new(chip_model); 3],
44 ext_in: 0,
45 }
46 }
47
48 pub fn syncable_voice(&self, i: usize) -> Syncable<&'_ Voice> {
49 let [a, b, c] = &self.voices;
50 let [main, sync_dest, sync_source] = rotate3([a, b, c], i);
51 Syncable {
52 main,
53 sync_dest,
54 sync_source,
55 }
56 }
57
58 pub fn syncable_voice_mut(&mut self, i: usize) -> Syncable<&'_ mut Voice> {
59 let [a, b, c] = &mut self.voices;
60 let [main, sync_dest, sync_source] = rotate3([a, b, c], i);
61 Syncable {
62 main,
63 sync_dest,
64 sync_source,
65 }
66 }
67
68 pub fn clock(&mut self) {
69 for i in 0..3 {
71 self.voices[i].envelope.clock();
72 }
73 for i in 0..3 {
75 self.voices[i].wave.clock();
76 }
77 for i in 0..3 {
79 self.syncable_voice_mut(i).wave().synchronize();
80 }
81 self.filter.clock(
83 self.syncable_voice(0).output(),
84 self.syncable_voice(1).output(),
85 self.syncable_voice(2).output(),
86 self.ext_in,
87 );
88 self.ext_filter.clock(self.filter.output());
90 }
91
92 pub fn clock_delta(&mut self, delta: u32) {
93 for i in 0..3 {
95 self.voices[i].envelope.clock_delta(delta);
96 }
97 let mut delta_osc = delta;
98 while delta_osc != 0 {
99 let mut delta_min = delta_osc;
103 for i in 0..3 {
104 let wave = self.syncable_voice(i).wave();
105 if !(wave.sync_dest.get_sync() && wave.main.get_frequency() != 0) {
108 continue;
109 }
110 let freq = wave.main.get_frequency() as u32;
111 let acc = wave.main.get_acc();
112 let delta_acc = if acc & 0x0080_0000 != 0 {
114 0x0100_0000 - acc
115 } else {
116 0x0080_0000 - acc
117 };
118 let mut delta_next = delta_acc / freq;
119 if delta_acc % freq != 0 {
120 delta_next += 1;
121 }
122 if delta_next < delta_min {
123 delta_min = delta_next;
124 }
125 }
126 for i in 0..3 {
128 self.voices[i].wave.clock_delta(delta_min);
129 }
130 for i in 0..3 {
132 self.syncable_voice_mut(i).wave().synchronize();
133 }
134 delta_osc -= delta_min;
135 }
136 self.filter.clock_delta(
138 delta,
139 self.syncable_voice(0).output(),
140 self.syncable_voice(1).output(),
141 self.syncable_voice(2).output(),
142 self.ext_in,
143 );
144 self.ext_filter.clock_delta(delta, self.filter.output());
146 }
147
148 pub fn output(&self) -> i16 {
149 let sample = self.ext_filter.output() / SAMPLES_PER_OUTPUT as i32;
151 if sample >= OUTPUT_HALF {
152 (OUTPUT_HALF - 1) as i16
153 } else if sample < -OUTPUT_HALF {
154 (-OUTPUT_HALF) as i16
155 } else {
156 sample as i16
157 }
158 }
159
160 pub fn reset(&mut self) {
161 self.ext_filter.reset();
162 self.filter.reset();
163 for i in 0..3 {
164 self.voices[i].reset();
165 }
166 self.ext_in = 0;
167 }
168
169 pub fn read(&self, reg: u8, bus_value: u8) -> u8 {
170 match reg {
171 reg::POTX => 0xff,
172 reg::POTY => 0xff,
173 reg::OSC3 => self.syncable_voice(2).wave().read_osc(),
174 reg::ENV3 => self.voices[2].envelope.read_env(),
175 _ => bus_value,
176 }
177 }
178
179 pub fn write(&mut self, reg: u8, value: u8) {
180 match reg {
181 reg::FREQLO1 => self.voices[0].wave.set_frequency_lo(value),
182 reg::FREQHI1 => self.voices[0].wave.set_frequency_hi(value),
183 reg::PWLO1 => self.voices[0].wave.set_pulse_width_lo(value),
184 reg::PWHI1 => self.voices[0].wave.set_pulse_width_hi(value),
185 reg::CR1 => self.voices[0].set_control(value),
186 reg::AD1 => self.voices[0].envelope.set_attack_decay(value),
187 reg::SR1 => self.voices[0].envelope.set_sustain_release(value),
188 reg::FREQLO2 => self.voices[1].wave.set_frequency_lo(value),
189 reg::FREQHI2 => self.voices[1].wave.set_frequency_hi(value),
190 reg::PWLO2 => self.voices[1].wave.set_pulse_width_lo(value),
191 reg::PWHI2 => self.voices[1].wave.set_pulse_width_hi(value),
192 reg::CR2 => self.voices[1].set_control(value),
193 reg::AD2 => self.voices[1].envelope.set_attack_decay(value),
194 reg::SR2 => self.voices[1].envelope.set_sustain_release(value),
195 reg::FREQLO3 => self.voices[2].wave.set_frequency_lo(value),
196 reg::FREQHI3 => self.voices[2].wave.set_frequency_hi(value),
197 reg::PWLO3 => self.voices[2].wave.set_pulse_width_lo(value),
198 reg::PWHI3 => self.voices[2].wave.set_pulse_width_hi(value),
199 reg::CR3 => self.voices[2].set_control(value),
200 reg::AD3 => self.voices[2].envelope.set_attack_decay(value),
201 reg::SR3 => self.voices[2].envelope.set_sustain_release(value),
202 reg::FCLO => self.filter.set_fc_lo(value),
203 reg::FCHI => self.filter.set_fc_hi(value),
204 reg::RESFILT => self.filter.set_res_filt(value),
205 reg::MODVOL => self.filter.set_mode_vol(value),
206 _ => {}
207 }
208 }
209}