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 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 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 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 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(¤t_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}