Skip to content

Commit

Permalink
♻️ refactor(key_signature): simplify tonality methods (#186)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertms10 committed Jun 18, 2023
1 parent d69234e commit 55e6c9c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 144 deletions.
15 changes: 0 additions & 15 deletions lib/src/note/note.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,6 @@ final class Note implements Comparable<Note>, Scalable<Note> {
static const Note a = Note(BaseNote.a);
static const Note b = Note(BaseNote.b);

/// Returns the [Note] from the [Tonality] given its fifths [distance] and
/// [mode].
///
/// Example:
/// ```dart
/// Note.fromDistance(2, TonalMode.major) == Note.d
/// Note.fromDistance(0, TonalMode.minor) == Note.a
/// ```
factory Note.fromDistance(int distance, TonalMode mode) {
final note = KeySignature.fromDistance(distance).majorNote;
if (mode == TonalMode.major) return note;

return note.transposeBy(-Interval.m3);
}

/// Parse [source] as a [Note] and return its value.
///
/// If the [source] string does not contain a valid [Note], a
Expand Down
46 changes: 22 additions & 24 deletions lib/src/tonality/key_signature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,6 @@ final class KeySignature implements Comparable<KeySignature> {
/// ```
int get distance => notes.length * (accidental == Accidental.flat ? -1 : 1);

/// Returns the [Note] that corresponds to the major [Tonality] of this
/// [KeySignature].
///
/// Example:
/// ```dart
/// KeySignature.fromDistance(0).majorNote == Note.c
/// KeySignature.fromDistance(2).majorNote == Note.d
/// ```
Note get majorNote {
final fifthInterval =
Interval.P5.descending(isDescending: accidental == Accidental.flat);

return EnharmonicNote(
(fifthInterval.semitones * notes.length + 1).chromaticModExcludeZero,
).resolveClosestSpelling(accidental.increment(notes.length ~/ 9));
}

/// Returns the [Tonality] that corresponds to this [KeySignature] from
/// [mode].
///
Expand All @@ -70,20 +53,35 @@ final class KeySignature implements Comparable<KeySignature> {
/// KeySignature.fromDistance(0).tonality(TonalMode.major) == Note.c.major
/// KeySignature.fromDistance(-2).tonality(TonalMode.minor) == Note.g.minor
/// ```
Tonality tonality(TonalMode mode) => Tonality.fromDistance(distance, mode);
Tonality tonality(TonalMode mode) {
final cachedTonalities = tonalities;

return switch (mode) {
TonalMode.major => cachedTonalities.major,
TonalMode.minor => cachedTonalities.minor,
};
}

/// Returns a [Set] with the two tonalities that are defined
/// by this [KeySignature].
///
/// Example:
/// ```dart
/// KeySignature.fromDistance(-2).tonalities == {
/// Note.b.flat.major,
/// Note.g.minor,
/// }
/// KeySignature.fromDistance(-2).tonalities == (
/// major: Note.b.flat.major,
/// minor: Note.g.minor,
/// )
/// ```
Set<Tonality> get tonalities =>
{tonality(TonalMode.major), tonality(TonalMode.minor)};
({Tonality major, Tonality minor}) get tonalities {
final interval = distance.isNegative ? Interval.P4 : Interval.P5;
final rootNote = List.filled(distance.abs(), null)
.fold(Note.c, (note, _) => note.transposeBy(interval));

return (
major: rootNote.major,
minor: rootNote.transposeBy(-Interval.m3).minor
);
}

@override
String toString() {
Expand Down
3 changes: 0 additions & 3 deletions lib/src/tonality/tonality.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ final class Tonality implements Comparable<Tonality> {

const Tonality(this.note, this.mode);

factory Tonality.fromDistance(int distance, TonalMode mode) =>
Tonality(Note.fromDistance(distance, mode), mode);

/// Returns the [TonalMode.major] or [TonalMode.minor] relative [Tonality]
/// of this [Tonality].
///
Expand Down
186 changes: 84 additions & 102 deletions test/src/tonality/key_signature_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,6 @@ void main() {
});
});

group('.majorNote', () {
test(
'should return the Note that corresponds to the major Tonality of '
'this KeySignature',
() {
expect(KeySignature.fromDistance(-4).majorNote, Note.a.flat);
expect(KeySignature.fromDistance(-3).majorNote, Note.e.flat);
expect(KeySignature.fromDistance(-2).majorNote, Note.b.flat);
expect(KeySignature.fromDistance(-1).majorNote, Note.f);
expect(KeySignature.fromDistance(0).majorNote, Note.c);
expect(KeySignature.fromDistance(1).majorNote, Note.g);
expect(KeySignature.fromDistance(2).majorNote, Note.d);
expect(KeySignature.fromDistance(3).majorNote, Note.a);
expect(KeySignature.fromDistance(4).majorNote, Note.e);
},
);
});

group('.tonality()', () {
test('should return the Tonality from TonalMode', () {
expect(
Expand Down Expand Up @@ -110,90 +92,90 @@ void main() {

group('.tonalities', () {
test('should return the Set of tonalities for this KeySignature', () {
expect(KeySignature.fromDistance(-10).tonalities, {
Note.e.flat.flat.major,
Note.c.flat.minor,
});
expect(KeySignature.fromDistance(-9).tonalities, {
Note.b.flat.flat.major,
Note.g.flat.minor,
});
expect(KeySignature.fromDistance(-8).tonalities, {
Note.f.flat.major,
Note.d.flat.minor,
});
expect(KeySignature.fromDistance(-7).tonalities, {
Note.c.flat.major,
Note.a.flat.minor,
});
expect(KeySignature.fromDistance(-6).tonalities, {
Note.g.flat.major,
Note.e.flat.minor,
});
expect(KeySignature.fromDistance(-5).tonalities, {
Note.d.flat.major,
Note.b.flat.minor,
});
expect(KeySignature.fromDistance(-4).tonalities, {
Note.a.flat.major,
Note.f.minor,
});
expect(KeySignature.fromDistance(-3).tonalities, {
Note.e.flat.major,
Note.c.minor,
});
expect(KeySignature.fromDistance(-2).tonalities, {
Note.b.flat.major,
Note.g.minor,
});
expect(KeySignature.fromDistance(-1).tonalities, {
Note.f.major,
Note.d.minor,
});
expect(KeySignature.fromDistance(0).tonalities, {
Note.c.major,
Note.a.minor,
});
expect(KeySignature.fromDistance(1).tonalities, {
Note.g.major,
Note.e.minor,
});
expect(KeySignature.fromDistance(2).tonalities, {
Note.d.major,
Note.b.minor,
});
expect(KeySignature.fromDistance(3).tonalities, {
Note.a.major,
Note.f.sharp.minor,
});
expect(KeySignature.fromDistance(4).tonalities, {
Note.e.major,
Note.c.sharp.minor,
});
expect(KeySignature.fromDistance(5).tonalities, {
Note.b.major,
Note.g.sharp.minor,
});
expect(KeySignature.fromDistance(6).tonalities, {
Note.f.sharp.major,
Note.d.sharp.minor,
});
expect(KeySignature.fromDistance(7).tonalities, {
Note.c.sharp.major,
Note.a.sharp.minor,
});
expect(KeySignature.fromDistance(8).tonalities, {
Note.g.sharp.major,
Note.e.sharp.minor,
});
expect(KeySignature.fromDistance(9).tonalities, {
Note.d.sharp.major,
Note.b.sharp.minor,
});
expect(KeySignature.fromDistance(10).tonalities, {
Note.a.sharp.major,
Note.f.sharp.sharp.minor,
});
expect(
KeySignature.fromDistance(-10).tonalities,
(major: Note.e.flat.flat.major, minor: Note.c.flat.minor),
);
expect(
KeySignature.fromDistance(-9).tonalities,
(major: Note.b.flat.flat.major, minor: Note.g.flat.minor),
);
expect(
KeySignature.fromDistance(-8).tonalities,
(major: Note.f.flat.major, minor: Note.d.flat.minor),
);
expect(
KeySignature.fromDistance(-7).tonalities,
(major: Note.c.flat.major, minor: Note.a.flat.minor),
);
expect(
KeySignature.fromDistance(-6).tonalities,
(major: Note.g.flat.major, minor: Note.e.flat.minor),
);
expect(
KeySignature.fromDistance(-5).tonalities,
(major: Note.d.flat.major, minor: Note.b.flat.minor),
);
expect(
KeySignature.fromDistance(-4).tonalities,
(major: Note.a.flat.major, minor: Note.f.minor),
);
expect(
KeySignature.fromDistance(-3).tonalities,
(major: Note.e.flat.major, minor: Note.c.minor),
);
expect(
KeySignature.fromDistance(-2).tonalities,
(major: Note.b.flat.major, minor: Note.g.minor),
);
expect(
KeySignature.fromDistance(-1).tonalities,
(major: Note.f.major, minor: Note.d.minor),
);
expect(
KeySignature.fromDistance(0).tonalities,
(major: Note.c.major, minor: Note.a.minor),
);
expect(
KeySignature.fromDistance(1).tonalities,
(major: Note.g.major, minor: Note.e.minor),
);
expect(
KeySignature.fromDistance(2).tonalities,
(major: Note.d.major, minor: Note.b.minor),
);
expect(
KeySignature.fromDistance(3).tonalities,
(major: Note.a.major, minor: Note.f.sharp.minor),
);
expect(
KeySignature.fromDistance(4).tonalities,
(major: Note.e.major, minor: Note.c.sharp.minor),
);
expect(
KeySignature.fromDistance(5).tonalities,
(major: Note.b.major, minor: Note.g.sharp.minor),
);
expect(
KeySignature.fromDistance(6).tonalities,
(major: Note.f.sharp.major, minor: Note.d.sharp.minor),
);
expect(
KeySignature.fromDistance(7).tonalities,
(major: Note.c.sharp.major, minor: Note.a.sharp.minor),
);
expect(
KeySignature.fromDistance(8).tonalities,
(major: Note.g.sharp.major, minor: Note.e.sharp.minor),
);
expect(
KeySignature.fromDistance(9).tonalities,
(major: Note.d.sharp.major, minor: Note.b.sharp.minor),
);
expect(
KeySignature.fromDistance(10).tonalities,
(major: Note.a.sharp.major, minor: Note.f.sharp.sharp.minor),
);
});
});

Expand Down

0 comments on commit 55e6c9c

Please sign in to comment.