Spaces:
Running
Running
File size: 2,557 Bytes
c42fe7e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# webapp/components/phoneme_editor.py
from typing import List, Dict
import streamlit as st
from webapp.services.phonemes.phoneme_dict import PHONEMES
def default_phoneme_for_lyric(lyric: str) -> str:
"""
Simple rule-based default phoneme suggestion for a lyric syllable.
- Direct match if the lyric exactly matches a phoneme
- Greedy two-letter prefix match
- Single-letter fallback
- Default to 'a'
"""
l = lyric.lower()
if l in PHONEMES:
return l
if len(l) >= 2 and l[:2] in PHONEMES:
return l[:2]
if l and l[0] in PHONEMES:
return l[0]
return "a"
def render_phoneme_editor(notes: List[Dict]) -> List[Dict]:
"""
Display an editable phoneme alignment table in Streamlit, including duration edits.
Args:
notes: list of dicts each containing:
- id: unique identifier
- pitch: pitch string (e.g. "C4")
- duration: float, original duration in seconds
- lyric: string, the syllable/lyric text
- is_slur: int (0 or 1)
Returns:
List of dicts with updated 'duration', 'phoneme', and 'is_slur' fields:
"""
st.header("2. Phoneme & Duration Alignment")
st.write("Adjust duration and select phoneme for each note:")
edited_notes: List[Dict] = []
for note in notes:
# Columns: Pitch, Duration input, Lyric, Phoneme select, Slur checkbox
cols = st.columns([1, 1.2, 1, 2, 1])
cols[0].markdown(f"**Pitch:** {note['pitch']}")
# Editable duration
duration = cols[1].number_input(
label="Dur (s)",
min_value=0.0,
value=note['duration'],
step=0.01,
format="%.3f",
key=f"dur_{note['id']}"
)
cols[2].markdown(f"**Lyric:** {note['lyric']}")
# Default phoneme suggestion
default = default_phoneme_for_lyric(note['lyric'])
default_idx = PHONEMES.index(default) if default in PHONEMES else 0
phoneme = cols[3].selectbox(
label="Phoneme",
options=PHONEMES,
index=default_idx,
key=f"phoneme_{note['id']}"
)
# Slur toggle
is_slur = cols[4].checkbox(
label="Slur",
value=bool(note.get('is_slur', 0)),
key=f"slur_{note['id']}"
)
edited_notes.append({
**note,
"duration": duration,
"phoneme": phoneme,
"is_slur": int(is_slur)
})
return edited_notes
|