Fix transcriber to compute ref and dim_diff from chord data
- Add _is_adjacent() to check if pitches differ by ±1 in one dimension - Add _compute_dim_diff() to compute prime * direction for dimension changes - Add _find_ref_and_dim_diff() to find the ref voice and dim_diff for changed pitches - Update output_chords_to_music_data() to compute ref and dim_diff by comparing consecutive chords - Update format_dim_diff() to include dim_diff == 0 check and fix ref mapping for 4 voices
This commit is contained in:
parent
d0bd15574d
commit
658837b83e
|
|
@ -155,7 +155,7 @@ def format_cents_deviation(freq):
|
|||
|
||||
def format_dim_diff(dim_diff, ref):
|
||||
"""Format dimensional difference markup."""
|
||||
if dim_diff is None or ref is None or ref < 0:
|
||||
if dim_diff is None or ref is None or ref < 0 or dim_diff == 0:
|
||||
return ""
|
||||
|
||||
diff_str = str(abs(dim_diff))
|
||||
|
|
@ -164,7 +164,8 @@ def format_dim_diff(dim_diff, ref):
|
|||
elif dim_diff < 0:
|
||||
diff_str += "↓"
|
||||
|
||||
ref_name = ["III", "II", "I"][ref] if 0 <= ref <= 2 else ""
|
||||
ref_names = ["IV", "III", "II", "I"]
|
||||
ref_name = ref_names[ref] if 0 <= ref <= 3 else ""
|
||||
|
||||
return f'_\\markup {{ \\lower #3 \\pad-markup #0.2 \\concat{{ "{ref_name}"\\normal-size-super " {diff_str}" }} }}'
|
||||
|
||||
|
|
@ -332,6 +333,60 @@ def generate_parts(music_data, name, output_dir="lilypond"):
|
|||
print(f"Generated: {part_file}")
|
||||
|
||||
|
||||
def _is_adjacent(hs1: tuple, hs2: tuple) -> bool:
|
||||
"""Check if two hs_arrays are adjacent (differ by ±1 in exactly one dimension, excluding dim 0)."""
|
||||
diff_count = 0
|
||||
for i in range(1, len(hs1)):
|
||||
diff = abs(hs1[i] - hs2[i])
|
||||
if diff > 1:
|
||||
return False
|
||||
if diff == 1:
|
||||
diff_count += 1
|
||||
return diff_count == 1
|
||||
|
||||
|
||||
def _compute_dim_diff(current: tuple, prev: tuple) -> int:
|
||||
"""Compute dim_diff between two hs_arrays. Returns prime * direction."""
|
||||
primes = [3, 5, 7]
|
||||
for i in range(1, 4):
|
||||
diff = current[i] - prev[i]
|
||||
if diff == 1:
|
||||
return primes[i - 1]
|
||||
if diff == -1:
|
||||
return -primes[i - 1]
|
||||
return 0
|
||||
|
||||
|
||||
def _find_ref_and_dim_diff(
|
||||
current_hs: tuple, prev_chord: list, staying_voices: list
|
||||
) -> tuple[int, int]:
|
||||
"""Find ref (staying voice index) and dim_diff for a changed pitch.
|
||||
|
||||
Args:
|
||||
current_hs: hs_array of current pitch
|
||||
prev_chord: list of hs_arrays from previous chord
|
||||
staying_voices: indices of voices that stay
|
||||
|
||||
Returns:
|
||||
(ref, dim_diff) tuple
|
||||
"""
|
||||
if not staying_voices:
|
||||
return -1, 0
|
||||
|
||||
adjacent = []
|
||||
for idx in staying_voices:
|
||||
prev_hs = prev_chord[idx]
|
||||
if _is_adjacent(current_hs, prev_hs):
|
||||
dim_diff = _compute_dim_diff(current_hs, prev_hs)
|
||||
adjacent.append((idx, dim_diff))
|
||||
|
||||
if not adjacent:
|
||||
return -1, 0
|
||||
|
||||
adjacent.sort(key=lambda x: abs(x[1]))
|
||||
return adjacent[0]
|
||||
|
||||
|
||||
def output_chords_to_music_data(chords, fundamental=55, chord_duration=4):
|
||||
"""Convert output_chords.json format to generic music data.
|
||||
|
||||
|
|
@ -350,20 +405,41 @@ def output_chords_to_music_data(chords, fundamental=55, chord_duration=4):
|
|||
|
||||
music_data = [[] for _ in range(num_voices)]
|
||||
|
||||
prev_chord = None
|
||||
for chord in chords:
|
||||
current_hs = [tuple(p["hs_array"]) for p in chord]
|
||||
|
||||
if prev_chord is None:
|
||||
staying_voices = []
|
||||
else:
|
||||
staying_voices = [
|
||||
i for i in range(num_voices) if current_hs[i] == prev_chord[i]
|
||||
]
|
||||
|
||||
for voice_idx, pitch in enumerate(chord):
|
||||
if voice_idx >= num_voices:
|
||||
break
|
||||
|
||||
frac = Fraction(pitch["fraction"])
|
||||
freq = fundamental * float(frac)
|
||||
current_hs_array = current_hs[voice_idx]
|
||||
|
||||
ref = None
|
||||
if prev_chord is None:
|
||||
ref = -1
|
||||
dim_diff = 0
|
||||
elif current_hs_array == prev_chord[voice_idx]:
|
||||
ref = -1
|
||||
dim_diff = 0
|
||||
else:
|
||||
ref, dim_diff = _find_ref_and_dim_diff(
|
||||
current_hs_array, prev_chord, staying_voices
|
||||
)
|
||||
|
||||
event = [freq, chord_duration, ref, dim_diff]
|
||||
music_data[voice_idx].append(event)
|
||||
|
||||
prev_chord = current_hs
|
||||
|
||||
return music_data
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue