1use std::fmt::{Display, Formatter};
12
13pub use algorithms::*;
14pub use envelope::*;
15pub use format::Format;
16pub use read::*;
17
18mod algorithms;
19mod envelope;
20mod format;
21mod read;
22
23const SYSEX_HEADER: [u8; 6] = [0xF0, 0x43, 0x00, 0x09, 0x20, 0x00];
24
25pub type OperatorId = u8;
26
27pub struct Hardware;
28
29impl Hardware {
30 pub const POLYPHONY: u32 = 16;
32}
33
34#[derive(Clone, Debug, Eq, PartialEq)]
35pub struct PresetName(String);
36
37impl PresetName {
38 pub const MAX_LENGTH: usize = 10;
40
41 pub fn from_lossy(data: &[u8]) -> PresetName {
55 let ascii = data
56 .iter()
57 .map(|c| match c & 0x7F {
58 c if (0x20..0x7f).contains(&c) => c, _ => b' ',
60 })
61 .take(PresetName::MAX_LENGTH)
62 .collect::<Vec<u8>>();
63 PresetName(String::from_utf8_lossy(&ascii).trim_end().to_string())
64 }
65}
66
67impl Default for PresetName {
68 fn default() -> Self {
69 PresetName("INIT VOICE".to_owned())
70 }
71}
72
73impl Display for PresetName {
74 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
75 f.write_str(&self.0)
76 }
77}
78
79#[derive(Copy, Clone, Debug, Eq, PartialEq)]
80#[repr(u8)]
81pub enum Waveform {
82 Triangle = 0,
83 SawDown = 1,
84 SawUp = 2,
85 Square = 3,
86 Sine = 4,
87 SampleAndHold = 5,
88}
89
90impl TryFrom<u8> for Waveform {
91 type Error = &'static str;
92
93 fn try_from(value: u8) -> Result<Self, Self::Error> {
94 match value {
95 0 => Ok(Waveform::Triangle),
96 1 => Ok(Waveform::SawDown),
97 2 => Ok(Waveform::SawUp),
98 3 => Ok(Waveform::Square),
99 4 => Ok(Waveform::Sine),
100 5 => Ok(Waveform::SampleAndHold),
101 _ => Err("Unknown waveform {value}"),
102 }
103 }
104}
105
106#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
107pub enum OperatorMode {
108 Fixed = 0,
109 Ratio = 1,
110}
111
112impl Display for OperatorMode {
113 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
114 use OperatorMode::*;
115 let txt = match self {
116 Fixed => "Fixed",
117 Ratio => "Ratio",
118 };
119 f.write_str(txt)
120 }
121}
122
123#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
124pub struct Operator {
125 pub envelope: Envelope,
128 pub scaling_break_point: u8,
129 pub scaling_left_depth: u8,
130 pub scaling_right_depth: u8,
131 pub scaling_left_curve: u8,
132 pub scaling_right_curve: u8,
133
134 pub detune: i8,
136
137 pub rate_scaling: u8,
138 pub velocity_sensitivity: u8,
139 pub modulation_sensitivity: u8,
140 pub output_level: u8,
141 pub mode: OperatorMode,
142 pub frequency_course: u8,
143 pub frequency_fine: u8,
144}
145
146impl Operator {
147 fn normalize(&self) -> Self {
149 Self {
150 scaling_break_point: self.scaling_break_point.clamp(0, 99),
151 scaling_left_depth: self.scaling_left_depth.clamp(0, 99),
152 scaling_right_depth: self.scaling_right_depth.clamp(0, 99),
153 scaling_left_curve: self.scaling_left_curve.clamp(0, 3),
154 scaling_right_curve: self.scaling_right_curve.clamp(0, 3),
155 detune: self.detune.clamp(0, 14),
156 rate_scaling: self.rate_scaling.clamp(0, 7),
157 velocity_sensitivity: self.velocity_sensitivity.clamp(0, 7),
158 modulation_sensitivity: self.modulation_sensitivity.clamp(0, 3),
159 output_level: self.output_level.clamp(0, 99),
160 frequency_course: self.frequency_course.clamp(0, 31),
161 frequency_fine: self.frequency_fine.clamp(0, 99),
162 ..*self
163 }
164 }
165}
166
167impl Default for Operator {
168 fn default() -> Self {
169 let mut envelope = Envelope::default();
172 envelope.levels[envelope.levels.len() - 1] = 0;
173
174 Operator {
175 envelope,
176 scaling_break_point: 39,
177 scaling_left_depth: 0,
178 scaling_right_depth: 0,
179 scaling_left_curve: 0,
180 scaling_right_curve: 0,
181 detune: 0,
182 rate_scaling: 0,
183 velocity_sensitivity: 0,
184 modulation_sensitivity: 0,
185 output_level: 0,
186 mode: OperatorMode::Fixed,
187 frequency_course: 1,
188 frequency_fine: 0,
189 }
190 }
191}
192
193#[derive(Clone, Debug, Eq, PartialEq)]
194pub struct Preset {
195 pub name: PresetName,
196 pub operators: [Operator; Preset::OPERATOR_COUNT],
197 pub pitch_envelope: Envelope,
198 pub algorithm_id: AlgorithmId,
199
200 #[doc(alias = "osc phase init")]
201 pub oscillator_key_sync: bool,
202 pub feedback_level: u8,
203 pub lfo_speed: u8,
204 pub lfo_delay: u8,
205 pub lfo_pitch_mod_depth: u8,
206 pub lfo_pitch_mod_sensitivity: u8,
207 pub lfo_amplitude_mod_depth: u8,
208 pub lfo_waveform: Waveform,
209 pub lfo_key_sync: bool,
210 pub transpose: u8,
211}
212
213impl Preset {
214 const OPERATOR_COUNT: usize = 6;
215
216 fn normalize(&self) -> Self {
218 Preset {
220 name: self.name.clone(),
221 operators: self.operators.map(|operator| operator.normalize()),
222 pitch_envelope: self.pitch_envelope.normalize(),
223 algorithm_id: self.algorithm_id.clamp(0, 31),
224 oscillator_key_sync: self.oscillator_key_sync,
225 feedback_level: self.feedback_level.clamp(0, 7),
226 lfo_speed: self.lfo_speed.clamp(0, 99),
227 lfo_delay: self.lfo_delay.clamp(0, 99),
228 lfo_pitch_mod_depth: self.lfo_pitch_mod_depth.clamp(0, 99),
229 lfo_pitch_mod_sensitivity: self.lfo_pitch_mod_sensitivity.clamp(0, 99),
230 lfo_amplitude_mod_depth: self.lfo_amplitude_mod_depth.clamp(0, 99),
231 lfo_waveform: self.lfo_waveform,
232 lfo_key_sync: self.lfo_key_sync,
233 transpose: self.transpose.clamp(0, 48),
234 }
235 }
236}
237
238impl Default for Preset {
239 fn default() -> Self {
240 let mut operators = [Operator::default(); Preset::OPERATOR_COUNT];
241 operators[0] = Operator {
242 output_level: 99,
243 ..Default::default()
244 };
245
246 let pitch_envelope = Envelope::from_rate_and_level(99, 50);
247 Preset {
248 name: PresetName::default(),
249 operators,
250 pitch_envelope,
251 algorithm_id: 0,
252 oscillator_key_sync: true,
253 feedback_level: 0,
254 lfo_speed: 35,
255 lfo_delay: 0,
256 lfo_pitch_mod_depth: 0,
257 lfo_pitch_mod_sensitivity: 3,
258 lfo_amplitude_mod_depth: 0,
259 lfo_waveform: Waveform::Triangle,
260 lfo_key_sync: true,
261 transpose: 24,
262 }
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use std::path::PathBuf;
269
270 use super::*;
271
272 pub(crate) fn test_data_path(components: &[&str]) -> PathBuf {
273 let mut parts = vec!["tests"];
274 parts.extend_from_slice(components);
275 parts.iter().collect::<PathBuf>()
276 }
277
278 #[test]
279 fn default() {
280 let preset = Preset::default();
281 assert_eq!(preset, preset);
282
283 assert_eq!(preset, preset.normalize());
286
287 assert_eq!(99, preset.pitch_envelope.rates[0]);
289 assert_eq!(50, preset.pitch_envelope.levels[0]);
290
291 assert_eq!(0, preset.algorithm_id);
293 assert!(preset.lfo_key_sync);
294 assert!(preset.oscillator_key_sync);
295 assert_eq!(35, preset.lfo_speed);
296 assert_eq!(3, preset.lfo_pitch_mod_sensitivity);
297 assert_eq!(24, preset.transpose);
298 assert_eq!("INIT VOICE", preset.name.to_string());
299
300 assert_eq!(99, preset.operators[0].output_level);
302 assert_eq!(0, preset.operators.last().unwrap().output_level);
303
304 assert_eq!(99, preset.operators[0].envelope.levels[0]);
306 assert_eq!(0, *preset.operators[0].envelope.levels.last().unwrap());
307
308 assert_eq!(0, preset.operators[0].rate_scaling);
310 assert_eq!(39, preset.operators[0].scaling_break_point);
311 assert_eq!(0, preset.operators[0].detune);
312 assert_eq!(OperatorMode::Fixed, preset.operators[0].mode);
313 assert_eq!(1, preset.operators[0].frequency_course);
314 assert_eq!(0, preset.operators[0].frequency_fine);
315 }
316
317 #[test]
318 fn normalize() {
319 let preset = Preset {
320 feedback_level: 123,
321 lfo_delay: 100,
322 transpose: 200,
323 ..Default::default()
324 }
325 .normalize();
326 assert_eq!(7, preset.feedback_level);
327 assert_eq!(99, preset.lfo_delay);
328 assert_eq!(48, preset.transpose);
329 }
330}