Refine melodic threshold to continuous scoring
- Use continuous scoring instead of binary pass/fail - Below min: score = (cents / min)^2 - Above max: score = ((1200 - cents) / (1200 - max))^2 - Use product across voices to penalize worst offenders
This commit is contained in:
parent
1926930c3d
commit
1eb95ffad7
35
src/graph.py
35
src/graph.py
|
|
@ -274,23 +274,36 @@ class PathFinder:
|
||||||
}
|
}
|
||||||
|
|
||||||
def _factor_melodic_threshold(self, edge_data: dict, config: dict) -> float:
|
def _factor_melodic_threshold(self, edge_data: dict, config: dict) -> float:
|
||||||
"""Returns 1.0 if all voice movements are within melodic threshold, 0.0 otherwise."""
|
"""Returns continuous score based on melodic threshold.
|
||||||
# Check weight - if 0, return 1.0 (neutral)
|
|
||||||
if config.get("weight_melodic", 1) == 0:
|
|
||||||
return 1.0
|
|
||||||
|
|
||||||
|
- cents == 0: score = 1.0 (no movement is always ideal)
|
||||||
|
- Below min (0 < cents < min): score = (cents / min)^2
|
||||||
|
- Within range (min <= cents <= max): score = 1.0
|
||||||
|
- Above max (cents > max): score = ((1200 - cents) / (1200 - max))^2
|
||||||
|
|
||||||
|
Returns product of all voice scores.
|
||||||
|
"""
|
||||||
melodic_min = config.get("melodic_threshold_min", 0)
|
melodic_min = config.get("melodic_threshold_min", 0)
|
||||||
melodic_max = config.get("melodic_threshold_max", float("inf"))
|
melodic_max = config.get("melodic_threshold_max", float("inf"))
|
||||||
|
|
||||||
cent_diffs = edge_data.get("cent_diffs", [])
|
cent_diffs = edge_data.get("cent_diffs", [])
|
||||||
|
|
||||||
if melodic_min is not None or melodic_max is not None:
|
if not cent_diffs:
|
||||||
for cents in cent_diffs:
|
return 1.0
|
||||||
if melodic_min is not None and cents < melodic_min:
|
|
||||||
return 0.0
|
product = 1.0
|
||||||
if melodic_max is not None and cents > melodic_max:
|
for cents in cent_diffs:
|
||||||
return 0.0
|
if cents == 0:
|
||||||
return 1.0
|
score = 1.0
|
||||||
|
elif cents < melodic_min:
|
||||||
|
score = (cents / melodic_min) ** 2
|
||||||
|
elif cents > melodic_max:
|
||||||
|
score = ((1200 - cents) / (1200 - melodic_max)) ** 2
|
||||||
|
else:
|
||||||
|
score = 1.0
|
||||||
|
product *= score
|
||||||
|
|
||||||
|
return product
|
||||||
|
|
||||||
def _factor_direct_tuning(self, edge_data: dict, config: dict) -> float:
|
def _factor_direct_tuning(self, edge_data: dict, config: dict) -> float:
|
||||||
"""Returns 1.0 if directly tunable (or disabled), 0.0 otherwise."""
|
"""Returns 1.0 if directly tunable (or disabled), 0.0 otherwise."""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue