From 98f5bad1b1308d7389f4de7b1ac1675af3002c6f Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 02:45:05 +0000 Subject: [PATCH] fix: resolve discontinuous jumps in Trajectory ID 6 (yoyo) compute method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed segment index finding logic in id6() method that was causing sharp discontinuous frequency jumps in melodic contour visualizations - Replaced buggy loop with proper boundary logic that matches TypeScript findLastIndex behavior - Added bounds checking for relative x position within segments - Ensures smooth interpolation between multiple pitches using segmented half-cosine interpolation (id1) without discontinuities Fixes issue where trajectory ID 6 with 3 pitches [234.76, 274.41, 248.72] Hz produced 0.214 octave jumps instead of smooth transitions. Closes #6 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Jon Myers --- idtap/classes/trajectory.py | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/idtap/classes/trajectory.py b/idtap/classes/trajectory.py index 64c2feb..5d84144 100644 --- a/idtap/classes/trajectory.py +++ b/idtap/classes/trajectory.py @@ -627,20 +627,35 @@ def id6(self, x: float, lf: Optional[List[float]] = None, da: Optional[List[floa dur_array = da if da is not None else self.dur_array if dur_array is None: dur_array = [1/(len(log_freqs)-1)] * (len(log_freqs)-1) - bends = [lambda y, i=i: self.id1(y, log_freqs[i:i+2]) for i in range(len(log_freqs)-1)] - outs = [] - for i in range(len(log_freqs)-1): - dur_sum = sum(dur_array[:i]) - outs.append(lambda y, i=i: bends[i]((y - dur_sum)/dur_array[i])) + + # Get segment start points starts = get_starts(dur_array) + + # Find the correct segment index using proper boundary logic + # This matches the TypeScript findLastIndex behavior index = -1 - for i, s in enumerate(starts): - if x >= s: - index = i + for i in range(len(starts)): + if x >= starts[i]: + # Check if this is the last segment or if x is before the next segment start + if i == len(starts) - 1 or x < starts[i + 1]: + index = i + break + if index == -1: - print(outs, index) - raise Exception('index error') - return outs[index](x) + # Fallback for edge cases (x < 0) + index = 0 + + # Create the interpolation function for this segment + bend = lambda y: self.id1(y, log_freqs[index:index+2]) + + # Calculate the relative position within this segment + dur_sum = sum(dur_array[:index]) + relative_x = (x - dur_sum) / dur_array[index] + + # Ensure relative_x is within [0, 1] bounds + relative_x = max(0.0, min(1.0, relative_x)) + + return bend(relative_x) def id7(self, x: float, lf: Optional[List[float]] = None, da: Optional[List[float]] = None) -> float: log_freqs = lf or self.log_freqs