Anchor-annotator 0.6.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.6.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.6.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 +25 -2
- anchor/models.py +103 -58
- anchor/plot.py +383 -360
- anchor/settings.py +9 -3
- anchor/ui_main_window.py +10 -0
- anchor/undo.py +18 -18
- anchor/widgets.py +26 -12
- anchor/workers.py +2483 -2462
- Anchor_annotator-0.6.0.dist-info/RECORD +0 -22
- {Anchor_annotator-0.6.0.dist-info → Anchor_annotator-0.7.0.dist-info}/LICENSE +0 -0
- {Anchor_annotator-0.6.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,82 +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
1340
|
self.currentBrush = self.parentItem().currentBrush
|
1332
|
-
self.
|
1333
|
-
self.
|
1334
|
-
self.
|
1335
|
-
left=self.begin,
|
1336
|
-
top=self.top_point,
|
1337
|
-
width=self.end - self.begin,
|
1338
|
-
height=self.height,
|
1339
|
-
)
|
1340
|
-
self.rect.setTop(self.top_point)
|
1341
|
-
self.rect.setBottom(self.bottom_point)
|
1342
|
-
self._generate_picture()
|
1343
|
-
|
1344
|
-
def setSelected(self, selected):
|
1345
|
-
new_brush = self.parentItem().currentBrush
|
1346
|
-
if new_brush != self.currentBrush:
|
1347
|
-
self.currentBrush = new_brush
|
1348
|
-
self._generate_picture()
|
1349
|
-
|
1350
|
-
def _generate_picture(self):
|
1351
|
-
painter = QtGui.QPainter(self.picture)
|
1352
|
-
painter.setPen(self.border)
|
1353
|
-
painter.setBrush(self.currentBrush)
|
1354
|
-
painter.drawRect(self.rect)
|
1355
|
-
painter.end()
|
1356
|
-
|
1357
|
-
def mouseClickEvent(self, ev):
|
1358
|
-
if ev.button() != QtCore.Qt.MouseButton.LeftButton:
|
1359
|
-
ev.ignore()
|
1360
|
-
return
|
1361
|
-
self.audioSelected.emit(self.begin, self.end)
|
1362
|
-
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
|
1363
1344
|
|
1364
1345
|
def boundingRect(self):
|
1365
|
-
|
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
|
+
)
|
1366
1354
|
return br
|
1367
1355
|
|
1368
|
-
def paint(self, painter
|
1369
|
-
|
1356
|
+
def paint(self, painter, option, widget=...):
|
1357
|
+
return
|
1370
1358
|
|
1371
1359
|
|
1372
1360
|
class TranscriberTextRegion(TextAttributeRegion):
|
1373
|
-
|
1374
|
-
audioSelected = QtCore.Signal(object, object)
|
1375
|
-
|
1361
|
+
@profile
|
1376
1362
|
def __init__(
|
1377
1363
|
self,
|
1378
1364
|
parent,
|
1379
|
-
|
1380
|
-
end: float,
|
1381
|
-
text: str,
|
1365
|
+
item,
|
1382
1366
|
top_point,
|
1383
1367
|
height,
|
1384
1368
|
selection_model: CorpusSelectionModel,
|
1385
|
-
border=None,
|
1386
1369
|
dictionary_model=None,
|
1387
1370
|
speaker_id=None,
|
1388
1371
|
alignment=None,
|
1389
1372
|
search_term=None,
|
1373
|
+
plot_theme=None,
|
1390
1374
|
):
|
1391
1375
|
super().__init__(
|
1392
1376
|
parent,
|
1393
|
-
begin,
|
1394
|
-
end,
|
1395
|
-
|
1377
|
+
item.begin,
|
1378
|
+
item.end,
|
1379
|
+
item.transcription_text,
|
1396
1380
|
top_point,
|
1397
1381
|
height,
|
1398
1382
|
selection_model,
|
1399
|
-
border,
|
1400
1383
|
dictionary_model,
|
1401
1384
|
speaker_id,
|
1385
|
+
plot_theme,
|
1402
1386
|
)
|
1403
|
-
|
1387
|
+
self.item = item
|
1404
1388
|
self.highlighter = TranscriberErrorHighlighter(self.text_edit.document())
|
1405
1389
|
if alignment is not None:
|
1406
1390
|
self.highlighter.set_alignment(alignment)
|
@@ -1409,9 +1393,6 @@ class TranscriberTextRegion(TextAttributeRegion):
|
|
1409
1393
|
|
1410
1394
|
|
1411
1395
|
class NormalizedTextRegion(TextAttributeRegion):
|
1412
|
-
viewRequested = QtCore.Signal(object, object)
|
1413
|
-
audioSelected = QtCore.Signal(object, object)
|
1414
|
-
|
1415
1396
|
def __init__(
|
1416
1397
|
self,
|
1417
1398
|
parent,
|
@@ -1421,10 +1402,10 @@ class NormalizedTextRegion(TextAttributeRegion):
|
|
1421
1402
|
top_point,
|
1422
1403
|
height,
|
1423
1404
|
selection_model: CorpusSelectionModel,
|
1424
|
-
border=None,
|
1425
1405
|
dictionary_model=None,
|
1426
1406
|
search_term=None,
|
1427
1407
|
speaker_id=None,
|
1408
|
+
plot_theme=None,
|
1428
1409
|
):
|
1429
1410
|
super().__init__(
|
1430
1411
|
parent,
|
@@ -1434,17 +1415,21 @@ class NormalizedTextRegion(TextAttributeRegion):
|
|
1434
1415
|
top_point,
|
1435
1416
|
height,
|
1436
1417
|
selection_model,
|
1437
|
-
border,
|
1438
1418
|
dictionary_model,
|
1439
1419
|
speaker_id,
|
1420
|
+
plot_theme,
|
1440
1421
|
)
|
1441
1422
|
|
1442
|
-
self.highlighter = Highlighter(self.text_edit.document())
|
1423
|
+
self.highlighter = Highlighter(self.text_item.text_edit.document())
|
1443
1424
|
self.highlighter.set_models(dictionary_model)
|
1444
1425
|
self.highlighter.set_speaker(speaker_id)
|
1445
1426
|
if search_term:
|
1446
1427
|
self.highlighter.setSearchTerm(search_term)
|
1447
1428
|
|
1429
|
+
def boundingRect(self):
|
1430
|
+
br = super().boundingRect()
|
1431
|
+
return br
|
1432
|
+
|
1448
1433
|
|
1449
1434
|
class Highlighter(QtGui.QSyntaxHighlighter):
|
1450
1435
|
WORDS = rf"[^\s{''.join(DEFAULT_WORD_BREAK_MARKERS)+''.join(DEFAULT_PUNCTUATION)}]+"
|
@@ -1537,6 +1522,7 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1537
1522
|
self.item = item
|
1538
1523
|
|
1539
1524
|
self.settings = AnchorSettings()
|
1525
|
+
self.plot_theme = self.settings.plot_theme
|
1540
1526
|
|
1541
1527
|
self.item_min = self.item.begin
|
1542
1528
|
self.item_max = self.item.end
|
@@ -1552,13 +1538,13 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1552
1538
|
self.text_margin_pixels = 2
|
1553
1539
|
self.height = abs(self.top_point - self.bottom_point)
|
1554
1540
|
|
1555
|
-
self.interval_background_color = self.
|
1556
|
-
self.hover_line_color = self.
|
1557
|
-
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
|
1558
1544
|
|
1559
|
-
self.break_line_color = self.
|
1560
|
-
self.text_color = self.
|
1561
|
-
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
|
1562
1548
|
self.plot_text_font = self.settings.big_font
|
1563
1549
|
self.setCursor(QtCore.Qt.CursorShape.SizeAllCursor)
|
1564
1550
|
self.pen = pg.mkPen(self.break_line_color, width=3)
|
@@ -1681,122 +1667,131 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1681
1667
|
return br
|
1682
1668
|
|
1683
1669
|
|
1684
|
-
class
|
1670
|
+
class IntervalTier(pg.GraphicsObject):
|
1671
|
+
highlightRequested = QtCore.Signal(object)
|
1672
|
+
|
1685
1673
|
def __init__(
|
1686
1674
|
self,
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
selection_model:
|
1691
|
-
|
1692
|
-
|
1675
|
+
parent,
|
1676
|
+
utterance: CtmInterval,
|
1677
|
+
intervals: typing.List[CtmInterval],
|
1678
|
+
selection_model: FileSelectionModel,
|
1679
|
+
top_point,
|
1680
|
+
bottom_point,
|
1681
|
+
word=False,
|
1693
1682
|
):
|
1694
|
-
super().__init__(
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
)
|
1703
|
-
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
|
1704
1697
|
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
options = QtGui.QTextOption()
|
1712
|
-
options.setWrapMode(QtGui.QTextOption.WrapMode.NoWrap)
|
1713
|
-
self.text.textItem.document().setDefaultTextOption(options)
|
1714
|
-
self.text.setParentItem(self)
|
1715
|
-
self.per_tier_range = self.top_point - self.bottom_point
|
1716
|
-
self.currentBrush = pg.mkBrush((0, 0, 0, 0))
|
1717
|
-
self.selection_model.viewChanged.connect(self.check_visibility)
|
1718
|
-
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()
|
1719
1704
|
|
1720
|
-
|
1721
|
-
|
1722
|
-
self.text.setColor(self.settings.plot_theme.selected_text_color)
|
1723
|
-
else:
|
1724
|
-
self.text.setColor(self.settings.plot_theme.text_color)
|
1705
|
+
symbol.addText(0, 0, self.plot_text_font, interval.label)
|
1706
|
+
br = symbol.boundingRect()
|
1725
1707
|
|
1726
|
-
|
1727
|
-
|
1728
|
-
self.selection_model.max_time - self.selection_model.min_time
|
1729
|
-
) < 0.001:
|
1730
|
-
self.hide()
|
1731
|
-
else:
|
1732
|
-
vb = self.getViewBox()
|
1733
|
-
visible_begin = max(self.item_min, self.selection_model.plot_min)
|
1734
|
-
visible_end = min(self.item_max, self.selection_model.plot_max)
|
1735
|
-
visible_duration = visible_end - visible_begin
|
1736
|
-
self.text.setPos(
|
1737
|
-
visible_begin + (visible_duration / 2), self.top_point - (self.per_tier_range / 2)
|
1738
|
-
)
|
1739
|
-
if vb is None:
|
1740
|
-
self.text.setVisible(
|
1741
|
-
(visible_end - visible_begin)
|
1742
|
-
/ (self.selection_model.max_time - self.selection_model.min_time)
|
1743
|
-
> 0.005
|
1744
|
-
)
|
1745
|
-
else:
|
1746
|
-
pixel_size = vb.viewPixelSize()[0]
|
1747
|
-
if pixel_size != 0:
|
1748
|
-
x_margin_px = 8
|
1749
|
-
available_text_width = visible_duration / pixel_size - (2 * x_margin_px)
|
1708
|
+
# getting transform object
|
1709
|
+
tr = QtGui.QTransform()
|
1750
1710
|
|
1751
|
-
|
1752
|
-
|
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)
|
1753
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
|
1754
1721
|
|
1755
|
-
|
1756
|
-
|
1757
|
-
self
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
):
|
1766
|
-
super().__init__(
|
1767
|
-
phone_interval, corpus_model, file_model, selection_model, bottom_point, top_point
|
1768
|
-
)
|
1769
|
-
if color is not None:
|
1770
|
-
self.currentBrush = pg.mkBrush(color)
|
1771
|
-
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
|
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)
|
1772
1732
|
|
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
|
1773
1748
|
|
1774
|
-
|
1775
|
-
highlightRequested = QtCore.Signal(object)
|
1749
|
+
return super().mousePressEvent(e)
|
1776
1750
|
|
1777
|
-
def
|
1778
|
-
self
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
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()
|
1790
1777
|
|
1791
|
-
def
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
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
|
+
)
|
1795
1785
|
|
1796
1786
|
|
1797
1787
|
class UtteranceRegion(MfaRegion):
|
1788
|
+
lookUpWord = QtCore.Signal(object)
|
1789
|
+
createWord = QtCore.Signal(object)
|
1790
|
+
|
1791
|
+
@profile
|
1798
1792
|
def __init__(
|
1799
1793
|
self,
|
1794
|
+
parent,
|
1800
1795
|
utterance: workers.UtteranceData,
|
1801
1796
|
corpus_model: CorpusModel,
|
1802
1797
|
file_model: FileUtterancesModel,
|
@@ -1817,6 +1812,8 @@ class UtteranceRegion(MfaRegion):
|
|
1817
1812
|
bottom_point,
|
1818
1813
|
top_point,
|
1819
1814
|
)
|
1815
|
+
self.setParentItem(parent)
|
1816
|
+
plot_theme = self.settings.plot_theme
|
1820
1817
|
self.hide()
|
1821
1818
|
self.item = utterance
|
1822
1819
|
self.selection_model = selection_model
|
@@ -1869,44 +1866,34 @@ class UtteranceRegion(MfaRegion):
|
|
1869
1866
|
|
1870
1867
|
self.corpus_model.utteranceTextUpdated.connect(self.update_text_from_model)
|
1871
1868
|
self.original_text = self.item.text
|
1872
|
-
self.
|
1869
|
+
self.text_item = NormalizedTextRegion(
|
1870
|
+
self,
|
1873
1871
|
self.item.begin,
|
1874
1872
|
self.item.end,
|
1875
|
-
self.item.
|
1873
|
+
self.item.normalized_text,
|
1874
|
+
self.top_point,
|
1875
|
+
self.per_tier_range,
|
1876
1876
|
self.selection_model,
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
per_tier_range=self.per_tier_range,
|
1881
|
-
dictionary_model=self.dictionary_model,
|
1882
|
-
speaker_id=self.item.speaker_id,
|
1883
|
-
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,
|
1884
1880
|
)
|
1885
|
-
self.text.setParentItem(self)
|
1886
1881
|
|
1887
|
-
self.text_edit = self.
|
1888
|
-
|
1889
|
-
|
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)
|
1890
1886
|
self.corpus_model.editableChanged.connect(self.change_editing)
|
1891
|
-
self.text_edit.setViewportMargins(
|
1892
|
-
self.text_margin_pixels,
|
1893
|
-
self.text_margin_pixels,
|
1894
|
-
self.text_margin_pixels,
|
1895
|
-
self.text_margin_pixels,
|
1896
|
-
)
|
1897
|
-
self.text_edit.setStyleSheet(self.settings.interval_style_sheet)
|
1898
1887
|
self.text_edit.installEventFilter(self)
|
1899
|
-
self.highlighter = Highlighter(self.text_edit.document())
|
1900
|
-
self.highlighter.set_models(dictionary_model)
|
1901
|
-
self.highlighter.set_speaker(self.item.speaker_id)
|
1902
|
-
if search_term:
|
1903
|
-
self.highlighter.setSearchTerm(search_term)
|
1904
1888
|
self.timer = QtCore.QTimer()
|
1905
1889
|
self.text_edit.textChanged.connect(self.refresh_timer)
|
1906
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)
|
1907
1893
|
self.timer.timeout.connect(self.save_changes)
|
1908
1894
|
self._cached_pixel_size = None
|
1909
1895
|
self.normalized_text = None
|
1896
|
+
self.transcription_text = None
|
1910
1897
|
i = -1
|
1911
1898
|
for tier_name, lookup in self.extra_tiers.items():
|
1912
1899
|
if not visible_tiers[tier_name]:
|
@@ -1924,23 +1911,19 @@ class UtteranceRegion(MfaRegion):
|
|
1924
1911
|
tier_top_point,
|
1925
1912
|
self.per_tier_range,
|
1926
1913
|
self.selection_model,
|
1927
|
-
border=pg.mkPen(self.settings.plot_theme.break_line_color),
|
1928
1914
|
dictionary_model=dictionary_model,
|
1929
1915
|
search_term=search_term,
|
1930
1916
|
speaker_id=utterance.speaker_id,
|
1931
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)
|
1932
1920
|
continue
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
1936
|
-
if (
|
1937
|
-
lookup == "transcription_text"
|
1938
|
-
and self.item.text
|
1939
|
-
and self.item.transcription_text
|
1940
|
-
):
|
1921
|
+
elif lookup == "transcription_text":
|
1922
|
+
alignment = None
|
1923
|
+
if self.item.normalized_text and self.item.transcription_text:
|
1941
1924
|
alignment = pairwise2.align.globalms(
|
1942
|
-
self.item.
|
1943
|
-
self.item.transcription_text.split(),
|
1925
|
+
self.item.normalized_text.lower().split(),
|
1926
|
+
self.item.transcription_text.lower().split(),
|
1944
1927
|
0,
|
1945
1928
|
-2,
|
1946
1929
|
-1,
|
@@ -1948,18 +1931,39 @@ class UtteranceRegion(MfaRegion):
|
|
1948
1931
|
gap_char=["-"],
|
1949
1932
|
one_alignment_only=True,
|
1950
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)
|
1951
1953
|
|
1952
1954
|
self.extra_tier_intervals[tier_name] = []
|
1953
1955
|
|
1954
1956
|
if intervals is None:
|
1955
1957
|
continue
|
1958
|
+
if not isinstance(intervals, list):
|
1959
|
+
intervals = [intervals]
|
1956
1960
|
min_confidence = None
|
1957
1961
|
max_confidence = None
|
1958
1962
|
cmap = pg.ColorMap(
|
1959
1963
|
None,
|
1960
1964
|
[
|
1961
|
-
|
1962
|
-
|
1965
|
+
plot_theme.error_color,
|
1966
|
+
plot_theme.interval_background_color,
|
1963
1967
|
],
|
1964
1968
|
)
|
1965
1969
|
cmap.linearize()
|
@@ -1971,64 +1975,49 @@ class UtteranceRegion(MfaRegion):
|
|
1971
1975
|
min_confidence = interval.confidence
|
1972
1976
|
if max_confidence is None or interval.confidence > max_confidence:
|
1973
1977
|
max_confidence = interval.confidence
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
color = cmap.map(normalized_confidence)
|
1999
|
-
interval_reg = PhoneRegion(
|
2000
|
-
interval,
|
2001
|
-
self.corpus_model,
|
2002
|
-
self.file_model,
|
2003
|
-
selection_model=selection_model,
|
2004
|
-
top_point=tier_top_point,
|
2005
|
-
bottom_point=tier_bottom_point,
|
2006
|
-
color=color,
|
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
|
2007
2002
|
)
|
2008
|
-
|
2009
|
-
|
2010
|
-
|
2011
|
-
interval_reg = WordRegion(
|
2012
|
-
interval,
|
2013
|
-
self.corpus_model,
|
2014
|
-
self.file_model,
|
2015
|
-
selection_model=selection_model,
|
2016
|
-
top_point=tier_top_point,
|
2017
|
-
bottom_point=tier_bottom_point,
|
2003
|
+
if self.normalized_text is not None:
|
2004
|
+
interval_tier.highlightRequested.connect(
|
2005
|
+
self.normalized_text.highlighter.setSearchTerm
|
2018
2006
|
)
|
2019
|
-
interval_reg.setParentItem(self)
|
2020
|
-
interval_reg.highlightRequested.connect(self.highlighter.setSearchTerm)
|
2021
|
-
interval_reg.audioSelected.connect(self.setSelected)
|
2022
2007
|
|
2008
|
+
for interval in intervals:
|
2009
|
+
if "phone_intervals" in lookup or "word_intervals" in lookup:
|
2010
|
+
continue
|
2023
2011
|
else:
|
2024
2012
|
interval_reg = IntervalTextRegion(
|
2025
2013
|
interval,
|
2026
2014
|
self.text_color,
|
2027
|
-
border=pg.mkPen(
|
2015
|
+
border=pg.mkPen(plot_theme.break_line_color, width=1),
|
2028
2016
|
top_point=tier_top_point,
|
2029
2017
|
height=self.per_tier_range,
|
2030
2018
|
background_brush=self.background_brush,
|
2031
2019
|
selected_brush=pg.mkBrush(self.selected_interval_color),
|
2020
|
+
plot_theme=self.plot_theme,
|
2032
2021
|
)
|
2033
2022
|
interval_reg.audioSelected.connect(self.setSelected)
|
2034
2023
|
interval_reg.setParentItem(self)
|
@@ -2037,9 +2026,23 @@ class UtteranceRegion(MfaRegion):
|
|
2037
2026
|
interval_reg.viewRequested.connect(self.viewRequested.emit)
|
2038
2027
|
self.extra_tier_intervals[tier_name].append(interval_reg)
|
2039
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)
|
2040
2031
|
self.show()
|
2041
2032
|
self.available_speakers = available_speakers
|
2042
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
|
+
|
2043
2046
|
def show(self):
|
2044
2047
|
for intervals in self.extra_tier_intervals.values():
|
2045
2048
|
for interval in intervals:
|
@@ -2056,14 +2059,6 @@ class UtteranceRegion(MfaRegion):
|
|
2056
2059
|
interval.hide()
|
2057
2060
|
super().show()
|
2058
2061
|
|
2059
|
-
def setSelected(self, selected: bool):
|
2060
|
-
if selected:
|
2061
|
-
if not self.selected:
|
2062
|
-
self.text_edit.setFocus()
|
2063
|
-
else:
|
2064
|
-
self.text_edit.clearFocus()
|
2065
|
-
super().setSelected(selected)
|
2066
|
-
|
2067
2062
|
def change_editing(self, editable: bool):
|
2068
2063
|
self.lines[0].movable = editable
|
2069
2064
|
self.lines[1].movable = editable
|
@@ -2083,7 +2078,7 @@ class UtteranceRegion(MfaRegion):
|
|
2083
2078
|
self.movable = False
|
2084
2079
|
self.setAcceptHoverEvents(False)
|
2085
2080
|
|
2086
|
-
def
|
2081
|
+
def construct_context_menu(self):
|
2087
2082
|
menu = QtWidgets.QMenu()
|
2088
2083
|
change_speaker_menu = QtWidgets.QMenu("Change speaker")
|
2089
2084
|
a = QtGui.QAction(menu)
|
@@ -2128,6 +2123,26 @@ class UtteranceRegion(MfaRegion):
|
|
2128
2123
|
change_speaker_menu.setStyleSheet(self.settings.menu_style_sheet)
|
2129
2124
|
visible_tiers_menu.setStyleSheet(self.settings.menu_style_sheet)
|
2130
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()
|
2131
2146
|
menu.exec_(ev.screenPos())
|
2132
2147
|
|
2133
2148
|
def update_tier_visibility(self, checked):
|
@@ -2280,7 +2295,7 @@ class UtteranceRegion(MfaRegion):
|
|
2280
2295
|
if utterance_id != self.item.id or new_text == self.original_text:
|
2281
2296
|
return
|
2282
2297
|
self.original_text = new_text
|
2283
|
-
with QtCore.QSignalBlocker(self.
|
2298
|
+
with QtCore.QSignalBlocker(self.text_item.text_edit):
|
2284
2299
|
position = self.text_edit.textCursor().position()
|
2285
2300
|
end_offset = self.text_edit.document().characterCount() - position
|
2286
2301
|
self.text_edit.setPlainText(new_text)
|
@@ -2330,10 +2345,11 @@ class WaveForm(pg.PlotCurveItem):
|
|
2330
2345
|
class PitchTrack(pg.PlotCurveItem):
|
2331
2346
|
def __init__(self, bottom_point, top_point):
|
2332
2347
|
self.settings = AnchorSettings()
|
2348
|
+
self.plot_theme = self.settings.plot_theme
|
2333
2349
|
self.top_point = top_point
|
2334
2350
|
self.bottom_point = bottom_point
|
2335
2351
|
self.mid_point = (self.top_point + self.bottom_point) / 2
|
2336
|
-
pen = pg.mkPen(self.
|
2352
|
+
pen = pg.mkPen(self.plot_theme.pitch_color, width=3)
|
2337
2353
|
super().__init__()
|
2338
2354
|
self.setPen(pen)
|
2339
2355
|
self.channel = 0
|
@@ -2342,24 +2358,24 @@ class PitchTrack(pg.PlotCurveItem):
|
|
2342
2358
|
self.setAcceptHoverEvents(False)
|
2343
2359
|
self.min_label = pg.TextItem(
|
2344
2360
|
str(self.settings.PITCH_MIN_F0),
|
2345
|
-
self.
|
2361
|
+
self.plot_theme.pitch_color,
|
2346
2362
|
anchor=(1, 1),
|
2347
2363
|
)
|
2348
2364
|
self.min_label.setFont(self.settings.font)
|
2349
2365
|
self.min_label.setParentItem(self)
|
2350
2366
|
self.max_label = pg.TextItem(
|
2351
2367
|
str(self.settings.PITCH_MAX_F0),
|
2352
|
-
self.
|
2368
|
+
self.plot_theme.pitch_color,
|
2353
2369
|
anchor=(1, 0),
|
2354
2370
|
)
|
2355
2371
|
self.max_label.setFont(self.settings.font)
|
2356
2372
|
self.max_label.setParentItem(self)
|
2357
2373
|
|
2358
2374
|
def update_theme(self):
|
2359
|
-
pen = pg.mkPen(self.
|
2375
|
+
pen = pg.mkPen(self.plot_theme.pitch_color, width=3)
|
2360
2376
|
self.setPen(pen)
|
2361
|
-
self.min_label.setColor(self.
|
2362
|
-
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)
|
2363
2379
|
|
2364
2380
|
def hoverEvent(self, ev):
|
2365
2381
|
return
|
@@ -2377,6 +2393,7 @@ class PitchTrack(pg.PlotCurveItem):
|
|
2377
2393
|
class Spectrogram(pg.ImageItem):
|
2378
2394
|
def __init__(self, bottom_point, top_point):
|
2379
2395
|
self.settings = AnchorSettings()
|
2396
|
+
self.plot_theme = self.settings.plot_theme
|
2380
2397
|
self.top_point = top_point
|
2381
2398
|
self.bottom_point = bottom_point
|
2382
2399
|
self.selection_model = None
|
@@ -2385,8 +2402,8 @@ class Spectrogram(pg.ImageItem):
|
|
2385
2402
|
self.cmap = pg.ColorMap(
|
2386
2403
|
None,
|
2387
2404
|
[
|
2388
|
-
self.
|
2389
|
-
self.
|
2405
|
+
self.plot_theme.background_color,
|
2406
|
+
self.plot_theme.spectrogram_color,
|
2390
2407
|
],
|
2391
2408
|
)
|
2392
2409
|
self.cmap.linearize()
|
@@ -2402,8 +2419,8 @@ class Spectrogram(pg.ImageItem):
|
|
2402
2419
|
self.cmap = pg.ColorMap(
|
2403
2420
|
None,
|
2404
2421
|
[
|
2405
|
-
self.
|
2406
|
-
self.
|
2422
|
+
self.plot_theme.background_color,
|
2423
|
+
self.plot_theme.spectrogram_color,
|
2407
2424
|
],
|
2408
2425
|
)
|
2409
2426
|
self.cmap.linearize()
|
@@ -2485,6 +2502,7 @@ class AudioPlots(pg.GraphicsObject):
|
|
2485
2502
|
def __init__(self, top_point, separator_point, bottom_point):
|
2486
2503
|
super().__init__()
|
2487
2504
|
self.settings = AnchorSettings()
|
2505
|
+
self.plot_theme = self.settings.plot_theme
|
2488
2506
|
self.selection_model: typing.Optional[FileSelectionModel] = None
|
2489
2507
|
self.top_point = top_point
|
2490
2508
|
self.separator_point = separator_point
|
@@ -2495,20 +2513,24 @@ class AudioPlots(pg.GraphicsObject):
|
|
2495
2513
|
self.wave_form.setParentItem(self)
|
2496
2514
|
self.spectrogram.setParentItem(self)
|
2497
2515
|
self.pitch_track.setParentItem(self)
|
2498
|
-
color = self.
|
2516
|
+
color = self.plot_theme.selected_range_color
|
2499
2517
|
color.setAlphaF(0.25)
|
2500
2518
|
self.selection_brush = pg.mkBrush(color)
|
2501
|
-
self.background_pen = pg.mkPen(self.
|
2502
|
-
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)
|
2503
2521
|
self.selection_area = SelectionArea(
|
2504
2522
|
top_point=self.top_point,
|
2505
2523
|
bottom_point=self.bottom_point,
|
2506
2524
|
brush=self.selection_brush,
|
2507
2525
|
clipItem=self,
|
2508
|
-
pen=pg.mkPen(self.
|
2526
|
+
pen=pg.mkPen(self.plot_theme.selected_interval_color),
|
2509
2527
|
)
|
2510
2528
|
self.selection_area.setParentItem(self)
|
2511
2529
|
|
2530
|
+
self.play_timer = QtCore.QTimer()
|
2531
|
+
self.play_timer.setInterval(1)
|
2532
|
+
self.play_timer.timeout.connect(self.update_play_line)
|
2533
|
+
|
2512
2534
|
self.play_line = pg.InfiniteLine(
|
2513
2535
|
pos=-20,
|
2514
2536
|
span=(0, 1),
|
@@ -2521,7 +2543,7 @@ class AudioPlots(pg.GraphicsObject):
|
|
2521
2543
|
pos=-20,
|
2522
2544
|
span=(0, 1),
|
2523
2545
|
pen=pg.mkPen(
|
2524
|
-
self.
|
2546
|
+
self.plot_theme.selected_interval_color,
|
2525
2547
|
width=3,
|
2526
2548
|
style=QtCore.Qt.PenStyle.DashLine,
|
2527
2549
|
),
|
@@ -2647,12 +2669,17 @@ class AudioPlots(pg.GraphicsObject):
|
|
2647
2669
|
br = QtCore.QRectF(self.picture.boundingRect())
|
2648
2670
|
return br
|
2649
2671
|
|
2650
|
-
def update_play_line(self, time):
|
2672
|
+
def update_play_line(self, time=None):
|
2651
2673
|
if time is None:
|
2652
2674
|
return
|
2675
|
+
self.play_line.setVisible(
|
2676
|
+
self.selection_model.min_time <= time <= self.selection_model.max_time
|
2677
|
+
)
|
2653
2678
|
self.play_line.setPos(time)
|
2654
2679
|
|
2655
2680
|
def update_plot(self):
|
2681
|
+
self.setVisible(False)
|
2682
|
+
self.play_line.setVisible(False)
|
2656
2683
|
if (
|
2657
2684
|
self.selection_model.model().file is None
|
2658
2685
|
or self.selection_model.model().file.sound_file is None
|
@@ -2662,9 +2689,8 @@ class AudioPlots(pg.GraphicsObject):
|
|
2662
2689
|
self.rect.setLeft(self.selection_model.plot_min)
|
2663
2690
|
self.rect.setRight(self.selection_model.plot_max)
|
2664
2691
|
self._generate_picture()
|
2665
|
-
self.
|
2666
|
-
self.
|
2667
|
-
self.update()
|
2692
|
+
# self.selection_area.update_region()
|
2693
|
+
self.setVisible(True)
|
2668
2694
|
|
2669
2695
|
|
2670
2696
|
class SpeakerTier(pg.GraphicsObject):
|
@@ -2690,14 +2716,13 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2690
2716
|
self.selection_model = selection_model
|
2691
2717
|
self.dictionary_model = dictionary_model
|
2692
2718
|
self.settings = AnchorSettings()
|
2719
|
+
self.plot_theme = self.settings.plot_theme
|
2693
2720
|
self.search_term = search_term
|
2694
2721
|
self.speaker_id = speaker_id
|
2695
2722
|
self.speaker_name = speaker_name
|
2696
2723
|
self.speaker_index = 0
|
2697
2724
|
self.top_point = top_point
|
2698
|
-
self.speaker_label = pg.TextItem(
|
2699
|
-
self.speaker_name, color=self.settings.plot_theme.break_line_color
|
2700
|
-
)
|
2725
|
+
self.speaker_label = pg.TextItem(self.speaker_name, color=self.plot_theme.break_line_color)
|
2701
2726
|
self.speaker_label.setFont(self.settings.font)
|
2702
2727
|
self.speaker_label.setParentItem(self)
|
2703
2728
|
self.speaker_label.setZValue(40)
|
@@ -2705,8 +2730,8 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2705
2730
|
self.annotation_range = self.top_point - self.bottom_point
|
2706
2731
|
self.extra_tiers = {}
|
2707
2732
|
self.visible_utterances: dict[str, UtteranceRegion] = {}
|
2708
|
-
self.background_brush = pg.mkBrush(self.
|
2709
|
-
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)
|
2710
2735
|
self.picture = QtGui.QPicture()
|
2711
2736
|
self.has_visible_utterances = False
|
2712
2737
|
self.has_selected_utterances = False
|
@@ -2722,6 +2747,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2722
2747
|
self.selection_model.selectionChanged.connect(self.update_select)
|
2723
2748
|
self.selection_model.model().utterancesReady.connect(self.refresh)
|
2724
2749
|
self.available_speakers = {}
|
2750
|
+
self.painter_path_cache = {True: {}, False: {}}
|
2725
2751
|
|
2726
2752
|
def wheelEvent(self, ev):
|
2727
2753
|
self.receivedWheelEvent.emit(ev)
|
@@ -2736,6 +2762,10 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2736
2762
|
p.drawPicture(0, 0, self.picture)
|
2737
2763
|
|
2738
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)
|
2739
2769
|
self.picture = QtGui.QPicture()
|
2740
2770
|
painter = QtGui.QPainter(self.picture)
|
2741
2771
|
painter.setPen(self.border)
|
@@ -2760,7 +2790,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2760
2790
|
|
2761
2791
|
def setSearchTerm(self, term):
|
2762
2792
|
for utt in self.visible_utterances.values():
|
2763
|
-
utt.highlighter.setSearchTerm(term)
|
2793
|
+
utt.text_item.highlighter.setSearchTerm(term)
|
2764
2794
|
|
2765
2795
|
def refreshTexts(self, utt_id, text):
|
2766
2796
|
for reg in self.visible_utterances.values():
|
@@ -2776,6 +2806,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2776
2806
|
reg.scene().removeItem(reg)
|
2777
2807
|
self.visible_utterances = {}
|
2778
2808
|
|
2809
|
+
@profile
|
2779
2810
|
def refresh(self, *args):
|
2780
2811
|
self.hide()
|
2781
2812
|
if self.selection_model.plot_min is None:
|
@@ -2820,6 +2851,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2820
2851
|
self.has_visible_utterances = True
|
2821
2852
|
# Utterance region always at the top
|
2822
2853
|
reg = UtteranceRegion(
|
2854
|
+
self,
|
2823
2855
|
u,
|
2824
2856
|
self.corpus_model,
|
2825
2857
|
self.file_model,
|
@@ -2845,7 +2877,6 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2845
2877
|
reg.viewRequested.connect(self.selection_model.set_view_times)
|
2846
2878
|
reg.textEdited.connect(self.update_utterance_text)
|
2847
2879
|
reg.selectRequested.connect(self.selection_model.update_select)
|
2848
|
-
reg.setParentItem(self)
|
2849
2880
|
self.visible_utterances[u.id] = reg
|
2850
2881
|
|
2851
2882
|
self.show()
|
@@ -2895,13 +2926,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2895
2926
|
if other_begin < end <= other_end or end > other_begin > other_end > beg:
|
2896
2927
|
reg.setRegion([beg, other_begin])
|
2897
2928
|
break
|
2898
|
-
reg.
|
2899
|
-
reg.text.update_times(self.selection_model.plot_min, self.selection_model.plot_max)
|
2900
|
-
if reg.normalized_text is not None:
|
2901
|
-
reg.normalized_text.text.begin, reg.normalized_text.text.end = reg.getRegion()
|
2902
|
-
reg.normalized_text.text.update_times(
|
2903
|
-
self.selection_model.plot_min, self.selection_model.plot_max
|
2904
|
-
)
|
2929
|
+
reg.update_edit_fields()
|
2905
2930
|
reg.select_self()
|
2906
2931
|
reg.update()
|
2907
2932
|
|
@@ -2916,7 +2941,5 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2916
2941
|
return
|
2917
2942
|
self.selection_model.model().update_utterance_times(utt, begin=new_begin, end=new_end)
|
2918
2943
|
self.selection_model.request_start_time(new_begin)
|
2919
|
-
reg.
|
2920
|
-
reg.text.end = new_end
|
2921
|
-
reg.update()
|
2944
|
+
reg.update_edit_fields()
|
2922
2945
|
self.lineDragFinished.emit(True)
|