pyxel/
tone.rs

1use crate::oscillator::Gain;
2use crate::settings::NUM_WAVEFORM_STEPS;
3
4pub type Amp4 = u8;
5pub type Waveform = [Amp4; NUM_WAVEFORM_STEPS as usize];
6
7#[derive(PartialEq, Copy, Clone)]
8pub enum Noise {
9    Off,
10    ShortPeriod,
11    LongPeriod,
12}
13
14impl Noise {
15    pub fn from_index(index: u32) -> Self {
16        match index {
17            1 => Self::ShortPeriod,
18            2 => Self::LongPeriod,
19            _ => Self::Off,
20        }
21    }
22
23    pub fn to_index(&self) -> u32 {
24        match self {
25            Self::Off => 0,
26            Self::ShortPeriod => 1,
27            Self::LongPeriod => 2,
28        }
29    }
30}
31
32pub struct Tone {
33    pub gain: Gain,
34    pub noise: Noise,
35    pub waveform: Waveform,
36}
37
38pub type SharedTone = shared_type!(Tone);
39
40impl Tone {
41    pub fn new() -> SharedTone {
42        new_shared_type!(Self {
43            gain: 1.0,
44            noise: Noise::Off,
45            waveform: [0; NUM_WAVEFORM_STEPS as usize],
46        })
47    }
48
49    pub fn amplitude(&self, phase: u32, noise_reg: &mut u16) -> f64 {
50        (match self.noise {
51            Noise::Off => self.waveform[phase as usize] as f64 / 7.5 - 1.0,
52            Noise::ShortPeriod | Noise::LongPeriod => {
53                if phase % 8 == 0 {
54                    let bit = if self.noise == Noise::LongPeriod {
55                        1
56                    } else {
57                        6
58                    };
59
60                    let feedback = (*noise_reg ^ (*noise_reg >> bit)) & 1;
61                    *noise_reg >>= 1;
62                    *noise_reg |= feedback << 14;
63                }
64
65                (*noise_reg & 1) as f64 * 2.0 - 1.0
66            }
67        }) * self.gain
68    }
69}