music_note/note/
accidental.rs1use crate::{Interval, Natural, Pitch};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum AccidentalKind {
5 Natural,
6 Single,
7 Double,
8}
9
10pub trait Accidental {
11 fn into_pitch(kind: AccidentalKind, natural: Natural) -> Pitch;
12
13 fn from_pitch(natural: Natural, pitch: Pitch) -> AccidentalKind;
14}
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum Sharp {}
18
19impl Accidental for Sharp {
20 fn into_pitch(kind: AccidentalKind, natural: Natural) -> Pitch {
21 let pitch = Pitch::natural(natural);
22 match kind {
23 AccidentalKind::Natural => pitch,
24 AccidentalKind::Single => pitch + Interval::MINOR_SECOND,
25 AccidentalKind::Double => pitch + Interval::MAJOR_SECOND,
26 }
27 }
28
29 fn from_pitch(natural: Natural, pitch: Pitch) -> AccidentalKind {
30 let natural_pitch = Pitch::natural(natural);
31 if pitch >= natural_pitch {
32 match pitch.sub(natural_pitch) {
33 Interval::UNISON => AccidentalKind::Natural,
34 Interval::MINOR_SECOND => AccidentalKind::Single,
35 Interval::MAJOR_SECOND => AccidentalKind::Double,
36 _ => unimplemented!(),
37 }
38 } else {
39 match natural_pitch.sub(pitch) {
40 Interval::MAJOR_SEVENTH => AccidentalKind::Single,
41 _ => unimplemented!(),
42 }
43 }
44 }
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum Flat {}
49
50impl Accidental for Flat {
51 fn into_pitch(kind: AccidentalKind, natural: Natural) -> Pitch {
52 let pitch = Pitch::natural(natural);
53 match kind {
54 AccidentalKind::Natural => pitch,
55 AccidentalKind::Single => pitch - Interval::MINOR_SECOND,
56 AccidentalKind::Double => pitch - Interval::MAJOR_SECOND,
57 }
58 }
59
60 fn from_pitch(natural: Natural, pitch: Pitch) -> AccidentalKind {
61 let natural_pitch = Pitch::natural(natural);
62 if pitch >= natural_pitch {
63 match pitch.sub(natural_pitch) {
64 Interval::UNISON => AccidentalKind::Natural,
65 Interval::MINOR_SECOND => AccidentalKind::Single,
66 Interval::MAJOR_SEVENTH => AccidentalKind::Single,
67 x => panic!("{:?}", x),
68 }
69 } else {
70 match natural_pitch.sub(pitch) {
71 Interval::MINOR_SECOND => AccidentalKind::Single,
72 Interval::MAJOR_SECOND => AccidentalKind::Double,
73 x => panic!("{:?}", x),
74 }
75 }
76 }
77}