Rename 'target range' to 'target register' throughout
- CLI: --target-range -> --target-register - CLI: --weight-target-range -> --weight-target-register - Config keys: target_range -> target_register - Update README, tests, and all internal references
This commit is contained in:
parent
24709c3eda
commit
e4b6d2cfdc
10
README.md
10
README.md
|
|
@ -41,7 +41,7 @@ These constraints weigh edges. Set weight to 0 to disable.
|
|||
--weight-contrary-motion N Weight for contrary motion (default: 0, 0=off)
|
||||
--weight-dca-hamiltonian N Weight for visiting unvisited nodes (default: 1, 0=off)
|
||||
--weight-dca-voice-movement N Weight for moving voices (default: 1, 0=off)
|
||||
--weight-target-range N Weight for target register (default: 1, 0=off)
|
||||
--weight-target-register N Weight for target register (default: 1, 0=off)
|
||||
|
||||
### Melodic Range
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ These constraints weigh edges. Set weight to 0 to disable.
|
|||
|
||||
### Target Register
|
||||
|
||||
--target-range N Target register in octaves (default: disabled, 2 = 2 octaves rise)
|
||||
--target-register N Target register in octaves (default: disabled, 2 = 2 octaves rise)
|
||||
|
||||
### Output Options
|
||||
|
||||
|
|
@ -93,10 +93,10 @@ The average pitch of all voices should rise toward the target (specified in octa
|
|||
python -m src.io
|
||||
|
||||
# Rising register to 2 octaves
|
||||
python -m src.io --target-range 2
|
||||
python -m src.io --target-register 2
|
||||
|
||||
# Heavy target range, no DCA voice movement
|
||||
python -m src.io --target-range 2 --weight-target-range 10 --weight-dca-voice-movement 0
|
||||
# Heavy target register, no DCA voice movement
|
||||
python -m src.io --target-register 2 --weight-target-register 10 --weight-dca-voice-movement 0
|
||||
|
||||
# Disable DCA Hamiltonian (allow revisiting nodes freely)
|
||||
python -m src.io --weight-dca-hamiltonian 0
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ def analyze_chords(
|
|||
Args:
|
||||
chords: List of chords, each chord is a list of pitch dicts
|
||||
config: Optional config with:
|
||||
- target_range_octaves: target octaves (default: 2.0)
|
||||
- target_register_octaves: target octaves (default: 2.0)
|
||||
- melodic_threshold_max: max cents per voice movement (default: 300)
|
||||
- max_path: path length (default: 50)
|
||||
- graph_nodes: total nodes in graph (optional, for Hamiltonian coverage)
|
||||
|
|
@ -27,7 +27,7 @@ def analyze_chords(
|
|||
if config is None:
|
||||
config = {}
|
||||
|
||||
target_octaves = config.get("target_range_octaves", 2.0)
|
||||
target_octaves = config.get("target_register_octaves", 2.0)
|
||||
melodic_max = config.get("melodic_threshold_max", 300)
|
||||
max_path = config.get("max_path", 50)
|
||||
graph_nodes = config.get("graph_nodes", None)
|
||||
|
|
@ -114,7 +114,7 @@ def analyze_chords(
|
|||
else:
|
||||
voice_stay_counts[v] += 1 # Increment stay count
|
||||
|
||||
# ========== Target Range ==========
|
||||
# ========== Target Register ==========
|
||||
target_cents = target_octaves * 1200
|
||||
|
||||
if chords:
|
||||
|
|
@ -167,7 +167,7 @@ def analyze_chords(
|
|||
# Hamiltonian
|
||||
"hamiltonian_unique_nodes": hamiltonian_unique_nodes,
|
||||
"hamiltonian_coverage": hamiltonian_coverage,
|
||||
# Target Range
|
||||
# Target Register
|
||||
"target_octaves": target_octaves,
|
||||
"target_cents": target_cents,
|
||||
"target_start_cents": start_avg,
|
||||
|
|
@ -209,7 +209,7 @@ def format_analysis(metrics: dict) -> str:
|
|||
lines.extend(
|
||||
[
|
||||
"",
|
||||
"--- Target Range ---",
|
||||
"--- Target Register ---",
|
||||
f"Target: {metrics['target_octaves']} octaves ({metrics['target_cents']:.0f} cents)",
|
||||
f"Start: {metrics['target_start_cents']:.0f} cents",
|
||||
f"End: {metrics['target_end_cents']:.0f} cents",
|
||||
|
|
@ -250,10 +250,10 @@ def main():
|
|||
help="Output raw JSON instead of formatted text",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target-range",
|
||||
"--target-register",
|
||||
type=float,
|
||||
default=2.0,
|
||||
help="Target range in octaves (default: 2.0)",
|
||||
help="Target register in octaves (default: 2.0)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--melodic-max",
|
||||
|
|
@ -281,7 +281,7 @@ def main():
|
|||
return 1
|
||||
|
||||
config = {
|
||||
"target_range_octaves": args.target_range,
|
||||
"target_register_octaves": args.target_register,
|
||||
"melodic_threshold_max": args.melodic_max,
|
||||
"max_path": args.max_path,
|
||||
"graph_nodes": args.graph_nodes,
|
||||
|
|
|
|||
22
src/io.py
22
src/io.py
|
|
@ -274,10 +274,10 @@ def main():
|
|||
help="Maximum cents for any pitch movement (0 = no maximum)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target-range",
|
||||
"--target-register",
|
||||
type=float,
|
||||
default=0,
|
||||
help="Target range in octaves for rising register (default: disabled, 2 = two octaves)",
|
||||
help="Target register in octaves (default: disabled, 2 = two octaves)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--allow-voice-crossing",
|
||||
|
|
@ -314,10 +314,10 @@ def main():
|
|||
help="Weight for DCA voice movement factor - favors voices that stay long to change (0=disabled, default: 1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--weight-target-range",
|
||||
"--weight-target-register",
|
||||
type=float,
|
||||
default=1,
|
||||
help="Weight for target range factor (0=disabled, default: 1)",
|
||||
help="Weight for target register factor (0=disabled, default: 1)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dims", type=int, default=7, help="Number of prime dimensions (4, 5, 7, or 8)"
|
||||
|
|
@ -437,13 +437,13 @@ def main():
|
|||
weights_config["weight_dca_hamiltonian"] = args.weight_dca_hamiltonian
|
||||
weights_config["weight_dca_voice_movement"] = args.weight_dca_voice_movement
|
||||
|
||||
# Target range
|
||||
if args.target_range > 0:
|
||||
weights_config["target_range"] = True
|
||||
weights_config["target_range_octaves"] = args.target_range
|
||||
weights_config["weight_target_range"] = args.weight_target_range
|
||||
# Target register
|
||||
if args.target_register > 0:
|
||||
weights_config["target_register"] = True
|
||||
weights_config["target_register_octaves"] = args.target_register
|
||||
weights_config["weight_target_register"] = args.weight_target_register
|
||||
else:
|
||||
weights_config["weight_target_range"] = 0 # disabled
|
||||
weights_config["weight_target_register"] = 0 # disabled
|
||||
|
||||
weights_config["max_path"] = args.max_path
|
||||
|
||||
|
|
@ -487,7 +487,7 @@ def main():
|
|||
|
||||
config = {
|
||||
"melodic_threshold_max": args.melodic_max,
|
||||
"target_range_octaves": args.target_range,
|
||||
"target_register_octaves": args.target_register,
|
||||
"max_path": args.max_path,
|
||||
"graph_nodes": graph.number_of_nodes() if graph else None,
|
||||
}
|
||||
|
|
|
|||
24
src/path.py
24
src/path.py
|
|
@ -131,7 +131,7 @@ class Path:
|
|||
sustain_before,
|
||||
self.weights_config,
|
||||
),
|
||||
"target_range": self._factor_target_range(
|
||||
"target_register": self._factor_target_register(
|
||||
path_chords,
|
||||
destination_chord,
|
||||
self.weights_config,
|
||||
|
|
@ -185,7 +185,7 @@ class Path:
|
|||
contrary_values = [c.scores.get("contrary_motion", 0) for c in candidates]
|
||||
hamiltonian_values = [c.scores.get("dca_hamiltonian", 0) for c in candidates]
|
||||
dca_values = [c.scores.get("dca_voice_movement", 0) for c in candidates]
|
||||
target_values = [c.scores.get("target_range", 0) for c in candidates]
|
||||
target_values = [c.scores.get("target_register", 0) for c in candidates]
|
||||
|
||||
def sum_normalize(values: list) -> list | None:
|
||||
"""Normalize values to sum to 1. Returns None if no discrimination."""
|
||||
|
|
@ -226,7 +226,7 @@ class Path:
|
|||
if dca_norm:
|
||||
w *= dca_norm[i] * config.get("weight_dca_voice_movement", 1)
|
||||
if target_norm:
|
||||
w *= target_norm[i] * config.get("weight_target_range", 1)
|
||||
w *= target_norm[i] * config.get("weight_target_register", 1)
|
||||
|
||||
step.weight = w**16
|
||||
weights.append(w)
|
||||
|
|
@ -237,7 +237,7 @@ class Path:
|
|||
"contrary_motion": contrary_norm[i] if contrary_norm else None,
|
||||
"dca_hamiltonian": hamiltonian_norm[i] if hamiltonian_norm else None,
|
||||
"dca_voice_movement": dca_norm[i] if dca_norm else None,
|
||||
"target_range": target_norm[i] if target_norm else None,
|
||||
"target_register": target_norm[i] if target_norm else None,
|
||||
}
|
||||
|
||||
return weights
|
||||
|
|
@ -350,23 +350,23 @@ class Path:
|
|||
|
||||
return sum_changing
|
||||
|
||||
def _factor_target_range(
|
||||
def _factor_target_register(
|
||||
self,
|
||||
path_chords: list[Chord],
|
||||
destination_chord: Chord,
|
||||
config: dict,
|
||||
) -> float:
|
||||
"""Returns factor based on movement toward target."""
|
||||
if config.get("weight_target_range", 1) == 0:
|
||||
if config.get("weight_target_register", 1) == 0:
|
||||
return 1.0
|
||||
|
||||
if not config.get("target_range", False):
|
||||
if not config.get("target_register", False):
|
||||
return 1.0
|
||||
|
||||
if len(path_chords) == 0:
|
||||
return 1.0
|
||||
|
||||
target_octaves = config.get("target_range_octaves", 2.0)
|
||||
target_octaves = config.get("target_register_octaves", 2.0)
|
||||
max_path = config.get("max_path", 50)
|
||||
target_cents = target_octaves * 1200
|
||||
|
||||
|
|
@ -463,14 +463,14 @@ class Path:
|
|||
"contrary_motion": 0.0,
|
||||
"dca_hamiltonian": 0.0,
|
||||
"dca_voice_movement": 0.0,
|
||||
"target_range": 0.0,
|
||||
"target_register": 0.0,
|
||||
}
|
||||
|
||||
w_melodic = weights.get("weight_melodic", 1)
|
||||
w_contrary = weights.get("weight_contrary_motion", 0)
|
||||
w_hamiltonian = weights.get("weight_dca_hamiltonian", 1)
|
||||
w_dca = weights.get("weight_dca_voice_movement", 1)
|
||||
w_target = weights.get("weight_target_range", 1)
|
||||
w_target = weights.get("weight_target_register", 1)
|
||||
|
||||
for step in self.steps:
|
||||
norm = step.normalized_scores
|
||||
|
|
@ -485,6 +485,8 @@ class Path:
|
|||
influence["dca_voice_movement"] += (
|
||||
norm.get("dca_voice_movement") or 0
|
||||
) * w_dca
|
||||
influence["target_range"] += (norm.get("target_range") or 0) * w_target
|
||||
influence["target_register"] += (
|
||||
norm.get("target_register") or 0
|
||||
) * w_target
|
||||
|
||||
return influence
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ class PathFinder:
|
|||
"melodic_threshold_max": 500,
|
||||
"hamiltonian": True,
|
||||
"dca": 2.0,
|
||||
"target_range": False,
|
||||
"target_range_octaves": 2.0,
|
||||
"target_register": False,
|
||||
"target_register_octaves": 2.0,
|
||||
}
|
||||
|
||||
def is_hamiltonian(self, path: list["Chord"]) -> bool:
|
||||
|
|
|
|||
|
|
@ -199,8 +199,8 @@ class TestCLI:
|
|||
# For now just verify the module can be imported
|
||||
assert main is not None
|
||||
|
||||
def test_target_range_weight(self):
|
||||
"""Test that target range weight can be enabled and influences path generation."""
|
||||
def test_target_register_weight(self):
|
||||
"""Test that target register weight can be enabled and influences path generation."""
|
||||
from src.harmonic_space import HarmonicSpace
|
||||
from src.pathfinder import PathFinder
|
||||
|
||||
|
|
@ -210,17 +210,17 @@ class TestCLI:
|
|||
|
||||
path_finder = PathFinder(graph)
|
||||
|
||||
# Test with target range disabled (default)
|
||||
# Test with target register disabled (default)
|
||||
config_no_target = path_finder._default_weights_config()
|
||||
assert config_no_target.get("target_range") is False
|
||||
assert config_no_target.get("target_register") is False
|
||||
|
||||
# Test with target range enabled
|
||||
# Test with target register enabled
|
||||
config_target = path_finder._default_weights_config()
|
||||
config_target["target_range"] = True
|
||||
config_target["target_range_octaves"] = 2.0
|
||||
config_target["target_register"] = True
|
||||
config_target["target_register_octaves"] = 2.0
|
||||
|
||||
assert config_target.get("target_range") is True
|
||||
assert config_target.get("target_range_octaves") == 2.0
|
||||
assert config_target.get("target_register") is True
|
||||
assert config_target.get("target_register_octaves") == 2.0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Reference in a new issue