From 4c6a6d6d4a490492cc0c3e956964598e47662dd8 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 24 Jun 2021 20:06:39 -0400 Subject: [PATCH 1/4] Implemented jazz minor scale and expanded relative key functionality --- music21/scale/__init__.py | 103 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 5 deletions(-) diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py index 22e8273112..b3a2553509 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -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) + + +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) + 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). + 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. + >>> 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) # scale degree 1 is treated as lowest + + >>> 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' + + # note: this changes the previously assigned AbstractDiatonicScale + # from the DiatonicScale base class + + self._abstract = AbstractJazzMinorScale() + # network building happens on object creation + # self._abstract.buildNetwork() + + class MelodicMinorScale(DiatonicScale): ''' A melodic minor scale, which is not the same ascending or descending From 83498f031b5d3ac0a0dcbb1cfe80689384290c0f Mon Sep 17 00:00:00 2001 From: Phantasmogenesis <65755354+Phantasmogenesis@users.noreply.github.com> Date: Fri, 25 Jun 2021 15:13:18 -0400 Subject: [PATCH 2/4] Update __init__.py Added description to jazz minor scale, rearranged so harmonic minor and melodic minor would be directly adjacent, and removed certain unnecessary comments. --- music21/scale/__init__.py | 99 +++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py index b3a2553509..5e7cab8a2c 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -882,6 +882,35 @@ def getRelativeMinor(self): return MinorScale(self.tonic) +class AbstractMelodicMinorScale(AbstractScale): + ''' + A directional scale. + ''' + + 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() + + def buildNetwork(self): + self.tonicDegree = 1 + self.dominantDegree = 5 + self._net = intervalNetwork.IntervalNetwork( + octaveDuplicating=self.octaveDuplicating, + pitchSimplification=None) + self._net.fillMelodicMinor() + + def getRelativeMajor(self): + return MajorScale(self.tonic) + + def getRelativeMinor(self): + return MinorScale(self.tonic) + + class AbstractJazzMinorScale(AbstractScale): ''' A true bi-directional scale containing the raised @@ -926,35 +955,7 @@ def getRelativeMajor(self): def getRelativeMinor(self): return MinorScale(self.tonic) - -class AbstractMelodicMinorScale(AbstractScale): - ''' - A directional scale. - ''' - - 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() - - def buildNetwork(self): - self.tonicDegree = 1 - self.dominantDegree = 5 - self._net = intervalNetwork.IntervalNetwork( - octaveDuplicating=self.octaveDuplicating, - pitchSimplification=None) - self._net.fillMelodicMinor() - - def getRelativeMajor(self): - return MajorScale(self.tonic) - - def getRelativeMinor(self): - return MinorScale(self.tonic) - + class AbstractCyclicalScale(AbstractScale): ''' A scale of any size built with an interval list of any form. @@ -2925,9 +2926,28 @@ def __init__(self, tonic=None): # self._abstract.buildNetwork() +class MelodicMinorScale(DiatonicScale): + ''' + A melodic minor scale, which is not the same ascending or descending + + >>> sc = scale.MelodicMinorScale('e4') + ''' + + 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() + + 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'] @@ -2949,28 +2969,7 @@ 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() - - -class MelodicMinorScale(DiatonicScale): - ''' - A melodic minor scale, which is not the same ascending or descending - - >>> sc = scale.MelodicMinorScale('e4') - ''' - - 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() # ------------------------------------------------------------------------------ From 6b88cbbe87fcf2c8e81a7effd1a243c22e1b952b Mon Sep 17 00:00:00 2001 From: Phantasmogenesis <65755354+Phantasmogenesis@users.noreply.github.com> Date: Sat, 26 Jun 2021 19:57:06 -0400 Subject: [PATCH 3/4] Implemented all minor scales as DiatonicScales and fixed problematic typographical errors --- music21/scale/__init__.py | 157 +++++++------------------------------- 1 file changed, 26 insertions(+), 131 deletions(-) diff --git a/music21/scale/__init__.py b/music21/scale/__init__.py index 5e7cab8a2c..1a127f632f 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -50,7 +50,6 @@ 'TERMINUS_LOW', 'TERMINUS_HIGH', 'ScaleException', 'Scale', 'AbstractScale', 'AbstractDiatonicScale', 'AbstractOctatonicScale', - 'AbstractHarmonicMinorScale', 'AbstractJazzMinorScale', 'AbstractMelodicMinorScale', 'AbstractCyclicalScale', 'AbstractOctaveRepeatingScale', 'AbstractRagAsawari', 'AbstractRagMarwa', 'AbstractWeightedHexatonicBlues', 'ConcreteScale', 'DiatonicScale', 'MajorScale', @@ -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 = srcList[5:] + srcList[:5] # 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,120 +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. - - 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() - - 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') - } - - def getRelativeMajor(self): - return MajorScale(self.tonic) - - def getRelativeMinor(self): - return MinorScale(self.tonic) - - -class AbstractMelodicMinorScale(AbstractScale): - ''' - A directional scale. - ''' - - 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() - - def buildNetwork(self): - self.tonicDegree = 1 - self.dominantDegree = 5 - self._net = intervalNetwork.IntervalNetwork( - octaveDuplicating=self.octaveDuplicating, - pitchSimplification=None) - self._net.fillMelodicMinor() - - def getRelativeMajor(self): - return MajorScale(self.tonic) - - def getRelativeMinor(self): - return MinorScale(self.tonic) - - -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) - - class AbstractCyclicalScale(AbstractScale): ''' A scale of any size built with an interval list of any form. @@ -2791,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): @@ -2903,7 +2804,7 @@ class HarmonicMinorScale(DiatonicScale): >>> sc.getDominant() - >>> sc.pitchFromDegree(1) # scale degree 1 is treated as lowest + >>> sc.pitchFromDegree(1) >>> sc = scale.HarmonicMinorScale() @@ -2918,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): @@ -2937,17 +2833,16 @@ 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'] @@ -2955,7 +2850,7 @@ class JazzMinorScale(DiatonicScale): >>> sc.getDominant() - >>> sc.pitchFromDegree(1) # scale degree 1 is treated as lowest + >>> sc.pitchFromDegree(1) >>> sc = scale.JazzMinorScale() >>> sc.deriveRanked(['C', 'E', 'G'], comparisonAttribute='name') @@ -2969,7 +2864,7 @@ def __init__(self, tonic=None): super().__init__(tonic=tonic) self.type = 'jazz minor' - self._abstract = AbstractJazzMinorScale() + self._abstract.buildNetwork(self.type) # ------------------------------------------------------------------------------ From 48c3695fdd6f237dd16d6c0350b081a35d38d4f4 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 28 Jun 2021 12:08:56 -0400 Subject: [PATCH 4/4] Fixed harmonic minor scale and changed abstract scale usage --- music21/key.py | 2 +- music21/scale/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 1a127f632f..5879bf0457 100644 --- a/music21/scale/__init__.py +++ b/music21/scale/__init__.py @@ -752,7 +752,7 @@ def buildNetwork(self, mode=None): self.relativeMajorDegree = 3 self.relativeMinorDegree = 1 elif mode == 'harmonic minor': - intervalList = srcList[5:] + srcList[:5] # a to A + intervalList = ['M2', 'm2', 'M2', 'M2', 'm2', 'A2', 'm2'] # a to A self.relativeMajorDegree = 3 self.relativeMinorDegree = 1 elif mode == 'melodic minor':