-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path__init__.py
More file actions
147 lines (113 loc) · 4.19 KB
/
Copy path__init__.py
File metadata and controls
147 lines (113 loc) · 4.19 KB
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from dataclasses import dataclass
from typing import List
from enum import Enum
class Vocal(Enum):
STANDARD = 0
PRIMARY = 1
SECONDARY = 2
@dataclass
class VocalElement:
word_index: int
text: str
line_index:int
is_explicit: bool = False
start_time: float = 0
end_time: float = 0
def __str__(self):
return self.text
@dataclass
class Line:
index: int
elements: List[VocalElement]
vocal: Vocal = Vocal.STANDARD
is_backing: bool = False
@property
def start_time(self) -> float:
return self.elements[0].get_start_time()
@property
def end_time(self) -> float:
return self.elements[-1].get_end_time()
def is_last_element(self, element:VocalElement|int) -> bool:
if isinstance(element, int):
if element == len(self.elements)-1:
return True
return False
if self.elements[-1] == element:
return True
return False
def __str__(self):
_str = ""
index = 0
for i in range(len(self.elements)):
if self.elements[i].word_index > index:
_str += " "
index = self.elements[i].word_index
_str += str(self.elements[i])
return _str
class Lyrics(list):
element_map = []
init_list:list[Line]
modification_stack = []
def __init__(self, init_list:list[Line], *args):
self.init_list = init_list
self.generate_element_map()
super().__init__(*args)
def generate_element_map(self) -> None:
for i,line in enumerate(self.init_list):
line:Line = line
for j, element in enumerate(line.elements):
self.element_map.append([element, i, j])
def get_element_map_index(self, element:VocalElement) -> int:
for i,map_item in enumerate(self.element_map):
if element == map_item[0]:
return i
return 0
def rebuild(self) -> None:
# Check if any empty lines
del_line_list = []
del_word_list = []
for i, line in enumerate(self.init_list):
for j, word in enumerate(line.elements):
if word is None:
del_word_list.append((i,j))
# Update word_index for words after it
for word in line.elements[j+1:]:
word.word_index -=1
for i,j in del_word_list:
del self.init_list[i].elements[j]
for i,line in enumerate(self.init_list):
# check if any empty words
if not line.elements:
del_line_list.append(i)
# Update line_index of all the elements after it
for _line in self.init_list[i+1:]:
for _elements in _line.elements:
_elements.line_index -=1
for i in del_line_list:
del self.init_list[i]
self.generate_element_map()
def process_lyrics(lyrics_str:str) -> Lyrics:
if lyrics_str == "":
return
text_lines:list[str] = lyrics_str.split("\n")
line_objects:list[Line] = []
for line_counter in range(len(text_lines)):
if text_lines[line_counter] == "":
continue
text_line = text_lines[line_counter]
if text_line.startswith("(") and text_line.endswith(")"):
text_line = text_line.strip("()")
is_backing = True
else:
is_backing = False
line = Line(index=line_counter, elements=[], vocal=Vocal.STANDARD, is_backing=is_backing)
for word_counter in range(len(text_line.split(" "))):
word = text_line.split(" ")[word_counter]
if '/' in word:
syllables = word.split('/')
for syllable_counter in range(len(syllables)):
line.elements.append(VocalElement(word_index=word_counter, text=syllables[syllable_counter], line_index=len(line_objects)))
continue
line.elements.append(VocalElement(word_index=word_counter, text=word, line_index=len(line_objects)))
line_objects.append(line)
return Lyrics(line_objects)