-
Notifications
You must be signed in to change notification settings - Fork 403
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
Implemented jazz minor scale and relative key functionality on harmonic, melodic, and jazz minors #1044
base: master
Are you sure you want to change the base?
Implemented jazz minor scale and relative key functionality on harmonic, melodic, and jazz minors #1044
Changes from 1 commit
4c6a6d6
83498f0
6b88cbb
48c3695
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,14 +50,14 @@ | |
'TERMINUS_LOW', 'TERMINUS_HIGH', | ||
'ScaleException', 'Scale', | ||
'AbstractScale', 'AbstractDiatonicScale', 'AbstractOctatonicScale', | ||
'AbstractHarmonicMinorScale', 'AbstractMelodicMinorScale', | ||
'AbstractHarmonicMinorScale', 'AbstractJazzMinorScale', 'AbstractMelodicMinorScale', | ||
'AbstractCyclicalScale', 'AbstractOctaveRepeatingScale', | ||
'AbstractRagAsawari', 'AbstractRagMarwa', 'AbstractWeightedHexatonicBlues', | ||
'ConcreteScale', 'DiatonicScale', 'MajorScale', | ||
'MinorScale', 'DorianScale', 'PhrygianScale', 'LydianScale', 'MixolydianScale', | ||
'HypodorianScale', 'HypophrygianScale', 'HypolydianScale', 'HypomixolydianScale', | ||
'LocrianScale', 'HypolocrianScale', 'HypoaeolianScale', | ||
'HarmonicMinorScale', 'MelodicMinorScale', | ||
'HarmonicMinorScale', 'JazzMinorScale', 'MelodicMinorScale', | ||
'OctatonicScale', 'OctaveRepeatingScale', 'CyclicalScale', 'ChromaticScale', | ||
'WholeToneScale', 'SieveScale', 'ScalaScale', 'RagAsawari', | ||
'RagMarwa', 'WeightedHexatonicBlues', | ||
|
@@ -847,13 +847,16 @@ class AbstractHarmonicMinorScale(AbstractScale): | |
A true bi-directional scale that with the augmented | ||
second to a leading tone. | ||
|
||
This is the only scale to use the "_alteredDegrees" property. | ||
The harmonic and jazz minor scales are the only to | ||
use the "_alteredDegrees" property. | ||
''' | ||
|
||
def __init__(self, mode=None): | ||
super().__init__() | ||
self.type = 'Abstract Harmonic Minor' | ||
self.octaveDuplicating = True | ||
self.relativeMinorDegree = 1 | ||
self.relativeMajorDegree = 3 | ||
self.dominantDegree: int = -1 | ||
self.buildNetwork() | ||
|
||
|
@@ -872,6 +875,57 @@ def buildNetwork(self): | |
'interval': interval.Interval('a1') | ||
} | ||
|
||
def getRelativeMajor(self): | ||
return MajorScale(self.tonic) | ||
|
||
def getRelativeMinor(self): | ||
return MinorScale(self.tonic) | ||
jacobtylerwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
class AbstractJazzMinorScale(AbstractScale): | ||
''' | ||
A true bi-directional scale containing the raised | ||
6th and 7th scale degrees. | ||
|
||
The harmonic and jazz minor scales are the only to | ||
use the "_alteredDegrees" property. | ||
''' | ||
|
||
def __init__(self, mode=None): | ||
super().__init__() | ||
self.type = 'Abstract Jazz Minor' | ||
self.relativeMinorDegree = 1 | ||
self.relativeMajorDegree = 3 | ||
self.octaveDuplicating = True | ||
self.dominantDegree: int = -1 | ||
self.buildNetwork() | ||
|
||
def buildNetwork(self): | ||
intervalList = ['M2', 'm2', 'M2', 'M2', 'm2', 'M2', 'M2'] # a to A | ||
self.tonicDegree = 1 | ||
self.dominantDegree = 5 | ||
self._net = intervalNetwork.IntervalNetwork(intervalList, | ||
octaveDuplicating=self.octaveDuplicating, | ||
pitchSimplification=None) | ||
|
||
# raise the sixth and seventh in all directions | ||
# 6 and 7 here are both scale step/degree, not node id | ||
self._alteredDegrees[6] = { | ||
'direction': intervalNetwork.DIRECTION_BI, | ||
'interval': interval.Interval('a1') | ||
} | ||
|
||
self._alteredDegrees[7] = { | ||
'direction': intervalNetwork.DIRECTION_BI, | ||
'interval': interval.Interval('a1') | ||
} | ||
|
||
def getRelativeMajor(self): | ||
return MajorScale(self.tonic) | ||
|
||
def getRelativeMinor(self): | ||
return MinorScale(self.tonic) | ||
jacobtylerwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
class AbstractMelodicMinorScale(AbstractScale): | ||
''' | ||
|
@@ -882,6 +936,8 @@ def __init__(self, mode=None): | |
super().__init__() | ||
self.type = 'Abstract Melodic Minor' | ||
self.octaveDuplicating = True | ||
self.relativeMinorDegree = 1 | ||
self.relativeMajorDegree = 3 | ||
self.dominantDegree: int = -1 | ||
self.buildNetwork() | ||
|
||
|
@@ -893,6 +949,11 @@ def buildNetwork(self): | |
pitchSimplification=None) | ||
self._net.fillMelodicMinor() | ||
|
||
def getRelativeMajor(self): | ||
return MajorScale(self.tonic) | ||
|
||
def getRelativeMinor(self): | ||
return MinorScale(self.tonic) | ||
|
||
class AbstractCyclicalScale(AbstractScale): | ||
''' | ||
|
@@ -2830,9 +2891,9 @@ class HarmonicMinorScale(DiatonicScale): | |
''' | ||
The harmonic minor collection, realized as a scale. | ||
|
||
(The usage of this collection as a scale, is quite ahistorical for | ||
(The usage of this collection as a scale is quite ahistorical for | ||
Western European classical music, but it is common in other parts of the | ||
world, but where the term "HarmonicMinor" would not be appropriate). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for the space, but the "but" should remain There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, because "where" is not delimiting certain parts of the world where the term is/is not meaningful. |
||
world, where the term "Harmonic Minor" would not be appropriate). | ||
|
||
>>> sc = scale.HarmonicMinorScale('e4') | ||
>>> [str(p) for p in sc.pitches] | ||
|
@@ -2864,6 +2925,38 @@ def __init__(self, tonic=None): | |
# self._abstract.buildNetwork() | ||
|
||
|
||
class JazzMinorScale(DiatonicScale): | ||
''' | ||
The jazz minor scale. | ||
jacobtylerwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
>>> sc = scale.JazzMinorScale('e4') | ||
jacobtylerwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
>>> [str(p) for p in sc.pitches] | ||
['E4', 'F#4', 'G4', 'A4', 'B4', 'C#5', 'D#5', 'E5'] | ||
>>> sc.getTonic() | ||
<music21.pitch.Pitch E4> | ||
>>> sc.getDominant() | ||
<music21.pitch.Pitch B4> | ||
>>> sc.pitchFromDegree(1) # scale degree 1 is treated as lowest | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. usually no need for comments in doc tests, write it as documentation just above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
To clarify, these comments are largely borrowed from other diatonic scales (mainly the harmonic minor) that I had used as a template. Should I rework the comments on these other scales as well? |
||
<music21.pitch.Pitch E4> | ||
>>> sc = scale.JazzMinorScale() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. space above and explain what's happening here. |
||
>>> sc.deriveRanked(['C', 'E', 'G'], comparisonAttribute='name') | ||
[(3, <music21.scale.JazzMinorScale G jazz minor>), | ||
(3, <music21.scale.JazzMinorScale F jazz minor>), | ||
(2, <music21.scale.JazzMinorScale B- jazz minor>), | ||
(2, <music21.scale.JazzMinorScale A jazz minor>)] | ||
''' | ||
|
||
def __init__(self, tonic=None): | ||
super().__init__(tonic=tonic) | ||
self.type = 'jazz minor' | ||
|
||
# note: this changes the previously assigned AbstractDiatonicScale | ||
# from the DiatonicScale base class | ||
|
||
self._abstract = AbstractJazzMinorScale() | ||
# network building happens on object creation | ||
# self._abstract.buildNetwork() | ||
jacobtylerwalls marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
class MelodicMinorScale(DiatonicScale): | ||
''' | ||
A melodic minor scale, which is not the same ascending or descending | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise, can you explain why this is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this code, an error message like this is given when using the getRelativeMinor/getRelativeMajor functions on the harmonic/melodic/jazz minor scales:
AttributeError: 'AbstractHarmonicMinorScale' object has no attribute 'relativeMinorDegree'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, got it, any of the non-natural minors, thanks. Yes, this should work because it's a method on
DiatonicScale
.Can we move these attribute assignments to
buildNetwork()
? That's where they seem to be in all other cases.