diff --git a/music21/key.py b/music21/key.py index c61c8e9f97..5cb21c166e 100644 --- a/music21/key.py +++ b/music21/key.py @@ -1078,7 +1078,7 @@ def deriveByDegree(self, degree, pitchRef): To use the harmonic form, change `.abstract` on the key to another abstract scale: - >>> minorKey.abstract = scale.AbstractHarmonicMinorScale() + >>> minorKey.abstract = key.Key(mode='harmonic minor').abstract >>> minorKey.deriveByDegree(7, 'E') >>> minorKey.deriveByDegree(6, 'G') diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py index 22e8273112..5879bf0457 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -50,14 +50,13 @@ 'TERMINUS_LOW', 'TERMINUS_HIGH', 'ScaleException', 'Scale', 'AbstractScale', 'AbstractDiatonicScale', 'AbstractOctatonicScale', - 'AbstractHarmonicMinorScale', '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', @@ -752,6 +751,22 @@ def buildNetwork(self, mode=None): intervalList = srcList[5:] + srcList[:5] # a to A self.relativeMajorDegree = 3 self.relativeMinorDegree = 1 + elif mode == 'harmonic minor': + intervalList = ['M2', 'm2', 'M2', 'M2', 'm2', 'A2', 'm2'] # a to A + self.relativeMajorDegree = 3 + self.relativeMinorDegree = 1 + elif mode == 'melodic minor': + self._net = intervalNetwork.IntervalNetwork( + octaveDuplicating=self.octaveDuplicating, + pitchSimplification=None) + self.relativeMajorDegree = 3 + self.relativeMinorDegree = 1 + self._net.fillMelodicMinor() + return + elif mode == 'jazz minor': + intervalList = ['M2', 'm2', 'M2', 'M2', 'M2', 'M2', 'm2'] # a to A + self.relativeMajorDegree = 3 + self.relativeMinorDegree = 1 elif mode == 'locrian': intervalList = srcList[6:] + srcList[:6] # b to B self.relativeMajorDegree = 2 @@ -842,58 +857,6 @@ def buildNetwork(self, mode=None): # might also set weights for tonic and dominant here -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. - ''' - - def __init__(self, mode=None): - super().__init__() - self.type = 'Abstract Harmonic Minor' - 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 seventh in all directions - # 7 here is scale step/degree, not node id - self._alteredDegrees[7] = { - 'direction': intervalNetwork.DIRECTION_BI, - 'interval': interval.Interval('a1') - } - - -class AbstractMelodicMinorScale(AbstractScale): - ''' - A directional scale. - ''' - - def __init__(self, mode=None): - super().__init__() - self.type = 'Abstract Melodic Minor' - self.octaveDuplicating = True - self.dominantDegree: int = -1 - self.buildNetwork() - - def buildNetwork(self): - self.tonicDegree = 1 - self.dominantDegree = 5 - self._net = intervalNetwork.IntervalNetwork( - octaveDuplicating=self.octaveDuplicating, - pitchSimplification=None) - self._net.fillMelodicMinor() - - class AbstractCyclicalScale(AbstractScale): ''' A scale of any size built with an interval list of any form. @@ -2729,7 +2692,7 @@ class HypophrygianScale(DiatonicScale): >>> sc.getDominant() - >>> sc.pitchFromDegree(1) # scale degree 1 is treated as lowest + >>> sc.pitchFromDegree(1) ''' def __init__(self, tonic=None): @@ -2830,9 +2793,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). + world, where the term "Harmonic Minor" would not be appropriate). >>> sc = scale.HarmonicMinorScale('e4') >>> [str(p) for p in sc.pitches] @@ -2841,7 +2804,7 @@ class HarmonicMinorScale(DiatonicScale): >>> sc.getDominant() - >>> sc.pitchFromDegree(1) # scale degree 1 is treated as lowest + >>> sc.pitchFromDegree(1) >>> sc = scale.HarmonicMinorScale() @@ -2856,12 +2819,7 @@ def __init__(self, tonic=None): super().__init__(tonic=tonic) self.type = 'harmonic minor' - # note: this changes the previously assigned AbstractDiatonicScale - # from the DiatonicScale base class - - self._abstract = AbstractHarmonicMinorScale() - # network building happens on object creation - # self._abstract.buildNetwork() + self._abstract.buildNetwork(self.type) class MelodicMinorScale(DiatonicScale): @@ -2875,9 +2833,38 @@ def __init__(self, tonic=None): super().__init__(tonic=tonic) self.type = 'melodic minor' - # note: this changes the previously assigned AbstractDiatonicScale - # from the DiatonicScale base class - self._abstract = AbstractMelodicMinorScale() + self._abstract.buildNetwork(self.type) + + +class JazzMinorScale(DiatonicScale): + ''' + The jazz minor scale. + + A synthetic scale identical to the ascending melodic minor. Useful in + jazz, especially over harmonies that employ minor-major seventh chords. + + >>> sc = scale.JazzMinorScale('e4') + >>> [str(p) for p in sc.pitches] + ['E4', 'F#4', 'G4', 'A4', 'B4', 'C#5', 'D#5', 'E5'] + >>> sc.getTonic() + + >>> sc.getDominant() + + >>> sc.pitchFromDegree(1) + + >>> sc = scale.JazzMinorScale() + >>> sc.deriveRanked(['C', 'E', 'G'], comparisonAttribute='name') + [(3, ), + (3, ), + (2, ), + (2, )] + ''' + + def __init__(self, tonic=None): + super().__init__(tonic=tonic) + self.type = 'jazz minor' + + self._abstract.buildNetwork(self.type) # ------------------------------------------------------------------------------