Anchor-annotator 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/METADATA +1 -1
- Anchor_annotator-0.7.0.dist-info/RECORD +22 -0
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/WHEEL +1 -1
- anchor/_version.py +2 -2
- anchor/db.py +1 -0
- anchor/main.py +31 -10
- anchor/models.py +103 -58
- anchor/plot.py +383 -362
- anchor/resources_rc.py +331 -150
- anchor/settings.py +10 -4
- anchor/ui_main_window.py +10 -0
- anchor/undo.py +18 -18
- anchor/widgets.py +103 -38
- anchor/workers.py +2485 -2462
- Anchor_annotator-0.5.0.dist-info/RECORD +0 -22
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/LICENSE +0 -0
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/top_level.txt +0 -0
anchor/plot.py
CHANGED
@@ -11,6 +11,7 @@ import numpy as np
|
|
11
11
|
import pyqtgraph as pg
|
12
12
|
import sqlalchemy
|
13
13
|
from Bio import pairwise2
|
14
|
+
from line_profiler_pycharm import profile
|
14
15
|
from montreal_forced_aligner.data import CtmInterval
|
15
16
|
from montreal_forced_aligner.db import Speaker, Utterance
|
16
17
|
from montreal_forced_aligner.dictionary.mixins import (
|
@@ -375,11 +376,12 @@ class AudioPlotItem(pg.PlotItem):
|
|
375
376
|
def __init__(self, top_point, bottom_point):
|
376
377
|
super().__init__(axisItems={"bottom": TimeAxis("bottom")})
|
377
378
|
self.settings = AnchorSettings()
|
379
|
+
self.plot_theme = self.settings.plot_theme
|
378
380
|
self.setDefaultPadding(0)
|
379
381
|
self.setClipToView(True)
|
380
382
|
|
381
|
-
self.getAxis("bottom").setPen(self.
|
382
|
-
self.getAxis("bottom").setTextPen(self.
|
383
|
+
self.getAxis("bottom").setPen(self.plot_theme.break_line_color)
|
384
|
+
self.getAxis("bottom").setTextPen(self.plot_theme.break_line_color)
|
383
385
|
self.getAxis("bottom").setTickFont(self.settings.small_font)
|
384
386
|
rect = QtCore.QRectF()
|
385
387
|
rect.setTop(top_point)
|
@@ -467,8 +469,8 @@ class UtteranceView(QtWidgets.QWidget):
|
|
467
469
|
)
|
468
470
|
self.audio_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
|
469
471
|
self.audio_layout.centralWidget.layout.setSpacing(0)
|
470
|
-
plot_theme = self.settings.plot_theme
|
471
|
-
self.audio_layout.setBackground(plot_theme.background_color)
|
472
|
+
self.plot_theme = self.settings.plot_theme
|
473
|
+
self.audio_layout.setBackground(self.plot_theme.background_color)
|
472
474
|
self.audio_plot = AudioPlots(2, 1, 0)
|
473
475
|
self.audio_plot_item = AudioPlotItem(2, 0)
|
474
476
|
self.audio_plot_item.addItem(self.audio_plot)
|
@@ -485,7 +487,7 @@ class UtteranceView(QtWidgets.QWidget):
|
|
485
487
|
self.speaker_tier_layout.setAspectLocked(False)
|
486
488
|
self.speaker_tier_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
|
487
489
|
self.speaker_tier_layout.centralWidget.layout.setSpacing(0)
|
488
|
-
self.speaker_tier_layout.setBackground(plot_theme.background_color)
|
490
|
+
self.speaker_tier_layout.setBackground(self.plot_theme.background_color)
|
489
491
|
self.speaker_tiers: dict[SpeakerTier] = {}
|
490
492
|
self.speaker_tier_items = {}
|
491
493
|
self.search_term = None
|
@@ -539,15 +541,13 @@ class UtteranceView(QtWidgets.QWidget):
|
|
539
541
|
self.corpus_model.refreshTiers.connect(self.finalize_loading_utterances)
|
540
542
|
|
541
543
|
def refresh_theme(self):
|
542
|
-
self.audio_layout.setBackground(self.
|
543
|
-
self.speaker_tier_layout.setBackground(self.
|
544
|
+
self.audio_layout.setBackground(self.plot_theme.background_color)
|
545
|
+
self.speaker_tier_layout.setBackground(self.plot_theme.background_color)
|
544
546
|
self.audio_plot.wave_form.update_theme()
|
545
547
|
self.audio_plot.spectrogram.update_theme()
|
546
548
|
self.audio_plot.pitch_track.update_theme()
|
547
|
-
self.audio_plot_item.getAxis("bottom").setPen(self.
|
548
|
-
self.audio_plot_item.getAxis("bottom").setTextPen(
|
549
|
-
self.settings.plot_theme.break_line_color
|
550
|
-
)
|
549
|
+
self.audio_plot_item.getAxis("bottom").setPen(self.plot_theme.break_line_color)
|
550
|
+
self.audio_plot_item.getAxis("bottom").setTextPen(self.plot_theme.break_line_color)
|
551
551
|
|
552
552
|
def refresh(self):
|
553
553
|
self.finalize_loading_utterances()
|
@@ -890,17 +890,15 @@ class Menu(QtWidgets.QMenu):
|
|
890
890
|
|
891
891
|
|
892
892
|
class TextEdit(QtWidgets.QTextEdit):
|
893
|
-
lookUpWord = QtCore.Signal(object)
|
894
|
-
createWord = QtCore.Signal(object)
|
895
893
|
lostFocus = QtCore.Signal()
|
894
|
+
gainedFocus = QtCore.Signal()
|
895
|
+
menuRequested = QtCore.Signal(object, object)
|
896
896
|
|
897
897
|
def __init__(self, dictionary_model, speaker_id, *args):
|
898
898
|
super().__init__(*args)
|
899
899
|
self.settings = AnchorSettings()
|
900
900
|
self.dictionary_model: DictionaryTableModel = dictionary_model
|
901
901
|
self.speaker_id = speaker_id
|
902
|
-
self.lookUpWord.connect(self.dictionary_model.lookup_word)
|
903
|
-
self.createWord.connect(self.dictionary_model.add_word)
|
904
902
|
self.setCursor(QtCore.Qt.CursorShape.IBeamCursor)
|
905
903
|
self.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
|
906
904
|
|
@@ -925,35 +923,25 @@ class TextEdit(QtWidgets.QTextEdit):
|
|
925
923
|
self.lostFocus.emit()
|
926
924
|
return super().focusOutEvent(e)
|
927
925
|
|
926
|
+
def focusInEvent(self, e: QtGui.QFocusEvent) -> None:
|
927
|
+
self.gainedFocus.emit()
|
928
|
+
return super().focusInEvent(e)
|
929
|
+
|
928
930
|
def generate_context_menu(self, location):
|
929
|
-
menu = Menu(self)
|
930
931
|
cursor = self.cursorForPosition(location)
|
931
932
|
cursor.select(QtGui.QTextCursor.SelectionType.WordUnderCursor)
|
932
933
|
word = cursor.selectedText()
|
933
|
-
|
934
|
-
menu.addSeparator()
|
935
|
-
if self.dictionary_model.check_word(word, speaker_id=self.speaker_id):
|
936
|
-
lookUpAction = QtGui.QAction(f'Look up "{word}" in dictionary', self)
|
937
|
-
lookUpAction.triggered.connect(lambda: self.lookUpWord.emit(word))
|
938
|
-
lookUpAction.triggered.connect(menu.hide)
|
939
|
-
menu.addAction(lookUpAction)
|
940
|
-
else:
|
941
|
-
createAction = QtGui.QAction(f'Add pronunciation for "{word}"', self)
|
942
|
-
createAction.triggered.connect(lambda: self.createWord.emit(word))
|
943
|
-
createAction.triggered.connect(menu.hide)
|
944
|
-
menu.addAction(createAction)
|
945
|
-
menu.setStyleSheet(self.settings.menu_style_sheet)
|
946
|
-
# show the menu
|
947
|
-
menu.exec_(self.mapToGlobal(location))
|
934
|
+
self.menuRequested.emit(word, self.mapToGlobal(location))
|
948
935
|
|
949
936
|
|
950
937
|
class UtterancePGTextItem(pg.TextItem):
|
938
|
+
@profile
|
951
939
|
def __init__(
|
952
940
|
self,
|
953
941
|
begin: float,
|
954
942
|
end: float,
|
955
943
|
text: str,
|
956
|
-
selection_model:
|
944
|
+
selection_model: FileSelectionModel,
|
957
945
|
top_point=None,
|
958
946
|
bottom_point=None,
|
959
947
|
per_tier_range=None,
|
@@ -962,6 +950,7 @@ class UtterancePGTextItem(pg.TextItem):
|
|
962
950
|
fill=None,
|
963
951
|
dictionary_model: Optional[DictionaryTableModel] = None,
|
964
952
|
speaker_id: int = 0,
|
953
|
+
editable: bool = True,
|
965
954
|
):
|
966
955
|
self.anchor = pg.Point(anchor)
|
967
956
|
self.rotateAxis = None
|
@@ -974,17 +963,16 @@ class UtterancePGTextItem(pg.TextItem):
|
|
974
963
|
self.dictionary_model = dictionary_model
|
975
964
|
self.speaker_id = speaker_id
|
976
965
|
pg.GraphicsObject.__init__(self)
|
966
|
+
self.editable = editable
|
977
967
|
self.text_edit = TextEdit(dictionary_model, speaker_id)
|
978
968
|
self.text_edit.cursorPositionChanged.connect(self.update)
|
979
969
|
|
980
|
-
# self.text_edit.setAutoFillBackground(False)
|
981
|
-
# self.text_edit.viewport().setAutoFillBackground(False)
|
982
970
|
self.textItem = QtWidgets.QGraphicsProxyWidget(self)
|
983
971
|
self.textItem.setWidget(self.text_edit)
|
972
|
+
self.text_edit.setPlainText(text)
|
984
973
|
self._lastTransform = None
|
985
974
|
self._lastScene = None
|
986
975
|
self._bounds = QtCore.QRectF()
|
987
|
-
self.text_edit.setPlainText(text)
|
988
976
|
self.fill = pg.mkBrush(fill)
|
989
977
|
self.border = pg.mkPen(border)
|
990
978
|
self._cached_pixel_size = None
|
@@ -994,9 +982,23 @@ class UtterancePGTextItem(pg.TextItem):
|
|
994
982
|
self.per_tier_range = per_tier_range
|
995
983
|
self.view_min = self.selection_model.plot_min
|
996
984
|
self.view_max = self.selection_model.plot_max
|
997
|
-
self.selection_model.viewChanged.connect(self.
|
985
|
+
self.selection_model.viewChanged.connect(self.update_view_times)
|
998
986
|
|
999
987
|
def update_times(self, begin, end):
|
988
|
+
self.begin = begin
|
989
|
+
self.end = end
|
990
|
+
if self.end <= self.view_min or self.begin >= self.view_max:
|
991
|
+
return
|
992
|
+
self.hide()
|
993
|
+
if (
|
994
|
+
self.view_min <= self.begin < self.view_max
|
995
|
+
or self.view_max >= self.end > self.view_min
|
996
|
+
or (self.begin <= self.view_min and self.end >= self.view_max)
|
997
|
+
):
|
998
|
+
self.update_pos()
|
999
|
+
self.show()
|
1000
|
+
|
1001
|
+
def update_view_times(self, begin, end):
|
1000
1002
|
self.view_min = begin
|
1001
1003
|
self.view_max = end
|
1002
1004
|
if self.end <= self.view_min or self.begin >= self.view_max:
|
@@ -1007,23 +1009,16 @@ class UtterancePGTextItem(pg.TextItem):
|
|
1007
1009
|
or self.view_max >= self.end > self.view_min
|
1008
1010
|
or (self.begin <= self.view_min and self.end >= self.view_max)
|
1009
1011
|
):
|
1012
|
+
self.update_pos()
|
1010
1013
|
self.show()
|
1011
1014
|
|
1012
|
-
def
|
1013
|
-
br = QtCore.QRectF(self.viewRect()) # bounds of containing ViewBox mapped to local coords.
|
1014
|
-
vb = self.getViewBox()
|
1015
|
-
if self.begin is None or self.view_min is None:
|
1016
|
-
return br
|
1015
|
+
def update_pos(self):
|
1017
1016
|
visible_begin = max(self.begin, self.view_min)
|
1018
1017
|
visible_end = min(self.end, self.view_max)
|
1019
|
-
|
1020
|
-
br.setLeft(visible_begin)
|
1021
|
-
br.setRight(visible_end)
|
1022
|
-
|
1023
|
-
br.setTop(self.top_point)
|
1024
|
-
# br.setBottom(self.top_point-self.per_tier_range)
|
1025
|
-
br.setBottom(self.bottom_point)
|
1026
1018
|
duration = visible_end - visible_begin
|
1019
|
+
vb = self.getViewBox()
|
1020
|
+
if vb is None:
|
1021
|
+
return
|
1027
1022
|
self._cached_pixel_size = vb.viewPixelSize()
|
1028
1023
|
x_margin_px = 25
|
1029
1024
|
y_margin_top_px = 25
|
@@ -1038,6 +1033,20 @@ class UtterancePGTextItem(pg.TextItem):
|
|
1038
1033
|
self.textItem.setGeometry(0, 0, width, height)
|
1039
1034
|
self.text_edit.setFixedWidth(width)
|
1040
1035
|
self.text_edit.setFixedHeight(height)
|
1036
|
+
|
1037
|
+
@profile
|
1038
|
+
def boundingRect(self):
|
1039
|
+
br = QtCore.QRectF() # bounds of containing ViewBox mapped to local coords.
|
1040
|
+
if self._cached_pixel_size is None:
|
1041
|
+
self.update_pos()
|
1042
|
+
visible_begin = max(self.begin, self.view_min)
|
1043
|
+
visible_end = min(self.end, self.view_max)
|
1044
|
+
|
1045
|
+
br.setLeft(visible_begin)
|
1046
|
+
br.setRight(visible_end)
|
1047
|
+
|
1048
|
+
br.setTop(self.top_point)
|
1049
|
+
br.setBottom(self.bottom_point)
|
1041
1050
|
return br
|
1042
1051
|
|
1043
1052
|
|
@@ -1093,9 +1102,10 @@ class TranscriberErrorHighlighter(QtGui.QSyntaxHighlighter):
|
|
1093
1102
|
super().__init__(*args)
|
1094
1103
|
self.alignment = None
|
1095
1104
|
self.settings = AnchorSettings()
|
1105
|
+
self.plot_theme = self.settings.plot_theme
|
1096
1106
|
|
1097
|
-
self.keyword_color = self.
|
1098
|
-
self.keyword_text_color = self.
|
1107
|
+
self.keyword_color = self.plot_theme.error_color
|
1108
|
+
self.keyword_text_color = self.plot_theme.error_text_color
|
1099
1109
|
self.highlight_format = QtGui.QTextCharFormat()
|
1100
1110
|
self.highlight_format.setBackground(self.keyword_color)
|
1101
1111
|
self.highlight_format.setForeground(self.keyword_text_color)
|
@@ -1114,16 +1124,15 @@ class TranscriberErrorHighlighter(QtGui.QSyntaxHighlighter):
|
|
1114
1124
|
return
|
1115
1125
|
current_align_ind = 0
|
1116
1126
|
for word_object in re.finditer(self.WORDS, text):
|
1117
|
-
while self.alignment.seqB[current_align_ind] != word_object.group():
|
1118
|
-
current_align_ind += 1
|
1119
1127
|
sb = self.alignment.seqB[current_align_ind]
|
1120
1128
|
sa = self.alignment.seqA[current_align_ind]
|
1121
|
-
if sb == word_object.group()
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1129
|
+
if sb == word_object.group():
|
1130
|
+
if sb != sa:
|
1131
|
+
self.setFormat(
|
1132
|
+
word_object.start(),
|
1133
|
+
word_object.end() - word_object.start(),
|
1134
|
+
self.highlight_format,
|
1135
|
+
)
|
1127
1136
|
current_align_ind += 1
|
1128
1137
|
if self.search_term:
|
1129
1138
|
if not self.search_term.case_sensitive:
|
@@ -1133,8 +1142,8 @@ class TranscriberErrorHighlighter(QtGui.QSyntaxHighlighter):
|
|
1133
1142
|
for i in range(word_object.start(), word_object.end()):
|
1134
1143
|
f = self.format(i)
|
1135
1144
|
f.setFontWeight(QtGui.QFont.Weight.Bold)
|
1136
|
-
f.setBackground(QtGui.QColor(self.
|
1137
|
-
f.setForeground(QtGui.QColor(self.
|
1145
|
+
f.setBackground(QtGui.QColor(self.plot_theme.break_line_color))
|
1146
|
+
f.setForeground(QtGui.QColor(self.plot_theme.background_color))
|
1138
1147
|
self.setFormat(i, 1, f)
|
1139
1148
|
|
1140
1149
|
|
@@ -1212,8 +1221,8 @@ class IntervalTextRegion(pg.GraphicsObject):
|
|
1212
1221
|
self.speaker_id = speaker_id
|
1213
1222
|
super().__init__()
|
1214
1223
|
text = interval.label
|
1215
|
-
self.
|
1216
|
-
self.
|
1224
|
+
self.text_item = TextItem(text, color=color, anchor=(0.5, 0.5))
|
1225
|
+
self.text_item.setParentItem(self)
|
1217
1226
|
|
1218
1227
|
self.picture = QtGui.QPicture()
|
1219
1228
|
self.interval = interval
|
@@ -1225,7 +1234,7 @@ class IntervalTextRegion(pg.GraphicsObject):
|
|
1225
1234
|
self.mouseHovering = False
|
1226
1235
|
self.selected = False
|
1227
1236
|
self.currentBrush = self.background_brush
|
1228
|
-
self.
|
1237
|
+
self.text_item.setPos(
|
1229
1238
|
(self.interval.begin + self.interval.end) / 2, self.top_point - (self.height / 2)
|
1230
1239
|
)
|
1231
1240
|
self.begin_line = pg.InfiniteLine()
|
@@ -1271,8 +1280,6 @@ class IntervalTextRegion(pg.GraphicsObject):
|
|
1271
1280
|
|
1272
1281
|
|
1273
1282
|
class TextAttributeRegion(pg.GraphicsObject):
|
1274
|
-
audioSelected = QtCore.Signal(object, object)
|
1275
|
-
|
1276
1283
|
def __init__(
|
1277
1284
|
self,
|
1278
1285
|
parent,
|
@@ -1281,16 +1288,19 @@ class TextAttributeRegion(pg.GraphicsObject):
|
|
1281
1288
|
text: str,
|
1282
1289
|
top_point,
|
1283
1290
|
height,
|
1284
|
-
selection_model:
|
1285
|
-
border=None,
|
1291
|
+
selection_model: FileSelectionModel,
|
1286
1292
|
dictionary_model=None,
|
1287
1293
|
speaker_id=None,
|
1294
|
+
plot_theme=None,
|
1288
1295
|
):
|
1289
1296
|
super().__init__()
|
1290
1297
|
self.begin = begin
|
1291
1298
|
self.end = end
|
1292
1299
|
self.text = text
|
1293
|
-
self.
|
1300
|
+
self.plot_theme = plot_theme
|
1301
|
+
self.settings = AnchorSettings()
|
1302
|
+
if self.plot_theme is None:
|
1303
|
+
self.plot_theme = self.settings.plot_theme
|
1294
1304
|
self.dictionary_model = dictionary_model
|
1295
1305
|
self.speaker_id = speaker_id
|
1296
1306
|
self.selection_model = selection_model
|
@@ -1301,7 +1311,8 @@ class TextAttributeRegion(pg.GraphicsObject):
|
|
1301
1311
|
self.height = height
|
1302
1312
|
self.bottom_point = self.top_point - self.height
|
1303
1313
|
self.setParentItem(parent)
|
1304
|
-
|
1314
|
+
|
1315
|
+
self.text_item = UtterancePGTextItem(
|
1305
1316
|
self.begin,
|
1306
1317
|
self.end,
|
1307
1318
|
self.text,
|
@@ -1314,8 +1325,8 @@ class TextAttributeRegion(pg.GraphicsObject):
|
|
1314
1325
|
speaker_id=self.speaker_id,
|
1315
1326
|
border=pg.mkPen(self.parentItem().settings.accent_light_color),
|
1316
1327
|
)
|
1317
|
-
self.
|
1318
|
-
self.text_edit = self.
|
1328
|
+
self.text_item.setParentItem(self)
|
1329
|
+
self.text_edit = self.text_item.text_edit
|
1319
1330
|
self.text_edit.setReadOnly(True)
|
1320
1331
|
self.text_edit.setViewportMargins(
|
1321
1332
|
self.parentItem().text_margin_pixels,
|
@@ -1325,87 +1336,55 @@ class TextAttributeRegion(pg.GraphicsObject):
|
|
1325
1336
|
)
|
1326
1337
|
self.text_edit.setStyleSheet(self.parentItem().settings.interval_style_sheet)
|
1327
1338
|
|
1328
|
-
self.picture = QtGui.QPicture()
|
1329
|
-
self.mouseHovering = False
|
1330
1339
|
self.selected = False
|
1331
|
-
self.background_brush = self.parentItem().background_brush
|
1332
|
-
self.selected_brush = self.parentItem().selected_brush
|
1333
1340
|
self.currentBrush = self.parentItem().currentBrush
|
1334
|
-
self.
|
1335
|
-
self.
|
1336
|
-
self.
|
1337
|
-
left=self.begin,
|
1338
|
-
top=self.top_point,
|
1339
|
-
width=self.end - self.begin,
|
1340
|
-
height=self.height,
|
1341
|
-
)
|
1342
|
-
self.rect.setTop(self.top_point)
|
1343
|
-
self.rect.setBottom(self.bottom_point)
|
1344
|
-
self._generate_picture()
|
1345
|
-
|
1346
|
-
def setSelected(self, selected):
|
1347
|
-
if selected:
|
1348
|
-
new_brush = self.selected_brush
|
1349
|
-
else:
|
1350
|
-
new_brush = self.background_brush
|
1351
|
-
if new_brush != self.currentBrush:
|
1352
|
-
self.currentBrush = new_brush
|
1353
|
-
self._generate_picture()
|
1354
|
-
|
1355
|
-
def _generate_picture(self):
|
1356
|
-
painter = QtGui.QPainter(self.picture)
|
1357
|
-
painter.setPen(self.border)
|
1358
|
-
painter.setBrush(self.currentBrush)
|
1359
|
-
painter.drawRect(self.rect)
|
1360
|
-
painter.end()
|
1361
|
-
|
1362
|
-
def mouseClickEvent(self, ev):
|
1363
|
-
if ev.button() != QtCore.Qt.MouseButton.LeftButton:
|
1364
|
-
ev.ignore()
|
1365
|
-
return
|
1366
|
-
self.audioSelected.emit(self.begin, self.end)
|
1367
|
-
ev.accept()
|
1341
|
+
self.text_item.setPos((self.begin + self.end) / 2, self.top_point - (self.height / 2))
|
1342
|
+
self._cached_pixel_size = None
|
1343
|
+
self.cached_bounds = None
|
1368
1344
|
|
1369
1345
|
def boundingRect(self):
|
1370
|
-
|
1346
|
+
visible_begin = max(self.begin, self.selection_model.plot_min)
|
1347
|
+
visible_end = min(self.end, self.selection_model.plot_max)
|
1348
|
+
br = QtCore.QRectF(
|
1349
|
+
visible_begin,
|
1350
|
+
self.bottom_point,
|
1351
|
+
visible_end - visible_begin,
|
1352
|
+
abs(self.top_point - self.bottom_point),
|
1353
|
+
)
|
1371
1354
|
return br
|
1372
1355
|
|
1373
|
-
def paint(self, painter
|
1374
|
-
|
1356
|
+
def paint(self, painter, option, widget=...):
|
1357
|
+
return
|
1375
1358
|
|
1376
1359
|
|
1377
1360
|
class TranscriberTextRegion(TextAttributeRegion):
|
1378
|
-
|
1379
|
-
audioSelected = QtCore.Signal(object, object)
|
1380
|
-
|
1361
|
+
@profile
|
1381
1362
|
def __init__(
|
1382
1363
|
self,
|
1383
1364
|
parent,
|
1384
|
-
|
1385
|
-
end: float,
|
1386
|
-
text: str,
|
1365
|
+
item,
|
1387
1366
|
top_point,
|
1388
1367
|
height,
|
1389
1368
|
selection_model: CorpusSelectionModel,
|
1390
|
-
border=None,
|
1391
1369
|
dictionary_model=None,
|
1392
1370
|
speaker_id=None,
|
1393
1371
|
alignment=None,
|
1394
1372
|
search_term=None,
|
1373
|
+
plot_theme=None,
|
1395
1374
|
):
|
1396
1375
|
super().__init__(
|
1397
1376
|
parent,
|
1398
|
-
begin,
|
1399
|
-
end,
|
1400
|
-
|
1377
|
+
item.begin,
|
1378
|
+
item.end,
|
1379
|
+
item.transcription_text,
|
1401
1380
|
top_point,
|
1402
1381
|
height,
|
1403
1382
|
selection_model,
|
1404
|
-
border,
|
1405
1383
|
dictionary_model,
|
1406
1384
|
speaker_id,
|
1385
|
+
plot_theme,
|
1407
1386
|
)
|
1408
|
-
|
1387
|
+
self.item = item
|
1409
1388
|
self.highlighter = TranscriberErrorHighlighter(self.text_edit.document())
|
1410
1389
|
if alignment is not None:
|
1411
1390
|
self.highlighter.set_alignment(alignment)
|
@@ -1414,9 +1393,6 @@ class TranscriberTextRegion(TextAttributeRegion):
|
|
1414
1393
|
|
1415
1394
|
|
1416
1395
|
class NormalizedTextRegion(TextAttributeRegion):
|
1417
|
-
viewRequested = QtCore.Signal(object, object)
|
1418
|
-
audioSelected = QtCore.Signal(object, object)
|
1419
|
-
|
1420
1396
|
def __init__(
|
1421
1397
|
self,
|
1422
1398
|
parent,
|
@@ -1426,10 +1402,10 @@ class NormalizedTextRegion(TextAttributeRegion):
|
|
1426
1402
|
top_point,
|
1427
1403
|
height,
|
1428
1404
|
selection_model: CorpusSelectionModel,
|
1429
|
-
border=None,
|
1430
1405
|
dictionary_model=None,
|
1431
1406
|
search_term=None,
|
1432
1407
|
speaker_id=None,
|
1408
|
+
plot_theme=None,
|
1433
1409
|
):
|
1434
1410
|
super().__init__(
|
1435
1411
|
parent,
|
@@ -1439,17 +1415,21 @@ class NormalizedTextRegion(TextAttributeRegion):
|
|
1439
1415
|
top_point,
|
1440
1416
|
height,
|
1441
1417
|
selection_model,
|
1442
|
-
border,
|
1443
1418
|
dictionary_model,
|
1444
1419
|
speaker_id,
|
1420
|
+
plot_theme,
|
1445
1421
|
)
|
1446
1422
|
|
1447
|
-
self.highlighter = Highlighter(self.text_edit.document())
|
1423
|
+
self.highlighter = Highlighter(self.text_item.text_edit.document())
|
1448
1424
|
self.highlighter.set_models(dictionary_model)
|
1449
1425
|
self.highlighter.set_speaker(speaker_id)
|
1450
1426
|
if search_term:
|
1451
1427
|
self.highlighter.setSearchTerm(search_term)
|
1452
1428
|
|
1429
|
+
def boundingRect(self):
|
1430
|
+
br = super().boundingRect()
|
1431
|
+
return br
|
1432
|
+
|
1453
1433
|
|
1454
1434
|
class Highlighter(QtGui.QSyntaxHighlighter):
|
1455
1435
|
WORDS = rf"[^\s{''.join(DEFAULT_WORD_BREAK_MARKERS)+''.join(DEFAULT_PUNCTUATION)}]+"
|
@@ -1542,6 +1522,7 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1542
1522
|
self.item = item
|
1543
1523
|
|
1544
1524
|
self.settings = AnchorSettings()
|
1525
|
+
self.plot_theme = self.settings.plot_theme
|
1545
1526
|
|
1546
1527
|
self.item_min = self.item.begin
|
1547
1528
|
self.item_max = self.item.end
|
@@ -1557,13 +1538,13 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1557
1538
|
self.text_margin_pixels = 2
|
1558
1539
|
self.height = abs(self.top_point - self.bottom_point)
|
1559
1540
|
|
1560
|
-
self.interval_background_color = self.
|
1561
|
-
self.hover_line_color = self.
|
1562
|
-
self.moving_line_color = self.
|
1541
|
+
self.interval_background_color = self.plot_theme.interval_background_color
|
1542
|
+
self.hover_line_color = self.plot_theme.hover_line_color
|
1543
|
+
self.moving_line_color = self.plot_theme.moving_line_color
|
1563
1544
|
|
1564
|
-
self.break_line_color = self.
|
1565
|
-
self.text_color = self.
|
1566
|
-
self.selected_interval_color = self.
|
1545
|
+
self.break_line_color = self.plot_theme.break_line_color
|
1546
|
+
self.text_color = self.plot_theme.text_color
|
1547
|
+
self.selected_interval_color = self.plot_theme.selected_interval_color
|
1567
1548
|
self.plot_text_font = self.settings.big_font
|
1568
1549
|
self.setCursor(QtCore.Qt.CursorShape.SizeAllCursor)
|
1569
1550
|
self.pen = pg.mkPen(self.break_line_color, width=3)
|
@@ -1686,122 +1667,131 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1686
1667
|
return br
|
1687
1668
|
|
1688
1669
|
|
1689
|
-
class
|
1670
|
+
class IntervalTier(pg.GraphicsObject):
|
1671
|
+
highlightRequested = QtCore.Signal(object)
|
1672
|
+
|
1690
1673
|
def __init__(
|
1691
1674
|
self,
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
selection_model:
|
1696
|
-
|
1697
|
-
|
1675
|
+
parent,
|
1676
|
+
utterance: CtmInterval,
|
1677
|
+
intervals: typing.List[CtmInterval],
|
1678
|
+
selection_model: FileSelectionModel,
|
1679
|
+
top_point,
|
1680
|
+
bottom_point,
|
1681
|
+
word=False,
|
1698
1682
|
):
|
1699
|
-
super().__init__(
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
)
|
1708
|
-
self.
|
1683
|
+
super().__init__()
|
1684
|
+
self.setParentItem(parent)
|
1685
|
+
self.intervals = intervals
|
1686
|
+
self.word = word
|
1687
|
+
self.array = pg.Qt.internals.PrimitiveArray(QtCore.QRectF, 4)
|
1688
|
+
self.array.resize(len(self.intervals))
|
1689
|
+
self.settings = AnchorSettings()
|
1690
|
+
self.plot_theme = self.settings.plot_theme
|
1691
|
+
memory = self.array.ndarray()
|
1692
|
+
self.anchor = pg.Point((0.5, 0.5))
|
1693
|
+
if self.word:
|
1694
|
+
self.plot_text_font = self.settings.font
|
1695
|
+
else:
|
1696
|
+
self.plot_text_font = self.settings.small_font
|
1709
1697
|
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
options = QtGui.QTextOption()
|
1717
|
-
options.setWrapMode(QtGui.QTextOption.WrapMode.NoWrap)
|
1718
|
-
self.text.textItem.document().setDefaultTextOption(options)
|
1719
|
-
self.text.setParentItem(self)
|
1720
|
-
self.per_tier_range = self.top_point - self.bottom_point
|
1721
|
-
self.currentBrush = pg.mkBrush((0, 0, 0, 0))
|
1722
|
-
self.selection_model.viewChanged.connect(self.check_visibility)
|
1723
|
-
self.check_visibility()
|
1698
|
+
fm = QtGui.QFontMetrics(self.plot_text_font)
|
1699
|
+
for i, interval in enumerate(intervals):
|
1700
|
+
memory[i, 0] = interval.begin
|
1701
|
+
memory[i, 2] = interval.end - interval.begin
|
1702
|
+
if interval.label not in self.parentItem().painter_path_cache[self.word]:
|
1703
|
+
symbol = QtGui.QPainterPath()
|
1724
1704
|
|
1725
|
-
|
1726
|
-
|
1727
|
-
self.text.setColor(self.settings.plot_theme.selected_text_color)
|
1728
|
-
else:
|
1729
|
-
self.text.setColor(self.settings.plot_theme.text_color)
|
1705
|
+
symbol.addText(0, 0, self.plot_text_font, interval.label)
|
1706
|
+
br = symbol.boundingRect()
|
1730
1707
|
|
1731
|
-
|
1732
|
-
|
1733
|
-
self.selection_model.max_time - self.selection_model.min_time
|
1734
|
-
) < 0.001:
|
1735
|
-
self.hide()
|
1736
|
-
else:
|
1737
|
-
vb = self.getViewBox()
|
1738
|
-
visible_begin = max(self.item_min, self.selection_model.plot_min)
|
1739
|
-
visible_end = min(self.item_max, self.selection_model.plot_max)
|
1740
|
-
visible_duration = visible_end - visible_begin
|
1741
|
-
self.text.setPos(
|
1742
|
-
visible_begin + (visible_duration / 2), self.top_point - (self.per_tier_range / 2)
|
1743
|
-
)
|
1744
|
-
if vb is None:
|
1745
|
-
self.text.setVisible(
|
1746
|
-
(visible_end - visible_begin)
|
1747
|
-
/ (self.selection_model.max_time - self.selection_model.min_time)
|
1748
|
-
> 0.005
|
1749
|
-
)
|
1750
|
-
else:
|
1751
|
-
pixel_size = vb.viewPixelSize()[0]
|
1752
|
-
if pixel_size != 0:
|
1753
|
-
x_margin_px = 8
|
1754
|
-
available_text_width = visible_duration / pixel_size - (2 * x_margin_px)
|
1708
|
+
# getting transform object
|
1709
|
+
tr = QtGui.QTransform()
|
1755
1710
|
|
1756
|
-
|
1757
|
-
|
1711
|
+
# translating
|
1712
|
+
tr.translate(-br.x() - br.width() / 2.0, fm.height() / 2.0)
|
1713
|
+
self.parentItem().painter_path_cache[self.word][interval.label] = tr.map(symbol)
|
1758
1714
|
|
1715
|
+
memory[:, 1] = bottom_point
|
1716
|
+
memory[:, 3] = top_point - bottom_point
|
1717
|
+
self.top_point = top_point
|
1718
|
+
self.bottom_point = bottom_point
|
1719
|
+
self.selection_model = selection_model
|
1720
|
+
self.utterance = utterance
|
1759
1721
|
|
1760
|
-
|
1761
|
-
|
1762
|
-
self
|
1763
|
-
phone_interval: CtmInterval,
|
1764
|
-
corpus_model: CorpusModel,
|
1765
|
-
file_model: FileUtterancesModel,
|
1766
|
-
selection_model: CorpusSelectionModel,
|
1767
|
-
bottom_point: float = 0,
|
1768
|
-
top_point: float = 1,
|
1769
|
-
color=None,
|
1770
|
-
):
|
1771
|
-
super().__init__(
|
1772
|
-
phone_interval, corpus_model, file_model, selection_model, bottom_point, top_point
|
1773
|
-
)
|
1774
|
-
if color is not None:
|
1775
|
-
self.currentBrush = pg.mkBrush(color)
|
1776
|
-
self._generate_picture()
|
1722
|
+
self.background_color = self.plot_theme.background_color
|
1723
|
+
self.hover_line_color = self.plot_theme.hover_line_color
|
1724
|
+
self.moving_line_color = self.plot_theme.moving_line_color
|
1777
1725
|
|
1726
|
+
self.break_line_color = self.plot_theme.break_line_color
|
1727
|
+
self.text_color = self.plot_theme.text_color
|
1728
|
+
self.selected_interval_color = self.plot_theme.selected_interval_color
|
1729
|
+
self.text_pen = pg.mkPen(self.text_color)
|
1730
|
+
self.border_pen = pg.mkPen(self.break_line_color, width=1)
|
1731
|
+
self.border_pen.setCapStyle(QtCore.Qt.PenCapStyle.FlatCap)
|
1778
1732
|
|
1779
|
-
|
1780
|
-
|
1733
|
+
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
|
1734
|
+
if e.button() == QtCore.Qt.MouseButton.LeftButton:
|
1735
|
+
time = e.pos().x()
|
1736
|
+
memory = self.array.ndarray()
|
1737
|
+
if memory.shape[0] > 0:
|
1738
|
+
index = np.searchsorted(memory[:, 0], time) - 1
|
1739
|
+
self.selection_model.select_audio(
|
1740
|
+
self.intervals[index].begin, self.intervals[index].end
|
1741
|
+
)
|
1742
|
+
if self.word:
|
1743
|
+
self.highlightRequested.emit(
|
1744
|
+
TextFilterQuery(self.intervals[index].label, word=True)
|
1745
|
+
)
|
1746
|
+
e.accept()
|
1747
|
+
return
|
1781
1748
|
|
1782
|
-
|
1783
|
-
self,
|
1784
|
-
word_interval: CtmInterval,
|
1785
|
-
corpus_model: CorpusModel,
|
1786
|
-
file_model: FileUtterancesModel,
|
1787
|
-
selection_model: CorpusSelectionModel,
|
1788
|
-
bottom_point: float = 0,
|
1789
|
-
top_point: float = 1,
|
1790
|
-
):
|
1791
|
-
super().__init__(
|
1792
|
-
word_interval, corpus_model, file_model, selection_model, bottom_point, top_point
|
1793
|
-
)
|
1794
|
-
self._generate_picture()
|
1749
|
+
return super().mousePressEvent(e)
|
1795
1750
|
|
1796
|
-
def
|
1797
|
-
|
1798
|
-
self.
|
1799
|
-
|
1751
|
+
def paint(self, painter, *args):
|
1752
|
+
inst = self.array.instances()
|
1753
|
+
vb = self.getViewBox()
|
1754
|
+
px = vb.viewPixelSize()
|
1755
|
+
painter.setPen(self.border_pen)
|
1756
|
+
painter.drawRects(inst)
|
1757
|
+
total_time = self.selection_model.max_time - self.selection_model.min_time
|
1758
|
+
for i, interval in enumerate(self.intervals):
|
1759
|
+
r = inst[i]
|
1760
|
+
visible_begin = max(r.left(), self.selection_model.plot_min)
|
1761
|
+
visible_end = min(r.right(), self.selection_model.plot_max)
|
1762
|
+
visible_duration = visible_end - visible_begin
|
1763
|
+
if visible_duration / total_time <= 0.0075:
|
1764
|
+
continue
|
1765
|
+
x = (r.left() + r.right()) / 2
|
1766
|
+
painter.save()
|
1767
|
+
options = QtGui.QTextOption()
|
1768
|
+
options.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
1769
|
+
painter.setRenderHint(painter.RenderHint.Antialiasing, True)
|
1770
|
+
painter.setPen(self.text_pen)
|
1771
|
+
painter.setBrush(self.text_color)
|
1772
|
+
painter.translate(x, (self.top_point + self.bottom_point) / 2)
|
1773
|
+
path = self.parentItem().painter_path_cache[self.word][interval.label]
|
1774
|
+
painter.scale(px[0], -px[1])
|
1775
|
+
painter.drawPath(path)
|
1776
|
+
painter.restore()
|
1777
|
+
|
1778
|
+
def boundingRect(self):
|
1779
|
+
return QtCore.QRectF(
|
1780
|
+
self.utterance.begin,
|
1781
|
+
self.bottom_point,
|
1782
|
+
self.utterance.end - self.utterance.begin,
|
1783
|
+
abs(self.top_point - self.bottom_point),
|
1784
|
+
)
|
1800
1785
|
|
1801
1786
|
|
1802
1787
|
class UtteranceRegion(MfaRegion):
|
1788
|
+
lookUpWord = QtCore.Signal(object)
|
1789
|
+
createWord = QtCore.Signal(object)
|
1790
|
+
|
1791
|
+
@profile
|
1803
1792
|
def __init__(
|
1804
1793
|
self,
|
1794
|
+
parent,
|
1805
1795
|
utterance: workers.UtteranceData,
|
1806
1796
|
corpus_model: CorpusModel,
|
1807
1797
|
file_model: FileUtterancesModel,
|
@@ -1822,6 +1812,8 @@ class UtteranceRegion(MfaRegion):
|
|
1822
1812
|
bottom_point,
|
1823
1813
|
top_point,
|
1824
1814
|
)
|
1815
|
+
self.setParentItem(parent)
|
1816
|
+
plot_theme = self.settings.plot_theme
|
1825
1817
|
self.hide()
|
1826
1818
|
self.item = utterance
|
1827
1819
|
self.selection_model = selection_model
|
@@ -1874,44 +1866,34 @@ class UtteranceRegion(MfaRegion):
|
|
1874
1866
|
|
1875
1867
|
self.corpus_model.utteranceTextUpdated.connect(self.update_text_from_model)
|
1876
1868
|
self.original_text = self.item.text
|
1877
|
-
self.
|
1869
|
+
self.text_item = NormalizedTextRegion(
|
1870
|
+
self,
|
1878
1871
|
self.item.begin,
|
1879
1872
|
self.item.end,
|
1880
|
-
self.item.
|
1873
|
+
self.item.normalized_text,
|
1874
|
+
self.top_point,
|
1875
|
+
self.per_tier_range,
|
1881
1876
|
self.selection_model,
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
per_tier_range=self.per_tier_range,
|
1886
|
-
dictionary_model=self.dictionary_model,
|
1887
|
-
speaker_id=self.item.speaker_id,
|
1888
|
-
border=pg.mkPen(self.settings.plot_theme.break_line_color),
|
1877
|
+
dictionary_model=dictionary_model,
|
1878
|
+
search_term=search_term,
|
1879
|
+
speaker_id=utterance.speaker_id,
|
1889
1880
|
)
|
1890
|
-
self.text.setParentItem(self)
|
1891
1881
|
|
1892
|
-
self.text_edit = self.
|
1893
|
-
|
1894
|
-
|
1882
|
+
self.text_edit = self.text_item.text_edit
|
1883
|
+
self.text_edit.gainedFocus.connect(self.select_self)
|
1884
|
+
self.text_edit.menuRequested.connect(self.generate_text_edit_menu)
|
1885
|
+
self.text_edit.setReadOnly(False)
|
1895
1886
|
self.corpus_model.editableChanged.connect(self.change_editing)
|
1896
|
-
self.text_edit.setViewportMargins(
|
1897
|
-
self.text_margin_pixels,
|
1898
|
-
self.text_margin_pixels,
|
1899
|
-
self.text_margin_pixels,
|
1900
|
-
self.text_margin_pixels,
|
1901
|
-
)
|
1902
|
-
self.text_edit.setStyleSheet(self.settings.interval_style_sheet)
|
1903
1887
|
self.text_edit.installEventFilter(self)
|
1904
|
-
self.highlighter = Highlighter(self.text_edit.document())
|
1905
|
-
self.highlighter.set_models(dictionary_model)
|
1906
|
-
self.highlighter.set_speaker(self.item.speaker_id)
|
1907
|
-
if search_term:
|
1908
|
-
self.highlighter.setSearchTerm(search_term)
|
1909
1888
|
self.timer = QtCore.QTimer()
|
1910
1889
|
self.text_edit.textChanged.connect(self.refresh_timer)
|
1911
1890
|
self.text_edit.lostFocus.connect(self.save_changes)
|
1891
|
+
self.text_edit.gainedFocus.connect(self.select_self)
|
1892
|
+
self.text_edit.menuRequested.connect(self.generate_text_edit_menu)
|
1912
1893
|
self.timer.timeout.connect(self.save_changes)
|
1913
1894
|
self._cached_pixel_size = None
|
1914
1895
|
self.normalized_text = None
|
1896
|
+
self.transcription_text = None
|
1915
1897
|
i = -1
|
1916
1898
|
for tier_name, lookup in self.extra_tiers.items():
|
1917
1899
|
if not visible_tiers[tier_name]:
|
@@ -1929,23 +1911,19 @@ class UtteranceRegion(MfaRegion):
|
|
1929
1911
|
tier_top_point,
|
1930
1912
|
self.per_tier_range,
|
1931
1913
|
self.selection_model,
|
1932
|
-
border=pg.mkPen(self.settings.plot_theme.break_line_color),
|
1933
1914
|
dictionary_model=dictionary_model,
|
1934
1915
|
search_term=search_term,
|
1935
1916
|
speaker_id=utterance.speaker_id,
|
1936
1917
|
)
|
1918
|
+
self.normalized_text.text_edit.gainedFocus.connect(self.select_self)
|
1919
|
+
self.normalized_text.text_edit.menuRequested.connect(self.generate_text_edit_menu)
|
1937
1920
|
continue
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
if (
|
1942
|
-
lookup == "transcription_text"
|
1943
|
-
and self.item.text
|
1944
|
-
and self.item.transcription_text
|
1945
|
-
):
|
1921
|
+
elif lookup == "transcription_text":
|
1922
|
+
alignment = None
|
1923
|
+
if self.item.normalized_text and self.item.transcription_text:
|
1946
1924
|
alignment = pairwise2.align.globalms(
|
1947
|
-
self.item.
|
1948
|
-
self.item.transcription_text.split(),
|
1925
|
+
self.item.normalized_text.lower().split(),
|
1926
|
+
self.item.transcription_text.lower().split(),
|
1949
1927
|
0,
|
1950
1928
|
-2,
|
1951
1929
|
-1,
|
@@ -1953,18 +1931,39 @@ class UtteranceRegion(MfaRegion):
|
|
1953
1931
|
gap_char=["-"],
|
1954
1932
|
one_alignment_only=True,
|
1955
1933
|
)[0]
|
1934
|
+
self.transcription_text = TranscriberTextRegion(
|
1935
|
+
self,
|
1936
|
+
self.item,
|
1937
|
+
tier_top_point,
|
1938
|
+
self.per_tier_range,
|
1939
|
+
self.selection_model,
|
1940
|
+
alignment=alignment,
|
1941
|
+
dictionary_model=dictionary_model,
|
1942
|
+
search_term=search_term,
|
1943
|
+
speaker_id=utterance.speaker_id,
|
1944
|
+
plot_theme=self.plot_theme,
|
1945
|
+
)
|
1946
|
+
self.transcription_text.setParentItem(self)
|
1947
|
+
self.transcription_text.text_edit.gainedFocus.connect(self.select_self)
|
1948
|
+
self.transcription_text.text_edit.menuRequested.connect(
|
1949
|
+
self.generate_text_edit_menu
|
1950
|
+
)
|
1951
|
+
continue
|
1952
|
+
intervals = getattr(self.item, lookup)
|
1956
1953
|
|
1957
1954
|
self.extra_tier_intervals[tier_name] = []
|
1958
1955
|
|
1959
1956
|
if intervals is None:
|
1960
1957
|
continue
|
1958
|
+
if not isinstance(intervals, list):
|
1959
|
+
intervals = [intervals]
|
1961
1960
|
min_confidence = None
|
1962
1961
|
max_confidence = None
|
1963
1962
|
cmap = pg.ColorMap(
|
1964
1963
|
None,
|
1965
1964
|
[
|
1966
|
-
|
1967
|
-
|
1965
|
+
plot_theme.error_color,
|
1966
|
+
plot_theme.interval_background_color,
|
1968
1967
|
],
|
1969
1968
|
)
|
1970
1969
|
cmap.linearize()
|
@@ -1976,64 +1975,49 @@ class UtteranceRegion(MfaRegion):
|
|
1976
1975
|
min_confidence = interval.confidence
|
1977
1976
|
if max_confidence is None or interval.confidence > max_confidence:
|
1978
1977
|
max_confidence = interval.confidence
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1978
|
+
interval_tier = IntervalTier(
|
1979
|
+
self,
|
1980
|
+
self.item,
|
1981
|
+
intervals,
|
1982
|
+
self.selection_model,
|
1983
|
+
top_point=tier_top_point,
|
1984
|
+
bottom_point=tier_bottom_point,
|
1985
|
+
word=False,
|
1986
|
+
)
|
1987
|
+
|
1988
|
+
elif "word_intervals" in lookup:
|
1989
|
+
interval_tier = IntervalTier(
|
1990
|
+
self,
|
1991
|
+
self.item,
|
1992
|
+
intervals,
|
1993
|
+
self.selection_model,
|
1994
|
+
top_point=tier_top_point,
|
1995
|
+
bottom_point=tier_bottom_point,
|
1996
|
+
word=True,
|
1997
|
+
)
|
1998
|
+
interval_tier.highlightRequested.connect(self.text_item.highlighter.setSearchTerm)
|
1999
|
+
if self.transcription_text is not None:
|
2000
|
+
interval_tier.highlightRequested.connect(
|
2001
|
+
self.transcription_text.highlighter.setSearchTerm
|
1994
2002
|
)
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
color = None
|
1999
|
-
if interval.confidence is not None:
|
2000
|
-
normalized_confidence = (interval.confidence - min_confidence) / (
|
2001
|
-
max_confidence - min_confidence
|
2002
|
-
)
|
2003
|
-
color = cmap.map(normalized_confidence)
|
2004
|
-
interval_reg = PhoneRegion(
|
2005
|
-
interval,
|
2006
|
-
self.corpus_model,
|
2007
|
-
self.file_model,
|
2008
|
-
selection_model=selection_model,
|
2009
|
-
top_point=tier_top_point,
|
2010
|
-
bottom_point=tier_bottom_point,
|
2011
|
-
color=color,
|
2003
|
+
if self.normalized_text is not None:
|
2004
|
+
interval_tier.highlightRequested.connect(
|
2005
|
+
self.normalized_text.highlighter.setSearchTerm
|
2012
2006
|
)
|
2013
|
-
interval_reg.setParentItem(self)
|
2014
|
-
interval_reg.audioSelected.connect(self.setSelected)
|
2015
|
-
elif "word_intervals" in lookup:
|
2016
|
-
interval_reg = WordRegion(
|
2017
|
-
interval,
|
2018
|
-
self.corpus_model,
|
2019
|
-
self.file_model,
|
2020
|
-
selection_model=selection_model,
|
2021
|
-
top_point=tier_top_point,
|
2022
|
-
bottom_point=tier_bottom_point,
|
2023
|
-
)
|
2024
|
-
interval_reg.setParentItem(self)
|
2025
|
-
interval_reg.highlightRequested.connect(self.highlighter.setSearchTerm)
|
2026
|
-
interval_reg.audioSelected.connect(self.setSelected)
|
2027
2007
|
|
2008
|
+
for interval in intervals:
|
2009
|
+
if "phone_intervals" in lookup or "word_intervals" in lookup:
|
2010
|
+
continue
|
2028
2011
|
else:
|
2029
2012
|
interval_reg = IntervalTextRegion(
|
2030
2013
|
interval,
|
2031
2014
|
self.text_color,
|
2032
|
-
border=pg.mkPen(
|
2015
|
+
border=pg.mkPen(plot_theme.break_line_color, width=1),
|
2033
2016
|
top_point=tier_top_point,
|
2034
2017
|
height=self.per_tier_range,
|
2035
2018
|
background_brush=self.background_brush,
|
2036
2019
|
selected_brush=pg.mkBrush(self.selected_interval_color),
|
2020
|
+
plot_theme=self.plot_theme,
|
2037
2021
|
)
|
2038
2022
|
interval_reg.audioSelected.connect(self.setSelected)
|
2039
2023
|
interval_reg.setParentItem(self)
|
@@ -2042,9 +2026,23 @@ class UtteranceRegion(MfaRegion):
|
|
2042
2026
|
interval_reg.viewRequested.connect(self.viewRequested.emit)
|
2043
2027
|
self.extra_tier_intervals[tier_name].append(interval_reg)
|
2044
2028
|
self.selection_model.viewChanged.connect(self.update_view_times)
|
2029
|
+
self.lookUpWord.connect(self.dictionary_model.lookup_word)
|
2030
|
+
self.createWord.connect(self.dictionary_model.add_word)
|
2045
2031
|
self.show()
|
2046
2032
|
self.available_speakers = available_speakers
|
2047
2033
|
|
2034
|
+
@property
|
2035
|
+
def painter_path_cache(self):
|
2036
|
+
return self.parentItem().painter_path_cache
|
2037
|
+
|
2038
|
+
def update_edit_fields(self):
|
2039
|
+
begin, end = self.getRegion()
|
2040
|
+
self.text_item.text_item.update_times(begin, end)
|
2041
|
+
if self.normalized_text is not None:
|
2042
|
+
self.normalized_text.text_item.update_times(begin, end)
|
2043
|
+
if self.transcription_text is not None:
|
2044
|
+
self.transcription_text.text_item.update_times(begin, end)
|
2045
|
+
|
2048
2046
|
def show(self):
|
2049
2047
|
for intervals in self.extra_tier_intervals.values():
|
2050
2048
|
for interval in intervals:
|
@@ -2061,11 +2059,6 @@ class UtteranceRegion(MfaRegion):
|
|
2061
2059
|
interval.hide()
|
2062
2060
|
super().show()
|
2063
2061
|
|
2064
|
-
def setSelected(self, selected: bool):
|
2065
|
-
if selected:
|
2066
|
-
self.text_edit.setFocus()
|
2067
|
-
super().setSelected(selected)
|
2068
|
-
|
2069
2062
|
def change_editing(self, editable: bool):
|
2070
2063
|
self.lines[0].movable = editable
|
2071
2064
|
self.lines[1].movable = editable
|
@@ -2085,7 +2078,7 @@ class UtteranceRegion(MfaRegion):
|
|
2085
2078
|
self.movable = False
|
2086
2079
|
self.setAcceptHoverEvents(False)
|
2087
2080
|
|
2088
|
-
def
|
2081
|
+
def construct_context_menu(self):
|
2089
2082
|
menu = QtWidgets.QMenu()
|
2090
2083
|
change_speaker_menu = QtWidgets.QMenu("Change speaker")
|
2091
2084
|
a = QtGui.QAction(menu)
|
@@ -2130,6 +2123,26 @@ class UtteranceRegion(MfaRegion):
|
|
2130
2123
|
change_speaker_menu.setStyleSheet(self.settings.menu_style_sheet)
|
2131
2124
|
visible_tiers_menu.setStyleSheet(self.settings.menu_style_sheet)
|
2132
2125
|
menu.setStyleSheet(self.settings.menu_style_sheet)
|
2126
|
+
return menu
|
2127
|
+
|
2128
|
+
def generate_text_edit_menu(self, word, location):
|
2129
|
+
menu = self.construct_context_menu()
|
2130
|
+
menu.addSeparator()
|
2131
|
+
if self.dictionary_model.check_word(word, speaker_id=self.item.speaker_id):
|
2132
|
+
lookUpAction = QtGui.QAction(f'Look up "{word}" in dictionary', self)
|
2133
|
+
lookUpAction.triggered.connect(lambda: self.lookUpWord.emit(word))
|
2134
|
+
lookUpAction.triggered.connect(menu.hide)
|
2135
|
+
menu.addAction(lookUpAction)
|
2136
|
+
else:
|
2137
|
+
createAction = QtGui.QAction(f'Add pronunciation for "{word}"', self)
|
2138
|
+
createAction.triggered.connect(lambda: self.createWord.emit(word))
|
2139
|
+
createAction.triggered.connect(menu.hide)
|
2140
|
+
menu.addAction(createAction)
|
2141
|
+
menu.setStyleSheet(self.settings.menu_style_sheet)
|
2142
|
+
menu.exec_(location)
|
2143
|
+
|
2144
|
+
def contextMenuEvent(self, ev: QtWidgets.QGraphicsSceneContextMenuEvent):
|
2145
|
+
menu = self.construct_context_menu()
|
2133
2146
|
menu.exec_(ev.screenPos())
|
2134
2147
|
|
2135
2148
|
def update_tier_visibility(self, checked):
|
@@ -2282,7 +2295,7 @@ class UtteranceRegion(MfaRegion):
|
|
2282
2295
|
if utterance_id != self.item.id or new_text == self.original_text:
|
2283
2296
|
return
|
2284
2297
|
self.original_text = new_text
|
2285
|
-
with QtCore.QSignalBlocker(self.
|
2298
|
+
with QtCore.QSignalBlocker(self.text_item.text_edit):
|
2286
2299
|
position = self.text_edit.textCursor().position()
|
2287
2300
|
end_offset = self.text_edit.document().characterCount() - position
|
2288
2301
|
self.text_edit.setPlainText(new_text)
|
@@ -2332,10 +2345,11 @@ class WaveForm(pg.PlotCurveItem):
|
|
2332
2345
|
class PitchTrack(pg.PlotCurveItem):
|
2333
2346
|
def __init__(self, bottom_point, top_point):
|
2334
2347
|
self.settings = AnchorSettings()
|
2348
|
+
self.plot_theme = self.settings.plot_theme
|
2335
2349
|
self.top_point = top_point
|
2336
2350
|
self.bottom_point = bottom_point
|
2337
2351
|
self.mid_point = (self.top_point + self.bottom_point) / 2
|
2338
|
-
pen = pg.mkPen(self.
|
2352
|
+
pen = pg.mkPen(self.plot_theme.pitch_color, width=3)
|
2339
2353
|
super().__init__()
|
2340
2354
|
self.setPen(pen)
|
2341
2355
|
self.channel = 0
|
@@ -2344,24 +2358,24 @@ class PitchTrack(pg.PlotCurveItem):
|
|
2344
2358
|
self.setAcceptHoverEvents(False)
|
2345
2359
|
self.min_label = pg.TextItem(
|
2346
2360
|
str(self.settings.PITCH_MIN_F0),
|
2347
|
-
self.
|
2361
|
+
self.plot_theme.pitch_color,
|
2348
2362
|
anchor=(1, 1),
|
2349
2363
|
)
|
2350
2364
|
self.min_label.setFont(self.settings.font)
|
2351
2365
|
self.min_label.setParentItem(self)
|
2352
2366
|
self.max_label = pg.TextItem(
|
2353
2367
|
str(self.settings.PITCH_MAX_F0),
|
2354
|
-
self.
|
2368
|
+
self.plot_theme.pitch_color,
|
2355
2369
|
anchor=(1, 0),
|
2356
2370
|
)
|
2357
2371
|
self.max_label.setFont(self.settings.font)
|
2358
2372
|
self.max_label.setParentItem(self)
|
2359
2373
|
|
2360
2374
|
def update_theme(self):
|
2361
|
-
pen = pg.mkPen(self.
|
2375
|
+
pen = pg.mkPen(self.plot_theme.pitch_color, width=3)
|
2362
2376
|
self.setPen(pen)
|
2363
|
-
self.min_label.setColor(self.
|
2364
|
-
self.max_label.setColor(self.
|
2377
|
+
self.min_label.setColor(self.plot_theme.pitch_color)
|
2378
|
+
self.max_label.setColor(self.plot_theme.pitch_color)
|
2365
2379
|
|
2366
2380
|
def hoverEvent(self, ev):
|
2367
2381
|
return
|
@@ -2379,6 +2393,7 @@ class PitchTrack(pg.PlotCurveItem):
|
|
2379
2393
|
class Spectrogram(pg.ImageItem):
|
2380
2394
|
def __init__(self, bottom_point, top_point):
|
2381
2395
|
self.settings = AnchorSettings()
|
2396
|
+
self.plot_theme = self.settings.plot_theme
|
2382
2397
|
self.top_point = top_point
|
2383
2398
|
self.bottom_point = bottom_point
|
2384
2399
|
self.selection_model = None
|
@@ -2387,8 +2402,8 @@ class Spectrogram(pg.ImageItem):
|
|
2387
2402
|
self.cmap = pg.ColorMap(
|
2388
2403
|
None,
|
2389
2404
|
[
|
2390
|
-
self.
|
2391
|
-
self.
|
2405
|
+
self.plot_theme.background_color,
|
2406
|
+
self.plot_theme.spectrogram_color,
|
2392
2407
|
],
|
2393
2408
|
)
|
2394
2409
|
self.cmap.linearize()
|
@@ -2404,8 +2419,8 @@ class Spectrogram(pg.ImageItem):
|
|
2404
2419
|
self.cmap = pg.ColorMap(
|
2405
2420
|
None,
|
2406
2421
|
[
|
2407
|
-
self.
|
2408
|
-
self.
|
2422
|
+
self.plot_theme.background_color,
|
2423
|
+
self.plot_theme.spectrogram_color,
|
2409
2424
|
],
|
2410
2425
|
)
|
2411
2426
|
self.cmap.linearize()
|
@@ -2487,6 +2502,7 @@ class AudioPlots(pg.GraphicsObject):
|
|
2487
2502
|
def __init__(self, top_point, separator_point, bottom_point):
|
2488
2503
|
super().__init__()
|
2489
2504
|
self.settings = AnchorSettings()
|
2505
|
+
self.plot_theme = self.settings.plot_theme
|
2490
2506
|
self.selection_model: typing.Optional[FileSelectionModel] = None
|
2491
2507
|
self.top_point = top_point
|
2492
2508
|
self.separator_point = separator_point
|
@@ -2497,20 +2513,24 @@ class AudioPlots(pg.GraphicsObject):
|
|
2497
2513
|
self.wave_form.setParentItem(self)
|
2498
2514
|
self.spectrogram.setParentItem(self)
|
2499
2515
|
self.pitch_track.setParentItem(self)
|
2500
|
-
color = self.
|
2516
|
+
color = self.plot_theme.selected_range_color
|
2501
2517
|
color.setAlphaF(0.25)
|
2502
2518
|
self.selection_brush = pg.mkBrush(color)
|
2503
|
-
self.background_pen = pg.mkPen(self.
|
2504
|
-
self.background_brush = pg.mkBrush(self.
|
2519
|
+
self.background_pen = pg.mkPen(self.plot_theme.background_color)
|
2520
|
+
self.background_brush = pg.mkBrush(self.plot_theme.background_color)
|
2505
2521
|
self.selection_area = SelectionArea(
|
2506
2522
|
top_point=self.top_point,
|
2507
2523
|
bottom_point=self.bottom_point,
|
2508
2524
|
brush=self.selection_brush,
|
2509
2525
|
clipItem=self,
|
2510
|
-
pen=pg.mkPen(self.
|
2526
|
+
pen=pg.mkPen(self.plot_theme.selected_interval_color),
|
2511
2527
|
)
|
2512
2528
|
self.selection_area.setParentItem(self)
|
2513
2529
|
|
2530
|
+
self.play_timer = QtCore.QTimer()
|
2531
|
+
self.play_timer.setInterval(1)
|
2532
|
+
self.play_timer.timeout.connect(self.update_play_line)
|
2533
|
+
|
2514
2534
|
self.play_line = pg.InfiniteLine(
|
2515
2535
|
pos=-20,
|
2516
2536
|
span=(0, 1),
|
@@ -2523,7 +2543,7 @@ class AudioPlots(pg.GraphicsObject):
|
|
2523
2543
|
pos=-20,
|
2524
2544
|
span=(0, 1),
|
2525
2545
|
pen=pg.mkPen(
|
2526
|
-
self.
|
2546
|
+
self.plot_theme.selected_interval_color,
|
2527
2547
|
width=3,
|
2528
2548
|
style=QtCore.Qt.PenStyle.DashLine,
|
2529
2549
|
),
|
@@ -2649,12 +2669,17 @@ class AudioPlots(pg.GraphicsObject):
|
|
2649
2669
|
br = QtCore.QRectF(self.picture.boundingRect())
|
2650
2670
|
return br
|
2651
2671
|
|
2652
|
-
def update_play_line(self, time):
|
2672
|
+
def update_play_line(self, time=None):
|
2653
2673
|
if time is None:
|
2654
2674
|
return
|
2675
|
+
self.play_line.setVisible(
|
2676
|
+
self.selection_model.min_time <= time <= self.selection_model.max_time
|
2677
|
+
)
|
2655
2678
|
self.play_line.setPos(time)
|
2656
2679
|
|
2657
2680
|
def update_plot(self):
|
2681
|
+
self.setVisible(False)
|
2682
|
+
self.play_line.setVisible(False)
|
2658
2683
|
if (
|
2659
2684
|
self.selection_model.model().file is None
|
2660
2685
|
or self.selection_model.model().file.sound_file is None
|
@@ -2664,9 +2689,8 @@ class AudioPlots(pg.GraphicsObject):
|
|
2664
2689
|
self.rect.setLeft(self.selection_model.plot_min)
|
2665
2690
|
self.rect.setRight(self.selection_model.plot_max)
|
2666
2691
|
self._generate_picture()
|
2667
|
-
self.
|
2668
|
-
self.
|
2669
|
-
self.update()
|
2692
|
+
# self.selection_area.update_region()
|
2693
|
+
self.setVisible(True)
|
2670
2694
|
|
2671
2695
|
|
2672
2696
|
class SpeakerTier(pg.GraphicsObject):
|
@@ -2692,14 +2716,13 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2692
2716
|
self.selection_model = selection_model
|
2693
2717
|
self.dictionary_model = dictionary_model
|
2694
2718
|
self.settings = AnchorSettings()
|
2719
|
+
self.plot_theme = self.settings.plot_theme
|
2695
2720
|
self.search_term = search_term
|
2696
2721
|
self.speaker_id = speaker_id
|
2697
2722
|
self.speaker_name = speaker_name
|
2698
2723
|
self.speaker_index = 0
|
2699
2724
|
self.top_point = top_point
|
2700
|
-
self.speaker_label = pg.TextItem(
|
2701
|
-
self.speaker_name, color=self.settings.plot_theme.break_line_color
|
2702
|
-
)
|
2725
|
+
self.speaker_label = pg.TextItem(self.speaker_name, color=self.plot_theme.break_line_color)
|
2703
2726
|
self.speaker_label.setFont(self.settings.font)
|
2704
2727
|
self.speaker_label.setParentItem(self)
|
2705
2728
|
self.speaker_label.setZValue(40)
|
@@ -2707,8 +2730,8 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2707
2730
|
self.annotation_range = self.top_point - self.bottom_point
|
2708
2731
|
self.extra_tiers = {}
|
2709
2732
|
self.visible_utterances: dict[str, UtteranceRegion] = {}
|
2710
|
-
self.background_brush = pg.mkBrush(self.
|
2711
|
-
self.border = pg.mkPen(self.
|
2733
|
+
self.background_brush = pg.mkBrush(self.plot_theme.background_color)
|
2734
|
+
self.border = pg.mkPen(self.plot_theme.break_line_color)
|
2712
2735
|
self.picture = QtGui.QPicture()
|
2713
2736
|
self.has_visible_utterances = False
|
2714
2737
|
self.has_selected_utterances = False
|
@@ -2724,6 +2747,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2724
2747
|
self.selection_model.selectionChanged.connect(self.update_select)
|
2725
2748
|
self.selection_model.model().utterancesReady.connect(self.refresh)
|
2726
2749
|
self.available_speakers = {}
|
2750
|
+
self.painter_path_cache = {True: {}, False: {}}
|
2727
2751
|
|
2728
2752
|
def wheelEvent(self, ev):
|
2729
2753
|
self.receivedWheelEvent.emit(ev)
|
@@ -2738,6 +2762,10 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2738
2762
|
p.drawPicture(0, 0, self.picture)
|
2739
2763
|
|
2740
2764
|
def _generate_picture(self):
|
2765
|
+
speaker_name = self.corpus_model.get_speaker_name(self.speaker_id)
|
2766
|
+
if speaker_name != self.speaker_name:
|
2767
|
+
self.speaker_name = speaker_name
|
2768
|
+
self.speaker_label.setText(self.speaker_name)
|
2741
2769
|
self.picture = QtGui.QPicture()
|
2742
2770
|
painter = QtGui.QPainter(self.picture)
|
2743
2771
|
painter.setPen(self.border)
|
@@ -2762,7 +2790,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2762
2790
|
|
2763
2791
|
def setSearchTerm(self, term):
|
2764
2792
|
for utt in self.visible_utterances.values():
|
2765
|
-
utt.highlighter.setSearchTerm(term)
|
2793
|
+
utt.text_item.highlighter.setSearchTerm(term)
|
2766
2794
|
|
2767
2795
|
def refreshTexts(self, utt_id, text):
|
2768
2796
|
for reg in self.visible_utterances.values():
|
@@ -2778,6 +2806,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2778
2806
|
reg.scene().removeItem(reg)
|
2779
2807
|
self.visible_utterances = {}
|
2780
2808
|
|
2809
|
+
@profile
|
2781
2810
|
def refresh(self, *args):
|
2782
2811
|
self.hide()
|
2783
2812
|
if self.selection_model.plot_min is None:
|
@@ -2822,6 +2851,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2822
2851
|
self.has_visible_utterances = True
|
2823
2852
|
# Utterance region always at the top
|
2824
2853
|
reg = UtteranceRegion(
|
2854
|
+
self,
|
2825
2855
|
u,
|
2826
2856
|
self.corpus_model,
|
2827
2857
|
self.file_model,
|
@@ -2847,7 +2877,6 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2847
2877
|
reg.viewRequested.connect(self.selection_model.set_view_times)
|
2848
2878
|
reg.textEdited.connect(self.update_utterance_text)
|
2849
2879
|
reg.selectRequested.connect(self.selection_model.update_select)
|
2850
|
-
reg.setParentItem(self)
|
2851
2880
|
self.visible_utterances[u.id] = reg
|
2852
2881
|
|
2853
2882
|
self.show()
|
@@ -2897,13 +2926,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2897
2926
|
if other_begin < end <= other_end or end > other_begin > other_end > beg:
|
2898
2927
|
reg.setRegion([beg, other_begin])
|
2899
2928
|
break
|
2900
|
-
reg.
|
2901
|
-
reg.text.update_times(self.selection_model.plot_min, self.selection_model.plot_max)
|
2902
|
-
if reg.normalized_text is not None:
|
2903
|
-
reg.normalized_text.text.begin, reg.normalized_text.text.end = reg.getRegion()
|
2904
|
-
reg.normalized_text.text.update_times(
|
2905
|
-
self.selection_model.plot_min, self.selection_model.plot_max
|
2906
|
-
)
|
2929
|
+
reg.update_edit_fields()
|
2907
2930
|
reg.select_self()
|
2908
2931
|
reg.update()
|
2909
2932
|
|
@@ -2918,7 +2941,5 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2918
2941
|
return
|
2919
2942
|
self.selection_model.model().update_utterance_times(utt, begin=new_begin, end=new_end)
|
2920
2943
|
self.selection_model.request_start_time(new_begin)
|
2921
|
-
reg.
|
2922
|
-
reg.text.end = new_end
|
2923
|
-
reg.update()
|
2944
|
+
reg.update_edit_fields()
|
2924
2945
|
self.lineDragFinished.emit(True)
|