From 2c25c5d75afd935a14e2eff20d081c2e153fb426 Mon Sep 17 00:00:00 2001 From: hill Date: Wed, 23 Sep 2026 11:57:59 +0200 Subject: [PATCH] Check a descending range against the altered pitch realizeAscending decides whether a pitch is in range by the pitch it collects, alteration applied; realizeDescending decided by the pitch before alteration. So coming down, harmonic minor's raised seventh was judged by the lowered one: left out where it belongs and let in where it does not. >>> sc = scale.HarmonicMinorScale('c4') >>> sc.getPitches('b2', 'e3', direction=scale.Direction.DESCENDING) [, , ] >>> sc = scale.HarmonicMinorScale('b-3') >>> sc.getPitches('c#4', 'g#4', direction=scale.Direction.DESCENDING)[0] Compare the collected pitch, as realizeAscending does. --- music21/scale/intervalNetwork.py | 10 +++++----- music21/scale/test_scale_main.py | 11 ++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/music21/scale/intervalNetwork.py b/music21/scale/intervalNetwork.py index d7e97b2ad..ee2ee0ef3 100644 --- a/music21/scale/intervalNetwork.py +++ b/music21/scale/intervalNetwork.py @@ -5,7 +5,7 @@ # Authors: Christopher Ariza # Michael Scott Asato Cuthbert # -# Copyright: Copyright © 2010-2023 Michael Scott Asato Cuthbert +# Copyright: Copyright © 2010-2026 Michael Scott Asato Cuthbert # License: BSD, see license.txt # ------------------------------------------------------------------------------ ''' @@ -1739,16 +1739,16 @@ def realizeDescending( while True: appendPitch = False if (minPitchObj is not None - and _gte(p.ps, minPitchObj.ps) + and _gte(pCollect.ps, minPitchObj.ps) and maxPitchObj is not None - and _lte(p.ps, maxPitchObj.ps)): + and _lte(pCollect.ps, maxPitchObj.ps)): appendPitch = True elif (minPitchObj is not None - and _gte(p.ps, minPitchObj.ps) + and _gte(pCollect.ps, minPitchObj.ps) and maxPitchObj is None): appendPitch = True elif (maxPitchObj is not None - and _lte(p.ps, maxPitchObj.ps) + and _lte(pCollect.ps, maxPitchObj.ps) and minPitchObj is None): appendPitch = True elif minPitchObj is None and maxPitchObj is None: diff --git a/music21/scale/test_scale_main.py b/music21/scale/test_scale_main.py index ded1bd6d9..457801de2 100644 --- a/music21/scale/test_scale_main.py +++ b/music21/scale/test_scale_main.py @@ -5,7 +5,7 @@ # Authors: Christopher Ariza # Michael Scott Asato Cuthbert # -# Copyright: Copyright © 2010-2024 Michael Scott Asato Cuthbert +# Copyright: Copyright © 2010-2026 Michael Scott Asato Cuthbert # License: BSD, see license.txt # ------------------------------------------------------------------------------ from __future__ import annotations @@ -272,6 +272,15 @@ def testCyclicalScales(self): sc2 = scale.CyclicalScale() self.assertEqual(self.pitchOut(sc2.getPitches()), '[C4, D-4]') + def testHarmonicMinorDescendingRange(self): + sc = scale.HarmonicMinorScale('c4') + descending = sc.getPitches('b2', 'e3', direction=Direction.DESCENDING) + self.assertEqual(self.pitchOut(descending), '[E-3, D3, C3, B2]') + + sc = scale.HarmonicMinorScale('b-3') + descending = sc.getPitches('c#4', 'g#4', direction=Direction.DESCENDING) + self.assertEqual(self.pitchOut(descending), '[G-4, F4, E-4, D-4]') + def testDeriveByDegree(self): sc1 = scale.MajorScale() self.assertEqual(str(sc1.deriveByDegree(7, 'G#')),