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):
|
def format_dim_diff(dim_diff, ref):
|
||||||
"""Format dimensional difference markup."""
|
"""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 ""
|
return ""
|
||||||
|
|
||||||
diff_str = str(abs(dim_diff))
|
diff_str = str(abs(dim_diff))
|
||||||
|
|
@ -164,7 +164,8 @@ def format_dim_diff(dim_diff, ref):
|
||||||
elif dim_diff < 0:
|
elif dim_diff < 0:
|
||||||
diff_str += "↓"
|
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}" }} }}'
|
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}")
|
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):
|
def output_chords_to_music_data(chords, fundamental=55, chord_duration=4):
|
||||||
"""Convert output_chords.json format to generic music data.
|
"""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)]
|
music_data = [[] for _ in range(num_voices)]
|
||||||
|
|
||||||
|
prev_chord = None
|
||||||
for chord in chords:
|
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):
|
for voice_idx, pitch in enumerate(chord):
|
||||||
if voice_idx >= num_voices:
|
if voice_idx >= num_voices:
|
||||||
break
|
break
|
||||||
|
|
||||||
frac = Fraction(pitch["fraction"])
|
frac = Fraction(pitch["fraction"])
|
||||||
freq = fundamental * float(frac)
|
freq = fundamental * float(frac)
|
||||||
|
current_hs_array = current_hs[voice_idx]
|
||||||
|
|
||||||
ref = None
|
if prev_chord is None:
|
||||||
|
ref = -1
|
||||||
dim_diff = 0
|
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]
|
event = [freq, chord_duration, ref, dim_diff]
|
||||||
music_data[voice_idx].append(event)
|
music_data[voice_idx].append(event)
|
||||||
|
|
||||||
|
prev_chord = current_hs
|
||||||
|
|
||||||
return music_data
|
return music_data
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue