Skip to content

Commit

Permalink
feat(mode)!: rewrite Mode enums (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertms10 committed Apr 30, 2023
1 parent f149838 commit aa4574e
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 85 deletions.
2 changes: 1 addition & 1 deletion lib/music_notes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ part 'src/note/notes.dart';
part 'src/note/positioned_note.dart';
part 'src/scale/scale.dart';
part 'src/tonality/key_signature.dart';
part 'src/tonality/modes.dart';
part 'src/tonality/mode.dart';
part 'src/tonality/tonality.dart';
part 'src/transposable.dart';
9 changes: 5 additions & 4 deletions lib/src/note/note.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,17 @@ class Note implements MusicItem, Transposable<Note> {
///
/// Example:
/// ```dart
/// Note.fromTonalityAccidentals(2, Modes.major, Accidental.sharp) == Note.d
/// Note.fromTonalityAccidentals(0, Modes.minor) == Note.a
/// Note.fromTonalityAccidentals(2, TonalMode.major, Accidental.sharp)
/// == Note.d
/// Note.fromTonalityAccidentals(0, TonalMode.minor) == Note.a
/// ```
factory Note.fromTonalityAccidentals(
int accidentals,
Modes mode, [
TonalMode mode, [
Accidental accidental = Accidental.natural,
]) {
final note = Note.fromRawAccidentals(accidentals, accidental);
if (mode == Modes.major) return note;
if (mode == TonalMode.major) return note;

return EnharmonicNote(note.semitones)
.transposeBy(-Interval.minorThird)
Expand Down
4 changes: 2 additions & 2 deletions lib/src/tonality/key_signature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ class KeySignature implements Comparable<KeySignature> {
/// }
/// ```
Set<Tonality> get tonalities => {
Tonality.fromAccidentals(accidentals, Modes.major, accidental),
Tonality.fromAccidentals(accidentals, TonalMode.major, accidental),
// TODO(albertms10): use `Tonality.relative`.
Tonality.fromAccidentals(accidentals, Modes.minor, accidental),
Tonality.fromAccidentals(accidentals, TonalMode.minor, accidental),
};

@override
Expand Down
58 changes: 58 additions & 0 deletions lib/src/tonality/mode.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
part of '../../music_notes.dart';

abstract class Mode implements Enum, Comparable<Mode> {
Scale get scale;
int get brightness;

static int compareModes(Mode a, Mode b) => compareMultiple([
() => a.brightness.compareTo(b.brightness),
() => a.name.compareTo(b.name),
]);
}

enum TonalMode implements Mode {
major(Scale.major, brightness: 0),
minor(Scale.naturalMinor, brightness: -3);

@override
final Scale scale;

@override
final int brightness;

const TonalMode(this.scale, {required this.brightness});

/// Returns the inverted of this [TonalMode].
///
/// Example:
/// ```dart
/// TonalMode.major.inverted == TonalMode.minor
/// TonalMode.minor.inverted == TonalMode.major
/// ```
TonalMode get opposite =>
this == TonalMode.major ? TonalMode.minor : TonalMode.major;

@override
int compareTo(Mode other) => Mode.compareModes(this, other);
}

enum ModalMode implements Mode {
lydian(Scale.lydian, brightness: 1),
ionian(Scale.ionian, brightness: 0),
mixolydian(Scale.mixolydian, brightness: -1),
dorian(Scale.dorian, brightness: -2),
aeolian(Scale.aeolian, brightness: -3),
phrygian(Scale.phrygian, brightness: -4),
locrian(Scale.locrian, brightness: -5);

@override
final Scale scale;

@override
final int brightness;

const ModalMode(this.scale, {required this.brightness});

@override
int compareTo(Mode other) => Mode.compareModes(this, other);
}
15 changes: 0 additions & 15 deletions lib/src/tonality/modes.dart

This file was deleted.

66 changes: 33 additions & 33 deletions lib/src/tonality/tonality.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,62 @@ part of '../../music_notes.dart';
@immutable
class Tonality implements Comparable<Tonality> {
final Note note;
final Modes mode;
final TonalMode mode;

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

static const cMajor = Tonality(Note.c, Modes.major);
static const cMinor = Tonality(Note.c, Modes.minor);
static const cMajor = Tonality(Note.c, TonalMode.major);
static const cMinor = Tonality(Note.c, TonalMode.minor);

static const cSharpMajor = Tonality(Note.cSharp, Modes.major);
static const cSharpMinor = Tonality(Note.cSharp, Modes.minor);
static const dFlatMajor = Tonality(Note.dFlat, Modes.major);
static const cSharpMajor = Tonality(Note.cSharp, TonalMode.major);
static const cSharpMinor = Tonality(Note.cSharp, TonalMode.minor);
static const dFlatMajor = Tonality(Note.dFlat, TonalMode.major);

static const dMajor = Tonality(Note.d, Modes.major);
static const dMinor = Tonality(Note.d, Modes.minor);
static const dMajor = Tonality(Note.d, TonalMode.major);
static const dMinor = Tonality(Note.d, TonalMode.minor);

static const dSharpMinor = Tonality(Note.dSharp, Modes.minor);
static const eFlatMajor = Tonality(Note.eFlat, Modes.major);
static const eFlatMinor = Tonality(Note.eFlat, Modes.minor);
static const dSharpMinor = Tonality(Note.dSharp, TonalMode.minor);
static const eFlatMajor = Tonality(Note.eFlat, TonalMode.major);
static const eFlatMinor = Tonality(Note.eFlat, TonalMode.minor);

static const eMajor = Tonality(Note.e, Modes.major);
static const eMinor = Tonality(Note.e, Modes.minor);
static const eMajor = Tonality(Note.e, TonalMode.major);
static const eMinor = Tonality(Note.e, TonalMode.minor);

static const fMajor = Tonality(Note.f, Modes.major);
static const fMinor = Tonality(Note.f, Modes.minor);
static const fMajor = Tonality(Note.f, TonalMode.major);
static const fMinor = Tonality(Note.f, TonalMode.minor);

static const fSharpMajor = Tonality(Note.fSharp, Modes.major);
static const fSharpMinor = Tonality(Note.fSharp, Modes.minor);
static const gFlatMajor = Tonality(Note.gFlat, Modes.major);
static const fSharpMajor = Tonality(Note.fSharp, TonalMode.major);
static const fSharpMinor = Tonality(Note.fSharp, TonalMode.minor);
static const gFlatMajor = Tonality(Note.gFlat, TonalMode.major);

static const gMajor = Tonality(Note.g, Modes.major);
static const gMinor = Tonality(Note.g, Modes.minor);
static const gMajor = Tonality(Note.g, TonalMode.major);
static const gMinor = Tonality(Note.g, TonalMode.minor);

static const gSharpMinor = Tonality(Note.gSharp, Modes.minor);
static const aFlatMajor = Tonality(Note.aFlat, Modes.major);
static const aFlatMinor = Tonality(Note.aFlat, Modes.minor);
static const gSharpMinor = Tonality(Note.gSharp, TonalMode.minor);
static const aFlatMajor = Tonality(Note.aFlat, TonalMode.major);
static const aFlatMinor = Tonality(Note.aFlat, TonalMode.minor);

static const aMajor = Tonality(Note.a, Modes.major);
static const aMinor = Tonality(Note.a, Modes.minor);
static const aMajor = Tonality(Note.a, TonalMode.major);
static const aMinor = Tonality(Note.a, TonalMode.minor);

static const aSharpMinor = Tonality(Note.aSharp, Modes.minor);
static const bFlatMajor = Tonality(Note.bFlat, Modes.major);
static const bFlatMinor = Tonality(Note.bFlat, Modes.minor);
static const aSharpMinor = Tonality(Note.aSharp, TonalMode.minor);
static const bFlatMajor = Tonality(Note.bFlat, TonalMode.major);
static const bFlatMinor = Tonality(Note.bFlat, TonalMode.minor);

static const bMajor = Tonality(Note.b, Modes.major);
static const bMinor = Tonality(Note.b, Modes.minor);
static const bMajor = Tonality(Note.b, TonalMode.major);
static const bMinor = Tonality(Note.b, TonalMode.minor);

factory Tonality.fromAccidentals(
int accidentals,
Modes mode, [
TonalMode mode, [
Accidental accidental = Accidental.natural,
]) =>
Tonality(
Note.fromTonalityAccidentals(accidentals, mode, accidental),
mode,
);

/// Returns the [Modes.major] or [Modes.minor] relative [Tonality]
/// Returns the [TonalMode.major] or [TonalMode.minor] relative [Tonality]
/// of this [Tonality].
///
/// Example:
Expand All @@ -70,7 +70,7 @@ class Tonality implements Comparable<Tonality> {
EnharmonicNote(note.semitones)
.transposeBy(
Interval.imperfect(
3 * (mode == Modes.major ? -1 : 1),
3 * (mode == TonalMode.major ? -1 : 1),
ImperfectQuality.minor,
),
)
Expand Down
4 changes: 2 additions & 2 deletions test/src/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import 'note/notes_test.dart' as notes_test;
import 'note/positioned_note_test.dart' as positioned_note_test;
import 'scale/scale_test.dart' as scale_test;
import 'tonality/key_signature_test.dart' as key_signature_test;
import 'tonality/modes_test.dart' as modes_test;
import 'tonality/mode_test.dart' as mode_test;
import 'tonality/tonality_test.dart' as tonality_test;

void main() {
Expand All @@ -29,6 +29,6 @@ void main() {
positioned_note_test.main();
scale_test.main();
key_signature_test.main();
modes_test.main();
mode_test.main();
tonality_test.main();
}
24 changes: 12 additions & 12 deletions test/src/tonality/key_signature_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,19 @@ void main() {
group('.tonalities', () {
test('should return the Set of tonalities for this KeySignature', () {
expect(const KeySignature(10, Accidental.flat).tonalities, {
const Tonality(Note(Notes.e, Accidental.doubleFlat), Modes.major),
const Tonality(Note(Notes.c, Accidental.flat), Modes.minor),
const Tonality(Note(Notes.e, Accidental.doubleFlat), TonalMode.major),
const Tonality(Note(Notes.c, Accidental.flat), TonalMode.minor),
});
expect(const KeySignature(9, Accidental.flat).tonalities, {
const Tonality(Note(Notes.b, Accidental.doubleFlat), Modes.major),
const Tonality(Note.gFlat, Modes.minor),
const Tonality(Note(Notes.b, Accidental.doubleFlat), TonalMode.major),
const Tonality(Note.gFlat, TonalMode.minor),
});
expect(const KeySignature(8, Accidental.flat).tonalities, {
const Tonality(Note(Notes.f, Accidental.flat), Modes.major),
const Tonality(Note.dFlat, Modes.minor),
const Tonality(Note(Notes.f, Accidental.flat), TonalMode.major),
const Tonality(Note.dFlat, TonalMode.minor),
});
expect(const KeySignature(7, Accidental.flat).tonalities, {
const Tonality(Note(Notes.c, Accidental.flat), Modes.major),
const Tonality(Note(Notes.c, Accidental.flat), TonalMode.major),
Tonality.aFlatMinor,
});
expect(const KeySignature(6, Accidental.flat).tonalities, {
Expand Down Expand Up @@ -117,15 +117,15 @@ void main() {
Tonality.aSharpMinor,
});
expect(const KeySignature(8, Accidental.sharp).tonalities, {
const Tonality(Note.gSharp, Modes.major),
const Tonality(Note(Notes.e, Accidental.sharp), Modes.minor),
const Tonality(Note.gSharp, TonalMode.major),
const Tonality(Note(Notes.e, Accidental.sharp), TonalMode.minor),
});
expect(const KeySignature(9, Accidental.sharp).tonalities, {
const Tonality(Note.dSharp, Modes.major),
const Tonality(Note(Notes.b, Accidental.sharp), Modes.minor),
const Tonality(Note.dSharp, TonalMode.major),
const Tonality(Note(Notes.b, Accidental.sharp), TonalMode.minor),
});
expect(const KeySignature(10, Accidental.sharp).tonalities, {
const Tonality(Note.aSharp, Modes.major),
const Tonality(Note.aSharp, TonalMode.major),
// TODO(albertms10): Failing test #50:
// Should be `Note(Notes.f, Accidental.doubleSharp)`.
Tonality.gMinor,
Expand Down
36 changes: 36 additions & 0 deletions test/src/tonality/mode_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'dart:collection' show SplayTreeSet;

import 'package:music_notes/music_notes.dart';
import 'package:test/test.dart';

void main() {
group('TonalMode', () {
group('.opposite', () {
test('should return the correct opposite mode', () {
expect(TonalMode.major.opposite, TonalMode.minor);
expect(TonalMode.minor.opposite, TonalMode.major);
});
});

group('.compareTo', () {
test('should correctly sort Mode items in a collection', () {
final orderedSet = SplayTreeSet<Mode>.of(const [
TonalMode.minor,
ModalMode.phrygian,
ModalMode.ionian,
TonalMode.major,
ModalMode.aeolian,
ModalMode.lydian,
]);
expect(orderedSet.toList(), const [
ModalMode.phrygian,
ModalMode.aeolian,
TonalMode.minor,
ModalMode.ionian,
TonalMode.major,
ModalMode.lydian,
]);
});
});
});
}
13 changes: 0 additions & 13 deletions test/src/tonality/modes_test.dart

This file was deleted.

6 changes: 3 additions & 3 deletions test/src/tonality/tonality_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void main() {
expect(Tonality.gSharpMinor.relative, Tonality.bMajor);
expect(
Tonality.aFlatMinor.relative,
const Tonality(Note(Notes.c, Accidental.flat), Modes.major),
const Tonality(Note(Notes.c, Accidental.flat), TonalMode.major),
);
});
});
Expand Down Expand Up @@ -66,12 +66,12 @@ void main() {
expect(Tonality.aFlatMajor.toString(), 'A♭ major');
expect(Tonality.fSharpMinor.toString(), 'F♯ minor');
expect(
const Tonality(Note(Notes.g, Accidental.doubleSharp), Modes.major)
const Tonality(Note(Notes.g, Accidental.doubleSharp), TonalMode.major)
.toString(),
'G𝄪 major',
);
expect(
const Tonality(Note(Notes.e, Accidental.doubleFlat), Modes.minor)
const Tonality(Note(Notes.e, Accidental.doubleFlat), TonalMode.minor)
.toString(),
'E𝄫 minor',
);
Expand Down

0 comments on commit aa4574e

Please sign in to comment.