Skip to content
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

Make _dissonanceScore independent of octaves #1695

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions music21/pitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,10 @@ def _convertHarmonicToCents(value: int|float) -> int:
# -----------------------------------------------------------------------------


def _dissonanceScore(pitches, smallPythagoreanRatio=True, accidentalPenalty=True, triadAward=True):
def _dissonanceScore(pitches: list[Pitch],
smallPythagoreanRatio: bool = True,
accidentalPenalty: bool = True,
triadAward: bool = True):
r'''
Calculates the 'dissonance' of a list of pitches based on three criteria:
it is considered more consonant if 1. the numerator and denominator of the
Expand All @@ -575,17 +578,20 @@ def _dissonanceScore(pitches, smallPythagoreanRatio=True, accidentalPenalty=True

if smallPythagoreanRatio or triadAward:
try:
intervals = [interval.Interval(noteStart=p1, noteEnd=p2)
for p1, p2 in itertools.combinations(pitches, 2)]
intervals = []
for p1, p2 in itertools.combinations(pitches, 2):
p2 = copy.deepcopy(p2)
p2.octave = None
this_interval = interval.Interval(noteStart=p1, noteEnd=p2)
intervals.append(this_interval)
except interval.IntervalException:
return math.inf
if smallPythagoreanRatio:
# score_ratio = Pythagorean ratio complexity per pitch
for this_interval in intervals:
# does not accept weird intervals, e.g. with semitones
ratio = interval.intervalToPythagoreanRatio(this_interval)
# d2 is 1.0
penalty = math.log(ratio.numerator * ratio.denominator / ratio) * 0.03792663444
penalty = math.log(ratio.denominator) * 0.07585326888
score_ratio += penalty

score_ratio /= len(pitches)
Expand All @@ -605,7 +611,7 @@ def _dissonanceScore(pitches, smallPythagoreanRatio=True, accidentalPenalty=True
+ accidentalPenalty + triadAward)


def _bruteForceEnharmonicsSearch(oldPitches, scoreFunc=_dissonanceScore):
def _bruteForceEnharmonicsSearch(oldPitches: list[Pitch], scoreFunc=_dissonanceScore):
'''
A brute-force way of simplifying -- useful if there are fewer than 5 pitches
'''
Expand All @@ -615,7 +621,7 @@ def _bruteForceEnharmonicsSearch(oldPitches, scoreFunc=_dissonanceScore):
return oldPitches[:1] + list(newPitches)


def _greedyEnharmonicsSearch(oldPitches, scoreFunc=_dissonanceScore):
def _greedyEnharmonicsSearch(oldPitches: list[Pitch], scoreFunc=_dissonanceScore):
newPitches = oldPitches[:1]
for oldPitch in oldPitches[1:]:
candidates = [oldPitch] + oldPitch.getAllCommonEnharmonics()
Expand Down
Loading