1use crate::errors::Error;
2
3#[derive(Debug, Clone, Copy)]
5pub enum Envelope {
6 Builtin(BuiltinEnvelopeShape),
7 InvertedBuiltin(BuiltinEnvelopeShape),
8 CustomBuiltin(u8),
9 RawEnvelope(RawEnvelope),
10}
11
12impl From<&Envelope> for u8 {
13 fn from(value: &Envelope) -> Self {
14 use Envelope::{Builtin, CustomBuiltin, InvertedBuiltin, RawEnvelope};
15
16 match value {
17 Builtin(builtin) => *builtin as u8,
18 InvertedBuiltin(builtin) => (*builtin as u8) ^ (0b00000100),
19 CustomBuiltin(n) => *n,
20
21 #[allow(unused)]
22 RawEnvelope(raw) => unimplemented!(),
23 }
24 }
25}
26
27#[derive(Debug, Clone, Copy)]
31#[repr(u8)]
32pub enum BuiltinEnvelopeShape {
33 FadeOut = 0b00001001,
35 FadeIn = 0b00001101,
37 Tooth = 0b00001111,
39 Saw = 0b00001100,
41 Triangle = 0b00001110,
43}
44
45#[allow(unused)]
50#[derive(Debug, Clone, Copy)]
51pub struct RawEnvelope {
52 data: [u8; 4096],
53 length_beats: u8,
54}
55
56#[allow(unused)]
57impl RawEnvelope {
58 fn invert(&mut self) {
59 for i in 0..4096 {
60 self.data[i] = 0xF - self.data[i];
61 }
62 }
63
64 fn scale(&mut self, scale: f32) {
65 for i in 0..4096 {
66 let scaled = (self.data[i] as f32 * scale).clamp(0.0, 255.0) as u8;
67 self.data[i] = scaled;
68 }
69 }
70
71 fn offset(&mut self, offset: i8) {
72 for i in 0..4096 {
73 self.data[i] += offset as u8;
74 }
75 }
76}
77
78#[derive(Debug)]
80pub enum EnvelopeFrequency {
81 Hertz(u16),
82 BeatsPerMinute(u16),
83 Integer(u16),
84}
85
86impl EnvelopeFrequency {
87 pub fn as_ep(self, master_clock_frequency: u32) -> Result<u16, Error> {
89 match self {
90 Self::Hertz(f_e) => {
91 if f_e == 0 {
92 return Err(Error::DivisionByZero);
93 }
94 let period = master_clock_frequency / (256 * f_e as u32);
95 period.try_into().map_err(|_| Error::TonePeriodOutOfRange(period as u16))
96 }
97 Self::BeatsPerMinute(bpm) => {
98 let hz = Self::Hertz(bpm).as_ep(master_clock_frequency)?;
99 (60 * hz).try_into().map_err(|_| Error::TonePeriodOutOfRange(0))
100 }
101 Self::Integer(x) => Ok(x),
102 }
103 }
104}