Skip to content

Commit

Permalink
✨ feat(interval): take distance sign into account in circleFrom (#…
Browse files Browse the repository at this point in the history
…199)

* ✨ feat(interval): take distance sign into account in `circleFrom`

* ✅ test(interval): add more test cases for `circleFrom`
  • Loading branch information
albertms10 committed Jun 23, 2023
1 parent 903e141 commit 265d087
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 18 deletions.
17 changes: 10 additions & 7 deletions lib/src/interval/interval.dart
Original file line number Diff line number Diff line change
Expand Up @@ -256,18 +256,21 @@ final class Interval implements Comparable<Interval> {
///
/// Interval.P4.circleFrom(Note.c, distance: 5)
/// == [Note.c, Note.f, Note.b.flat, Note.e.flat, Note.a.flat, Note.d.flat]
///
/// Interval.P4.circleFrom(Note.c, distance: -3)
/// == Interval.P5.circleFrom(Note.c, distance: 3)
/// ```
List<T> circleFrom<T extends Scalable<T>>(
T scalable, {
required int distance,
}) =>
distance == 0
? [scalable]
: List.filled(distance.abs(), null).fold(
[scalable],
(circleItems, _) =>
[...circleItems, circleItems.last.transposeBy(this)],
);
List.filled(distance.abs(), null).fold(
[scalable],
(circleItems, _) => [
...circleItems,
circleItems.last.transposeBy(distance.isNegative ? -this : this),
],
);

/// Adds [other] to this [Interval].
///
Expand Down
11 changes: 5 additions & 6 deletions lib/src/note/note.dart
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,8 @@ final class Note implements Comparable<Note>, Scalable<Note> {
(
sharps:
Interval.P5.circleFrom(this, distance: distance).skip(1).toList(),
flats: (-Interval.P5)
.circleFrom(this, distance: distance)
.skip(1)
.toList(),
flats:
Interval.P5.circleFrom(this, distance: -distance).skip(1).toList(),
);

/// Returns the flattened version of [circleOfFifths] from this [Note] up to
Expand Down Expand Up @@ -277,12 +275,13 @@ final class Note implements Comparable<Note>, Scalable<Note> {
int get circleOfFifthsDistance =>
Tonality(this, TonalMode.major).keySignature.distance;

/// Returns the exact fifths distance between this [Note] and [other].
/// Returns the fifths distance between this [Note] and [other].
///
/// Example:
/// ```dart
/// Note.c.fifthsDistanceWith(Note.e.flat) == -3
/// Note.f.sharp.fifthsDistanceWith(Note.b) == -1
/// Note.a.flat.fifthsDistanceWith(Note.c.sharp) == 11
/// Note.a.flat.fifthsDistanceWith(Note.d.flat) == -1
/// ```
int fifthsDistanceWith(Note other) =>
Interval.P5.distanceBetween(this, other);
Expand Down
10 changes: 5 additions & 5 deletions lib/src/tonality/key_signature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ final class KeySignature implements Comparable<KeySignature> {
factory KeySignature.fromDistance(int distance) {
if (distance == 0) return empty;

final interval = distance.isNegative ? Interval.P4 : Interval.P5;
final startingNote = distance.isNegative ? Note.b.flat : Note.f.sharp;
final firstAccidentalNote =
distance.isNegative ? Note.b.flat : Note.f.sharp;

return KeySignature(
interval.circleFrom(startingNote, distance: distance.incrementBy(-1)),
Interval.P5
.circleFrom(firstAccidentalNote, distance: distance.incrementBy(-1)),
);
}

Expand Down Expand Up @@ -70,8 +71,7 @@ final class KeySignature implements Comparable<KeySignature> {
/// )
/// ```
({Tonality major, Tonality minor}) get tonalities {
final interval = distance.isNegative ? Interval.P4 : Interval.P5;
final rootNote = interval.circleFrom(Note.c, distance: distance).last;
final rootNote = Interval.P5.circleFrom(Note.c, distance: distance).last;

return (
major: rootNote.major,
Expand Down
5 changes: 5 additions & 0 deletions test/src/interval/interval_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,11 @@ void main() {
Note.a.flat.flat,
],
);

expect(
Interval.P4.circleFrom(Note.c, distance: -7),
Interval.P5.circleFrom(Note.c, distance: 7),
);
});
});

Expand Down

0 comments on commit 265d087

Please sign in to comment.