beep_evdev/
lib.rs

1use evdev::{Device, EventType, InputEvent, SoundType};
2use std::thread::sleep;
3use std::time::Duration;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8pub const DEFAULT_DELAY: Duration = Duration::from_millis(100);
9pub const DEFAULT_FREQ: u16 = 440;
10pub const DEFAULT_LEN: Duration = Duration::from_millis(200);
11pub const DEFAULT_REPEATS: u16 = 1;
12const FILE: &str = "/dev/input/by-path/platform-pcspkr-event-spkr";
13
14/// A sequence of notes
15#[derive(Clone, Debug, Eq, PartialEq)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17pub struct Melody(Vec<Note>);
18
19impl Melody {
20    #[must_use]
21    pub fn new(notes: Vec<Note>) -> Self {
22        Self(notes)
23    }
24
25    /// Plays the melody
26    ///
27    /// # Examples
28    /// ```
29    /// use beep_evdev::Melody;
30    ///
31    /// let melody: Melody = vec![
32    ///     (659, 120).into(),
33    ///     (622, 120).into(),
34    ///     (659, 120).into(),
35    ///     (622, 120).into(),
36    ///     (659, 120).into(),
37    ///     (94, 120).into(),
38    ///     (587, 120).into(),
39    ///     (523, 120).into(),
40    ///     (440, 120).into(),
41    ///     (262, 120).into(),
42    ///     (330, 120).into(),
43    ///     (440, 120).into(),
44    ///     (494, 120).into(),
45    ///     (330, 120).into(),
46    ///     (415, 120).into(),
47    ///     (494, 120).into(),
48    ///     (523, 120).into(),
49    ///     (330, 120).into(),
50    ///     (659, 120).into(),
51    ///     (622, 120).into(),
52    ///     (659, 120).into(),
53    ///     (622, 120).into(),
54    ///     (659, 120).into(),
55    ///     (494, 120).into(),
56    ///     (587, 120).into(),
57    ///     (523, 120).into(),
58    ///     (440, 120).into(),
59    ///     (262, 120).into(),
60    ///     (330, 120).into(),
61    ///     (440, 120).into(),
62    ///     (494, 120).into(),
63    ///     (330, 120).into(),
64    ///     (523, 120).into(),
65    ///     (494, 120).into(),
66    ///     (440, 120).into(),
67    /// ]
68    /// .into();
69    /// melody.play().expect("could not play melody :-(");
70    /// ```
71    ///
72    /// # Errors
73    /// Returns an [`std::io::Error`] on I/O errors
74    pub fn play(&self) -> Result<(), std::io::Error> {
75        for note in &self.0 {
76            note.play()?;
77        }
78
79        Ok(())
80    }
81}
82
83impl Default for Melody {
84    fn default() -> Self {
85        Self::new(vec![Note::default()])
86    }
87}
88
89impl From<Vec<Note>> for Melody {
90    fn from(notes: Vec<Note>) -> Self {
91        Self::new(notes)
92    }
93}
94
95impl From<&[Note]> for Melody {
96    fn from(notes: &[Note]) -> Self {
97        Self::new(Vec::from(notes))
98    }
99}
100
101/// A note of a certain frequency and duration
102/// that may be repeated with a delay
103#[derive(Clone, Debug, Eq, PartialEq)]
104#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
105pub struct Note {
106    frequency: u16,
107    length: Duration,
108    repeats: u16,
109    delay: Duration,
110}
111
112impl Note {
113    /// Creates a new note
114    /// # Attributes
115    /// * frequency - The frequency in Hertz
116    /// * length -  The length of the note
117    /// * repeats - The amount of repeats
118    /// * delay - The delay before each repeat
119    #[must_use]
120    pub const fn new(frequency: u16, length: Duration, repeats: u16, delay: Duration) -> Self {
121        Self {
122            frequency,
123            length,
124            repeats,
125            delay,
126        }
127    }
128
129    /// Plays the note
130    ///
131    /// # Examples
132    /// ```
133    /// use beep_evdev::Note;
134    ///
135    /// Note::default().play().expect("could not play melody :-(");
136    /// ```
137    ///
138    /// # Errors
139    /// Returns an [`std::io::Error`] on I/O errors
140    pub fn play(&self) -> Result<(), std::io::Error> {
141        if self.repeats > 0 {
142            beep(self.frequency)?;
143            sleep(self.length);
144            beep(0)?;
145        }
146
147        for _ in 1..self.repeats {
148            sleep(self.delay);
149            beep(self.frequency)?;
150            sleep(self.length);
151            beep(0)?;
152        }
153
154        Ok(())
155    }
156}
157
158impl Default for Note {
159    fn default() -> Self {
160        Self::new(DEFAULT_FREQ, DEFAULT_LEN, DEFAULT_REPEATS, DEFAULT_DELAY)
161    }
162}
163
164impl From<(u16, u64)> for Note {
165    /// Creates a note from a `(frequency, length)` tuple with default repeats and delay
166    fn from((frequency, length): (u16, u64)) -> Self {
167        Self::from((frequency, Duration::from_millis(length)))
168    }
169}
170
171impl From<(u16, Duration)> for Note {
172    /// Creates a note from a `(frequency, length)` tuple with default repeats and delay
173    fn from((frequency, length): (u16, Duration)) -> Self {
174        Self::new(frequency, length, DEFAULT_REPEATS, DEFAULT_DELAY)
175    }
176}
177
178/// Beeps the PC speaker at the given frequency
179///
180/// # Examples
181/// ```
182/// use beep_evdev::beep;
183/// use std::{thread, time};
184///
185/// beep(440).expect("could not beep");
186/// thread::sleep(time::Duration::from_millis(500));
187/// beep(880).expect("could not beep");
188/// thread::sleep(time::Duration::from_millis(500));
189/// beep(0).expect("could not beep");
190/// ```
191///
192/// # Errors
193/// Returns [`std::io::Error`] on I/O errors
194pub fn beep(hertz: u16) -> std::io::Result<()> {
195    Device::open(FILE)?.send_events(&[InputEvent::new(
196        EventType::SOUND,
197        SoundType::SND_TONE.0,
198        i32::from(hertz),
199    )])
200}