-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(harmonic_function): add class and
Scale
method (#176)
* feat(harmonic_function): add class and `Scale` method * refactor(harmonic_function): rename static constants * test(harmonic_function): add test cases * docs(harmonic_function): address typo in example
- Loading branch information
1 parent
d97b5f6
commit ccb5f57
Showing
6 changed files
with
236 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
part of '../../music_notes.dart'; | ||
|
||
class HarmonicFunction { | ||
final List<ScaleDegree> scaleDegrees; | ||
|
||
/// Creates a new [HarmonicFunction] from [scaleDegrees]. | ||
const HarmonicFunction(this.scaleDegrees); | ||
|
||
static const tonic = HarmonicFunction([ScaleDegree.i]); | ||
static const ii = HarmonicFunction([ScaleDegree.ii]); | ||
static const neapolitanSixth = | ||
HarmonicFunction([ScaleDegree.neapolitanSixth]); | ||
static const iii = HarmonicFunction([ScaleDegree.iii]); | ||
static const iv = HarmonicFunction([ScaleDegree.iv]); | ||
static const dominantV = | ||
HarmonicFunction([ScaleDegree(5, quality: ImperfectQuality.major)]); | ||
static const vi = HarmonicFunction([ScaleDegree.vi]); | ||
static const vii = HarmonicFunction([ScaleDegree.vii]); | ||
|
||
@override | ||
String toString() => scaleDegrees.join('/'); | ||
|
||
/// Returns a new [HarmonicFunction] relating this [HarmonicFunction] to | ||
/// [other]. | ||
/// | ||
/// Example: | ||
/// ```dart | ||
/// HarmonicFunction.dominantV / | ||
/// HarmonicFunction.dominantV / | ||
/// HarmonicFunction.dominantV | ||
/// == HarmonicFunction([ | ||
/// ScaleDegree.v.major, ScaleDegree.v.major, ScaleDegree.v.major, | ||
/// ]) | ||
/// ``` | ||
HarmonicFunction operator /(HarmonicFunction other) => | ||
HarmonicFunction([...scaleDegrees, ...other.scaleDegrees]); | ||
|
||
@override | ||
bool operator ==(Object other) => | ||
other is HarmonicFunction && | ||
const ListEquality<ScaleDegree>() | ||
.equals(scaleDegrees, other.scaleDegrees); | ||
|
||
@override | ||
int get hashCode => Object.hashAll(scaleDegrees); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import 'package:music_notes/music_notes.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
group('HarmonicFunction', () { | ||
group('operator /', () { | ||
test('should return the HarmonicFunction relating this to other', () { | ||
expect( | ||
HarmonicFunction.dominantV / HarmonicFunction.dominantV, | ||
HarmonicFunction([ScaleDegree.v.major, ScaleDegree.v.major]), | ||
); | ||
expect( | ||
HarmonicFunction.ii / HarmonicFunction.ii, | ||
const HarmonicFunction([ScaleDegree.ii, ScaleDegree.ii]), | ||
); | ||
expect( | ||
HarmonicFunction.vi / HarmonicFunction.iv, | ||
const HarmonicFunction([ScaleDegree.vi, ScaleDegree.iv]), | ||
); | ||
expect( | ||
HarmonicFunction.tonic / HarmonicFunction.ii / HarmonicFunction.iii, | ||
const HarmonicFunction( | ||
[ScaleDegree.i, ScaleDegree.ii, ScaleDegree.iii], | ||
), | ||
); | ||
}); | ||
}); | ||
|
||
group('.toString()', () { | ||
test( | ||
'should return the string representation of this HarmonicFunction', | ||
() { | ||
expect(HarmonicFunction.tonic.toString(), 'I'); | ||
expect(HarmonicFunction.vii.toString(), 'VII'); | ||
expect( | ||
(HarmonicFunction.dominantV / HarmonicFunction.dominantV) | ||
.toString(), | ||
'V/V', | ||
); | ||
expect( | ||
(HarmonicFunction([ScaleDegree.iv.minor]) / | ||
HarmonicFunction.neapolitanSixth / | ||
HarmonicFunction.dominantV) | ||
.toString(), | ||
'iv/♭II6/V', | ||
); | ||
}, | ||
); | ||
}); | ||
|
||
group('.hashCode', () { | ||
test('should return the same hashCode for equal HarmonicFunctions', () { | ||
expect( | ||
HarmonicFunction.tonic.hashCode, | ||
HarmonicFunction.tonic.hashCode, | ||
); | ||
expect( | ||
HarmonicFunction.neapolitanSixth.hashCode, | ||
HarmonicFunction.neapolitanSixth.hashCode, | ||
); | ||
}); | ||
|
||
test( | ||
'should return different hashCodes for different HarmonicFunctions', | ||
() { | ||
expect( | ||
HarmonicFunction.tonic.hashCode, | ||
isNot(equals(HarmonicFunction.ii.hashCode)), | ||
); | ||
expect( | ||
const HarmonicFunction([ScaleDegree.vi, ScaleDegree.i]).hashCode, | ||
isNot(equals(HarmonicFunction.vi.hashCode)), | ||
); | ||
}, | ||
); | ||
|
||
test('should ignore equal HarmonicFunction instances in a Set', () { | ||
final collection = { | ||
HarmonicFunction.tonic, | ||
HarmonicFunction.neapolitanSixth, | ||
HarmonicFunction.iii, | ||
HarmonicFunction.iv / HarmonicFunction.iv, | ||
}; | ||
collection.addAll(collection); | ||
expect(collection.toList(), [ | ||
HarmonicFunction.tonic, | ||
HarmonicFunction.neapolitanSixth, | ||
HarmonicFunction.iii, | ||
HarmonicFunction.iv / HarmonicFunction.iv, | ||
]); | ||
}); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters