From 3e0f2bc90645ad9f0beee41e2bee1a0a4b03013b Mon Sep 17 00:00:00 2001 From: Michael Winter Date: Mon, 30 Mar 2026 20:47:20 +0200 Subject: [PATCH] Add target register oscillations, amplitude, and fix negative target_register --- src/io.py | 20 ++++++++++++++++++-- src/path.py | 12 +++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/io.py b/src/io.py index 980583d..bfe7a9d 100644 --- a/src/io.py +++ b/src/io.py @@ -369,7 +369,7 @@ def main(): "--target-register", type=float, default=0, - help="Target register in octaves (default: disabled, 2 = two octaves)", + help="Target register in octaves (default: disabled, 2 = rise 2 octaves, -2 = fall 2 octaves)", ) parser.add_argument( "--target-register-power", @@ -377,6 +377,18 @@ def main(): default=1.0, help="Power to curve target register progress (1=linear, 2=quadratic, etc.)", ) + parser.add_argument( + "--target-register-oscillations", + type=float, + default=0, + help="Number of sine wave oscillations for target register modulation (0=linear)", + ) + parser.add_argument( + "--target-register-amplitude", + type=float, + default=0.25, + help="Amplitude of sine wave modulation for target register", + ) parser.add_argument( "--allow-voice-crossing", action="store_true", @@ -649,11 +661,15 @@ def main(): weights_config["weight_dca_voice_movement"] = args.weight_dca_voice_movement # Target register - if args.target_register > 0: + 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 weights_config["target_register_power"] = args.target_register_power + weights_config["target_register_oscillations"] = ( + args.target_register_oscillations + ) + weights_config["target_register_amplitude"] = args.target_register_amplitude else: weights_config["weight_target_register"] = 0 # disabled diff --git a/src/path.py b/src/path.py index cd730da..9d58e7b 100644 --- a/src/path.py +++ b/src/path.py @@ -6,6 +6,7 @@ Path and PathStep classes for storing path state from PathFinder. from __future__ import annotations from dataclasses import dataclass, field from typing import Any +import math from .pitch import Pitch from .chord import Chord @@ -378,6 +379,14 @@ class Path: ) progress = len(path_chords) / max_path progress_curve = progress**power + + oscillations = config.get("target_register_oscillations", 0) + amplitude = config.get("target_register_amplitude", 0.25) + if oscillations > 0: + sine_wave = math.sin(progress_curve * 2 * math.pi * oscillations) + modulation = amplitude * sine_wave + progress_curve = max(0, progress_curve + modulation) + current_target = start_avg_cents + (progress_curve * target_cents) current_chord = path_chords[-1] @@ -389,9 +398,6 @@ class Path: p.to_cents() for p in destination_chord.pitches ) / len(destination_chord.pitches) - if current_target <= 0: - return 1.0 - dist_before = abs(current_avg_cents - current_target) dist_after = abs(candidate_avg_cents - current_target)