Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(size): ♻️ redeclare simple in extension types to allow chaining #438

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,16 @@ Pitch.parse('Eb3'); // E♭3
Create an `Interval`:

```dart
Interval.P4; // P4
const Interval.imperfect(Size.tenth, ImperfectQuality.major); // M10
Interval.d5; // d5
Size.sixth.augmented; // A6
Size.eleventh.simple.perfect; // P4
```

Or turn it descending:

```dart
-Interval.m6; // m-6
-Interval.m7; // m-7
Interval.M3.descending(); // M-3
```

Expand Down
5 changes: 3 additions & 2 deletions example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ void main() {
Pitch.parse('Eb3'); // E♭3

// Intervals
Interval.P4; // P4
const Interval.imperfect(Size.tenth, ImperfectQuality.major); // M10
Interval.d5; // d5
Size.sixth.augmented; // A6
Size.twelfth.simple.perfect; // P5

-Interval.m6; // m-6
-Interval.m7; // m-7
Interval.M3.descending(); // M-3

Note.c.interval(Note.g); // P5
Expand Down
47 changes: 25 additions & 22 deletions lib/src/interval/size.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ extension type const Size._(int size) implements int {
/// [Size] to the corresponding [ImperfectQuality.minor] or
/// [PerfectQuality.perfect] semitones.
static const _sizeToSemitones = {
Size.unison: 0, // P
Size.second: 1, // m
Size.third: 3, // m
Size.fourth: 5, // P
Size.fifth: 7, // P
Size.sixth: 8, // m
Size.seventh: 10, // m
Size.octave: 12, // P
unison: 0, // P
second: 1, // m
third: 3, // m
fourth: 5, // P
fifth: 7, // P
sixth: 8, // m
seventh: 10, // m
octave: 12, // P
};

/// The [Size] that matches with [semitones] in [_sizeToSemitones].
Expand Down Expand Up @@ -107,10 +107,10 @@ extension type const Size._(int size) implements int {
/// ```
int get semitones {
final simpleAbs = simple.abs();
final octaveShift = chromaticDivisions * (absShift ~/ Size.octave);
final octaveShift = chromaticDivisions * (absShift ~/ octave);
// We exclude perfect octaves (simplified as 8) from the lookup to consider
// them 0 (as if they were modulo `Size.octave`).
final size = Size(simpleAbs == Size.octave ? 1 : simpleAbs);
final size = Size(simpleAbs == octave ? 1 : simpleAbs);

return (_sizeToSemitones[size]! + octaveShift) * sign;
}
Expand All @@ -119,7 +119,7 @@ extension type const Size._(int size) implements int {
int get absShift {
final sizeAbs = abs();

return sizeAbs + sizeAbs ~/ Size.octave;
return sizeAbs + sizeAbs ~/ octave;
}

/// The [PerfectQuality.diminished] or [ImperfectQuality.diminished] interval
Expand Down Expand Up @@ -156,7 +156,7 @@ extension type const Size._(int size) implements int {
/// Size.sixth.isPerfect == false
/// (-Size.eleventh).isPerfect == true
/// ```
bool get isPerfect => absShift % (Size.octave / 2) < 2;
bool get isPerfect => absShift % (octave / 2) < 2;

/// Whether this [Size] is greater than [Size.octave].
///
Expand All @@ -169,7 +169,10 @@ extension type const Size._(int size) implements int {
/// (-Size.eleventh).isCompound == true
/// Size.thirteenth.isCompound == true
/// ```
bool get isCompound => abs() > Size.octave;
bool get isCompound => abs() > octave;

static int _simple(Size size) =>
size.isCompound ? size.absShift.nonZeroMod(octave) * size.sign : size;

/// The simplified version of this [Size].
///
Expand All @@ -180,9 +183,7 @@ extension type const Size._(int size) implements int {
/// Size.octave.simple == Size.octave
/// const Size(-22).simple == -Size.octave
/// ```
Size get simple => Size(
isCompound ? absShift.nonZeroMod(Size.octave) * sign : size,
);
Size get simple => Size(_simple(this));

/// This [Size] formatted as a string.
String format({IntervalNotation system = IntervalNotation.standard}) =>
Expand All @@ -205,9 +206,7 @@ extension type const PerfectSize._(int size) implements Size {
const PerfectSize(this.size)
// Copied from [Size.isPerfect] to allow const.
: assert(
((size < 0 ? 0 - size : size) + (size < 0 ? 0 - size : size) ~/ 8) %
4 <
2,
((size < 0 ? -size : size) + (size < 0 ? -size : size) ~/ 8) % 4 < 2,
'Interval must be perfect.',
);

Expand All @@ -221,6 +220,9 @@ extension type const PerfectSize._(int size) implements Size {
/// ```
Interval get perfect => Interval.perfect(this);

@redeclare
PerfectSize get simple => PerfectSize(Size._simple(this));

/// The negation of this [PerfectSize].
///
/// Example:
Expand All @@ -238,9 +240,7 @@ extension type const ImperfectSize._(int size) implements Size {
const ImperfectSize(this.size)
// Copied from [Size.isPerfect] to allow const.
: assert(
((size < 0 ? 0 - size : size) + (size < 0 ? 0 - size : size) ~/ 8) %
4 >=
2,
((size < 0 ? -size : size) + (size < 0 ? -size : size) ~/ 8) % 4 >= 2,
'Interval must be imperfect.',
);

Expand All @@ -264,6 +264,9 @@ extension type const ImperfectSize._(int size) implements Size {
/// ```
Interval get minor => Interval.imperfect(this, ImperfectQuality.minor);

@redeclare
ImperfectSize get simple => ImperfectSize(Size._simple(this));

/// The negation of this [ImperfectSize].
///
/// Example:
Expand Down
5 changes: 5 additions & 0 deletions test/src/interval/size_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void main() {
expect(Size.unison.perfect, Interval.P1);
expect(Size.fourth.perfect, Interval.P4);
expect((-Size.fifth).perfect, -Interval.P5);
expect(Size.twelfth.simple.perfect, Interval.P5);
});
});

Expand All @@ -58,6 +59,7 @@ void main() {
expect(Size.second.major, Interval.M2);
expect(Size.sixth.major, Interval.M6);
expect((-Size.ninth).major, -Interval.M9);
expect(Size.thirteenth.simple.major, Interval.M6);
});
});

Expand All @@ -66,6 +68,7 @@ void main() {
expect(Size.third.minor, Interval.m3);
expect(Size.seventh.minor, Interval.m7);
expect((-Size.sixth).minor, -Interval.m6);
expect(Size.ninth.simple.minor, Interval.m2);
});
});

Expand All @@ -74,6 +77,7 @@ void main() {
expect(Size.second.diminished, Interval.d2);
expect(Size.fifth.diminished, Interval.d5);
expect((-Size.seventh).diminished, -Interval.d7);
expect(Size.eleventh.simple.diminished, Interval.d4);
});
});

Expand All @@ -82,6 +86,7 @@ void main() {
expect(Size.third.augmented, Interval.A3);
expect(Size.fourth.augmented, Interval.A4);
expect((-Size.sixth).augmented, -Interval.A6);
expect(Size.twelfth.simple.augmented, Interval.A5);
});
});
});
Expand Down