1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::fmt;
use std::str::FromStr;
use crate::{Semitones, StaffSteps};
#[derive(Debug)]
pub struct ParseIntervalError {
name: String,
}
impl fmt::Display for ParseIntervalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Could not parse interval name \"{}\"", self.name)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Interval {
PerfectUnison,
MajorSecond,
MinorThird,
MajorThird,
PerfectFourth,
DiminishedFifth,
PerfectFifth,
AugmentedFifth,
MajorSixth,
DiminishedSeventh,
MinorSeventh,
MajorSeventh,
MinorNinth,
MajorNinth,
AugmentedNinth,
PerfectEleventh,
MajorThirteenth,
}
impl Interval {
pub fn to_semitones(self) -> Semitones {
use Interval::*;
match self {
PerfectUnison => 0,
MajorSecond => 2,
MinorThird => 3,
MajorThird => 4,
PerfectFourth => 5,
DiminishedFifth => 6,
PerfectFifth => 7,
AugmentedFifth => 8,
MajorSixth => 9,
DiminishedSeventh => 9,
MinorSeventh => 10,
MajorSeventh => 11,
MinorNinth => 13,
MajorNinth => 14,
AugmentedNinth => 15,
PerfectEleventh => 17,
MajorThirteenth => 21,
}
}
pub fn to_number(self) -> StaffSteps {
use Interval::*;
match self {
PerfectUnison => 1,
MajorSecond => 2,
MinorThird => 3,
MajorThird => 3,
PerfectFourth => 4,
DiminishedFifth => 5,
PerfectFifth => 5,
AugmentedFifth => 5,
MajorSixth => 6,
DiminishedSeventh => 7,
MinorSeventh => 7,
MajorSeventh => 7,
MinorNinth => 9,
MajorNinth => 9,
AugmentedNinth => 9,
PerfectEleventh => 11,
MajorThirteenth => 13,
}
}
}
impl FromStr for Interval {
type Err = ParseIntervalError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use Interval::*;
let name = s.to_string();
let interval = match s {
"P1" => PerfectUnison,
"M2" => MajorSecond,
"m3" => MinorThird,
"M3" => MajorThird,
"P4" => PerfectFourth,
"d5" => DiminishedFifth,
"P5" => PerfectFifth,
"A5" => AugmentedFifth,
"M6" => MajorSixth,
"d7" => DiminishedSeventh,
"m7" => MinorSeventh,
"M7" => MajorSeventh,
"m9" => MinorNinth,
"M9" => MajorNinth,
"A9" => AugmentedNinth,
"P11" => PerfectEleventh,
"M13" => MajorThirteenth,
_ => return Err(ParseIntervalError { name }),
};
Ok(interval)
}
}