1use crate::fade::FadeBuffer;
2use crate::tuning::Tuning;
3use crate::voice::Voice;
4use crate::{MidiEvent, Note};
5use std::sync::Arc;
6
7pub struct Synth<V: Voice + Clone> {
9 opts: SynthOpts,
11 buffer: Vec<f32>,
13 voice: V,
15 voices: Vec<VoiceHandle<V>>,
17 counter: usize,
19 fade_out: FadeBuffer<256>,
21 pitch_bend: f32,
23 sample_rate: u32,
25}
26
27#[derive(Clone)]
29pub struct SynthOpts {
30 pub tuning: Arc<Tuning>,
32 pub max_block_size: usize,
35 pub max_voices: usize,
37 pub mono: bool,
39 pub portamento: Portamento,
41 pub max_pitch_bend: f32,
43}
44
45#[derive(Copy, Clone)]
47pub enum Portamento {
48 Off,
50 Fixed(f32),
53 Variable(f32),
56}
57
58struct VoiceHandle<V: Voice> {
59 voice: V,
60 phase: VoicePhase,
61 pitch: f32,
62 counter: usize,
63}
64
65#[derive(Clone, Copy, PartialEq, Eq)]
66enum VoicePhase {
67 On(Note),
68 Released(Note),
69 Off,
70}
71
72impl<V: Voice + Clone> Synth<V> {
73 pub fn new(opts: SynthOpts, voice: V) -> Self {
79 let mut out = Self {
80 opts,
81 buffer: vec![],
82 voice,
83 voices: vec![],
84 counter: 0,
85 fade_out: FadeBuffer::new(),
86 pitch_bend: 1.0,
87 sample_rate: 0,
88 };
89 out.update_opts(|_| {});
90 out
91 }
92
93 pub fn update_opts(&mut self, f: impl FnOnce(&mut SynthOpts)) {
98 f(&mut self.opts);
99 self.voices.resize_with(self.opts.max_voices, || {
100 VoiceHandle::new(self.voice.clone())
101 });
102 self.buffer.resize(self.opts.max_block_size * 2, 0.0);
103 }
104
105 pub fn update_voice(&mut self, voice: V) {
109 self.voice = voice;
110 for voice in &mut self.voices {
111 *voice = VoiceHandle::new(self.voice.clone());
112 }
113 }
114
115 pub fn set_sample_rate(&mut self, sample_rate: u32) {
117 self.sample_rate = sample_rate;
118 self.voice.set_sample_rate(sample_rate);
119 for voice in &mut self.voices {
120 voice.set_sample_rate(sample_rate);
121 }
122 }
123
124 pub fn trigger(&mut self, note: Note, velocity: u8) {
130 let voice = self
131 .voices
132 .iter_mut()
133 .min_by_key(|v| v.priority(note))
134 .unwrap();
135 let pitch = self.opts.tuning.pitch(note);
136 voice.trigger(note, velocity, pitch, self.counter);
137 self.counter += 1;
138
139 }
141
142 pub fn release(&mut self, note: Note) {
144 let voice = self.voices.iter_mut().find(|v| v.note_on() == Some(note));
145 if let Some(voice) = voice {
146 voice.release(self.counter);
147 self.counter += 1;
148 }
149 }
150
151 pub fn set_pitch_bend_raw(&mut self, value: u16) {
153 let semitones = ((value as f32 - 8192.0) / 8192.0) * self.opts.max_pitch_bend;
154 self.set_pitch_bend(semitones);
155 }
156
157 pub fn set_pitch_bend(&mut self, semitones: f32) {
159 self.pitch_bend = 2f32.powf(semitones / 12.0);
160 }
161
162 pub fn midi_event(&mut self, event: MidiEvent) {
164 match event {
165 MidiEvent::NoteOn { note, velocity, .. } => self.trigger(note, velocity),
166 MidiEvent::NoteOff { note, .. } => self.release(note),
167 MidiEvent::PitchBend { value, .. } => self.set_pitch_bend_raw(value),
168 }
169 }
170
171 pub fn process(&mut self, output: [&mut [f32]; 2]) {
173 let [left, right] = output;
174
175 let len = left.len();
176 assert_eq!(right.len(), len);
177 assert!(len <= self.opts.max_block_size);
178
179 let (left_temp, right_temp) = self.buffer[..2 * len].split_at_mut(len);
181
182 let mut written = false;
184
185 for handle in &mut self.voices {
187 if !handle.active() {
188 continue;
189 }
190 if written {
191 handle.process(self.pitch_bend, [left_temp, right_temp]);
192 add_buffers(left, left_temp);
193 add_buffers(right, right_temp);
194 } else {
195 handle.process(self.pitch_bend, [left, right]);
196 written = true;
197 }
198 }
199
200 if !written {
202 left.fill(0.0);
203 right.fill(0.0);
204 }
205
206 self.fade_out.process([left, right]);
208 }
209}
210
211impl<V: Voice> VoiceHandle<V> {
212 fn new(voice: V) -> Self {
213 Self {
214 voice,
215 phase: VoicePhase::Off,
216 pitch: 0.0,
217 counter: 0,
218 }
219 }
220
221 fn active(&self) -> bool {
223 self.phase != VoicePhase::Off
224 }
225
226 fn note_on(&self) -> Option<Note> {
228 if let VoicePhase::On(note) = self.phase {
229 Some(note)
230 } else {
231 None
232 }
233 }
234
235 fn priority(&self, note: Note) -> usize {
237 match self.phase {
238 VoicePhase::On(n) if n == note => 0,
240 VoicePhase::Off => 1,
242 VoicePhase::Released(n) if n == note => 2,
244 VoicePhase::Released(_) => 3 + self.counter,
246 VoicePhase::On(_) => usize::MAX / 2 + self.counter,
248 }
249 }
250
251 fn set_sample_rate(&mut self, sample_rate: u32) {
253 self.voice.set_sample_rate(sample_rate);
254 }
255
256 fn trigger(&mut self, note: Note, velocity: u8, pitch: f32, counter: usize) {
258 self.voice.trigger(note, velocity);
259 self.phase = VoicePhase::On(note);
260 self.pitch = pitch; self.counter = counter;
262 }
263
264 pub fn release(&mut self, counter: usize) {
266 let note = match self.phase {
267 VoicePhase::On(note) => note,
268 VoicePhase::Released(note) => note,
269 VoicePhase::Off => return,
270 };
271
272 self.voice.release();
273 self.phase = VoicePhase::Released(note);
274 self.counter = counter;
275 }
276
277 fn process(&mut self, pitch_bend: f32, output: [&mut [f32]; 2]) {
279 let active = self.voice.process(self.pitch * pitch_bend, output);
280 if !active {
281 self.phase = VoicePhase::Off;
282 }
283 }
284}
285
286fn add_buffers(dst: &mut [f32], src: &[f32]) {
287 assert_eq!(src.len(), dst.len());
288 for i in 0..src.len() {
289 dst[i] += src[i];
290 }
291}