Anchor-annotator 0.4.0__py3-none-any.whl → 0.6.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,7 @@ 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.currentBrush = self.parentItem().currentBrush
1290
1332
  self.text.setPos((self.begin + self.end) / 2, self.top_point - (self.height / 2))
1291
1333
  self.begin_line = pg.InfiniteLine()
1292
1334
  self.rect = QtCore.QRectF(
@@ -1296,9 +1338,15 @@ class TextAttributeRegion(pg.GraphicsObject):
1296
1338
  height=self.height,
1297
1339
  )
1298
1340
  self.rect.setTop(self.top_point)
1299
- self.rect.setBottom(self.top_point - self.height)
1341
+ self.rect.setBottom(self.bottom_point)
1300
1342
  self._generate_picture()
1301
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
+
1302
1350
  def _generate_picture(self):
1303
1351
  painter = QtGui.QPainter(self.picture)
1304
1352
  painter.setPen(self.border)
@@ -1428,18 +1476,23 @@ class Highlighter(QtGui.QSyntaxHighlighter):
1428
1476
  def highlightBlock(self, text):
1429
1477
  self.settings.sync()
1430
1478
  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
1479
  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}]+"
1480
+ try:
1481
+ tokenizers = self.dictionary_model.corpus_model.corpus.get_tokenizers()
1482
+ dictionary_id = self.dictionary_model.corpus_model.corpus.get_dict_id_for_speaker(
1483
+ self.speaker_id
1484
+ )
1485
+ if isinstance(tokenizers, dict) and dictionary_id is not None:
1486
+ tokenizer = self.dictionary_model.corpus_model.corpus.get_tokenizer(dictionary_id)
1487
+ else:
1488
+ tokenizer = tokenizers
1489
+ if isinstance(tokenizer, SimpleTokenizer):
1490
+ extra_symbols = "".join(tokenizer.punctuation) + "".join(
1491
+ tokenizer.word_break_markers
1492
+ )
1493
+ words = rf"[^\s{extra_symbols}]+"
1494
+ except Exception:
1495
+ pass
1443
1496
  if self.dictionary_model is not None and self.dictionary_model.word_sets:
1444
1497
  for word_object in re.finditer(words, text):
1445
1498
  if not self.dictionary_model.check_word(word_object.group(), self.speaker_id):
@@ -1470,8 +1523,6 @@ class MfaRegion(pg.LinearRegionItem):
1470
1523
  audioSelected = QtCore.Signal(object, object)
1471
1524
  viewRequested = QtCore.Signal(object, object)
1472
1525
 
1473
- settings = AnchorSettings()
1474
-
1475
1526
  def __init__(
1476
1527
  self,
1477
1528
  item: CtmInterval,
@@ -1485,6 +1536,8 @@ class MfaRegion(pg.LinearRegionItem):
1485
1536
  pg.GraphicsObject.__init__(self)
1486
1537
  self.item = item
1487
1538
 
1539
+ self.settings = AnchorSettings()
1540
+
1488
1541
  self.item_min = self.item.begin
1489
1542
  self.item_max = self.item.end
1490
1543
  if selection_model.settings.right_to_left:
@@ -1497,15 +1550,15 @@ class MfaRegion(pg.LinearRegionItem):
1497
1550
  self.top_point = top_point
1498
1551
  self.span = (self.bottom_point, self.top_point)
1499
1552
  self.text_margin_pixels = 2
1553
+ self.height = abs(self.top_point - self.bottom_point)
1500
1554
 
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)
1555
+ self.interval_background_color = self.settings.plot_theme.interval_background_color
1556
+ self.hover_line_color = self.settings.plot_theme.hover_line_color
1557
+ self.moving_line_color = self.settings.plot_theme.moving_line_color
1505
1558
 
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)
1559
+ self.break_line_color = self.settings.plot_theme.break_line_color
1560
+ self.text_color = self.settings.plot_theme.text_color
1561
+ self.selected_interval_color = self.settings.plot_theme.selected_interval_color
1509
1562
  self.plot_text_font = self.settings.big_font
1510
1563
  self.setCursor(QtCore.Qt.CursorShape.SizeAllCursor)
1511
1564
  self.pen = pg.mkPen(self.break_line_color, width=3)
@@ -1531,15 +1584,42 @@ class MfaRegion(pg.LinearRegionItem):
1531
1584
  self.swapMode = "sort"
1532
1585
  self.clipItem = None
1533
1586
  self._boundingRectCache = None
1534
- self.setBrush(self.background_brush)
1535
1587
  self.movable = False
1536
1588
  self.cached_visible_duration = None
1537
1589
  self.cached_view = None
1590
+ self.currentBrush = self.background_brush
1591
+ self.picture = QtGui.QPicture()
1592
+ self.rect = QtCore.QRectF(
1593
+ left=self.item_min,
1594
+ top=self.top_point,
1595
+ width=self.item_max - self.item_min,
1596
+ height=self.height,
1597
+ )
1598
+ self.rect.setTop(self.top_point)
1599
+ self.rect.setLeft(self.item_min)
1600
+ self.rect.setRight(self.item_max)
1601
+ self.rect.setBottom(self.bottom_point)
1602
+ self._generate_picture()
1603
+ self.sigRegionChanged.connect(self.update_bounds)
1604
+ self.sigRegionChangeFinished.connect(self.update_bounds)
1538
1605
 
1539
- def paint(self, p, *args):
1540
- p.setBrush(self.currentBrush)
1541
- p.setPen(self.border_pen)
1542
- p.drawRect(self.boundingRect())
1606
+ def update_bounds(self):
1607
+ beg, end = self.getRegion()
1608
+ self.rect.setLeft(beg)
1609
+ self.rect.setRight(end)
1610
+ self._generate_picture()
1611
+
1612
+ def _generate_picture(self):
1613
+ if self.selection_model is None:
1614
+ return
1615
+ painter = QtGui.QPainter(self.picture)
1616
+ painter.setPen(self.border_pen)
1617
+ painter.setBrush(self.currentBrush)
1618
+ painter.drawRect(self.rect)
1619
+ painter.end()
1620
+
1621
+ def paint(self, painter, *args):
1622
+ painter.drawPicture(0, 0, self.picture)
1543
1623
 
1544
1624
  def mouseClickEvent(self, ev: QtGui.QMouseEvent):
1545
1625
  if ev.button() != QtCore.Qt.MouseButton.LeftButton:
@@ -1559,10 +1639,12 @@ class MfaRegion(pg.LinearRegionItem):
1559
1639
 
1560
1640
  def setSelected(self, selected: bool):
1561
1641
  if selected:
1562
- self.setBrush(pg.mkBrush(self.selected_interval_color))
1642
+ new_brush = pg.mkBrush(self.selected_interval_color)
1563
1643
  else:
1564
- # self.interval_background_color.setAlpha(0)
1565
- self.setBrush(pg.mkBrush(self.interval_background_color))
1644
+ new_brush = pg.mkBrush(self.interval_background_color)
1645
+ if new_brush != self.currentBrush:
1646
+ self.currentBrush = new_brush
1647
+ self._generate_picture()
1566
1648
  self.update()
1567
1649
 
1568
1650
  def setMouseHover(self, hover: bool):
@@ -1578,6 +1660,26 @@ class MfaRegion(pg.LinearRegionItem):
1578
1660
  if self.selected and not deselect and not reset:
1579
1661
  return
1580
1662
 
1663
+ def boundingRect(self):
1664
+ try:
1665
+ visible_begin = max(self.item_min, self.selection_model.plot_min)
1666
+ visible_end = min(self.item_max, self.selection_model.plot_max)
1667
+ except TypeError:
1668
+ visible_begin = self.item_min
1669
+ visible_end = self.item_max
1670
+ br = QtCore.QRectF(self.picture.boundingRect())
1671
+ br.setLeft(visible_begin)
1672
+ br.setRight(visible_end)
1673
+
1674
+ br.setTop(self.top_point)
1675
+ br.setBottom(self.bottom_point + 0.01)
1676
+ br = br.normalized()
1677
+
1678
+ if self._boundingRectCache != br:
1679
+ self._boundingRectCache = br
1680
+ self.prepareGeometryChange()
1681
+ return br
1682
+
1581
1683
 
1582
1684
  class AlignmentRegion(MfaRegion):
1583
1685
  def __init__(
@@ -1611,49 +1713,43 @@ class AlignmentRegion(MfaRegion):
1611
1713
  self.text.textItem.document().setDefaultTextOption(options)
1612
1714
  self.text.setParentItem(self)
1613
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()
1719
+
1720
+ def setSelected(self, selected: bool):
1721
+ if selected:
1722
+ self.text.setColor(self.settings.plot_theme.selected_text_color)
1723
+ else:
1724
+ self.text.setColor(self.settings.plot_theme.text_color)
1614
1725
 
1615
- def viewRangeChanged(self):
1726
+ def check_visibility(self):
1616
1727
  if (self.item_max - self.item_min) / (
1617
1728
  self.selection_model.max_time - self.selection_model.min_time
1618
1729
  ) < 0.001:
1619
1730
  self.hide()
1620
1731
  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:
1732
+ vb = self.getViewBox()
1637
1733
  visible_begin = max(self.item_min, self.selection_model.plot_min)
1638
1734
  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
-
1735
+ visible_duration = visible_end - visible_begin
1648
1736
  self.text.setPos(
1649
1737
  visible_begin + (visible_duration / 2), self.top_point - (self.per_tier_range / 2)
1650
1738
  )
1651
- br = br.normalized()
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)
1652
1750
 
1653
- if self._boundingRectCache != br:
1654
- self._boundingRectCache = br
1655
- self.prepareGeometryChange()
1656
- return br
1751
+ self.text.setVisible(available_text_width > 10)
1752
+ self.show()
1657
1753
 
1658
1754
 
1659
1755
  class PhoneRegion(AlignmentRegion):
@@ -1665,10 +1761,14 @@ class PhoneRegion(AlignmentRegion):
1665
1761
  selection_model: CorpusSelectionModel,
1666
1762
  bottom_point: float = 0,
1667
1763
  top_point: float = 1,
1764
+ color=None,
1668
1765
  ):
1669
1766
  super().__init__(
1670
1767
  phone_interval, corpus_model, file_model, selection_model, bottom_point, top_point
1671
1768
  )
1769
+ if color is not None:
1770
+ self.currentBrush = pg.mkBrush(color)
1771
+ self._generate_picture()
1672
1772
 
1673
1773
 
1674
1774
  class WordRegion(AlignmentRegion):
@@ -1686,6 +1786,7 @@ class WordRegion(AlignmentRegion):
1686
1786
  super().__init__(
1687
1787
  word_interval, corpus_model, file_model, selection_model, bottom_point, top_point
1688
1788
  )
1789
+ self._generate_picture()
1689
1790
 
1690
1791
  def mouseClickEvent(self, ev: QtGui.QMouseEvent):
1691
1792
  search_term = TextFilterQuery(self.item.label, word=True)
@@ -1779,7 +1880,7 @@ class UtteranceRegion(MfaRegion):
1779
1880
  per_tier_range=self.per_tier_range,
1780
1881
  dictionary_model=self.dictionary_model,
1781
1882
  speaker_id=self.item.speaker_id,
1782
- border=pg.mkPen(self.settings.accent_light_color),
1883
+ border=pg.mkPen(self.settings.plot_theme.break_line_color),
1783
1884
  )
1784
1885
  self.text.setParentItem(self)
1785
1886
 
@@ -1823,7 +1924,7 @@ class UtteranceRegion(MfaRegion):
1823
1924
  tier_top_point,
1824
1925
  self.per_tier_range,
1825
1926
  self.selection_model,
1826
- border=pg.mkPen(self.settings.accent_light_color),
1927
+ border=pg.mkPen(self.settings.plot_theme.break_line_color),
1827
1928
  dictionary_model=dictionary_model,
1828
1929
  search_term=search_term,
1829
1930
  speaker_id=utterance.speaker_id,
@@ -1852,9 +1953,25 @@ class UtteranceRegion(MfaRegion):
1852
1953
 
1853
1954
  if intervals is None:
1854
1955
  continue
1956
+ min_confidence = None
1957
+ max_confidence = None
1958
+ cmap = pg.ColorMap(
1959
+ None,
1960
+ [
1961
+ self.settings.plot_theme.error_color,
1962
+ self.settings.plot_theme.interval_background_color,
1963
+ ],
1964
+ )
1965
+ cmap.linearize()
1966
+ if "phone_intervals" in lookup:
1967
+ for interval in intervals:
1968
+ if interval.confidence is None:
1969
+ continue
1970
+ if min_confidence is None or interval.confidence < min_confidence:
1971
+ min_confidence = interval.confidence
1972
+ if max_confidence is None or interval.confidence > max_confidence:
1973
+ max_confidence = interval.confidence
1855
1974
  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
1975
  if lookup == "transcription_text":
1859
1976
  interval_reg = TranscriberTextRegion(
1860
1977
  self,
@@ -1864,13 +1981,21 @@ class UtteranceRegion(MfaRegion):
1864
1981
  tier_top_point,
1865
1982
  self.per_tier_range,
1866
1983
  self.selection_model,
1867
- border=pg.mkPen(self.settings.accent_light_color),
1984
+ border=pg.mkPen(self.settings.plot_theme.break_line_color),
1868
1985
  alignment=alignment,
1869
1986
  dictionary_model=dictionary_model,
1870
1987
  search_term=search_term,
1871
1988
  speaker_id=utterance.speaker_id,
1872
1989
  )
1990
+ interval_reg.setParentItem(self)
1991
+ interval_reg.audioSelected.connect(self.setSelected)
1873
1992
  elif "phone_intervals" in lookup:
1993
+ color = None
1994
+ if interval.confidence is not None and max_confidence != min_confidence:
1995
+ normalized_confidence = (interval.confidence - min_confidence) / (
1996
+ max_confidence - min_confidence
1997
+ )
1998
+ color = cmap.map(normalized_confidence)
1874
1999
  interval_reg = PhoneRegion(
1875
2000
  interval,
1876
2001
  self.corpus_model,
@@ -1878,8 +2003,10 @@ class UtteranceRegion(MfaRegion):
1878
2003
  selection_model=selection_model,
1879
2004
  top_point=tier_top_point,
1880
2005
  bottom_point=tier_bottom_point,
2006
+ color=color,
1881
2007
  )
1882
2008
  interval_reg.setParentItem(self)
2009
+ interval_reg.audioSelected.connect(self.setSelected)
1883
2010
  elif "word_intervals" in lookup:
1884
2011
  interval_reg = WordRegion(
1885
2012
  interval,
@@ -1891,18 +2018,19 @@ class UtteranceRegion(MfaRegion):
1891
2018
  )
1892
2019
  interval_reg.setParentItem(self)
1893
2020
  interval_reg.highlightRequested.connect(self.highlighter.setSearchTerm)
2021
+ interval_reg.audioSelected.connect(self.setSelected)
1894
2022
 
1895
2023
  else:
1896
2024
  interval_reg = IntervalTextRegion(
1897
2025
  interval,
1898
2026
  self.text_color,
1899
- border=pg.mkPen(self.settings.accent_light_color, width=3),
2027
+ border=pg.mkPen(self.settings.plot_theme.break_line_color, width=3),
1900
2028
  top_point=tier_top_point,
1901
2029
  height=self.per_tier_range,
1902
- # font=self.settings.font,
1903
2030
  background_brush=self.background_brush,
1904
- selected_brush=pg.mkBrush(self.selected_range_color),
2031
+ selected_brush=pg.mkBrush(self.selected_interval_color),
1905
2032
  )
2033
+ interval_reg.audioSelected.connect(self.setSelected)
1906
2034
  interval_reg.setParentItem(self)
1907
2035
 
1908
2036
  interval_reg.audioSelected.connect(self.audioSelected.emit)
@@ -1912,6 +2040,30 @@ class UtteranceRegion(MfaRegion):
1912
2040
  self.show()
1913
2041
  self.available_speakers = available_speakers
1914
2042
 
2043
+ def show(self):
2044
+ for intervals in self.extra_tier_intervals.values():
2045
+ for interval in intervals:
2046
+ if (
2047
+ self.selection_model.min_time
2048
+ < interval.item.end
2049
+ <= self.selection_model.max_time
2050
+ or self.selection_model.min_time
2051
+ <= interval.item.begin
2052
+ < self.selection_model.max_time
2053
+ ):
2054
+ interval.show()
2055
+ else:
2056
+ interval.hide()
2057
+ super().show()
2058
+
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
+
1915
2067
  def change_editing(self, editable: bool):
1916
2068
  self.lines[0].movable = editable
1917
2069
  self.lines[1].movable = editable
@@ -1979,7 +2131,10 @@ class UtteranceRegion(MfaRegion):
1979
2131
  menu.exec_(ev.screenPos())
1980
2132
 
1981
2133
  def update_tier_visibility(self, checked):
1982
- tier_name = self.sender().text().split(maxsplit=1)[-1]
2134
+ sender = self.sender()
2135
+ if not isinstance(sender, QtGui.QAction):
2136
+ return
2137
+ tier_name = sender.text().split(maxsplit=1)[-1]
1983
2138
  self.settings.setValue(self.settings.tier_visibility_mapping[tier_name], checked)
1984
2139
  self.settings.sync()
1985
2140
  self.corpus_model.refreshTiers.emit()
@@ -1994,7 +2149,10 @@ class UtteranceRegion(MfaRegion):
1994
2149
  self.file_model.update_utterance_speaker(self.item, speaker_id)
1995
2150
 
1996
2151
  def update_speaker(self):
1997
- speaker_name = self.sender().text()
2152
+ sender = self.sender()
2153
+ if not isinstance(sender, QtGui.QAction):
2154
+ return
2155
+ speaker_name = sender.text()
1998
2156
  if speaker_name == "New speaker":
1999
2157
  speaker_id = 0
2000
2158
  else:
@@ -2150,7 +2308,7 @@ class WaveForm(pg.PlotCurveItem):
2150
2308
  self.top_point = top_point
2151
2309
  self.bottom_point = bottom_point
2152
2310
  self.mid_point = (self.top_point + self.bottom_point) / 2
2153
- pen = pg.mkPen(self.settings.value(self.settings.MAIN_TEXT_COLOR), width=1)
2311
+ pen = pg.mkPen(self.settings.plot_theme.wave_line_color, width=1)
2154
2312
  super(WaveForm, self).__init__()
2155
2313
  self.setPen(pen)
2156
2314
  self.channel = 0
@@ -2158,6 +2316,10 @@ class WaveForm(pg.PlotCurveItem):
2158
2316
  self.selection_model = None
2159
2317
  self.setAcceptHoverEvents(False)
2160
2318
 
2319
+ def update_theme(self):
2320
+ pen = pg.mkPen(self.settings.plot_theme.wave_line_color, width=1)
2321
+ self.setPen(pen)
2322
+
2161
2323
  def hoverEvent(self, ev):
2162
2324
  return
2163
2325
 
@@ -2171,7 +2333,7 @@ class PitchTrack(pg.PlotCurveItem):
2171
2333
  self.top_point = top_point
2172
2334
  self.bottom_point = bottom_point
2173
2335
  self.mid_point = (self.top_point + self.bottom_point) / 2
2174
- pen = pg.mkPen(self.settings.value(self.settings.PRIMARY_LIGHT_COLOR), width=3)
2336
+ pen = pg.mkPen(self.settings.plot_theme.pitch_color, width=3)
2175
2337
  super().__init__()
2176
2338
  self.setPen(pen)
2177
2339
  self.channel = 0
@@ -2180,19 +2342,25 @@ class PitchTrack(pg.PlotCurveItem):
2180
2342
  self.setAcceptHoverEvents(False)
2181
2343
  self.min_label = pg.TextItem(
2182
2344
  str(self.settings.PITCH_MIN_F0),
2183
- self.settings.value(self.settings.PRIMARY_VERY_LIGHT_COLOR),
2345
+ self.settings.plot_theme.pitch_color,
2184
2346
  anchor=(1, 1),
2185
2347
  )
2186
2348
  self.min_label.setFont(self.settings.font)
2187
2349
  self.min_label.setParentItem(self)
2188
2350
  self.max_label = pg.TextItem(
2189
2351
  str(self.settings.PITCH_MAX_F0),
2190
- self.settings.value(self.settings.PRIMARY_VERY_LIGHT_COLOR),
2352
+ self.settings.plot_theme.pitch_color,
2191
2353
  anchor=(1, 0),
2192
2354
  )
2193
2355
  self.max_label.setFont(self.settings.font)
2194
2356
  self.max_label.setParentItem(self)
2195
2357
 
2358
+ def update_theme(self):
2359
+ pen = pg.mkPen(self.settings.plot_theme.pitch_color, width=3)
2360
+ self.setPen(pen)
2361
+ self.min_label.setColor(self.settings.plot_theme.pitch_color)
2362
+ self.max_label.setColor(self.settings.plot_theme.pitch_color)
2363
+
2196
2364
  def hoverEvent(self, ev):
2197
2365
  return
2198
2366
 
@@ -2215,7 +2383,11 @@ class Spectrogram(pg.ImageItem):
2215
2383
  self.channel = 0
2216
2384
  super(Spectrogram, self).__init__()
2217
2385
  self.cmap = pg.ColorMap(
2218
- None, [self.settings.primary_very_dark_color, self.settings.accent_light_color]
2386
+ None,
2387
+ [
2388
+ self.settings.plot_theme.background_color,
2389
+ self.settings.plot_theme.spectrogram_color,
2390
+ ],
2219
2391
  )
2220
2392
  self.cmap.linearize()
2221
2393
  self.color_bar = pg.ColorBarItem(colorMap=self.cmap)
@@ -2226,6 +2398,19 @@ class Spectrogram(pg.ImageItem):
2226
2398
  self.cached_channel = None
2227
2399
  self.stft = None
2228
2400
 
2401
+ def update_theme(self):
2402
+ self.cmap = pg.ColorMap(
2403
+ None,
2404
+ [
2405
+ self.settings.plot_theme.background_color,
2406
+ self.settings.plot_theme.spectrogram_color,
2407
+ ],
2408
+ )
2409
+ self.cmap.linearize()
2410
+ self.color_bar.setColorMap(self.cmap)
2411
+ self.color_bar.setImageItem(self)
2412
+ self.update()
2413
+
2229
2414
  def set_models(self, selection_model: CorpusSelectionModel):
2230
2415
  self.selection_model = selection_model
2231
2416
 
@@ -2287,8 +2472,12 @@ class SelectionArea(pg.LinearRegionItem):
2287
2472
  self.setVisible(False)
2288
2473
  else:
2289
2474
  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)
2475
+ self.lines[0].label.setText(
2476
+ f"{begin:.3f}", self.settings.plot_theme.selected_range_color
2477
+ )
2478
+ self.lines[1].label.setText(
2479
+ f"{end:.3f}", self.settings.plot_theme.selected_range_color
2480
+ )
2292
2481
  self.setVisible(True)
2293
2482
 
2294
2483
 
@@ -2306,17 +2495,17 @@ class AudioPlots(pg.GraphicsObject):
2306
2495
  self.wave_form.setParentItem(self)
2307
2496
  self.spectrogram.setParentItem(self)
2308
2497
  self.pitch_track.setParentItem(self)
2309
- color = self.settings.error_color
2498
+ color = self.settings.plot_theme.selected_range_color
2310
2499
  color.setAlphaF(0.25)
2311
2500
  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)
2501
+ self.background_pen = pg.mkPen(self.settings.plot_theme.break_line_color)
2502
+ self.background_brush = pg.mkBrush(self.settings.plot_theme.background_color)
2314
2503
  self.selection_area = SelectionArea(
2315
2504
  top_point=self.top_point,
2316
2505
  bottom_point=self.bottom_point,
2317
2506
  brush=self.selection_brush,
2318
2507
  clipItem=self,
2319
- pen=pg.mkPen(self.settings.error_color),
2508
+ pen=pg.mkPen(self.settings.plot_theme.selected_interval_color),
2320
2509
  )
2321
2510
  self.selection_area.setParentItem(self)
2322
2511
 
@@ -2331,7 +2520,11 @@ class AudioPlots(pg.GraphicsObject):
2331
2520
  self.update_line = pg.InfiniteLine(
2332
2521
  pos=-20,
2333
2522
  span=(0, 1),
2334
- pen=pg.mkPen(self.settings.error_color, width=3, style=QtCore.Qt.PenStyle.DashLine),
2523
+ pen=pg.mkPen(
2524
+ self.settings.plot_theme.selected_interval_color,
2525
+ width=3,
2526
+ style=QtCore.Qt.PenStyle.DashLine,
2527
+ ),
2335
2528
  movable=False, # We have our own code to handle dragless moving.
2336
2529
  )
2337
2530
  self.update_line.setParentItem(self)
@@ -2419,7 +2612,7 @@ class AudioPlots(pg.GraphicsObject):
2419
2612
  self.selection_area.setVisible(True)
2420
2613
  self.selection_model.select_audio(min_time, max_time)
2421
2614
  else:
2422
- self.selection_model.request_start_time(ev.pos().x())
2615
+ self.selection_model.request_start_time(ev.pos().x(), update=True)
2423
2616
  ev.accept()
2424
2617
 
2425
2618
  def hoverEvent(self, ev):
@@ -2502,7 +2695,9 @@ class SpeakerTier(pg.GraphicsObject):
2502
2695
  self.speaker_name = speaker_name
2503
2696
  self.speaker_index = 0
2504
2697
  self.top_point = top_point
2505
- self.speaker_label = pg.TextItem(self.speaker_name, color=self.settings.accent_base_color)
2698
+ self.speaker_label = pg.TextItem(
2699
+ self.speaker_name, color=self.settings.plot_theme.break_line_color
2700
+ )
2506
2701
  self.speaker_label.setFont(self.settings.font)
2507
2702
  self.speaker_label.setParentItem(self)
2508
2703
  self.speaker_label.setZValue(40)
@@ -2510,8 +2705,8 @@ class SpeakerTier(pg.GraphicsObject):
2510
2705
  self.annotation_range = self.top_point - self.bottom_point
2511
2706
  self.extra_tiers = {}
2512
2707
  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)
2708
+ self.background_brush = pg.mkBrush(self.settings.plot_theme.background_color)
2709
+ self.border = pg.mkPen(self.settings.plot_theme.break_line_color)
2515
2710
  self.picture = QtGui.QPicture()
2516
2711
  self.has_visible_utterances = False
2517
2712
  self.has_selected_utterances = False
@@ -2526,28 +2721,14 @@ class SpeakerTier(pg.GraphicsObject):
2526
2721
  self.corpus_model.refreshUtteranceText.connect(self.refreshTexts)
2527
2722
  self.selection_model.selectionChanged.connect(self.update_select)
2528
2723
  self.selection_model.model().utterancesReady.connect(self.refresh)
2529
- self.file_model.speakersChanged.connect(self.update_available_speakers)
2530
2724
  self.available_speakers = {}
2531
2725
 
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
2726
  def wheelEvent(self, ev):
2541
2727
  self.receivedWheelEvent.emit(ev)
2542
2728
 
2543
2729
  def create_utterance(self, begin, end):
2544
2730
  self.file_model.create_utterance(self.speaker_id, begin, end)
2545
2731
 
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
2732
  def boundingRect(self):
2552
2733
  return QtCore.QRectF(self.picture.boundingRect())
2553
2734
 
@@ -2610,14 +2791,16 @@ class SpeakerTier(pg.GraphicsObject):
2610
2791
  visible_ids = [x.id for x in model_visible_utterances]
2611
2792
  for reg in self.visible_utterances.values():
2612
2793
  reg.hide()
2794
+
2795
+ item_min, item_max = reg.getRegion()
2613
2796
  if (
2614
- self.selection_model.min_time - reg.item.end > 15
2615
- or reg.item.begin - self.selection_model.max_time > 15
2797
+ self.selection_model.min_time - item_max > 15
2798
+ or item_min - self.selection_model.max_time > 15
2616
2799
  or (
2617
2800
  reg.item.id not in visible_ids
2618
2801
  and (
2619
- reg.item.begin < self.selection_model.max_time
2620
- or reg.item.end > self.selection_model.min_time
2802
+ item_min < self.selection_model.max_time
2803
+ or item_max > self.selection_model.min_time
2621
2804
  )
2622
2805
  )
2623
2806
  ):
@@ -2706,10 +2889,10 @@ class SpeakerTier(pg.GraphicsObject):
2706
2889
  if r == reg:
2707
2890
  continue
2708
2891
  other_begin, other_end = r.getRegion()
2709
- if other_begin <= beg < other_end:
2892
+ if other_begin <= beg < other_end or beg <= other_begin < other_end < end:
2710
2893
  reg.setRegion([other_end, end])
2711
2894
  break
2712
- if other_begin < end <= other_end:
2895
+ if other_begin < end <= other_end or end > other_begin > other_end > beg:
2713
2896
  reg.setRegion([beg, other_begin])
2714
2897
  break
2715
2898
  reg.text.begin, reg.text.end = reg.getRegion()
@@ -2732,7 +2915,7 @@ class SpeakerTier(pg.GraphicsObject):
2732
2915
  if new_begin == utt.begin and new_end == utt.end:
2733
2916
  return
2734
2917
  self.selection_model.model().update_utterance_times(utt, begin=new_begin, end=new_end)
2735
- self.selection_model.select_audio(new_begin, None)
2918
+ self.selection_model.request_start_time(new_begin)
2736
2919
  reg.text.begin = new_begin
2737
2920
  reg.text.end = new_end
2738
2921
  reg.update()