Skip to main content

mlua_pulse/
midi.rs

1use crate::error::{PulseError, PulseResult};
2
3/// Converts a frequency in Hz to a MIDI note number.
4pub fn frequency_to_midi_note(frequency: f32) -> PulseResult<u8> {
5    if !frequency.is_finite() || frequency <= 0.0 {
6        return Err(PulseError::InvalidFrequency { frequency });
7    }
8
9    Ok(tunes::midi::frequency_to_midi_note(frequency))
10}
11
12/// Converts a MIDI note number to a frequency in Hz.
13pub fn midi_note_to_frequency(note: i64) -> PulseResult<f32> {
14    if !(0..=127).contains(&note) {
15        return Err(PulseError::InvalidMidiNote { note });
16    }
17
18    let note = u8::try_from(note).map_err(|_| PulseError::InvalidMidiNote { note })?;
19    Ok(tunes::midi::midi_note_to_frequency(note))
20}
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25
26    #[test]
27    fn converts_between_frequency_and_midi_notes() {
28        assert_eq!(frequency_to_midi_note(440.0).unwrap(), 69);
29        assert!((midi_note_to_frequency(69).unwrap() - 440.0).abs() < 0.01);
30    }
31
32    #[test]
33    fn rejects_invalid_midi_inputs() {
34        assert_eq!(
35            midi_note_to_frequency(200).unwrap_err().to_string(),
36            "invalid midi note: 200"
37        );
38        assert_eq!(
39            frequency_to_midi_note(f32::NAN).unwrap_err().to_string(),
40            "invalid frequency: NaN"
41        );
42        assert_eq!(
43            frequency_to_midi_note(0.0).unwrap_err().to_string(),
44            "invalid frequency: 0"
45        );
46        assert_eq!(
47            frequency_to_midi_note(-440.0).unwrap_err().to_string(),
48            "invalid frequency: -440"
49        );
50    }
51}