redact_composer_musical/note/
note_name.rs

1use crate::{Key, Note, PitchClass, PitchClassCollection};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[cfg(feature = "redact-composer")]
7use redact_composer_core::derive::Element;
8
9/// Musical note name.
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[cfg_attr(feature = "redact-composer", derive(Element))]
13#[allow(missing_docs)]
14pub enum NoteName {
15    Abb,
16    Ab,
17    A,
18    As,
19    Ass,
20    Bbb,
21    Bb,
22    B,
23    Bs,
24    Bss,
25    Cbb,
26    Cb,
27    C,
28    Cs,
29    Css,
30    Dbb,
31    Db,
32    D,
33    Ds,
34    Dss,
35    Ebb,
36    Eb,
37    E,
38    Es,
39    Ess,
40    Fbb,
41    Fb,
42    F,
43    Fs,
44    Fss,
45    Gbb,
46    Gb,
47    G,
48    Gs,
49    Gss,
50}
51
52impl NoteName {
53    /// Returns this note name as a [`Note`] in a given octave.
54    /// ```
55    /// use redact_composer_musical::{Note, NoteName::C};
56    /// assert_eq!(C.in_octave(4), Note(60));
57    /// ```
58    pub fn in_octave(&self, octave: i8) -> Note {
59        (*self, octave).into()
60    }
61}
62
63impl From<NoteName> for u8 {
64    fn from(note: NoteName) -> Self {
65        use NoteName::*;
66        match note {
67            C | Bs | Dbb => 0,
68            Cs | Db | Bss => 1,
69            D | Css | Ebb => 2,
70            Ds | Eb | Fbb => 3,
71            E | Fb | Dss => 4,
72            F | Es | Gbb => 5,
73            Fs | Gb | Ess => 6,
74            G | Fss | Abb => 7,
75            Gs | Ab => 8,
76            A | Gss | Bbb => 9,
77            As | Bb | Cbb => 10,
78            B | Cb | Ass => 11,
79        }
80    }
81}
82
83impl PartialEq<PitchClass> for NoteName {
84    /// ```
85    /// use redact_composer_musical::{NoteName, PitchClass};
86    /// assert!(NoteName::C.eq(&PitchClass(0)));
87    /// ```
88    fn eq(&self, pitch_class: &PitchClass) -> bool {
89        PitchClass::from(*self) == *pitch_class
90    }
91}
92
93#[allow(dead_code)]
94impl NoteName {
95    /// Strips any accidental (for example, [`NoteName::Ab`] will return [`NoteName::A`]).
96    pub(crate) fn letter(&self) -> NoteName {
97        use NoteName::*;
98        match self {
99            Abb | Ab | A | As | Ass => A,
100            Bbb | Bb | B | Bs | Bss => B,
101            Cbb | Cb | C | Cs | Css => C,
102            Dbb | Db | D | Ds | Dss => D,
103            Ebb | Eb | E | Es | Ess => E,
104            Fbb | Fb | F | Fs | Fss => F,
105            Gbb | Gb | G | Gs | Gss => G,
106        }
107    }
108
109    pub(crate) fn next_letter(&self) -> NoteName {
110        use NoteName::*;
111        match self.letter() {
112            A => B,
113            B => C,
114            C => D,
115            D => E,
116            E => F,
117            F => G,
118            G => A,
119            _ => unreachable!(),
120        }
121    }
122
123    pub(crate) fn prev_letter(&self) -> NoteName {
124        use NoteName::*;
125        match self.letter() {
126            A => G,
127            B => A,
128            C => B,
129            D => C,
130            E => D,
131            F => E,
132            G => F,
133            _ => unreachable!(),
134        }
135    }
136
137    pub(crate) fn has_sharp(&self) -> bool {
138        use NoteName::*;
139        matches!(
140            self,
141            As | Bs | Cs | Ds | Es | Fs | Gs | Ass | Bss | Css | Dss | Ess | Fss | Gss
142        )
143    }
144
145    pub(crate) fn has_flat(&self) -> bool {
146        use NoteName::*;
147        matches!(
148            self,
149            Ab | Bb | Cb | Db | Eb | Fb | Gb | Abb | Bbb | Cbb | Dbb | Ebb | Fbb | Gbb
150        )
151    }
152
153    pub(crate) fn has_double_sharp(&self) -> bool {
154        use NoteName::*;
155        matches!(self, Ass | Bss | Css | Dss | Ess | Fss | Gss)
156    }
157
158    pub(crate) fn has_double_flat(&self) -> bool {
159        use NoteName::*;
160        matches!(self, Abb | Bbb | Cbb | Dbb | Ebb | Fbb | Gbb)
161    }
162
163    pub(crate) fn complexity(&self) -> u8 {
164        use NoteName::*;
165        match self {
166            A | B | C | D | E | F | G => 0,
167            As | Bs | Cs | Ds | Es | Fs | Gs => 1,
168            Ab | Bb | Cb | Db | Eb | Fb | Gb => 1,
169            Ass | Bss | Css | Dss | Ess | Fss | Gss => 2,
170            Abb | Bbb | Cbb | Dbb | Ebb | Fbb | Gbb => 2,
171        }
172    }
173}
174
175impl PitchClass {
176    /// Provides the note names matching this pitch class.
177    pub fn names(&self) -> Vec<NoteName> {
178        use NoteName::*;
179        match self.0 {
180            0 => vec![C, Bs, Dbb],
181            1 => vec![Cs, Db, Bss],
182            2 => vec![D, Css, Ebb],
183            3 => vec![Ds, Eb, Fbb],
184            4 => vec![E, Fb, Dss],
185            5 => vec![F, Es, Gbb],
186            6 => vec![Fs, Gb, Ess],
187            7 => vec![G, Fss, Abb],
188            8 => vec![Gs, Ab],
189            9 => vec![A, Gss, Bbb],
190            10 => vec![As, Bb, Cbb],
191            11 => vec![B, Cb, Ass],
192            _ => panic!(),
193        }
194    }
195
196    /// Returns this pitch class's name within the context of a [`Key`]. Pitch classes not in the
197    /// given key will return some variation of a name equating to the pitch class, but exactly
198    /// which is subject to change.
199    pub fn name_in_key(&self, key: &Key) -> NoteName {
200        let pitch_names = self.names();
201        let key_note_names = key.note_names();
202
203        let in_key_note = key_note_names
204            .iter()
205            .find(|n| &PitchClass::from(**n) == self);
206
207        if let Some(note) = in_key_note {
208            return *note;
209        }
210
211        let letter_matching_key_note = key_note_names
212            .iter()
213            .find(|n| &PitchClass::from(n.letter()) == self);
214
215        if let Some(key_note) = letter_matching_key_note {
216            return *key_note;
217        }
218
219        let naturalized_note = pitch_names.iter().find(|n| !n.has_sharp() && !n.has_flat());
220
221        if let Some(note) = naturalized_note {
222            return *note;
223        }
224
225        let key_sharps = key_note_names.iter().filter(|n| n.has_sharp()).count();
226        let key_flats = key_note_names.iter().filter(|n| n.has_flat()).count();
227
228        if key_sharps >= key_flats {
229            if let Some(note) = pitch_names.iter().find(|n| n.has_sharp()) {
230                *note
231            } else if let Some(note) = pitch_names.iter().find(|n| n.has_flat()) {
232                *note
233            } else {
234                pitch_names[0]
235            }
236        } else if let Some(note) = pitch_names.iter().find(|n| n.has_flat()) {
237            *note
238        } else if let Some(note) = pitch_names.iter().find(|n| n.has_sharp()) {
239            *note
240        } else {
241            pitch_names[0]
242        }
243    }
244}
245
246impl Key {
247    /// Returns the [`NoteName`] of the key's tonic pitch class.
248    pub fn root_name(&self) -> NoteName {
249        match self.name_pref {
250            Some(n) => Self::simplify_root(n),
251            None => self
252                .root
253                .names()
254                .into_iter()
255                .min_by_key(NoteName::complexity)
256                .expect("Key should be nameable for any NoteName"),
257        }
258    }
259
260    pub(crate) fn simplify_root(name: NoteName) -> NoteName {
261        if name.complexity() > 1 {
262            PitchClass::from(name)
263                .names()
264                .into_iter()
265                .min_by_key(NoteName::complexity)
266                .unwrap()
267        } else {
268            name
269        }
270    }
271
272    /// Returns the ordered list of [`NoteName`]'s associated with the key's pitch classes.
273    /// ```
274    /// use redact_composer_musical::{Key, NoteName::*, Scale::Major};
275    /// let key = Key::from((D, Major));
276    /// assert_eq!(key.note_names(), [D, E, Fs, G, A, B, Cs])
277    /// ```
278    pub fn note_names(&self) -> Vec<NoteName> {
279        let first = self.root_name();
280
281        let mut next_letter = first.next_letter();
282        let mut sharp_pref: Option<bool> = if first.has_sharp() || first.has_flat() {
283            Some(first.has_sharp())
284        } else {
285            None
286        };
287
288        let mut names = vec![first];
289        for pitch in self.pitch_classes().into_iter().skip(1) {
290            // First try finding a name that matches the sharp/flat preference
291            let name_options = pitch.names().into_iter().collect::<Vec<_>>();
292            let maybe_name = name_options
293                .iter()
294                .filter(|n| n.letter() == next_letter)
295                .filter(|n| {
296                    if let Some(pref_sharp) = sharp_pref {
297                        if pref_sharp {
298                            n.has_sharp()
299                        } else {
300                            n.has_flat()
301                        }
302                    } else {
303                        true
304                    }
305                })
306                .min_by_key(|n| n.complexity())
307                .copied();
308
309            let name = if let Some(name) = maybe_name {
310                name
311            } else {
312                // If no match found for the sharp/flat preference, remove the restriction
313                name_options
314                    .iter()
315                    .filter(|n| n.letter() == next_letter)
316                    .min_by_key(|n| n.complexity())
317                    .copied()
318                    .expect("Bug: Every Key note name should have a following note name.")
319            };
320
321            names.push(name);
322
323            if sharp_pref.is_none() && (name.has_sharp() || name.has_flat()) {
324                sharp_pref = Some(name.has_sharp());
325            }
326
327            next_letter = name.next_letter();
328        }
329
330        names
331    }
332}
333
334#[cfg(test)]
335mod test {
336    mod scale_note_names {
337        use crate::{Key, NoteName::*, Scale::*};
338
339        #[test]
340        fn ab_scales() {
341            assert_eq!(
342                Key::from((Ab, Major)).note_names(),
343                [Ab, Bb, C, Db, Eb, F, G]
344            );
345            assert_eq!(
346                Key::from((Ab, NaturalMinor)).note_names(),
347                [Ab, Bb, Cb, Db, Eb, Fb, Gb]
348            );
349            assert_eq!(
350                Key::from((Ab, MelodicMinor)).note_names(),
351                [Ab, Bb, Cb, Db, Eb, F, G]
352            );
353            assert_eq!(
354                Key::from((Ab, HarmonicMinor)).note_names(),
355                [Ab, Bb, Cb, Db, Eb, Fb, G]
356            );
357        }
358
359        #[test]
360        fn a_scales() {
361            assert_eq!(Key::from((A, Major)).note_names(), [A, B, Cs, D, E, Fs, Gs]);
362            assert_eq!(
363                Key::from((A, NaturalMinor)).note_names(),
364                [A, B, C, D, E, F, G]
365            );
366            assert_eq!(
367                Key::from((A, MelodicMinor)).note_names(),
368                [A, B, C, D, E, Fs, Gs]
369            );
370            assert_eq!(
371                Key::from((A, HarmonicMinor)).note_names(),
372                [A, B, C, D, E, F, Gs]
373            );
374        }
375
376        #[test]
377        fn as_scales() {
378            assert_eq!(
379                Key::from((As, Major)).note_names(),
380                [As, Bs, Css, Ds, Es, Fss, Gss]
381            );
382            assert_eq!(
383                Key::from((As, NaturalMinor)).note_names(),
384                [As, Bs, Cs, Ds, Es, Fs, Gs]
385            );
386            assert_eq!(
387                Key::from((As, MelodicMinor)).note_names(),
388                [As, Bs, Cs, Ds, Es, Fss, Gss]
389            );
390            assert_eq!(
391                Key::from((As, HarmonicMinor)).note_names(),
392                [As, Bs, Cs, Ds, Es, Fs, Gss]
393            );
394        }
395
396        #[test]
397        fn bb_scales() {
398            assert_eq!(Key::from((Bb, Major)).note_names(), [Bb, C, D, Eb, F, G, A]);
399            assert_eq!(
400                Key::from((Bb, NaturalMinor)).note_names(),
401                [Bb, C, Db, Eb, F, Gb, Ab]
402            );
403            assert_eq!(
404                Key::from((Bb, MelodicMinor)).note_names(),
405                [Bb, C, Db, Eb, F, G, A]
406            );
407            assert_eq!(
408                Key::from((Bb, HarmonicMinor)).note_names(),
409                [Bb, C, Db, Eb, F, Gb, A]
410            );
411        }
412
413        #[test]
414        fn b_scales() {
415            assert_eq!(
416                Key::from((B, Major)).note_names(),
417                [B, Cs, Ds, E, Fs, Gs, As]
418            );
419            assert_eq!(
420                Key::from((B, NaturalMinor)).note_names(),
421                [B, Cs, D, E, Fs, G, A]
422            );
423            assert_eq!(
424                Key::from((B, MelodicMinor)).note_names(),
425                [B, Cs, D, E, Fs, Gs, As]
426            );
427            assert_eq!(
428                Key::from((B, HarmonicMinor)).note_names(),
429                [B, Cs, D, E, Fs, G, As]
430            );
431        }
432
433        #[test]
434        fn bs_scales() {
435            assert_eq!(
436                Key::from((Bs, Major)).note_names(),
437                [Bs, Css, Dss, Es, Fss, Gss, Ass]
438            );
439            assert_eq!(
440                Key::from((Bs, NaturalMinor)).note_names(),
441                [Bs, Css, Ds, Es, Fss, Gs, As]
442            );
443            assert_eq!(
444                Key::from((Bs, MelodicMinor)).note_names(),
445                [Bs, Css, Ds, Es, Fss, Gss, Ass]
446            );
447            assert_eq!(
448                Key::from((Bs, HarmonicMinor)).note_names(),
449                [Bs, Css, Ds, Es, Fss, Gs, Ass]
450            );
451        }
452
453        #[test]
454        fn cb_scales() {
455            assert_eq!(
456                Key::from((Cb, Major)).note_names(),
457                [Cb, Db, Eb, Fb, Gb, Ab, Bb]
458            );
459            assert_eq!(
460                Key::from((Cb, NaturalMinor)).note_names(),
461                [Cb, Db, Ebb, Fb, Gb, Abb, Bbb]
462            );
463            assert_eq!(
464                Key::from((Cb, MelodicMinor)).note_names(),
465                [Cb, Db, Ebb, Fb, Gb, Ab, Bb]
466            );
467            assert_eq!(
468                Key::from((Cb, HarmonicMinor)).note_names(),
469                [Cb, Db, Ebb, Fb, Gb, Abb, Bb]
470            );
471        }
472
473        #[test]
474        fn c_scales() {
475            assert_eq!(Key::from((C, Major)).note_names(), [C, D, E, F, G, A, B]);
476            assert_eq!(
477                Key::from((C, NaturalMinor)).note_names(),
478                [C, D, Eb, F, G, Ab, Bb]
479            );
480            assert_eq!(
481                Key::from((C, MelodicMinor)).note_names(),
482                [C, D, Eb, F, G, A, B]
483            );
484            assert_eq!(
485                Key::from((C, HarmonicMinor)).note_names(),
486                [C, D, Eb, F, G, Ab, B]
487            );
488        }
489
490        #[test]
491        fn cs_scales() {
492            assert_eq!(
493                Key::from((Cs, Major)).note_names(),
494                [Cs, Ds, Es, Fs, Gs, As, Bs]
495            );
496            assert_eq!(
497                Key::from((Cs, NaturalMinor)).note_names(),
498                [Cs, Ds, E, Fs, Gs, A, B]
499            );
500            assert_eq!(
501                Key::from((Cs, MelodicMinor)).note_names(),
502                [Cs, Ds, E, Fs, Gs, As, Bs]
503            );
504            assert_eq!(
505                Key::from((Cs, HarmonicMinor)).note_names(),
506                [Cs, Ds, E, Fs, Gs, A, Bs]
507            );
508        }
509
510        #[test]
511        fn db_scales() {
512            assert_eq!(
513                Key::from((Db, Major)).note_names(),
514                [Db, Eb, F, Gb, Ab, Bb, C]
515            );
516            assert_eq!(
517                Key::from((Db, NaturalMinor)).note_names(),
518                [Db, Eb, Fb, Gb, Ab, Bbb, Cb]
519            );
520            assert_eq!(
521                Key::from((Db, MelodicMinor)).note_names(),
522                [Db, Eb, Fb, Gb, Ab, Bb, C]
523            );
524            assert_eq!(
525                Key::from((Db, HarmonicMinor)).note_names(),
526                [Db, Eb, Fb, Gb, Ab, Bbb, C]
527            );
528        }
529
530        #[test]
531        fn d_scales() {
532            assert_eq!(Key::from((D, Major)).note_names(), [D, E, Fs, G, A, B, Cs]);
533            assert_eq!(
534                Key::from((D, NaturalMinor)).note_names(),
535                [D, E, F, G, A, Bb, C]
536            );
537            assert_eq!(
538                Key::from((D, MelodicMinor)).note_names(),
539                [D, E, F, G, A, B, Cs]
540            );
541            assert_eq!(
542                Key::from((D, HarmonicMinor)).note_names(),
543                [D, E, F, G, A, Bb, Cs]
544            );
545        }
546
547        #[test]
548        fn ds_scales() {
549            assert_eq!(
550                Key::from((Ds, Major)).note_names(),
551                [Ds, Es, Fss, Gs, As, Bs, Css]
552            );
553            assert_eq!(
554                Key::from((Ds, NaturalMinor)).note_names(),
555                [Ds, Es, Fs, Gs, As, B, Cs]
556            );
557            assert_eq!(
558                Key::from((Ds, MelodicMinor)).note_names(),
559                [Ds, Es, Fs, Gs, As, Bs, Css]
560            );
561            assert_eq!(
562                Key::from((Ds, HarmonicMinor)).note_names(),
563                [Ds, Es, Fs, Gs, As, B, Css]
564            );
565        }
566
567        #[test]
568        fn eb_scales() {
569            assert_eq!(
570                Key::from((Eb, Major)).note_names(),
571                [Eb, F, G, Ab, Bb, C, D]
572            );
573            assert_eq!(
574                Key::from((Eb, NaturalMinor)).note_names(),
575                [Eb, F, Gb, Ab, Bb, Cb, Db]
576            );
577            assert_eq!(
578                Key::from((Eb, MelodicMinor)).note_names(),
579                [Eb, F, Gb, Ab, Bb, C, D]
580            );
581            assert_eq!(
582                Key::from((Eb, HarmonicMinor)).note_names(),
583                [Eb, F, Gb, Ab, Bb, Cb, D]
584            );
585        }
586
587        #[test]
588        fn e_scales() {
589            assert_eq!(
590                Key::from((E, Major)).note_names(),
591                [E, Fs, Gs, A, B, Cs, Ds]
592            );
593            assert_eq!(
594                Key::from((E, NaturalMinor)).note_names(),
595                [E, Fs, G, A, B, C, D]
596            );
597            assert_eq!(
598                Key::from((E, MelodicMinor)).note_names(),
599                [E, Fs, G, A, B, Cs, Ds]
600            );
601            assert_eq!(
602                Key::from((E, HarmonicMinor)).note_names(),
603                [E, Fs, G, A, B, C, Ds]
604            );
605        }
606
607        #[test]
608        fn es_scales() {
609            assert_eq!(
610                Key::from((Es, Major)).note_names(),
611                [Es, Fss, Gss, As, Bs, Css, Dss]
612            );
613            assert_eq!(
614                Key::from((Es, NaturalMinor)).note_names(),
615                [Es, Fss, Gs, As, Bs, Cs, Ds]
616            );
617            assert_eq!(
618                Key::from((Es, MelodicMinor)).note_names(),
619                [Es, Fss, Gs, As, Bs, Css, Dss]
620            );
621            assert_eq!(
622                Key::from((Es, HarmonicMinor)).note_names(),
623                [Es, Fss, Gs, As, Bs, Cs, Dss]
624            );
625        }
626
627        #[test]
628        fn fb_scales() {
629            assert_eq!(
630                Key::from((Fb, Major)).note_names(),
631                [Fb, Gb, Ab, Bbb, Cb, Db, Eb]
632            );
633            assert_eq!(
634                Key::from((Fb, NaturalMinor)).note_names(),
635                [Fb, Gb, Abb, Bbb, Cb, Dbb, Ebb]
636            );
637            assert_eq!(
638                Key::from((Fb, MelodicMinor)).note_names(),
639                [Fb, Gb, Abb, Bbb, Cb, Db, Eb]
640            );
641            assert_eq!(
642                Key::from((Fb, HarmonicMinor)).note_names(),
643                [Fb, Gb, Abb, Bbb, Cb, Dbb, Eb]
644            );
645        }
646
647        #[test]
648        fn f_scales() {
649            assert_eq!(Key::from((F, Major)).note_names(), [F, G, A, Bb, C, D, E]);
650            assert_eq!(
651                Key::from((F, NaturalMinor)).note_names(),
652                [F, G, Ab, Bb, C, Db, Eb]
653            );
654            assert_eq!(
655                Key::from((F, MelodicMinor)).note_names(),
656                [F, G, Ab, Bb, C, D, E]
657            );
658            assert_eq!(
659                Key::from((F, HarmonicMinor)).note_names(),
660                [F, G, Ab, Bb, C, Db, E]
661            );
662        }
663
664        #[test]
665        fn fs_scales() {
666            assert_eq!(
667                Key::from((Fs, Major)).note_names(),
668                [Fs, Gs, As, B, Cs, Ds, Es]
669            );
670            assert_eq!(
671                Key::from((Fs, NaturalMinor)).note_names(),
672                [Fs, Gs, A, B, Cs, D, E]
673            );
674            assert_eq!(
675                Key::from((Fs, MelodicMinor)).note_names(),
676                [Fs, Gs, A, B, Cs, Ds, Es]
677            );
678            assert_eq!(
679                Key::from((Fs, HarmonicMinor)).note_names(),
680                [Fs, Gs, A, B, Cs, D, Es]
681            );
682        }
683
684        #[test]
685        fn gb_scales() {
686            assert_eq!(
687                Key::from((Gb, Major)).note_names(),
688                [Gb, Ab, Bb, Cb, Db, Eb, F]
689            );
690            assert_eq!(
691                Key::from((Gb, NaturalMinor)).note_names(),
692                [Gb, Ab, Bbb, Cb, Db, Ebb, Fb]
693            );
694            assert_eq!(
695                Key::from((Gb, MelodicMinor)).note_names(),
696                [Gb, Ab, Bbb, Cb, Db, Eb, F]
697            );
698            assert_eq!(
699                Key::from((Gb, HarmonicMinor)).note_names(),
700                [Gb, Ab, Bbb, Cb, Db, Ebb, F]
701            );
702        }
703
704        #[test]
705        fn g_scales() {
706            assert_eq!(Key::from((G, Major)).note_names(), [G, A, B, C, D, E, Fs]);
707            assert_eq!(
708                Key::from((G, NaturalMinor)).note_names(),
709                [G, A, Bb, C, D, Eb, F]
710            );
711            assert_eq!(
712                Key::from((G, MelodicMinor)).note_names(),
713                [G, A, Bb, C, D, E, Fs]
714            );
715            assert_eq!(
716                Key::from((G, HarmonicMinor)).note_names(),
717                [G, A, Bb, C, D, Eb, Fs]
718            );
719        }
720
721        #[test]
722        fn gs_scales() {
723            assert_eq!(
724                Key::from((Gs, Major)).note_names(),
725                [Gs, As, Bs, Cs, Ds, Es, Fss]
726            );
727            assert_eq!(
728                Key::from((Gs, NaturalMinor)).note_names(),
729                [Gs, As, B, Cs, Ds, E, Fs]
730            );
731            assert_eq!(
732                Key::from((Gs, MelodicMinor)).note_names(),
733                [Gs, As, B, Cs, Ds, Es, Fss]
734            );
735            assert_eq!(
736                Key::from((Gs, HarmonicMinor)).note_names(),
737                [Gs, As, B, Cs, Ds, E, Fss]
738            );
739        }
740    }
741}