1use core::ptr::write_volatile;
2
3const PSG_BASE: *mut u8 = 0xc00011 as _;
4const NUM_CHANNELS: u8 = 4;
5
6#[repr(u8)]
8#[derive(Clone, Copy, Debug)]
9pub enum NoiseFrequency {
10    High = 0,
11    Mid = 1,
12    Low = 2,
13    Channel2 = 3,
14}
15
16#[repr(u16)]
18#[derive(Clone, Copy, Debug)]
19pub enum Note {
20    C3 = 851,
21    CSharp3 = 803,
22    D3 = 758,
23    DSharp3 = 715,
24    E3 = 675,
25    F3 = 637,
26    FSharp3 = 601,
27    G3 = 568,
28    GSharp3 = 536,
29    A3 = 506,
30    ASharp3 = 477,
31    B3 = 450,
32}
33
34impl Note {
35    pub fn increase_octave(self, o: usize) -> u16 {
38        (self as u16) >> o
39    }
40}
41
42impl From<Note> for u16 {
43    fn from(n: Note) -> Self {
44        n as u16
45    }
46}
47
48pub struct PSG;
53
54impl PSG {
55    pub fn new() -> PSG {
60        let psg = PSG;
61
62        for c in 0..NUM_CHANNELS {
63            psg.set_volume(c, 0);
64        }
65
66        psg
67    }
68
69    fn write(&self, v: u8) {
70        unsafe { write_volatile(PSG_BASE, v) };
71    }
72
73    pub fn set_volume(&self, channel: u8, volume: u8) {
75        self.write(0x90 | ((channel & 3) << 5) | (0x1f - (volume & 0x1f)));
76    }
77
78    pub fn set_pitch(&self, channel: u8, frequency: impl Into<u16>) {
82        let frequency = frequency.into();
83        self.write(0x80 | ((channel & 3) << 5) | ((frequency as u8) & 0xf));
84        self.write((frequency >> 4) as u8);
85    }
86
87    pub fn set_noise(&self, white: bool, frequency: NoiseFrequency) {
89        let white = if white { 4 } else { 0 };
90        self.write(0xe0 | white | (frequency as u8));
91    }
92}