Anchor-annotator 0.4.0__py3-none-any.whl → 0.5.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/plot.py CHANGED
@@ -162,8 +162,8 @@ class UtteranceClusterView(pg.PlotWidget):
162
162
  def __init__(self, *args):
163
163
  super().__init__(*args)
164
164
  self.settings = AnchorSettings()
165
-
166
- self.setBackground(self.settings.value(self.settings.PRIMARY_VERY_DARK_COLOR))
165
+ plot_theme = self.settings.plot_theme
166
+ self.setBackground(plot_theme.background_color)
167
167
  self.corpus_model = None
168
168
  self.speaker_model: SpeakerModel = None
169
169
  self.selection_model: FileSelectionModel = None
@@ -378,8 +378,8 @@ class AudioPlotItem(pg.PlotItem):
378
378
  self.setDefaultPadding(0)
379
379
  self.setClipToView(True)
380
380
 
381
- self.getAxis("bottom").setPen(self.settings.value(self.settings.ACCENT_LIGHT_COLOR))
382
- self.getAxis("bottom").setTextPen(self.settings.value(self.settings.ACCENT_LIGHT_COLOR))
381
+ self.getAxis("bottom").setPen(self.settings.plot_theme.break_line_color)
382
+ self.getAxis("bottom").setTextPen(self.settings.plot_theme.break_line_color)
383
383
  self.getAxis("bottom").setTickFont(self.settings.small_font)
384
384
  rect = QtCore.QRectF()
385
385
  rect.setTop(top_point)
@@ -437,6 +437,7 @@ class SpeakerTierItem(pg.PlotItem):
437
437
  a.setText("Create utterance")
438
438
  a.triggered.connect(functools.partial(item.create_utterance, begin=begin, end=end))
439
439
  menu.addAction(a)
440
+
440
441
  menu.setStyleSheet(item.settings.menu_style_sheet)
441
442
  menu.exec_(event.screenPos())
442
443
 
@@ -461,9 +462,13 @@ class UtteranceView(QtWidgets.QWidget):
461
462
 
462
463
  # self.break_line.setZValue(30)
463
464
  self.audio_layout = pg.GraphicsLayoutWidget()
465
+ self.audio_layout.viewport().setAttribute(
466
+ QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False
467
+ )
464
468
  self.audio_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
465
469
  self.audio_layout.centralWidget.layout.setSpacing(0)
466
- self.audio_layout.setBackground(self.settings.value(self.settings.PRIMARY_VERY_DARK_COLOR))
470
+ plot_theme = self.settings.plot_theme
471
+ self.audio_layout.setBackground(plot_theme.background_color)
467
472
  self.audio_plot = AudioPlots(2, 1, 0)
468
473
  self.audio_plot_item = AudioPlotItem(2, 0)
469
474
  self.audio_plot_item.addItem(self.audio_plot)
@@ -474,9 +479,13 @@ class UtteranceView(QtWidgets.QWidget):
474
479
  self.show_transcription = True
475
480
  self.show_alignment = True
476
481
  self.speaker_tier_layout = pg.GraphicsLayoutWidget()
482
+ self.speaker_tier_layout.viewport().setAttribute(
483
+ QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False
484
+ )
477
485
  self.speaker_tier_layout.setAspectLocked(False)
478
486
  self.speaker_tier_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
479
487
  self.speaker_tier_layout.centralWidget.layout.setSpacing(0)
488
+ self.speaker_tier_layout.setBackground(plot_theme.background_color)
480
489
  self.speaker_tiers: dict[SpeakerTier] = {}
481
490
  self.speaker_tier_items = {}
482
491
  self.search_term = None
@@ -526,6 +535,25 @@ class UtteranceView(QtWidgets.QWidget):
526
535
  self.selection_model.waveformReady.connect(self.finalize_loading_auto_wave_form)
527
536
  self.selection_model.speakerRequested.connect(self.set_default_speaker)
528
537
  self.file_model.selectionRequested.connect(self.finalize_loading_utterances)
538
+ self.file_model.speakersChanged.connect(self.finalize_loading_utterances)
539
+ self.corpus_model.refreshTiers.connect(self.finalize_loading_utterances)
540
+
541
+ def refresh_theme(self):
542
+ self.audio_layout.setBackground(self.settings.plot_theme.background_color)
543
+ self.speaker_tier_layout.setBackground(self.settings.plot_theme.background_color)
544
+ self.audio_plot.wave_form.update_theme()
545
+ self.audio_plot.spectrogram.update_theme()
546
+ self.audio_plot.pitch_track.update_theme()
547
+ self.audio_plot_item.getAxis("bottom").setPen(self.settings.plot_theme.break_line_color)
548
+ self.audio_plot_item.getAxis("bottom").setTextPen(
549
+ self.settings.plot_theme.break_line_color
550
+ )
551
+
552
+ def refresh(self):
553
+ self.finalize_loading_utterances()
554
+ self.finalize_loading_auto_wave_form()
555
+ self.finalize_loading_pitch_track()
556
+ self.finalize_loading_spectrogram()
529
557
 
530
558
  def finalize_loading_utterances(self):
531
559
  if self.file_model.file is None:
@@ -536,7 +564,10 @@ class UtteranceView(QtWidgets.QWidget):
536
564
  self.speaker_tier_items = {}
537
565
  self.speaker_tier_layout.clear()
538
566
  available_speakers = {}
539
- speaker_tier_height = self.separator_point - self.bottom_point
567
+ num_visible_speakers = min(
568
+ len(self.file_model.speakers), self.settings.value(self.settings.TIER_MAX_SPEAKERS)
569
+ )
570
+ speaker_tier_height = (self.separator_point - self.bottom_point) / num_visible_speakers
540
571
  for i, speaker_id in enumerate(self.file_model.speakers):
541
572
  speaker_name = self.corpus_model.get_speaker_name(speaker_id)
542
573
  top_point = i * speaker_tier_height
@@ -574,8 +605,10 @@ class UtteranceView(QtWidgets.QWidget):
574
605
  if tier.speaker_id == self.default_speaker_id:
575
606
  scroll_to = i
576
607
  row_height = self.tier_scroll_area.height()
577
- self.speaker_tier_layout.setFixedHeight(len(self.speaker_tiers) * row_height)
578
- if len(self.speaker_tiers) > 1:
608
+ self.speaker_tier_layout.setFixedHeight(
609
+ len(self.speaker_tiers) * row_height / num_visible_speakers
610
+ )
611
+ if len(self.file_model.speakers) > num_visible_speakers:
579
612
  self.tier_scroll_area.verticalScrollBar().setSingleStep(row_height)
580
613
  self.tier_scroll_area.verticalScrollBar().setPageStep(row_height)
581
614
  self.tier_scroll_area.verticalScrollBar().setMinimum(0)
@@ -589,7 +622,6 @@ class UtteranceView(QtWidgets.QWidget):
589
622
  0, 0, self.settings.scroll_bar_height, 0
590
623
  )
591
624
  if scroll_to is not None:
592
- # self.tier_scroll_area.scrollContentsBy(0, scroll_to * tier_height)
593
625
  self.tier_scroll_area.verticalScrollBar().setValue(
594
626
  scroll_to * self.tier_scroll_area.height()
595
627
  )
@@ -1061,8 +1093,9 @@ class TranscriberErrorHighlighter(QtGui.QSyntaxHighlighter):
1061
1093
  super().__init__(*args)
1062
1094
  self.alignment = None
1063
1095
  self.settings = AnchorSettings()
1064
- self.keyword_color = self.settings.error_color
1065
- self.keyword_text_color = self.settings.primary_very_dark_color
1096
+
1097
+ self.keyword_color = self.settings.plot_theme.error_color
1098
+ self.keyword_text_color = self.settings.plot_theme.error_text_color
1066
1099
  self.highlight_format = QtGui.QTextCharFormat()
1067
1100
  self.highlight_format.setBackground(self.keyword_color)
1068
1101
  self.highlight_format.setForeground(self.keyword_text_color)
@@ -1206,6 +1239,15 @@ class IntervalTextRegion(pg.GraphicsObject):
1206
1239
  self.rect.setBottom(self.top_point - self.height)
1207
1240
  self._generate_picture()
1208
1241
 
1242
+ def setSelected(self, selected):
1243
+ if selected:
1244
+ new_brush = self.selected_brush
1245
+ else:
1246
+ new_brush = self.background_brush
1247
+ if new_brush != self.currentBrush:
1248
+ self.currentBrush = new_brush
1249
+ self._generate_picture()
1250
+
1209
1251
  def _generate_picture(self):
1210
1252
  painter = QtGui.QPainter(self.picture)
1211
1253
  painter.setPen(self.border)
@@ -1286,7 +1328,9 @@ class TextAttributeRegion(pg.GraphicsObject):
1286
1328
  self.picture = QtGui.QPicture()
1287
1329
  self.mouseHovering = False
1288
1330
  self.selected = False
1289
- self.currentBrush = self.parentItem().background_brush
1331
+ self.background_brush = self.parentItem().background_brush
1332
+ self.selected_brush = self.parentItem().selected_brush
1333
+ self.currentBrush = self.parentItem().currentBrush
1290
1334
  self.text.setPos((self.begin + self.end) / 2, self.top_point - (self.height / 2))
1291
1335
  self.begin_line = pg.InfiniteLine()
1292
1336
  self.rect = QtCore.QRectF(
@@ -1296,9 +1340,18 @@ class TextAttributeRegion(pg.GraphicsObject):
1296
1340
  height=self.height,
1297
1341
  )
1298
1342
  self.rect.setTop(self.top_point)
1299
- self.rect.setBottom(self.top_point - self.height)
1343
+ self.rect.setBottom(self.bottom_point)
1300
1344
  self._generate_picture()
1301
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
+
1302
1355
  def _generate_picture(self):
1303
1356
  painter = QtGui.QPainter(self.picture)
1304
1357
  painter.setPen(self.border)
@@ -1428,18 +1481,23 @@ class Highlighter(QtGui.QSyntaxHighlighter):
1428
1481
  def highlightBlock(self, text):
1429
1482
  self.settings.sync()
1430
1483
  self.spellcheck_format.setUnderlineColor(self.settings.error_color)
1431
- tokenizers = self.dictionary_model.corpus_model.corpus.get_tokenizers()
1432
- dictionary_id = self.dictionary_model.corpus_model.corpus.get_dict_id_for_speaker(
1433
- self.speaker_id
1434
- )
1435
1484
  words = self.WORDS
1436
- if isinstance(tokenizers, dict) and dictionary_id is not None:
1437
- tokenizer = self.dictionary_model.corpus_model.corpus.get_tokenizer(dictionary_id)
1438
- else:
1439
- tokenizer = tokenizers
1440
- if isinstance(tokenizer, SimpleTokenizer):
1441
- extra_symbols = "".join(tokenizer.punctuation) + "".join(tokenizer.word_break_markers)
1442
- words = rf"[^\s{extra_symbols}]+"
1485
+ try:
1486
+ tokenizers = self.dictionary_model.corpus_model.corpus.get_tokenizers()
1487
+ dictionary_id = self.dictionary_model.corpus_model.corpus.get_dict_id_for_speaker(
1488
+ self.speaker_id
1489
+ )
1490
+ if isinstance(tokenizers, dict) and dictionary_id is not None:
1491
+ tokenizer = self.dictionary_model.corpus_model.corpus.get_tokenizer(dictionary_id)
1492
+ else:
1493
+ tokenizer = tokenizers
1494
+ if isinstance(tokenizer, SimpleTokenizer):
1495
+ extra_symbols = "".join(tokenizer.punctuation) + "".join(
1496
+ tokenizer.word_break_markers
1497
+ )
1498
+ words = rf"[^\s{extra_symbols}]+"
1499
+ except Exception:
1500
+ pass
1443
1501
  if self.dictionary_model is not None and self.dictionary_model.word_sets:
1444
1502
  for word_object in re.finditer(words, text):
1445
1503
  if not self.dictionary_model.check_word(word_object.group(), self.speaker_id):
@@ -1470,8 +1528,6 @@ class MfaRegion(pg.LinearRegionItem):
1470
1528
  audioSelected = QtCore.Signal(object, object)
1471
1529
  viewRequested = QtCore.Signal(object, object)
1472
1530
 
1473
- settings = AnchorSettings()
1474
-
1475
1531
  def __init__(
1476
1532
  self,
1477
1533
  item: CtmInterval,
@@ -1485,6 +1541,8 @@ class MfaRegion(pg.LinearRegionItem):
1485
1541
  pg.GraphicsObject.__init__(self)
1486
1542
  self.item = item
1487
1543
 
1544
+ self.settings = AnchorSettings()
1545
+
1488
1546
  self.item_min = self.item.begin
1489
1547
  self.item_max = self.item.end
1490
1548
  if selection_model.settings.right_to_left:
@@ -1497,15 +1555,15 @@ class MfaRegion(pg.LinearRegionItem):
1497
1555
  self.top_point = top_point
1498
1556
  self.span = (self.bottom_point, self.top_point)
1499
1557
  self.text_margin_pixels = 2
1558
+ self.height = abs(self.top_point - self.bottom_point)
1500
1559
 
1501
- self.selected_range_color = self.settings.value(self.settings.PRIMARY_BASE_COLOR).lighter()
1502
- self.interval_background_color = self.settings.value(self.settings.PRIMARY_DARK_COLOR)
1503
- self.hover_line_color = self.settings.value(self.settings.ERROR_COLOR)
1504
- self.moving_line_color = self.settings.value(self.settings.ERROR_COLOR)
1560
+ self.interval_background_color = self.settings.plot_theme.interval_background_color
1561
+ self.hover_line_color = self.settings.plot_theme.hover_line_color
1562
+ self.moving_line_color = self.settings.plot_theme.moving_line_color
1505
1563
 
1506
- self.break_line_color = self.settings.value(self.settings.ACCENT_LIGHT_COLOR)
1507
- self.text_color = self.settings.value(self.settings.MAIN_TEXT_COLOR)
1508
- self.selected_interval_color = self.settings.value(self.settings.PRIMARY_BASE_COLOR)
1564
+ self.break_line_color = self.settings.plot_theme.break_line_color
1565
+ self.text_color = self.settings.plot_theme.text_color
1566
+ self.selected_interval_color = self.settings.plot_theme.selected_interval_color
1509
1567
  self.plot_text_font = self.settings.big_font
1510
1568
  self.setCursor(QtCore.Qt.CursorShape.SizeAllCursor)
1511
1569
  self.pen = pg.mkPen(self.break_line_color, width=3)
@@ -1531,15 +1589,42 @@ class MfaRegion(pg.LinearRegionItem):
1531
1589
  self.swapMode = "sort"
1532
1590
  self.clipItem = None
1533
1591
  self._boundingRectCache = None
1534
- self.setBrush(self.background_brush)
1535
1592
  self.movable = False
1536
1593
  self.cached_visible_duration = None
1537
1594
  self.cached_view = None
1595
+ self.currentBrush = self.background_brush
1596
+ self.picture = QtGui.QPicture()
1597
+ self.rect = QtCore.QRectF(
1598
+ left=self.item_min,
1599
+ top=self.top_point,
1600
+ width=self.item_max - self.item_min,
1601
+ height=self.height,
1602
+ )
1603
+ self.rect.setTop(self.top_point)
1604
+ self.rect.setLeft(self.item_min)
1605
+ self.rect.setRight(self.item_max)
1606
+ self.rect.setBottom(self.bottom_point)
1607
+ self._generate_picture()
1608
+ self.sigRegionChanged.connect(self.update_bounds)
1609
+ self.sigRegionChangeFinished.connect(self.update_bounds)
1538
1610
 
1539
- def paint(self, p, *args):
1540
- p.setBrush(self.currentBrush)
1541
- p.setPen(self.border_pen)
1542
- p.drawRect(self.boundingRect())
1611
+ def update_bounds(self):
1612
+ beg, end = self.getRegion()
1613
+ self.rect.setLeft(beg)
1614
+ self.rect.setRight(end)
1615
+ self._generate_picture()
1616
+
1617
+ def _generate_picture(self):
1618
+ if self.selection_model is None:
1619
+ return
1620
+ painter = QtGui.QPainter(self.picture)
1621
+ painter.setPen(self.border_pen)
1622
+ painter.setBrush(self.currentBrush)
1623
+ painter.drawRect(self.rect)
1624
+ painter.end()
1625
+
1626
+ def paint(self, painter, *args):
1627
+ painter.drawPicture(0, 0, self.picture)
1543
1628
 
1544
1629
  def mouseClickEvent(self, ev: QtGui.QMouseEvent):
1545
1630
  if ev.button() != QtCore.Qt.MouseButton.LeftButton:
@@ -1559,10 +1644,12 @@ class MfaRegion(pg.LinearRegionItem):
1559
1644
 
1560
1645
  def setSelected(self, selected: bool):
1561
1646
  if selected:
1562
- self.setBrush(pg.mkBrush(self.selected_interval_color))
1647
+ new_brush = pg.mkBrush(self.selected_interval_color)
1563
1648
  else:
1564
- # self.interval_background_color.setAlpha(0)
1565
- self.setBrush(pg.mkBrush(self.interval_background_color))
1649
+ new_brush = pg.mkBrush(self.interval_background_color)
1650
+ if new_brush != self.currentBrush:
1651
+ self.currentBrush = new_brush
1652
+ self._generate_picture()
1566
1653
  self.update()
1567
1654
 
1568
1655
  def setMouseHover(self, hover: bool):
@@ -1578,6 +1665,26 @@ class MfaRegion(pg.LinearRegionItem):
1578
1665
  if self.selected and not deselect and not reset:
1579
1666
  return
1580
1667
 
1668
+ def boundingRect(self):
1669
+ try:
1670
+ visible_begin = max(self.item_min, self.selection_model.plot_min)
1671
+ visible_end = min(self.item_max, self.selection_model.plot_max)
1672
+ except TypeError:
1673
+ visible_begin = self.item_min
1674
+ visible_end = self.item_max
1675
+ br = QtCore.QRectF(self.picture.boundingRect())
1676
+ br.setLeft(visible_begin)
1677
+ br.setRight(visible_end)
1678
+
1679
+ br.setTop(self.top_point)
1680
+ br.setBottom(self.bottom_point + 0.01)
1681
+ br = br.normalized()
1682
+
1683
+ if self._boundingRectCache != br:
1684
+ self._boundingRectCache = br
1685
+ self.prepareGeometryChange()
1686
+ return br
1687
+
1581
1688
 
1582
1689
  class AlignmentRegion(MfaRegion):
1583
1690
  def __init__(
@@ -1611,49 +1718,43 @@ class AlignmentRegion(MfaRegion):
1611
1718
  self.text.textItem.document().setDefaultTextOption(options)
1612
1719
  self.text.setParentItem(self)
1613
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()
1614
1724
 
1615
- def viewRangeChanged(self):
1725
+ def setSelected(self, selected: bool):
1726
+ if selected:
1727
+ self.text.setColor(self.settings.plot_theme.selected_text_color)
1728
+ else:
1729
+ self.text.setColor(self.settings.plot_theme.text_color)
1730
+
1731
+ def check_visibility(self):
1616
1732
  if (self.item_max - self.item_min) / (
1617
1733
  self.selection_model.max_time - self.selection_model.min_time
1618
1734
  ) < 0.001:
1619
1735
  self.hide()
1620
1736
  else:
1621
- self.show()
1622
- super().viewRangeChanged()
1623
-
1624
- def boundingRect(self):
1625
- br = QtCore.QRectF(self.viewRect()) # bounds of containing ViewBox mapped to local coords.
1626
- vb = self.getViewBox()
1627
-
1628
- pixel_size = vb.viewPixelSize()
1629
-
1630
- br.setLeft(self.item_min)
1631
- br.setRight(self.item_max)
1632
-
1633
- br.setTop(self.top_point)
1634
- # br.setBottom(self.top_point-self.per_tier_range)
1635
- br.setBottom(self.bottom_point + 0.01)
1636
- try:
1737
+ vb = self.getViewBox()
1637
1738
  visible_begin = max(self.item_min, self.selection_model.plot_min)
1638
1739
  visible_end = min(self.item_max, self.selection_model.plot_max)
1639
- except TypeError:
1640
- return br
1641
- visible_duration = visible_end - visible_begin
1642
- x_margin_px = 8
1643
- available_text_width = visible_duration / pixel_size[0] - (2 * x_margin_px)
1644
- self.text.setVisible(available_text_width > 10)
1645
- if visible_duration != self.cached_visible_duration:
1646
- self.cached_visible_duration = visible_duration
1647
-
1740
+ visible_duration = visible_end - visible_begin
1648
1741
  self.text.setPos(
1649
1742
  visible_begin + (visible_duration / 2), self.top_point - (self.per_tier_range / 2)
1650
1743
  )
1651
- br = br.normalized()
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)
1652
1755
 
1653
- if self._boundingRectCache != br:
1654
- self._boundingRectCache = br
1655
- self.prepareGeometryChange()
1656
- return br
1756
+ self.text.setVisible(available_text_width > 10)
1757
+ self.show()
1657
1758
 
1658
1759
 
1659
1760
  class PhoneRegion(AlignmentRegion):
@@ -1665,10 +1766,14 @@ class PhoneRegion(AlignmentRegion):
1665
1766
  selection_model: CorpusSelectionModel,
1666
1767
  bottom_point: float = 0,
1667
1768
  top_point: float = 1,
1769
+ color=None,
1668
1770
  ):
1669
1771
  super().__init__(
1670
1772
  phone_interval, corpus_model, file_model, selection_model, bottom_point, top_point
1671
1773
  )
1774
+ if color is not None:
1775
+ self.currentBrush = pg.mkBrush(color)
1776
+ self._generate_picture()
1672
1777
 
1673
1778
 
1674
1779
  class WordRegion(AlignmentRegion):
@@ -1686,6 +1791,7 @@ class WordRegion(AlignmentRegion):
1686
1791
  super().__init__(
1687
1792
  word_interval, corpus_model, file_model, selection_model, bottom_point, top_point
1688
1793
  )
1794
+ self._generate_picture()
1689
1795
 
1690
1796
  def mouseClickEvent(self, ev: QtGui.QMouseEvent):
1691
1797
  search_term = TextFilterQuery(self.item.label, word=True)
@@ -1779,7 +1885,7 @@ class UtteranceRegion(MfaRegion):
1779
1885
  per_tier_range=self.per_tier_range,
1780
1886
  dictionary_model=self.dictionary_model,
1781
1887
  speaker_id=self.item.speaker_id,
1782
- border=pg.mkPen(self.settings.accent_light_color),
1888
+ border=pg.mkPen(self.settings.plot_theme.break_line_color),
1783
1889
  )
1784
1890
  self.text.setParentItem(self)
1785
1891
 
@@ -1823,7 +1929,7 @@ class UtteranceRegion(MfaRegion):
1823
1929
  tier_top_point,
1824
1930
  self.per_tier_range,
1825
1931
  self.selection_model,
1826
- border=pg.mkPen(self.settings.accent_light_color),
1932
+ border=pg.mkPen(self.settings.plot_theme.break_line_color),
1827
1933
  dictionary_model=dictionary_model,
1828
1934
  search_term=search_term,
1829
1935
  speaker_id=utterance.speaker_id,
@@ -1852,9 +1958,25 @@ class UtteranceRegion(MfaRegion):
1852
1958
 
1853
1959
  if intervals is None:
1854
1960
  continue
1961
+ min_confidence = None
1962
+ max_confidence = None
1963
+ cmap = pg.ColorMap(
1964
+ None,
1965
+ [
1966
+ self.settings.plot_theme.error_color,
1967
+ self.settings.plot_theme.interval_background_color,
1968
+ ],
1969
+ )
1970
+ cmap.linearize()
1971
+ if "phone_intervals" in lookup:
1972
+ for interval in intervals:
1973
+ if interval.confidence is None:
1974
+ continue
1975
+ if min_confidence is None or interval.confidence < min_confidence:
1976
+ min_confidence = interval.confidence
1977
+ if max_confidence is None or interval.confidence > max_confidence:
1978
+ max_confidence = interval.confidence
1855
1979
  for interval in intervals:
1856
- # if (interval.end - interval.begin) /(self.selection_model.max_time -self.selection_model.min_time) < 0.01:
1857
- # continue
1858
1980
  if lookup == "transcription_text":
1859
1981
  interval_reg = TranscriberTextRegion(
1860
1982
  self,
@@ -1864,13 +1986,21 @@ class UtteranceRegion(MfaRegion):
1864
1986
  tier_top_point,
1865
1987
  self.per_tier_range,
1866
1988
  self.selection_model,
1867
- border=pg.mkPen(self.settings.accent_light_color),
1989
+ border=pg.mkPen(self.settings.plot_theme.break_line_color),
1868
1990
  alignment=alignment,
1869
1991
  dictionary_model=dictionary_model,
1870
1992
  search_term=search_term,
1871
1993
  speaker_id=utterance.speaker_id,
1872
1994
  )
1995
+ interval_reg.setParentItem(self)
1996
+ interval_reg.audioSelected.connect(self.setSelected)
1873
1997
  elif "phone_intervals" in lookup:
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)
1874
2004
  interval_reg = PhoneRegion(
1875
2005
  interval,
1876
2006
  self.corpus_model,
@@ -1878,8 +2008,10 @@ class UtteranceRegion(MfaRegion):
1878
2008
  selection_model=selection_model,
1879
2009
  top_point=tier_top_point,
1880
2010
  bottom_point=tier_bottom_point,
2011
+ color=color,
1881
2012
  )
1882
2013
  interval_reg.setParentItem(self)
2014
+ interval_reg.audioSelected.connect(self.setSelected)
1883
2015
  elif "word_intervals" in lookup:
1884
2016
  interval_reg = WordRegion(
1885
2017
  interval,
@@ -1891,18 +2023,19 @@ class UtteranceRegion(MfaRegion):
1891
2023
  )
1892
2024
  interval_reg.setParentItem(self)
1893
2025
  interval_reg.highlightRequested.connect(self.highlighter.setSearchTerm)
2026
+ interval_reg.audioSelected.connect(self.setSelected)
1894
2027
 
1895
2028
  else:
1896
2029
  interval_reg = IntervalTextRegion(
1897
2030
  interval,
1898
2031
  self.text_color,
1899
- border=pg.mkPen(self.settings.accent_light_color, width=3),
2032
+ border=pg.mkPen(self.settings.plot_theme.break_line_color, width=3),
1900
2033
  top_point=tier_top_point,
1901
2034
  height=self.per_tier_range,
1902
- # font=self.settings.font,
1903
2035
  background_brush=self.background_brush,
1904
- selected_brush=pg.mkBrush(self.selected_range_color),
2036
+ selected_brush=pg.mkBrush(self.selected_interval_color),
1905
2037
  )
2038
+ interval_reg.audioSelected.connect(self.setSelected)
1906
2039
  interval_reg.setParentItem(self)
1907
2040
 
1908
2041
  interval_reg.audioSelected.connect(self.audioSelected.emit)
@@ -1912,6 +2045,27 @@ class UtteranceRegion(MfaRegion):
1912
2045
  self.show()
1913
2046
  self.available_speakers = available_speakers
1914
2047
 
2048
+ def show(self):
2049
+ for intervals in self.extra_tier_intervals.values():
2050
+ for interval in intervals:
2051
+ if (
2052
+ self.selection_model.min_time
2053
+ < interval.item.end
2054
+ <= self.selection_model.max_time
2055
+ or self.selection_model.min_time
2056
+ <= interval.item.begin
2057
+ < self.selection_model.max_time
2058
+ ):
2059
+ interval.show()
2060
+ else:
2061
+ interval.hide()
2062
+ super().show()
2063
+
2064
+ def setSelected(self, selected: bool):
2065
+ if selected:
2066
+ self.text_edit.setFocus()
2067
+ super().setSelected(selected)
2068
+
1915
2069
  def change_editing(self, editable: bool):
1916
2070
  self.lines[0].movable = editable
1917
2071
  self.lines[1].movable = editable
@@ -1979,7 +2133,10 @@ class UtteranceRegion(MfaRegion):
1979
2133
  menu.exec_(ev.screenPos())
1980
2134
 
1981
2135
  def update_tier_visibility(self, checked):
1982
- tier_name = self.sender().text().split(maxsplit=1)[-1]
2136
+ sender = self.sender()
2137
+ if not isinstance(sender, QtGui.QAction):
2138
+ return
2139
+ tier_name = sender.text().split(maxsplit=1)[-1]
1983
2140
  self.settings.setValue(self.settings.tier_visibility_mapping[tier_name], checked)
1984
2141
  self.settings.sync()
1985
2142
  self.corpus_model.refreshTiers.emit()
@@ -1994,7 +2151,10 @@ class UtteranceRegion(MfaRegion):
1994
2151
  self.file_model.update_utterance_speaker(self.item, speaker_id)
1995
2152
 
1996
2153
  def update_speaker(self):
1997
- speaker_name = self.sender().text()
2154
+ sender = self.sender()
2155
+ if not isinstance(sender, QtGui.QAction):
2156
+ return
2157
+ speaker_name = sender.text()
1998
2158
  if speaker_name == "New speaker":
1999
2159
  speaker_id = 0
2000
2160
  else:
@@ -2150,7 +2310,7 @@ class WaveForm(pg.PlotCurveItem):
2150
2310
  self.top_point = top_point
2151
2311
  self.bottom_point = bottom_point
2152
2312
  self.mid_point = (self.top_point + self.bottom_point) / 2
2153
- pen = pg.mkPen(self.settings.value(self.settings.MAIN_TEXT_COLOR), width=1)
2313
+ pen = pg.mkPen(self.settings.plot_theme.wave_line_color, width=1)
2154
2314
  super(WaveForm, self).__init__()
2155
2315
  self.setPen(pen)
2156
2316
  self.channel = 0
@@ -2158,6 +2318,10 @@ class WaveForm(pg.PlotCurveItem):
2158
2318
  self.selection_model = None
2159
2319
  self.setAcceptHoverEvents(False)
2160
2320
 
2321
+ def update_theme(self):
2322
+ pen = pg.mkPen(self.settings.plot_theme.wave_line_color, width=1)
2323
+ self.setPen(pen)
2324
+
2161
2325
  def hoverEvent(self, ev):
2162
2326
  return
2163
2327
 
@@ -2171,7 +2335,7 @@ class PitchTrack(pg.PlotCurveItem):
2171
2335
  self.top_point = top_point
2172
2336
  self.bottom_point = bottom_point
2173
2337
  self.mid_point = (self.top_point + self.bottom_point) / 2
2174
- pen = pg.mkPen(self.settings.value(self.settings.PRIMARY_LIGHT_COLOR), width=3)
2338
+ pen = pg.mkPen(self.settings.plot_theme.pitch_color, width=3)
2175
2339
  super().__init__()
2176
2340
  self.setPen(pen)
2177
2341
  self.channel = 0
@@ -2180,19 +2344,25 @@ class PitchTrack(pg.PlotCurveItem):
2180
2344
  self.setAcceptHoverEvents(False)
2181
2345
  self.min_label = pg.TextItem(
2182
2346
  str(self.settings.PITCH_MIN_F0),
2183
- self.settings.value(self.settings.PRIMARY_VERY_LIGHT_COLOR),
2347
+ self.settings.plot_theme.pitch_color,
2184
2348
  anchor=(1, 1),
2185
2349
  )
2186
2350
  self.min_label.setFont(self.settings.font)
2187
2351
  self.min_label.setParentItem(self)
2188
2352
  self.max_label = pg.TextItem(
2189
2353
  str(self.settings.PITCH_MAX_F0),
2190
- self.settings.value(self.settings.PRIMARY_VERY_LIGHT_COLOR),
2354
+ self.settings.plot_theme.pitch_color,
2191
2355
  anchor=(1, 0),
2192
2356
  )
2193
2357
  self.max_label.setFont(self.settings.font)
2194
2358
  self.max_label.setParentItem(self)
2195
2359
 
2360
+ def update_theme(self):
2361
+ pen = pg.mkPen(self.settings.plot_theme.pitch_color, width=3)
2362
+ self.setPen(pen)
2363
+ self.min_label.setColor(self.settings.plot_theme.pitch_color)
2364
+ self.max_label.setColor(self.settings.plot_theme.pitch_color)
2365
+
2196
2366
  def hoverEvent(self, ev):
2197
2367
  return
2198
2368
 
@@ -2215,7 +2385,11 @@ class Spectrogram(pg.ImageItem):
2215
2385
  self.channel = 0
2216
2386
  super(Spectrogram, self).__init__()
2217
2387
  self.cmap = pg.ColorMap(
2218
- None, [self.settings.primary_very_dark_color, self.settings.accent_light_color]
2388
+ None,
2389
+ [
2390
+ self.settings.plot_theme.background_color,
2391
+ self.settings.plot_theme.spectrogram_color,
2392
+ ],
2219
2393
  )
2220
2394
  self.cmap.linearize()
2221
2395
  self.color_bar = pg.ColorBarItem(colorMap=self.cmap)
@@ -2226,6 +2400,19 @@ class Spectrogram(pg.ImageItem):
2226
2400
  self.cached_channel = None
2227
2401
  self.stft = None
2228
2402
 
2403
+ def update_theme(self):
2404
+ self.cmap = pg.ColorMap(
2405
+ None,
2406
+ [
2407
+ self.settings.plot_theme.background_color,
2408
+ self.settings.plot_theme.spectrogram_color,
2409
+ ],
2410
+ )
2411
+ self.cmap.linearize()
2412
+ self.color_bar.setColorMap(self.cmap)
2413
+ self.color_bar.setImageItem(self)
2414
+ self.update()
2415
+
2229
2416
  def set_models(self, selection_model: CorpusSelectionModel):
2230
2417
  self.selection_model = selection_model
2231
2418
 
@@ -2287,8 +2474,12 @@ class SelectionArea(pg.LinearRegionItem):
2287
2474
  self.setVisible(False)
2288
2475
  else:
2289
2476
  self.setRegion([begin, end])
2290
- self.lines[0].label.setText(f"{begin:.3f}", self.settings.error_color)
2291
- self.lines[1].label.setText(f"{end:.3f}", self.settings.error_color)
2477
+ self.lines[0].label.setText(
2478
+ f"{begin:.3f}", self.settings.plot_theme.selected_range_color
2479
+ )
2480
+ self.lines[1].label.setText(
2481
+ f"{end:.3f}", self.settings.plot_theme.selected_range_color
2482
+ )
2292
2483
  self.setVisible(True)
2293
2484
 
2294
2485
 
@@ -2306,17 +2497,17 @@ class AudioPlots(pg.GraphicsObject):
2306
2497
  self.wave_form.setParentItem(self)
2307
2498
  self.spectrogram.setParentItem(self)
2308
2499
  self.pitch_track.setParentItem(self)
2309
- color = self.settings.error_color
2500
+ color = self.settings.plot_theme.selected_range_color
2310
2501
  color.setAlphaF(0.25)
2311
2502
  self.selection_brush = pg.mkBrush(color)
2312
- self.background_pen = pg.mkPen(self.settings.accent_light_color)
2313
- self.background_brush = pg.mkBrush(self.settings.primary_very_dark_color)
2503
+ self.background_pen = pg.mkPen(self.settings.plot_theme.break_line_color)
2504
+ self.background_brush = pg.mkBrush(self.settings.plot_theme.background_color)
2314
2505
  self.selection_area = SelectionArea(
2315
2506
  top_point=self.top_point,
2316
2507
  bottom_point=self.bottom_point,
2317
2508
  brush=self.selection_brush,
2318
2509
  clipItem=self,
2319
- pen=pg.mkPen(self.settings.error_color),
2510
+ pen=pg.mkPen(self.settings.plot_theme.selected_interval_color),
2320
2511
  )
2321
2512
  self.selection_area.setParentItem(self)
2322
2513
 
@@ -2331,7 +2522,11 @@ class AudioPlots(pg.GraphicsObject):
2331
2522
  self.update_line = pg.InfiniteLine(
2332
2523
  pos=-20,
2333
2524
  span=(0, 1),
2334
- pen=pg.mkPen(self.settings.error_color, width=3, style=QtCore.Qt.PenStyle.DashLine),
2525
+ pen=pg.mkPen(
2526
+ self.settings.plot_theme.selected_interval_color,
2527
+ width=3,
2528
+ style=QtCore.Qt.PenStyle.DashLine,
2529
+ ),
2335
2530
  movable=False, # We have our own code to handle dragless moving.
2336
2531
  )
2337
2532
  self.update_line.setParentItem(self)
@@ -2419,7 +2614,7 @@ class AudioPlots(pg.GraphicsObject):
2419
2614
  self.selection_area.setVisible(True)
2420
2615
  self.selection_model.select_audio(min_time, max_time)
2421
2616
  else:
2422
- self.selection_model.request_start_time(ev.pos().x())
2617
+ self.selection_model.request_start_time(ev.pos().x(), update=True)
2423
2618
  ev.accept()
2424
2619
 
2425
2620
  def hoverEvent(self, ev):
@@ -2502,7 +2697,9 @@ class SpeakerTier(pg.GraphicsObject):
2502
2697
  self.speaker_name = speaker_name
2503
2698
  self.speaker_index = 0
2504
2699
  self.top_point = top_point
2505
- self.speaker_label = pg.TextItem(self.speaker_name, color=self.settings.accent_base_color)
2700
+ self.speaker_label = pg.TextItem(
2701
+ self.speaker_name, color=self.settings.plot_theme.break_line_color
2702
+ )
2506
2703
  self.speaker_label.setFont(self.settings.font)
2507
2704
  self.speaker_label.setParentItem(self)
2508
2705
  self.speaker_label.setZValue(40)
@@ -2510,8 +2707,8 @@ class SpeakerTier(pg.GraphicsObject):
2510
2707
  self.annotation_range = self.top_point - self.bottom_point
2511
2708
  self.extra_tiers = {}
2512
2709
  self.visible_utterances: dict[str, UtteranceRegion] = {}
2513
- self.background_brush = pg.mkBrush(self.settings.primary_very_dark_color)
2514
- self.border = pg.mkPen(self.settings.accent_light_color)
2710
+ self.background_brush = pg.mkBrush(self.settings.plot_theme.background_color)
2711
+ self.border = pg.mkPen(self.settings.plot_theme.break_line_color)
2515
2712
  self.picture = QtGui.QPicture()
2516
2713
  self.has_visible_utterances = False
2517
2714
  self.has_selected_utterances = False
@@ -2526,28 +2723,14 @@ class SpeakerTier(pg.GraphicsObject):
2526
2723
  self.corpus_model.refreshUtteranceText.connect(self.refreshTexts)
2527
2724
  self.selection_model.selectionChanged.connect(self.update_select)
2528
2725
  self.selection_model.model().utterancesReady.connect(self.refresh)
2529
- self.file_model.speakersChanged.connect(self.update_available_speakers)
2530
2726
  self.available_speakers = {}
2531
2727
 
2532
- def update_available_speakers(self):
2533
- self.available_speakers = {}
2534
- for speaker_id in self.file_model.speakers:
2535
- speaker_name = self.corpus_model.get_speaker_name(speaker_id)
2536
- self.available_speakers[speaker_name] = speaker_id
2537
- for reg in self.visible_utterances.values():
2538
- reg.available_speakers = self.available_speakers
2539
-
2540
2728
  def wheelEvent(self, ev):
2541
2729
  self.receivedWheelEvent.emit(ev)
2542
2730
 
2543
2731
  def create_utterance(self, begin, end):
2544
2732
  self.file_model.create_utterance(self.speaker_id, begin, end)
2545
2733
 
2546
- def setSearchterm(self, term):
2547
- self.search_term = term
2548
- for reg in self.visible_utterances.values():
2549
- reg.highlighter.setSearchTerm(term)
2550
-
2551
2734
  def boundingRect(self):
2552
2735
  return QtCore.QRectF(self.picture.boundingRect())
2553
2736
 
@@ -2610,14 +2793,16 @@ class SpeakerTier(pg.GraphicsObject):
2610
2793
  visible_ids = [x.id for x in model_visible_utterances]
2611
2794
  for reg in self.visible_utterances.values():
2612
2795
  reg.hide()
2796
+
2797
+ item_min, item_max = reg.getRegion()
2613
2798
  if (
2614
- self.selection_model.min_time - reg.item.end > 15
2615
- or reg.item.begin - self.selection_model.max_time > 15
2799
+ self.selection_model.min_time - item_max > 15
2800
+ or item_min - self.selection_model.max_time > 15
2616
2801
  or (
2617
2802
  reg.item.id not in visible_ids
2618
2803
  and (
2619
- reg.item.begin < self.selection_model.max_time
2620
- or reg.item.end > self.selection_model.min_time
2804
+ item_min < self.selection_model.max_time
2805
+ or item_max > self.selection_model.min_time
2621
2806
  )
2622
2807
  )
2623
2808
  ):
@@ -2706,10 +2891,10 @@ class SpeakerTier(pg.GraphicsObject):
2706
2891
  if r == reg:
2707
2892
  continue
2708
2893
  other_begin, other_end = r.getRegion()
2709
- if other_begin <= beg < other_end:
2894
+ if other_begin <= beg < other_end or beg <= other_begin < other_end < end:
2710
2895
  reg.setRegion([other_end, end])
2711
2896
  break
2712
- if other_begin < end <= other_end:
2897
+ if other_begin < end <= other_end or end > other_begin > other_end > beg:
2713
2898
  reg.setRegion([beg, other_begin])
2714
2899
  break
2715
2900
  reg.text.begin, reg.text.end = reg.getRegion()
@@ -2732,7 +2917,7 @@ class SpeakerTier(pg.GraphicsObject):
2732
2917
  if new_begin == utt.begin and new_end == utt.end:
2733
2918
  return
2734
2919
  self.selection_model.model().update_utterance_times(utt, begin=new_begin, end=new_end)
2735
- self.selection_model.select_audio(new_begin, None)
2920
+ self.selection_model.request_start_time(new_begin)
2736
2921
  reg.text.begin = new_begin
2737
2922
  reg.text.end = new_end
2738
2923
  reg.update()