pc_beeper/
lib.rs

1//! The most primitive audio device available on PC-compatible systems with characteristic "beeps" and "squeaks"
2//!
3//! ## Usage
4//! ```rust
5//! use pc_beeper::Speaker;
6//!
7//! let mut speaker = Speaker::new();
8//! speaker.beep(1000, 10);
9//! ```
10#![no_std]
11
12use x86_64::instructions::port::Port;
13
14/// Channel 2 data port (read/write)
15const CHANNEL_TWO_DATA_PORT: u16 = 0x42;
16
17/// Mode/Command register (write only, a read is ignored)
18const COMMAND_REGISTER: u16 = 0x43;
19
20/// PC Speaker positions
21const SPEAKER_POSITIONS: u16 = 0x61;
22
23/// Struct for storage ports
24pub struct Speaker {
25    channel_2_data_port: Port<u8>,
26    command_register: Port<u8>,
27    speaker_positions: Port<u8>,
28}
29
30impl Speaker {
31    /// Creates a new `Speaker`.
32    pub const fn new() -> Speaker {
33        Speaker {
34            channel_2_data_port: Port::new(CHANNEL_TWO_DATA_PORT),
35            command_register: Port::new(COMMAND_REGISTER),
36            speaker_positions: Port::new(SPEAKER_POSITIONS),
37        }
38    }
39
40    /// Play sound using built in speaker
41    fn play_sound(&mut self, n_frequency: u32) {
42        let div = 1193180 / n_frequency;
43
44        unsafe {
45            self.command_register.write(0xb6);
46            self.channel_2_data_port.write(div as u8);
47            self.channel_2_data_port.write((div >> 8) as u8);
48        }
49
50        let tmp = unsafe { self.speaker_positions.read() };
51
52        if tmp != (tmp | 3) {
53            unsafe { self.speaker_positions.write(tmp | 3) };
54        }
55    }
56
57    /// Make it shutup
58    fn nosound(&mut self) {
59        let tmp = unsafe { self.speaker_positions.read() };
60
61        unsafe { self.speaker_positions.write(tmp & 0xFC) };
62    }
63
64    fn timer_wait(&mut self, n: u32) {
65        for _i in 0..10_000 * n {}
66    }
67
68    /// Make a beep
69    pub fn beep(&mut self, frequency: u32, duration: u32) {
70        self.play_sound(frequency);
71        self.timer_wait(duration);
72        self.nosound();
73    }
74}