note_pen/
key.rs

1use crate::note::Note;
2use crate::prelude::Pitch;
3use crate::{Accidental, Alphabet, KeySignature};
4
5#[derive(Clone, Debug)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub enum Key {
8    Chromatic,
9    Diatonic { signature: KeySignature, root: Note },
10}
11
12impl Key {
13    pub fn new_chromatic() -> Self {
14        Self::Chromatic
15    }
16
17    pub fn new_diatonic(signature: KeySignature, root: Note) -> Self {
18        Self::Diatonic { signature, root }
19    }
20
21    pub fn new_major(root: Note) -> Option<Self> {
22        match root {
23            Note {
24                alphabet: Alphabet::C,
25                accidental: Accidental::Natural,
26                octave: _,
27            } => Some(Self::new_diatonic(KeySignature::new_sharp(0), root)),
28            // sharps
29            Note {
30                alphabet: Alphabet::G,
31                accidental: Accidental::Natural,
32                octave: _,
33            } => Some(Self::new_diatonic(KeySignature::new_sharp(1), root)),
34            Note {
35                alphabet: Alphabet::D,
36                accidental: Accidental::Natural,
37                octave: _,
38            } => Some(Self::new_diatonic(KeySignature::new_sharp(2), root)),
39            Note {
40                alphabet: Alphabet::A,
41                accidental: Accidental::Natural,
42                octave: _,
43            } => Some(Self::new_diatonic(KeySignature::new_sharp(3), root)),
44            Note {
45                alphabet: Alphabet::E,
46                accidental: Accidental::Natural,
47                octave: _,
48            } => Some(Self::new_diatonic(KeySignature::new_sharp(4), root)),
49            Note {
50                alphabet: Alphabet::B,
51                accidental: Accidental::Natural,
52                octave: _,
53            } => Some(Self::new_diatonic(KeySignature::new_sharp(5), root)),
54            Note {
55                alphabet: Alphabet::F,
56                accidental: Accidental::Sharp,
57                octave: _,
58            } => Some(Self::new_diatonic(KeySignature::new_sharp(6), root)),
59            Note {
60                alphabet: Alphabet::C,
61                accidental: Accidental::Sharp,
62                octave: _,
63            } => Some(Self::new_diatonic(KeySignature::new_sharp(7), root)),
64            // flats
65            Note {
66                alphabet: Alphabet::F,
67                accidental: Accidental::Natural,
68                octave: _,
69            } => Some(Self::new_diatonic(KeySignature::new_flat(1), root)),
70            Note {
71                alphabet: Alphabet::B,
72                accidental: Accidental::Flat,
73                octave: _,
74            } => Some(Self::new_diatonic(KeySignature::new_flat(2), root)),
75            Note {
76                alphabet: Alphabet::E,
77                accidental: Accidental::Flat,
78                octave: _,
79            } => Some(Self::new_diatonic(KeySignature::new_flat(3), root)),
80            Note {
81                alphabet: Alphabet::A,
82                accidental: Accidental::Flat,
83                octave: _,
84            } => Some(Self::new_diatonic(KeySignature::new_flat(4), root)),
85            Note {
86                alphabet: Alphabet::D,
87                accidental: Accidental::Flat,
88                octave: _,
89            } => Some(Self::new_diatonic(KeySignature::new_flat(5), root)),
90            Note {
91                alphabet: Alphabet::G,
92                accidental: Accidental::Flat,
93                octave: _,
94            } => Some(Self::new_diatonic(KeySignature::new_flat(6), root)),
95            Note {
96                alphabet: Alphabet::C,
97                accidental: Accidental::Flat,
98                octave: _,
99            } => Some(Self::new_diatonic(KeySignature::new_flat(7), root)),
100            _ => None,
101        }
102    }
103
104    pub fn new_minor(root: Note) -> Option<Self> {
105        match root {
106            Note {
107                alphabet: Alphabet::A,
108                accidental: Accidental::Natural,
109                octave: _,
110            } => Some(Self::new_diatonic(KeySignature::new_sharp(0), root)),
111            // sharps
112            Note {
113                alphabet: Alphabet::E,
114                accidental: Accidental::Natural,
115                octave: _,
116            } => Some(Self::new_diatonic(KeySignature::new_sharp(1), root)),
117            Note {
118                alphabet: Alphabet::B,
119                accidental: Accidental::Natural,
120                octave: _,
121            } => Some(Self::new_diatonic(KeySignature::new_sharp(2), root)),
122            Note {
123                alphabet: Alphabet::F,
124                accidental: Accidental::Sharp,
125                octave: _,
126            } => Some(Self::new_diatonic(KeySignature::new_sharp(3), root)),
127            Note {
128                alphabet: Alphabet::C,
129                accidental: Accidental::Sharp,
130                octave: _,
131            } => Some(Self::new_diatonic(KeySignature::new_sharp(4), root)),
132            Note {
133                alphabet: Alphabet::G,
134                accidental: Accidental::Sharp,
135                octave: _,
136            } => Some(Self::new_diatonic(KeySignature::new_sharp(5), root)),
137            Note {
138                alphabet: Alphabet::D,
139                accidental: Accidental::Sharp,
140                octave: _,
141            } => Some(Self::new_diatonic(KeySignature::new_sharp(6), root)),
142            Note {
143                alphabet: Alphabet::A,
144                accidental: Accidental::Sharp,
145                octave: _,
146            } => Some(Self::new_diatonic(KeySignature::new_sharp(7), root)),
147            // flats
148            Note {
149                alphabet: Alphabet::D,
150                accidental: Accidental::Natural,
151                octave: _,
152            } => Some(Self::new_diatonic(KeySignature::new_flat(1), root)),
153            Note {
154                alphabet: Alphabet::G,
155                accidental: Accidental::Flat,
156                octave: _,
157            } => Some(Self::new_diatonic(KeySignature::new_flat(2), root)),
158            Note {
159                alphabet: Alphabet::C,
160                accidental: Accidental::Flat,
161                octave: _,
162            } => Some(Self::new_diatonic(KeySignature::new_flat(3), root)),
163            Note {
164                alphabet: Alphabet::F,
165                accidental: Accidental::Flat,
166                octave: _,
167            } => Some(Self::new_diatonic(KeySignature::new_flat(4), root)),
168            Note {
169                alphabet: Alphabet::B,
170                accidental: Accidental::Flat,
171                octave: _,
172            } => Some(Self::new_diatonic(KeySignature::new_flat(5), root)),
173            Note {
174                alphabet: Alphabet::E,
175                accidental: Accidental::Flat,
176                octave: _,
177            } => Some(Self::new_diatonic(KeySignature::new_flat(6), root)),
178            Note {
179                alphabet: Alphabet::A,
180                accidental: Accidental::Flat,
181                octave: _,
182            } => Some(Self::new_diatonic(KeySignature::new_flat(7), root)),
183            _ => None,
184        }
185    }
186}
187
188#[derive(Clone, Debug)]
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190pub struct Scale {
191    pub notes: Vec<Note>,
192}
193
194impl From<&Key> for Scale {
195    fn from(key: &Key) -> Self {
196        match key {
197            Key::Chromatic => {
198                let notes = (0..12).map(|i| Note::from_id(Pitch(i))).collect();
199                Self { notes }
200            }
201            Key::Diatonic { signature, root } => {
202                let root_alphabet = root.alphabet;
203                let mut current_alphabet = root_alphabet;
204                let mut notes: Vec<Note> = vec![];
205                for i in 0..7 {
206                    let octave = if i == 0 {
207                        root.octave
208                    } else if current_alphabet == Alphabet::A {
209                        notes[i - 1].octave + 1
210                    } else {
211                        notes[i - 1].octave
212                    };
213                    let note = Note::new(
214                        current_alphabet,
215                        match signature.notes.contains(&current_alphabet) {
216                            true => signature.accidental,
217                            false => Accidental::Natural,
218                        },
219                        octave,
220                    );
221                    notes.push(note);
222                    current_alphabet = current_alphabet.next();
223                }
224                debug_assert!(notes.contains(&root));
225                Self { notes }
226            }
227        }
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    #[test]
234    fn test_major() {
235        let key = super::Key::new_major(crate::Note::new(
236            crate::Alphabet::C,
237            crate::Accidental::Natural,
238            4,
239        ))
240        .unwrap();
241        let scale = super::Scale::from(&key);
242        assert_eq!(scale.notes.len(), 7);
243        assert_eq!(
244            scale.notes[0],
245            crate::Note::new(crate::Alphabet::C, crate::Accidental::Natural, 4)
246        );
247        assert_eq!(
248            scale.notes[1],
249            crate::Note::new(crate::Alphabet::D, crate::Accidental::Natural, 4)
250        );
251        assert_eq!(
252            scale.notes[2],
253            crate::Note::new(crate::Alphabet::E, crate::Accidental::Natural, 4)
254        );
255        assert_eq!(
256            scale.notes[3],
257            crate::Note::new(crate::Alphabet::F, crate::Accidental::Natural, 4)
258        );
259        assert_eq!(
260            scale.notes[4],
261            crate::Note::new(crate::Alphabet::G, crate::Accidental::Natural, 4)
262        );
263        assert_eq!(
264            scale.notes[5],
265            crate::Note::new(crate::Alphabet::A, crate::Accidental::Natural, 5)
266        );
267        assert_eq!(
268            scale.notes[6],
269            crate::Note::new(crate::Alphabet::B, crate::Accidental::Natural, 5)
270        );
271        let key = super::Key::new_major(crate::Note::new(
272            crate::Alphabet::G,
273            crate::Accidental::Natural,
274            4,
275        ))
276        .unwrap();
277        let scale = super::Scale::from(&key);
278        assert_eq!(scale.notes.len(), 7);
279        assert_eq!(
280            scale.notes[0],
281            crate::Note::new(crate::Alphabet::G, crate::Accidental::Natural, 4)
282        );
283        assert_eq!(
284            scale.notes[1],
285            crate::Note::new(crate::Alphabet::A, crate::Accidental::Natural, 5)
286        );
287        assert_eq!(
288            scale.notes[2],
289            crate::Note::new(crate::Alphabet::B, crate::Accidental::Natural, 5)
290        );
291        assert_eq!(
292            scale.notes[3],
293            crate::Note::new(crate::Alphabet::C, crate::Accidental::Natural, 5)
294        );
295        assert_eq!(
296            scale.notes[4],
297            crate::Note::new(crate::Alphabet::D, crate::Accidental::Natural, 5)
298        );
299        assert_eq!(
300            scale.notes[5],
301            crate::Note::new(crate::Alphabet::E, crate::Accidental::Natural, 5)
302        );
303        assert_eq!(
304            scale.notes[6],
305            crate::Note::new(crate::Alphabet::F, crate::Accidental::Sharp, 5)
306        );
307        let key = super::Key::new_major(crate::Note::new(
308            crate::Alphabet::F,
309            crate::Accidental::Sharp,
310            4,
311        ))
312        .unwrap();
313        let scale = super::Scale::from(&key);
314        assert_eq!(scale.notes.len(), 7);
315        assert_eq!(
316            scale.notes[0],
317            crate::Note::new(crate::Alphabet::F, crate::Accidental::Sharp, 4)
318        );
319        assert_eq!(
320            scale.notes[1],
321            crate::Note::new(crate::Alphabet::G, crate::Accidental::Sharp, 4)
322        );
323        assert_eq!(
324            scale.notes[2],
325            crate::Note::new(crate::Alphabet::A, crate::Accidental::Sharp, 5)
326        );
327        assert_eq!(
328            scale.notes[3],
329            crate::Note::new(crate::Alphabet::B, crate::Accidental::Natural, 5)
330        );
331        assert_eq!(
332            scale.notes[4],
333            crate::Note::new(crate::Alphabet::C, crate::Accidental::Sharp, 5)
334        );
335        assert_eq!(
336            scale.notes[5],
337            crate::Note::new(crate::Alphabet::D, crate::Accidental::Sharp, 5)
338        );
339        assert_eq!(
340            scale.notes[6],
341            crate::Note::new(crate::Alphabet::E, crate::Accidental::Sharp, 5)
342        );
343    }
344
345    #[test]
346    fn test_minor() {
347        let key = super::Key::new_minor(crate::Note::new(
348            crate::Alphabet::A,
349            crate::Accidental::Natural,
350            4,
351        ))
352        .unwrap();
353        let scale = super::Scale::from(&key);
354        assert_eq!(scale.notes.len(), 7);
355        assert_eq!(
356            scale.notes[0],
357            crate::Note::new(crate::Alphabet::A, crate::Accidental::Natural, 4)
358        );
359        assert_eq!(
360            scale.notes[1],
361            crate::Note::new(crate::Alphabet::B, crate::Accidental::Natural, 4)
362        );
363        assert_eq!(
364            scale.notes[2],
365            crate::Note::new(crate::Alphabet::C, crate::Accidental::Natural, 4)
366        );
367        assert_eq!(
368            scale.notes[3],
369            crate::Note::new(crate::Alphabet::D, crate::Accidental::Natural, 4)
370        );
371        assert_eq!(
372            scale.notes[4],
373            crate::Note::new(crate::Alphabet::E, crate::Accidental::Natural, 4)
374        );
375        assert_eq!(
376            scale.notes[5],
377            crate::Note::new(crate::Alphabet::F, crate::Accidental::Natural, 4)
378        );
379        assert_eq!(
380            scale.notes[6],
381            crate::Note::new(crate::Alphabet::G, crate::Accidental::Natural, 4)
382        );
383        let key = super::Key::new_minor(crate::Note::new(
384            crate::Alphabet::E,
385            crate::Accidental::Natural,
386            4,
387        ))
388        .unwrap();
389        let scale = super::Scale::from(&key);
390        assert_eq!(scale.notes.len(), 7);
391        assert_eq!(
392            scale.notes[0],
393            crate::Note::new(crate::Alphabet::E, crate::Accidental::Natural, 4)
394        );
395        assert_eq!(
396            scale.notes[1],
397            crate::Note::new(crate::Alphabet::F, crate::Accidental::Sharp, 4)
398        );
399        assert_eq!(
400            scale.notes[2],
401            crate::Note::new(crate::Alphabet::G, crate::Accidental::Natural, 4)
402        );
403        assert_eq!(
404            scale.notes[3],
405            crate::Note::new(crate::Alphabet::A, crate::Accidental::Natural, 5)
406        );
407        assert_eq!(
408            scale.notes[4],
409            crate::Note::new(crate::Alphabet::B, crate::Accidental::Natural, 5)
410        );
411        assert_eq!(
412            scale.notes[5],
413            crate::Note::new(crate::Alphabet::C, crate::Accidental::Natural, 5)
414        );
415        assert_eq!(
416            scale.notes[6],
417            crate::Note::new(crate::Alphabet::D, crate::Accidental::Natural, 5)
418        );
419    }
420
421    #[test]
422    fn test_flat() {
423        let key = super::Key::new_major(crate::Note::new(
424            crate::Alphabet::F,
425            crate::Accidental::Natural,
426            4,
427        ))
428        .unwrap();
429        let scale = super::Scale::from(&key);
430        assert_eq!(scale.notes.len(), 7);
431        assert_eq!(
432            scale.notes[0],
433            crate::Note::new(crate::Alphabet::F, crate::Accidental::Natural, 4)
434        );
435        assert_eq!(
436            scale.notes[1],
437            crate::Note::new(crate::Alphabet::G, crate::Accidental::Natural, 4)
438        );
439        assert_eq!(
440            scale.notes[2],
441            crate::Note::new(crate::Alphabet::A, crate::Accidental::Natural, 5)
442        );
443        assert_eq!(
444            scale.notes[3],
445            crate::Note::new(crate::Alphabet::B, crate::Accidental::Flat, 5)
446        );
447        assert_eq!(
448            scale.notes[4],
449            crate::Note::new(crate::Alphabet::C, crate::Accidental::Natural, 5)
450        );
451        assert_eq!(
452            scale.notes[5],
453            crate::Note::new(crate::Alphabet::D, crate::Accidental::Natural, 5)
454        );
455        assert_eq!(
456            scale.notes[6],
457            crate::Note::new(crate::Alphabet::E, crate::Accidental::Natural, 5)
458        );
459    }
460}