1use std::fmt::Display;
2
3use serde::{Deserialize, Serialize};
4
5use crate::prelude::Semitones;
6
7#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
9pub enum Octave {
10 N1,
11 P0,
12 P1,
13 P2,
14 P3,
15 P4,
16 P5,
17 P6,
18 P7,
19 P8,
20 P9,
21 P10,
22}
23
24impl Octave {
25 pub const CENTER: Self = Self::P4;
26
27 pub fn is_even(&self) -> bool {
28 match self {
29 Octave::P0 |
30 Octave::P2 |
31 Octave::P4 |
32 Octave::P6 |
33 Octave::P8 |
34 Octave::P10 => true,
35 _ => false,
36 }
37 }
38}
39
40impl Default for Octave {
41 fn default() -> Self {
42 Self::CENTER
43 }
44}
45
46impl Display for Octave {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(f, "{}", match self {
49 Octave::N1 => "N1",
50 Octave::P0 => "P0",
51 Octave::P1 => "P1",
52 Octave::P2 => "P2",
53 Octave::P3 => "P3",
54 Octave::P4 => "P4",
55 Octave::P5 => "P5",
56 Octave::P6 => "P6",
57 Octave::P7 => "P7",
58 Octave::P8 => "P8",
59 Octave::P9 => "P9",
60 Octave::P10 => "P10",
61 })
62 }
63}
64
65impl Octave {
66 pub fn to_ident(&self) -> String {
67 format!("{}", self)
68 }
69 pub fn from_ident(ident: &str) -> Self {
70 match ident {
71 "P0" => Self::P0,
72 "P1" => Self::P1,
73 "P2" => Self::P2,
74 "P3" => Self::P3,
75 "P4" => Self::P4,
76 "P5" => Self::P5,
77 "P6" => Self::P6,
78 "P7" => Self::P7,
79 "P8" => Self::P8,
80 "P9" => Self::P9,
81 "P10" => Self::P10,
82 _ => Self::N1,
83 }
84 }
85 pub fn get_higher(&self) -> Self {
86 (Semitones::from(*self) + Semitones(12)).into()
87 }
88 pub fn get_lower(&self) -> Self {
89 (Semitones::from(*self) - Semitones(12)).into()
90 }
91}
92
93impl From<Octave> for Semitones {
94 fn from(v: Octave) -> Self {
95 let v = match v {
96 Octave::N1 => -12,
97 Octave::P0 => 0,
98 Octave::P1 => 12,
99 Octave::P2 => 12 * 2,
100 Octave::P3 => 12 * 3,
101 Octave::P4 => 12 * 4,
102 Octave::P5 => 12 * 5,
103 Octave::P6 => 12 * 6,
104 Octave::P7 => 12 * 7,
105 Octave::P8 => 12 * 8,
106 Octave::P9 => 12 * 9,
107 Octave::P10 => 12 * 10,
108 };
109 Self::from(v)
110 }
111}
112
113impl From<Semitones> for Octave {
114 fn from(v: Semitones) -> Self {
115 if v.0 < 0 {
116 return Octave::N1;
117 }
118 match v.0 / 12 {
119 0 => Octave::P0,
120 1 => Octave::P1,
121 2 => Octave::P2,
122 3 => Octave::P3,
123 4 => Octave::P4,
124 5 => Octave::P5,
125 6 => Octave::P6,
126 7 => Octave::P7,
127 8 => Octave::P8,
128 9 => Octave::P9,
129 _ => Octave::P10,
130 }
131 }
132}