Anchor-annotator 0.1.0__py3-none-any.whl → 0.2.1__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.1.0.dist-info → Anchor_annotator-0.2.1.dist-info}/METADATA +1 -1
- Anchor_annotator-0.2.1.dist-info/RECORD +21 -0
- anchor/_version.py +2 -2
- anchor/main.py +44 -22
- anchor/models.py +826 -481
- anchor/plot.py +428 -399
- anchor/undo.py +103 -134
- anchor/widgets.py +36 -45
- anchor/workers.py +43 -17
- Anchor_annotator-0.1.0.dist-info/RECORD +0 -21
- {Anchor_annotator-0.1.0.dist-info → Anchor_annotator-0.2.1.dist-info}/LICENSE +0 -0
- {Anchor_annotator-0.1.0.dist-info → Anchor_annotator-0.2.1.dist-info}/WHEEL +0 -0
- {Anchor_annotator-0.1.0.dist-info → Anchor_annotator-0.2.1.dist-info}/top_level.txt +0 -0
anchor/plot.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import functools
|
3
4
|
import logging
|
4
5
|
import os.path
|
5
6
|
import re
|
@@ -10,6 +11,7 @@ import numpy as np
|
|
10
11
|
import pyqtgraph as pg
|
11
12
|
import sqlalchemy
|
12
13
|
from Bio import pairwise2
|
14
|
+
from line_profiler_pycharm import profile
|
13
15
|
from montreal_forced_aligner.data import CtmInterval
|
14
16
|
from montreal_forced_aligner.db import Speaker, Utterance
|
15
17
|
from PySide6 import QtCore, QtGui, QtWidgets
|
@@ -19,6 +21,8 @@ from anchor.models import (
|
|
19
21
|
CorpusModel,
|
20
22
|
CorpusSelectionModel,
|
21
23
|
DictionaryTableModel,
|
24
|
+
FileSelectionModel,
|
25
|
+
FileUtterancesModel,
|
22
26
|
SpeakerModel,
|
23
27
|
TextFilterQuery,
|
24
28
|
)
|
@@ -408,6 +412,31 @@ class SpeakerTierItem(pg.PlotItem):
|
|
408
412
|
self.setMenuEnabled(False)
|
409
413
|
self.hideButtons()
|
410
414
|
|
415
|
+
def contextMenuEvent(self, event: QtWidgets.QGraphicsSceneContextMenuEvent):
|
416
|
+
vb = self.getViewBox()
|
417
|
+
item = self.items[0]
|
418
|
+
x = vb.mapFromItemToView(self, event.pos()).x()
|
419
|
+
begin = max(x - 0.5, 0)
|
420
|
+
end = min(x + 0.5, item.selection_model.model().file.duration)
|
421
|
+
for x in item.visible_utterances.values():
|
422
|
+
if begin >= x.item_min and end <= x.item_max:
|
423
|
+
event.accept()
|
424
|
+
return
|
425
|
+
if begin < x.item_max and begin > x.item_max:
|
426
|
+
begin = x.item_max
|
427
|
+
if end > x.item_min and end < x.item_min:
|
428
|
+
end = x.item_min
|
429
|
+
break
|
430
|
+
if end - begin > 0.001:
|
431
|
+
menu = QtWidgets.QMenu()
|
432
|
+
|
433
|
+
a = QtGui.QAction(menu)
|
434
|
+
a.setText("Create utterance")
|
435
|
+
a.triggered.connect(functools.partial(item.create_utterance, begin=begin, end=end))
|
436
|
+
menu.addAction(a)
|
437
|
+
menu.setStyleSheet(item.settings.menu_style_sheet)
|
438
|
+
menu.exec_(event.screenPos())
|
439
|
+
|
411
440
|
|
412
441
|
class UtteranceView(QtWidgets.QWidget):
|
413
442
|
undoRequested = QtCore.Signal()
|
@@ -418,23 +447,15 @@ class UtteranceView(QtWidgets.QWidget):
|
|
418
447
|
super().__init__(*args)
|
419
448
|
self.settings = AnchorSettings()
|
420
449
|
self.corpus_model: typing.Optional[CorpusModel] = None
|
450
|
+
self.file_model: typing.Optional[FileUtterancesModel] = None
|
421
451
|
self.dictionary_model: typing.Optional[DictionaryTableModel] = None
|
422
|
-
self.selection_model: typing.Optional[
|
452
|
+
self.selection_model: typing.Optional[FileSelectionModel] = None
|
423
453
|
layout = QtWidgets.QVBoxLayout()
|
424
454
|
self.bottom_point = 0
|
425
455
|
self.top_point = 8
|
426
456
|
self.height = self.top_point - self.bottom_point
|
427
457
|
self.separator_point = (self.height / 2) + self.bottom_point
|
428
|
-
|
429
|
-
self.auto_waveform_worker = workers.AutoWaveformWorker()
|
430
|
-
self.spectrogram_worker = workers.SpectrogramWorker()
|
431
|
-
self.pitch_track_worker = workers.PitchWorker()
|
432
|
-
self.speaker_tier_worker = workers.SpeakerTierWorker()
|
433
|
-
self.waveform_worker.signals.result.connect(self.finalize_loading_wave_form)
|
434
|
-
self.auto_waveform_worker.signals.result.connect(self.finalize_loading_auto_wave_form)
|
435
|
-
self.spectrogram_worker.signals.result.connect(self.finalize_loading_spectrogram)
|
436
|
-
self.pitch_track_worker.signals.result.connect(self.finalize_loading_pitch_track)
|
437
|
-
self.speaker_tier_worker.signals.result.connect(self.finalize_loading_utterances)
|
458
|
+
|
438
459
|
# self.break_line.setZValue(30)
|
439
460
|
self.audio_layout = pg.GraphicsLayoutWidget()
|
440
461
|
self.audio_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
|
@@ -454,7 +475,9 @@ class UtteranceView(QtWidgets.QWidget):
|
|
454
475
|
self.speaker_tier_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
|
455
476
|
self.speaker_tier_layout.centralWidget.layout.setSpacing(0)
|
456
477
|
self.speaker_tiers: dict[SpeakerTier] = {}
|
478
|
+
self.speaker_tier_items = {}
|
457
479
|
self.search_term = None
|
480
|
+
self.default_speaker_id = None
|
458
481
|
self.extra_tiers = {}
|
459
482
|
self.tier_scroll_area = QtWidgets.QScrollArea()
|
460
483
|
self.audio_scroll_area = QtWidgets.QScrollArea()
|
@@ -476,22 +499,16 @@ class UtteranceView(QtWidgets.QWidget):
|
|
476
499
|
scroll_layout.setSpacing(0)
|
477
500
|
self.setLayout(layout)
|
478
501
|
|
479
|
-
def clean_up_for_close(self):
|
480
|
-
self.spectrogram_worker.stop()
|
481
|
-
self.pitch_track_worker.stop()
|
482
|
-
self.waveform_worker.stop()
|
483
|
-
self.auto_waveform_worker.stop()
|
484
|
-
self.speaker_tier_worker.stop()
|
485
|
-
|
486
502
|
def set_models(
|
487
503
|
self,
|
488
504
|
corpus_model: CorpusModel,
|
489
|
-
|
505
|
+
file_model: FileUtterancesModel,
|
506
|
+
selection_model: FileSelectionModel,
|
490
507
|
dictionary_model: DictionaryTableModel,
|
491
508
|
):
|
492
509
|
self.corpus_model = corpus_model
|
510
|
+
self.file_model = file_model
|
493
511
|
self.corpus_model.corpusLoaded.connect(self.set_extra_tiers)
|
494
|
-
self.corpus_model.refreshTiers.connect(self.set_up_new_file)
|
495
512
|
self.selection_model = selection_model
|
496
513
|
self.dictionary_model = dictionary_model
|
497
514
|
for t in self.speaker_tiers.values():
|
@@ -499,55 +516,61 @@ class UtteranceView(QtWidgets.QWidget):
|
|
499
516
|
self.audio_plot.set_models(self.selection_model)
|
500
517
|
self.selection_model.viewChanged.connect(self.update_plot)
|
501
518
|
# self.corpus_model.utteranceTextUpdated.connect(self.refresh_utterance_text)
|
502
|
-
self.selection_model.fileChanged.connect(self.set_up_new_file)
|
503
|
-
self.selection_model.channelChanged.connect(self.update_channel)
|
504
519
|
self.selection_model.resetView.connect(self.reset_plot)
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
520
|
+
self.file_model.utterancesReady.connect(self.finalize_loading_utterances)
|
521
|
+
self.selection_model.spectrogramReady.connect(self.finalize_loading_spectrogram)
|
522
|
+
self.selection_model.pitchTrackReady.connect(self.finalize_loading_pitch_track)
|
523
|
+
self.selection_model.waveformReady.connect(self.finalize_loading_auto_wave_form)
|
524
|
+
self.selection_model.speakerRequested.connect(self.set_default_speaker)
|
525
|
+
self.file_model.selectionRequested.connect(self.finalize_loading_utterances)
|
526
|
+
|
527
|
+
def finalize_loading_utterances(self):
|
528
|
+
if self.file_model.file is None:
|
512
529
|
return
|
530
|
+
scroll_to = None
|
531
|
+
|
513
532
|
self.speaker_tiers = {}
|
514
533
|
self.speaker_tier_items = {}
|
515
534
|
self.speaker_tier_layout.clear()
|
516
535
|
available_speakers = {}
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
self.
|
536
|
+
speaker_tier_height = self.separator_point - self.bottom_point
|
537
|
+
for i, speaker_id in enumerate(self.file_model.speakers):
|
538
|
+
speaker_name = self.corpus_model.get_speaker_name(speaker_id)
|
539
|
+
top_point = i * speaker_tier_height
|
540
|
+
bottom_point = top_point - speaker_tier_height
|
541
|
+
tier = SpeakerTier(
|
542
|
+
top_point,
|
543
|
+
bottom_point,
|
544
|
+
speaker_id,
|
545
|
+
speaker_name,
|
546
|
+
self.corpus_model,
|
547
|
+
self.file_model,
|
548
|
+
self.selection_model,
|
549
|
+
self.dictionary_model,
|
550
|
+
search_term=self.search_term,
|
551
|
+
)
|
552
|
+
tier.draggingLine.connect(self.audio_plot.update_drag_line)
|
553
|
+
tier.lineDragFinished.connect(self.audio_plot.hide_drag_line)
|
554
|
+
tier.receivedWheelEvent.connect(self.audio_plot.wheelEvent)
|
555
|
+
tier.set_extra_tiers(self.extra_tiers)
|
556
|
+
tier.setZValue(30)
|
557
|
+
available_speakers[speaker_name] = speaker_id
|
558
|
+
self.speaker_tiers[speaker_id] = tier
|
537
559
|
for i, (key, tier) in enumerate(self.speaker_tiers.items()):
|
538
|
-
tier.set_speaker_index(0, 1)
|
539
560
|
tier.set_available_speakers(available_speakers)
|
540
561
|
tier.refresh()
|
541
|
-
|
562
|
+
top_point = i * speaker_tier_height
|
563
|
+
bottom_point = top_point - speaker_tier_height
|
564
|
+
tier_item = SpeakerTierItem(top_point, bottom_point)
|
542
565
|
tier_item.setRange(
|
543
566
|
xRange=[self.selection_model.plot_min, self.selection_model.plot_max]
|
544
567
|
)
|
545
568
|
tier_item.addItem(tier)
|
546
569
|
self.speaker_tier_items[key] = tier_item
|
547
570
|
self.speaker_tier_layout.addItem(tier_item, i, 0)
|
571
|
+
if tier.speaker_id == self.default_speaker_id:
|
572
|
+
scroll_to = i
|
548
573
|
row_height = self.audio_plot_item.height()
|
549
|
-
if len(self.speaker_tiers) > 1 and len(self.extra_tiers) < 2:
|
550
|
-
row_height = int(row_height / 2)
|
551
574
|
self.speaker_tier_layout.setFixedHeight(len(self.speaker_tiers) * row_height)
|
552
575
|
if len(self.speaker_tiers) > 1:
|
553
576
|
self.tier_scroll_area.verticalScrollBar().setSingleStep(row_height)
|
@@ -562,91 +585,73 @@ class UtteranceView(QtWidgets.QWidget):
|
|
562
585
|
self.audio_layout.centralWidget.layout.setContentsMargins(
|
563
586
|
0, 0, self.settings.scroll_bar_height, 0
|
564
587
|
)
|
588
|
+
if scroll_to is not None:
|
589
|
+
# self.tier_scroll_area.scrollContentsBy(0, scroll_to * tier_height)
|
590
|
+
self.tier_scroll_area.verticalScrollBar().setValue(
|
591
|
+
scroll_to * self.tier_scroll_area.height()
|
592
|
+
)
|
593
|
+
self.default_speaker_id = None
|
565
594
|
else:
|
566
595
|
self.audio_layout.centralWidget.layout.setContentsMargins(0, 0, 0, 0)
|
567
596
|
self.tier_scroll_area.setVerticalScrollBarPolicy(
|
568
597
|
QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff
|
569
598
|
)
|
570
599
|
|
571
|
-
def
|
572
|
-
|
573
|
-
if (
|
574
|
-
self.selection_model.current_file is None
|
575
|
-
or file_path != self.selection_model.current_file.sound_file.sound_file_path
|
576
|
-
):
|
577
|
-
return
|
578
|
-
self.audio_plot.wave_form.y = y
|
579
|
-
self.get_latest_waveform()
|
600
|
+
def set_default_speaker(self, speaker_id):
|
601
|
+
self.default_speaker_id = speaker_id
|
580
602
|
|
581
|
-
def finalize_loading_spectrogram(self
|
582
|
-
|
583
|
-
if self.
|
584
|
-
|
585
|
-
begin, end = -end, -begin
|
586
|
-
if begin != self.selection_model.plot_min or end != self.selection_model.plot_max:
|
603
|
+
def finalize_loading_spectrogram(self):
|
604
|
+
self.audio_plot.spectrogram.hide()
|
605
|
+
if self.selection_model.spectrogram is None:
|
606
|
+
self.audio_plot.spectrogram.clear()
|
587
607
|
return
|
588
|
-
self.audio_plot.spectrogram.setData(
|
608
|
+
self.audio_plot.spectrogram.setData(
|
609
|
+
self.selection_model.spectrogram,
|
610
|
+
self.selection_model.selected_channel,
|
611
|
+
self.selection_model.plot_min,
|
612
|
+
self.selection_model.plot_max,
|
613
|
+
self.selection_model.min_db,
|
614
|
+
self.selection_model.max_db,
|
615
|
+
)
|
589
616
|
|
590
|
-
def finalize_loading_pitch_track(self
|
591
|
-
pitch_track
|
592
|
-
|
593
|
-
|
594
|
-
begin, end = -end, -begin
|
595
|
-
if begin != self.selection_model.plot_min or end != self.selection_model.plot_max:
|
596
|
-
return
|
597
|
-
if pitch_track is None:
|
617
|
+
def finalize_loading_pitch_track(self):
|
618
|
+
self.audio_plot.pitch_track.hide()
|
619
|
+
self.audio_plot.pitch_track.clear()
|
620
|
+
if self.selection_model.pitch_track_y is None:
|
598
621
|
return
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
622
|
+
self.audio_plot.pitch_track.setData(
|
623
|
+
x=self.selection_model.pitch_track_x,
|
624
|
+
y=self.selection_model.pitch_track_y,
|
625
|
+
connect="finite",
|
626
|
+
)
|
627
|
+
self.audio_plot.pitch_track.set_range(
|
628
|
+
self.settings.value(self.settings.PITCH_MIN_F0),
|
629
|
+
self.settings.value(self.settings.PITCH_MAX_F0),
|
630
|
+
self.selection_model.plot_max,
|
603
631
|
)
|
604
|
-
self.audio_plot.pitch_track.hide()
|
605
|
-
self.audio_plot.pitch_track.setData(x=x, y=pitch_track, connect="finite")
|
606
|
-
self.audio_plot.pitch_track.set_range(min_f0, max_f0, end)
|
607
632
|
self.audio_plot.pitch_track.show()
|
608
633
|
|
609
|
-
def finalize_loading_auto_wave_form(self
|
610
|
-
|
611
|
-
if self.
|
612
|
-
y = np.flip(y, 0)
|
613
|
-
begin, end = -end, -begin
|
614
|
-
if begin != self.selection_model.plot_min or end != self.selection_model.plot_max:
|
634
|
+
def finalize_loading_auto_wave_form(self):
|
635
|
+
self.audio_plot.wave_form.hide()
|
636
|
+
if self.selection_model.waveform_y is None:
|
615
637
|
return
|
616
|
-
|
617
|
-
|
638
|
+
self.audio_plot_item.setRange(
|
639
|
+
xRange=[self.selection_model.plot_min, self.selection_model.plot_max]
|
640
|
+
)
|
641
|
+
self.audio_plot.update_plot()
|
642
|
+
self.audio_plot.wave_form.setData(
|
643
|
+
x=self.selection_model.waveform_x, y=self.selection_model.waveform_y
|
618
644
|
)
|
619
|
-
# self.audio_plot.wave_form.hide()
|
620
|
-
self.audio_plot.wave_form.setData(x=x, y=y)
|
621
645
|
self.audio_plot.wave_form.show()
|
622
646
|
|
623
|
-
def get_utterances(self):
|
624
|
-
for tier in self.speaker_tiers.values():
|
625
|
-
tier.reset_tier()
|
626
|
-
self.speaker_tier_layout.removeItem(tier)
|
627
|
-
if self.selection_model.current_file is None:
|
628
|
-
return
|
629
|
-
self.speaker_tier_worker.stop()
|
630
|
-
self.speaker_tier_worker.set_params(self.selection_model.current_file.id)
|
631
|
-
self.speaker_tier_worker.start()
|
632
|
-
|
633
647
|
def set_extra_tiers(self):
|
634
|
-
self.speaker_tier_worker.query_alignment = False
|
635
|
-
self.speaker_tier_worker.session = self.corpus_model.session
|
636
648
|
self.extra_tiers = {}
|
637
|
-
visible_tiers = self.settings.visible_tiers
|
638
649
|
self.extra_tiers["Normalized text"] = "normalized_text"
|
639
650
|
if self.corpus_model.has_alignments and "Words" not in self.extra_tiers:
|
640
651
|
self.extra_tiers["Words"] = "aligned_word_intervals"
|
641
|
-
if visible_tiers.get("Words", True):
|
642
|
-
self.speaker_tier_worker.query_alignment = True
|
643
652
|
self.extra_tiers["Phones"] = "aligned_phone_intervals"
|
644
|
-
if visible_tiers.get("Phones", True):
|
645
|
-
self.speaker_tier_worker.query_alignment = True
|
646
653
|
if self.corpus_model.has_reference_alignments and "Reference" not in self.extra_tiers:
|
647
654
|
self.extra_tiers["Reference"] = "reference_phone_intervals"
|
648
|
-
if visible_tiers.get("Reference", True):
|
649
|
-
self.speaker_tier_worker.query_alignment = True
|
650
655
|
if (
|
651
656
|
self.corpus_model.has_transcribed_alignments
|
652
657
|
and "Transcription" not in self.extra_tiers
|
@@ -654,10 +659,6 @@ class UtteranceView(QtWidgets.QWidget):
|
|
654
659
|
self.extra_tiers["Transcription"] = "transcription_text"
|
655
660
|
self.extra_tiers["Transcribed words"] = "transcribed_word_intervals"
|
656
661
|
self.extra_tiers["Transcribed phones"] = "transcribed_phone_intervals"
|
657
|
-
if visible_tiers.get("Transcribed words", True):
|
658
|
-
self.speaker_tier_worker.query_alignment = True
|
659
|
-
if visible_tiers.get("Transcribed phones", True):
|
660
|
-
self.speaker_tier_worker.query_alignment = True
|
661
662
|
if (
|
662
663
|
self.corpus_model.has_per_speaker_transcribed_alignments
|
663
664
|
and "Transcription" not in self.extra_tiers
|
@@ -665,29 +666,6 @@ class UtteranceView(QtWidgets.QWidget):
|
|
665
666
|
self.extra_tiers["Transcription"] = "transcription_text"
|
666
667
|
self.extra_tiers["Transcribed words"] = "per_speaker_transcribed_word_intervals"
|
667
668
|
self.extra_tiers["Transcribed phones"] = "per_speaker_transcribed_phone_intervals"
|
668
|
-
if visible_tiers.get("Transcribed words", True):
|
669
|
-
self.speaker_tier_worker.query_alignment = True
|
670
|
-
if visible_tiers.get("Transcribed phones", True):
|
671
|
-
self.speaker_tier_worker.query_alignment = True
|
672
|
-
|
673
|
-
def update_channel(self):
|
674
|
-
self.get_latest_waveform()
|
675
|
-
|
676
|
-
def set_up_new_file(self, *args):
|
677
|
-
self.audio_plot.spectrogram.cached_begin = None
|
678
|
-
self.audio_plot.spectrogram.cached_end = None
|
679
|
-
self.audio_plot.wave_form.y = None
|
680
|
-
for t in self.speaker_tiers.values():
|
681
|
-
t.visible_utterances = {}
|
682
|
-
self.speaker_tiers = {}
|
683
|
-
if self.selection_model.current_file is None:
|
684
|
-
return
|
685
|
-
self.get_utterances()
|
686
|
-
self.waveform_worker.stop()
|
687
|
-
self.waveform_worker.set_params(
|
688
|
-
self.selection_model.current_file.sound_file.sound_file_path
|
689
|
-
)
|
690
|
-
self.waveform_worker.start()
|
691
669
|
|
692
670
|
def set_search_term(self):
|
693
671
|
term = self.corpus_model.text_filter
|
@@ -704,74 +682,23 @@ class UtteranceView(QtWidgets.QWidget):
|
|
704
682
|
def draw_text_grid(self):
|
705
683
|
scroll_to = None
|
706
684
|
for i, (key, tier) in enumerate(self.speaker_tiers.items()):
|
685
|
+
self.speaker_tier_items[key].hide()
|
707
686
|
tier.refresh()
|
708
|
-
if tier.
|
687
|
+
if tier.speaker_id == self.default_speaker_id:
|
709
688
|
scroll_to = i
|
710
689
|
tier_height = self.speaker_tier_items[key].height()
|
711
690
|
self.speaker_tier_items[key].setRange(
|
712
691
|
xRange=[self.selection_model.plot_min, self.selection_model.plot_max]
|
713
692
|
)
|
693
|
+
self.speaker_tier_items[key].show()
|
714
694
|
if scroll_to is not None:
|
715
|
-
self.tier_scroll_area.
|
695
|
+
self.tier_scroll_area.verticalScrollBar().setValue(scroll_to * tier_height)
|
696
|
+
self.default_speaker_id = None
|
716
697
|
|
717
698
|
def update_show_speakers(self, state):
|
718
699
|
self.show_all_speakers = state > 0
|
719
700
|
self.update_plot()
|
720
701
|
|
721
|
-
def get_latest_waveform(self):
|
722
|
-
if self.audio_plot.wave_form.y is None:
|
723
|
-
return
|
724
|
-
self.audio_plot.wave_form.hide()
|
725
|
-
# self.audio_plot.spectrogram.hide()
|
726
|
-
self.audio_plot.pitch_track.hide()
|
727
|
-
begin_samp = int(
|
728
|
-
self.selection_model.min_time * self.selection_model.current_file.sample_rate
|
729
|
-
)
|
730
|
-
end_samp = int(
|
731
|
-
self.selection_model.max_time * self.selection_model.current_file.sample_rate
|
732
|
-
)
|
733
|
-
if len(self.audio_plot.wave_form.y.shape) > 1:
|
734
|
-
y = self.audio_plot.wave_form.y[
|
735
|
-
begin_samp:end_samp, self.selection_model.selected_channel
|
736
|
-
]
|
737
|
-
else:
|
738
|
-
y = self.audio_plot.wave_form.y[begin_samp:end_samp]
|
739
|
-
self.spectrogram_worker.stop()
|
740
|
-
self.spectrogram_worker.set_params(
|
741
|
-
y,
|
742
|
-
self.selection_model.current_file.sound_file.sample_rate,
|
743
|
-
self.selection_model.min_time,
|
744
|
-
self.selection_model.max_time,
|
745
|
-
self.selection_model.selected_channel,
|
746
|
-
)
|
747
|
-
self.spectrogram_worker.start()
|
748
|
-
if self.selection_model.max_time - self.selection_model.min_time <= 10:
|
749
|
-
self.pitch_track_worker.stop()
|
750
|
-
self.pitch_track_worker.set_params(
|
751
|
-
y,
|
752
|
-
self.selection_model.current_file.sound_file.sample_rate,
|
753
|
-
self.selection_model.min_time,
|
754
|
-
self.selection_model.max_time,
|
755
|
-
self.selection_model.selected_channel,
|
756
|
-
self.audio_plot.pitch_track.bottom_point,
|
757
|
-
self.audio_plot.pitch_track.top_point,
|
758
|
-
)
|
759
|
-
self.pitch_track_worker.start()
|
760
|
-
self.auto_waveform_worker.stop()
|
761
|
-
self.auto_waveform_worker.set_params(
|
762
|
-
y,
|
763
|
-
self.audio_plot.wave_form.bottom_point,
|
764
|
-
self.audio_plot.wave_form.top_point,
|
765
|
-
self.selection_model.min_time,
|
766
|
-
self.selection_model.max_time,
|
767
|
-
self.selection_model.selected_channel,
|
768
|
-
)
|
769
|
-
self.auto_waveform_worker.start()
|
770
|
-
self.audio_plot_item.setRange(
|
771
|
-
xRange=[self.selection_model.plot_min, self.selection_model.plot_max]
|
772
|
-
)
|
773
|
-
self.audio_plot.update_plot()
|
774
|
-
|
775
702
|
def reset_plot(self, *args):
|
776
703
|
self.reset_text_grid()
|
777
704
|
self.audio_plot.wave_form.clear()
|
@@ -781,9 +708,8 @@ class UtteranceView(QtWidgets.QWidget):
|
|
781
708
|
def update_plot(self, *args):
|
782
709
|
if self.corpus_model.rowCount() == 0:
|
783
710
|
return
|
784
|
-
if self.
|
711
|
+
if self.file_model.file is None or self.selection_model.min_time is None:
|
785
712
|
return
|
786
|
-
self.get_latest_waveform()
|
787
713
|
self.audio_plot.update_plot()
|
788
714
|
self.draw_text_grid()
|
789
715
|
|
@@ -798,7 +724,7 @@ class UtteranceView(QtWidgets.QWidget):
|
|
798
724
|
if tier.top_point > pos > tier.bottom_point:
|
799
725
|
new_speaker_id = tier.speaker_id
|
800
726
|
if new_speaker_id is not None and new_speaker_id != old_speaker_id:
|
801
|
-
self.
|
727
|
+
self.file_model.update_utterance_speaker(utterance, new_speaker_id)
|
802
728
|
|
803
729
|
|
804
730
|
class UtteranceLine(pg.InfiniteLine):
|
@@ -1041,20 +967,23 @@ class UtterancePGTextItem(pg.TextItem):
|
|
1041
967
|
self.selection_model.viewChanged.connect(self.update_times)
|
1042
968
|
|
1043
969
|
def update_times(self, begin, end):
|
1044
|
-
self.hide()
|
1045
970
|
self.view_min = begin
|
1046
971
|
self.view_max = end
|
1047
|
-
|
972
|
+
if self.end <= self.view_min or self.begin >= self.view_max:
|
973
|
+
return
|
974
|
+
self.hide()
|
1048
975
|
if (
|
1049
976
|
self.view_min <= self.begin < self.view_max
|
1050
977
|
or self.view_max >= self.end > self.view_min
|
1051
978
|
or (self.begin <= self.view_min and self.end >= self.view_max)
|
1052
|
-
)
|
979
|
+
):
|
1053
980
|
self.show()
|
1054
981
|
|
1055
982
|
def boundingRect(self):
|
1056
983
|
br = QtCore.QRectF(self.viewRect()) # bounds of containing ViewBox mapped to local coords.
|
1057
984
|
vb = self.getViewBox()
|
985
|
+
if self.begin is None or self.view_min is None:
|
986
|
+
return br
|
1058
987
|
visible_begin = max(self.begin, self.view_min)
|
1059
988
|
visible_end = min(self.end, self.view_max)
|
1060
989
|
|
@@ -1532,24 +1461,24 @@ class Highlighter(QtGui.QSyntaxHighlighter):
|
|
1532
1461
|
|
1533
1462
|
|
1534
1463
|
class MfaRegion(pg.LinearRegionItem):
|
1535
|
-
dragFinished = QtCore.Signal(object)
|
1536
1464
|
textEdited = QtCore.Signal(object, object)
|
1537
1465
|
undoRequested = QtCore.Signal()
|
1538
1466
|
redoRequested = QtCore.Signal()
|
1539
1467
|
playRequested = QtCore.Signal()
|
1540
|
-
selectRequested = QtCore.Signal(object, object, object
|
1468
|
+
selectRequested = QtCore.Signal(object, object, object)
|
1541
1469
|
audioSelected = QtCore.Signal(object, object)
|
1542
1470
|
viewRequested = QtCore.Signal(object, object)
|
1543
1471
|
|
1544
1472
|
settings = AnchorSettings()
|
1545
1473
|
|
1474
|
+
@profile
|
1546
1475
|
def __init__(
|
1547
1476
|
self,
|
1548
1477
|
item: CtmInterval,
|
1549
1478
|
corpus_model: CorpusModel,
|
1479
|
+
file_model: FileUtterancesModel,
|
1550
1480
|
dictionary_model: typing.Optional[DictionaryTableModel],
|
1551
|
-
selection_model:
|
1552
|
-
selected: bool = False,
|
1481
|
+
selection_model: FileSelectionModel,
|
1553
1482
|
bottom_point: float = 0,
|
1554
1483
|
top_point: float = 1,
|
1555
1484
|
):
|
@@ -1561,11 +1490,11 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1561
1490
|
if selection_model.settings.right_to_left:
|
1562
1491
|
self.item_min, self.item_max = -self.item_max, -self.item_min
|
1563
1492
|
self.corpus_model = corpus_model
|
1493
|
+
self.file_model = file_model
|
1564
1494
|
self.dictionary_model = dictionary_model
|
1565
1495
|
self.selection_model = selection_model
|
1566
1496
|
self.bottom_point = bottom_point
|
1567
1497
|
self.top_point = top_point
|
1568
|
-
self.selected = selected
|
1569
1498
|
self.span = (self.bottom_point, self.top_point)
|
1570
1499
|
self.text_margin_pixels = 2
|
1571
1500
|
|
@@ -1584,7 +1513,7 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1584
1513
|
self.border_pen = pg.mkPen(self.break_line_color, width=2)
|
1585
1514
|
self.border_pen.setCapStyle(QtCore.Qt.PenCapStyle.FlatCap)
|
1586
1515
|
|
1587
|
-
if self.
|
1516
|
+
if self.selection_model.checkSelected(getattr(self.item, "id", None)):
|
1588
1517
|
self.background_brush = pg.mkBrush(self.selected_interval_color)
|
1589
1518
|
else:
|
1590
1519
|
# self.interval_background_color.setAlpha(0)
|
@@ -1604,44 +1533,6 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1604
1533
|
self._boundingRectCache = None
|
1605
1534
|
self.setBrush(self.background_brush)
|
1606
1535
|
self.movable = False
|
1607
|
-
|
1608
|
-
# note LinearRegionItem.Horizontal and LinearRegionItem.Vertical
|
1609
|
-
# are kept for backward compatibility.
|
1610
|
-
lineKwds = dict(
|
1611
|
-
movable=False,
|
1612
|
-
bounds=None,
|
1613
|
-
span=self.span,
|
1614
|
-
pen=self.pen,
|
1615
|
-
hoverPen=self.hoverPen,
|
1616
|
-
movingPen=self.movingPen,
|
1617
|
-
)
|
1618
|
-
self.lines = [
|
1619
|
-
UtteranceLine(
|
1620
|
-
QtCore.QPointF(self.item_min, 0),
|
1621
|
-
angle=90,
|
1622
|
-
initial=True,
|
1623
|
-
view_min=self.selection_model.plot_min,
|
1624
|
-
view_max=self.selection_model.plot_max,
|
1625
|
-
**lineKwds,
|
1626
|
-
),
|
1627
|
-
UtteranceLine(
|
1628
|
-
QtCore.QPointF(self.item_max, 0),
|
1629
|
-
angle=90,
|
1630
|
-
initial=False,
|
1631
|
-
view_min=self.selection_model.plot_min,
|
1632
|
-
view_max=self.selection_model.plot_max,
|
1633
|
-
**lineKwds,
|
1634
|
-
),
|
1635
|
-
]
|
1636
|
-
|
1637
|
-
for line in self.lines:
|
1638
|
-
line.setZValue(30)
|
1639
|
-
line.setParentItem(self)
|
1640
|
-
line.sigPositionChangeFinished.connect(self.lineMoveFinished)
|
1641
|
-
self.lines[0].sigPositionChanged.connect(self._line0Moved)
|
1642
|
-
self.lines[1].sigPositionChanged.connect(self._line1Moved)
|
1643
|
-
self.lines[0].hoverChanged.connect(self.popup)
|
1644
|
-
self.lines[1].hoverChanged.connect(self.popup)
|
1645
1536
|
self.cached_visible_duration = None
|
1646
1537
|
self.cached_view = None
|
1647
1538
|
|
@@ -1650,33 +1541,6 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1650
1541
|
p.setPen(self.border_pen)
|
1651
1542
|
p.drawRect(self.boundingRect())
|
1652
1543
|
|
1653
|
-
def mouseDragEvent(self, ev):
|
1654
|
-
if not self.movable or ev.button() != QtCore.Qt.MouseButton.LeftButton:
|
1655
|
-
return
|
1656
|
-
ev.accept()
|
1657
|
-
|
1658
|
-
if ev.isStart():
|
1659
|
-
bdp = ev.buttonDownPos()
|
1660
|
-
self.cursorOffsets = [line.pos() - bdp for line in self.lines]
|
1661
|
-
self.startPositions = [line.pos() for line in self.lines]
|
1662
|
-
self.moving = True
|
1663
|
-
|
1664
|
-
if not self.moving:
|
1665
|
-
return
|
1666
|
-
|
1667
|
-
# self.lines[0].blockSignals(True) # only want to update once
|
1668
|
-
# for i, l in enumerate(self.lines):
|
1669
|
-
# l.setPos(self.cursorOffsets[i] + ev.pos())
|
1670
|
-
# self.lines[0].blockSignals(False)
|
1671
|
-
self.prepareGeometryChange()
|
1672
|
-
|
1673
|
-
if ev.isFinish():
|
1674
|
-
self.moving = False
|
1675
|
-
self.dragFinished.emit(ev.pos())
|
1676
|
-
self.sigRegionChangeFinished.emit(self)
|
1677
|
-
else:
|
1678
|
-
self.sigRegionChanged.emit(self)
|
1679
|
-
|
1680
1544
|
def mouseClickEvent(self, ev: QtGui.QMouseEvent):
|
1681
1545
|
if ev.button() != QtCore.Qt.MouseButton.LeftButton:
|
1682
1546
|
ev.ignore()
|
@@ -1693,26 +1557,14 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1693
1557
|
self.viewRequested.emit(self.item_min - padding, self.item_max + padding)
|
1694
1558
|
ev.accept()
|
1695
1559
|
|
1696
|
-
def change_editing(self, editable: bool):
|
1697
|
-
self.movable = editable
|
1698
|
-
self.lines[0].movable = editable
|
1699
|
-
self.lines[1].movable = editable
|
1700
|
-
|
1701
1560
|
def setSelected(self, selected: bool):
|
1702
|
-
|
1703
|
-
if self.selected:
|
1561
|
+
if selected:
|
1704
1562
|
self.setBrush(pg.mkBrush(self.selected_interval_color))
|
1705
1563
|
else:
|
1706
1564
|
# self.interval_background_color.setAlpha(0)
|
1707
1565
|
self.setBrush(pg.mkBrush(self.interval_background_color))
|
1708
1566
|
self.update()
|
1709
1567
|
|
1710
|
-
def popup(self, hover: bool):
|
1711
|
-
if hover or self.moving or self.lines[0].moving or self.lines[1].moving:
|
1712
|
-
self.setZValue(30)
|
1713
|
-
else:
|
1714
|
-
self.setZValue(0)
|
1715
|
-
|
1716
1568
|
def setMouseHover(self, hover: bool):
|
1717
1569
|
# Inform the item that the mouse is(not) hovering over it
|
1718
1570
|
if self.mouseHovering == hover:
|
@@ -1721,30 +1573,38 @@ class MfaRegion(pg.LinearRegionItem):
|
|
1721
1573
|
self.popup(hover)
|
1722
1574
|
self.update()
|
1723
1575
|
|
1724
|
-
def select_self(self, deselect=False, reset=True
|
1576
|
+
def select_self(self, deselect=False, reset=True):
|
1725
1577
|
self.selected = True
|
1726
1578
|
if self.selected and not deselect and not reset:
|
1727
1579
|
return
|
1728
1580
|
|
1729
1581
|
|
1730
1582
|
class AlignmentRegion(MfaRegion):
|
1583
|
+
@profile
|
1731
1584
|
def __init__(
|
1732
1585
|
self,
|
1733
1586
|
phone_interval: CtmInterval,
|
1734
1587
|
corpus_model: CorpusModel,
|
1588
|
+
file_model: FileUtterancesModel,
|
1735
1589
|
selection_model: CorpusSelectionModel,
|
1736
|
-
selected: bool = False,
|
1737
1590
|
bottom_point: float = 0,
|
1738
1591
|
top_point: float = 1,
|
1739
1592
|
):
|
1740
1593
|
super().__init__(
|
1741
|
-
phone_interval,
|
1594
|
+
phone_interval,
|
1595
|
+
corpus_model,
|
1596
|
+
file_model,
|
1597
|
+
None,
|
1598
|
+
selection_model,
|
1599
|
+
bottom_point,
|
1600
|
+
top_point,
|
1742
1601
|
)
|
1743
1602
|
self.original_text = self.item.label
|
1744
1603
|
|
1745
1604
|
self.text = pg.TextItem(
|
1746
1605
|
self.item.label, anchor=(0.5, 0.5), color=self.text_color # , border=pg.mkColor("r")
|
1747
1606
|
)
|
1607
|
+
self.text.setVisible(False)
|
1748
1608
|
|
1749
1609
|
self.text.setFont(self.settings.font)
|
1750
1610
|
options = QtGui.QTextOption()
|
@@ -1753,22 +1613,30 @@ class AlignmentRegion(MfaRegion):
|
|
1753
1613
|
self.text.setParentItem(self)
|
1754
1614
|
self.per_tier_range = self.top_point - self.bottom_point
|
1755
1615
|
|
1616
|
+
def viewRangeChanged(self):
|
1617
|
+
if (self.item_max - self.item_min) / (
|
1618
|
+
self.selection_model.max_time - self.selection_model.min_time
|
1619
|
+
) < 0.001:
|
1620
|
+
self.hide()
|
1621
|
+
else:
|
1622
|
+
self.show()
|
1623
|
+
super().viewRangeChanged()
|
1624
|
+
|
1756
1625
|
def boundingRect(self):
|
1757
1626
|
br = QtCore.QRectF(self.viewRect()) # bounds of containing ViewBox mapped to local coords.
|
1758
1627
|
vb = self.getViewBox()
|
1759
1628
|
|
1760
1629
|
pixel_size = vb.viewPixelSize()
|
1761
|
-
rng = self.getRegion()
|
1762
1630
|
|
1763
|
-
br.setLeft(
|
1764
|
-
br.setRight(
|
1631
|
+
br.setLeft(self.item_min)
|
1632
|
+
br.setRight(self.item_max)
|
1765
1633
|
|
1766
1634
|
br.setTop(self.top_point)
|
1767
1635
|
# br.setBottom(self.top_point-self.per_tier_range)
|
1768
1636
|
br.setBottom(self.bottom_point + 0.01)
|
1769
1637
|
try:
|
1770
|
-
visible_begin = max(
|
1771
|
-
visible_end = min(
|
1638
|
+
visible_begin = max(self.item_min, self.selection_model.plot_min)
|
1639
|
+
visible_end = min(self.item_max, self.selection_model.plot_max)
|
1772
1640
|
except TypeError:
|
1773
1641
|
return br
|
1774
1642
|
visible_duration = visible_end - visible_begin
|
@@ -1794,39 +1662,47 @@ class PhoneRegion(AlignmentRegion):
|
|
1794
1662
|
self,
|
1795
1663
|
phone_interval: CtmInterval,
|
1796
1664
|
corpus_model: CorpusModel,
|
1665
|
+
file_model: FileUtterancesModel,
|
1797
1666
|
selection_model: CorpusSelectionModel,
|
1798
|
-
selected: bool = False,
|
1799
1667
|
bottom_point: float = 0,
|
1800
1668
|
top_point: float = 1,
|
1801
1669
|
):
|
1802
1670
|
super().__init__(
|
1803
|
-
phone_interval, corpus_model,
|
1671
|
+
phone_interval, corpus_model, file_model, selection_model, bottom_point, top_point
|
1804
1672
|
)
|
1805
1673
|
|
1806
1674
|
|
1807
1675
|
class WordRegion(AlignmentRegion):
|
1676
|
+
highlightRequested = QtCore.Signal(object)
|
1677
|
+
|
1808
1678
|
def __init__(
|
1809
1679
|
self,
|
1810
|
-
|
1680
|
+
word_interval: CtmInterval,
|
1811
1681
|
corpus_model: CorpusModel,
|
1682
|
+
file_model: FileUtterancesModel,
|
1812
1683
|
selection_model: CorpusSelectionModel,
|
1813
|
-
selected: bool = False,
|
1814
1684
|
bottom_point: float = 0,
|
1815
1685
|
top_point: float = 1,
|
1816
1686
|
):
|
1817
1687
|
super().__init__(
|
1818
|
-
|
1688
|
+
word_interval, corpus_model, file_model, selection_model, bottom_point, top_point
|
1819
1689
|
)
|
1820
1690
|
|
1691
|
+
def mouseClickEvent(self, ev: QtGui.QMouseEvent):
|
1692
|
+
search_term = TextFilterQuery(self.item.label, word=True)
|
1693
|
+
self.highlightRequested.emit(search_term)
|
1694
|
+
super().mouseClickEvent(ev)
|
1695
|
+
|
1821
1696
|
|
1822
1697
|
class UtteranceRegion(MfaRegion):
|
1698
|
+
@profile
|
1823
1699
|
def __init__(
|
1824
1700
|
self,
|
1825
1701
|
utterance: workers.UtteranceData,
|
1826
1702
|
corpus_model: CorpusModel,
|
1703
|
+
file_model: FileUtterancesModel,
|
1827
1704
|
dictionary_model: DictionaryTableModel,
|
1828
|
-
selection_model:
|
1829
|
-
selected: bool = False,
|
1705
|
+
selection_model: FileSelectionModel,
|
1830
1706
|
bottom_point: float = 0,
|
1831
1707
|
top_point: float = 1,
|
1832
1708
|
extra_tiers=None,
|
@@ -1836,9 +1712,9 @@ class UtteranceRegion(MfaRegion):
|
|
1836
1712
|
super().__init__(
|
1837
1713
|
utterance,
|
1838
1714
|
corpus_model,
|
1715
|
+
file_model,
|
1839
1716
|
dictionary_model,
|
1840
1717
|
selection_model,
|
1841
|
-
selected,
|
1842
1718
|
bottom_point,
|
1843
1719
|
top_point,
|
1844
1720
|
)
|
@@ -1852,8 +1728,45 @@ class UtteranceRegion(MfaRegion):
|
|
1852
1728
|
visible_tiers = self.settings.visible_tiers
|
1853
1729
|
self.num_tiers = len([x for x in extra_tiers if visible_tiers[x]]) + 1
|
1854
1730
|
self.per_tier_range = (top_point - bottom_point) / self.num_tiers
|
1731
|
+
self.selected = self.selection_model.checkSelected(self.item.id)
|
1855
1732
|
|
1856
|
-
|
1733
|
+
# note LinearRegionItem.Horizontal and LinearRegionItem.Vertical
|
1734
|
+
# are kept for backward compatibility.
|
1735
|
+
lineKwds = dict(
|
1736
|
+
movable=True,
|
1737
|
+
bounds=None,
|
1738
|
+
span=self.span,
|
1739
|
+
pen=self.pen,
|
1740
|
+
hoverPen=self.hoverPen,
|
1741
|
+
movingPen=self.movingPen,
|
1742
|
+
)
|
1743
|
+
self.lines = [
|
1744
|
+
UtteranceLine(
|
1745
|
+
QtCore.QPointF(self.item_min, 0),
|
1746
|
+
angle=90,
|
1747
|
+
initial=True,
|
1748
|
+
view_min=self.selection_model.plot_min,
|
1749
|
+
view_max=self.selection_model.plot_max,
|
1750
|
+
**lineKwds,
|
1751
|
+
),
|
1752
|
+
UtteranceLine(
|
1753
|
+
QtCore.QPointF(self.item_max, 0),
|
1754
|
+
angle=90,
|
1755
|
+
initial=False,
|
1756
|
+
view_min=self.selection_model.plot_min,
|
1757
|
+
view_max=self.selection_model.plot_max,
|
1758
|
+
**lineKwds,
|
1759
|
+
),
|
1760
|
+
]
|
1761
|
+
|
1762
|
+
for line in self.lines:
|
1763
|
+
line.setZValue(30)
|
1764
|
+
line.setParentItem(self)
|
1765
|
+
line.sigPositionChangeFinished.connect(self.lineMoveFinished)
|
1766
|
+
self.lines[0].sigPositionChanged.connect(self._line0Moved)
|
1767
|
+
self.lines[1].sigPositionChanged.connect(self._line1Moved)
|
1768
|
+
self.lines[0].hoverChanged.connect(self.popup)
|
1769
|
+
self.lines[1].hoverChanged.connect(self.popup)
|
1857
1770
|
|
1858
1771
|
self.corpus_model.utteranceTextUpdated.connect(self.update_text_from_model)
|
1859
1772
|
self.original_text = self.item.text
|
@@ -1945,6 +1858,8 @@ class UtteranceRegion(MfaRegion):
|
|
1945
1858
|
if intervals is None:
|
1946
1859
|
continue
|
1947
1860
|
for interval in intervals:
|
1861
|
+
# if (interval.end - interval.begin) /(self.selection_model.max_time -self.selection_model.min_time) < 0.01:
|
1862
|
+
# continue
|
1948
1863
|
if lookup == "transcription_text":
|
1949
1864
|
interval_reg = TranscriberTextRegion(
|
1950
1865
|
self,
|
@@ -1964,8 +1879,8 @@ class UtteranceRegion(MfaRegion):
|
|
1964
1879
|
interval_reg = PhoneRegion(
|
1965
1880
|
interval,
|
1966
1881
|
self.corpus_model,
|
1882
|
+
self.file_model,
|
1967
1883
|
selection_model=selection_model,
|
1968
|
-
selected=False,
|
1969
1884
|
top_point=tier_top_point,
|
1970
1885
|
bottom_point=tier_bottom_point,
|
1971
1886
|
)
|
@@ -1974,12 +1889,13 @@ class UtteranceRegion(MfaRegion):
|
|
1974
1889
|
interval_reg = WordRegion(
|
1975
1890
|
interval,
|
1976
1891
|
self.corpus_model,
|
1892
|
+
self.file_model,
|
1977
1893
|
selection_model=selection_model,
|
1978
|
-
selected=False,
|
1979
1894
|
top_point=tier_top_point,
|
1980
1895
|
bottom_point=tier_bottom_point,
|
1981
1896
|
)
|
1982
1897
|
interval_reg.setParentItem(self)
|
1898
|
+
interval_reg.highlightRequested.connect(self.highlighter.setSearchTerm)
|
1983
1899
|
|
1984
1900
|
else:
|
1985
1901
|
interval_reg = IntervalTextRegion(
|
@@ -2001,6 +1917,25 @@ class UtteranceRegion(MfaRegion):
|
|
2001
1917
|
self.show()
|
2002
1918
|
self.available_speakers = available_speakers
|
2003
1919
|
|
1920
|
+
def change_editing(self, editable: bool):
|
1921
|
+
self.lines[0].movable = editable
|
1922
|
+
self.lines[1].movable = editable
|
1923
|
+
self.text_edit.setReadOnly(not editable)
|
1924
|
+
|
1925
|
+
def popup(self, hover: bool):
|
1926
|
+
if hover or self.moving or self.lines[0].moving or self.lines[1].moving:
|
1927
|
+
self.setZValue(30)
|
1928
|
+
else:
|
1929
|
+
self.setZValue(0)
|
1930
|
+
|
1931
|
+
def setMovable(self, m=True):
|
1932
|
+
"""Set lines to be movable by the user, or not. If lines are movable, they will
|
1933
|
+
also accept HoverEvents."""
|
1934
|
+
for line in self.lines:
|
1935
|
+
line.setMovable(m)
|
1936
|
+
self.movable = False
|
1937
|
+
self.setAcceptHoverEvents(False)
|
1938
|
+
|
2004
1939
|
def contextMenuEvent(self, ev: QtWidgets.QGraphicsSceneContextMenuEvent):
|
2005
1940
|
menu = QtWidgets.QMenu()
|
2006
1941
|
change_speaker_menu = QtWidgets.QMenu("Change speaker")
|
@@ -2032,6 +1967,17 @@ class UtteranceRegion(MfaRegion):
|
|
2032
1967
|
a.toggled.connect(self.update_tier_visibility)
|
2033
1968
|
visible_tiers_menu.addAction(a)
|
2034
1969
|
menu.addMenu(visible_tiers_menu)
|
1970
|
+
menu.addSeparator()
|
1971
|
+
|
1972
|
+
a = QtGui.QAction(menu)
|
1973
|
+
a.setText("Split utterance")
|
1974
|
+
a.triggered.connect(self.split_utterance)
|
1975
|
+
menu.addAction(a)
|
1976
|
+
|
1977
|
+
a = QtGui.QAction(menu)
|
1978
|
+
a.setText("Delete utterance")
|
1979
|
+
a.triggered.connect(self.delete_utterance)
|
1980
|
+
menu.addAction(a)
|
2035
1981
|
change_speaker_menu.setStyleSheet(self.settings.menu_style_sheet)
|
2036
1982
|
visible_tiers_menu.setStyleSheet(self.settings.menu_style_sheet)
|
2037
1983
|
menu.setStyleSheet(self.settings.menu_style_sheet)
|
@@ -2050,7 +1996,7 @@ class UtteranceRegion(MfaRegion):
|
|
2050
1996
|
if dialog.exec_():
|
2051
1997
|
speaker_id = dialog.speaker_dropdown.current_text()
|
2052
1998
|
if isinstance(speaker_id, int):
|
2053
|
-
self.
|
1999
|
+
self.file_model.update_utterance_speaker(self.item, speaker_id)
|
2054
2000
|
|
2055
2001
|
def update_speaker(self):
|
2056
2002
|
speaker_name = self.sender().text()
|
@@ -2058,21 +2004,21 @@ class UtteranceRegion(MfaRegion):
|
|
2058
2004
|
speaker_id = 0
|
2059
2005
|
else:
|
2060
2006
|
speaker_id = self.available_speakers[speaker_name]
|
2061
|
-
self.
|
2007
|
+
self.file_model.update_utterance_speaker(self.item, speaker_id)
|
2008
|
+
|
2009
|
+
def split_utterance(self):
|
2010
|
+
self.file_model.split_utterances([self.item])
|
2011
|
+
|
2012
|
+
def delete_utterance(self):
|
2013
|
+
self.file_model.delete_utterances([self.item])
|
2062
2014
|
|
2063
2015
|
def refresh_timer(self):
|
2064
2016
|
self.timer.start(500)
|
2065
2017
|
self.update()
|
2066
2018
|
|
2067
|
-
def
|
2068
|
-
|
2069
|
-
self.
|
2070
|
-
|
2071
|
-
def select_self(self, deselect=False, reset=True, focus=False):
|
2072
|
-
self.selected = True
|
2073
|
-
if self.selected and not deselect and not reset:
|
2074
|
-
return
|
2075
|
-
self.selectRequested.emit(self.item.id, deselect, reset, focus)
|
2019
|
+
def select_self(self, deselect=False, reset=True):
|
2020
|
+
self.setSelected(not deselect)
|
2021
|
+
self.selectRequested.emit(self.item.id, deselect, reset)
|
2076
2022
|
|
2077
2023
|
def mouseDoubleClickEvent(self, ev: QtGui.QMouseEvent):
|
2078
2024
|
if ev.button() != QtCore.Qt.MouseButton.LeftButton:
|
@@ -2080,7 +2026,10 @@ class UtteranceRegion(MfaRegion):
|
|
2080
2026
|
return
|
2081
2027
|
deselect = False
|
2082
2028
|
reset = True
|
2083
|
-
if ev.modifiers()
|
2029
|
+
if ev.modifiers() in [
|
2030
|
+
QtCore.Qt.KeyboardModifier.ControlModifier,
|
2031
|
+
QtCore.Qt.KeyboardModifier.ShiftModifier,
|
2032
|
+
]:
|
2084
2033
|
reset = False
|
2085
2034
|
if self.selected:
|
2086
2035
|
deselect = True
|
@@ -2089,7 +2038,7 @@ class UtteranceRegion(MfaRegion):
|
|
2089
2038
|
self.selected = True
|
2090
2039
|
else:
|
2091
2040
|
self.selected = True
|
2092
|
-
self.select_self(deselect=deselect, reset=reset
|
2041
|
+
self.select_self(deselect=deselect, reset=reset)
|
2093
2042
|
ev.accept()
|
2094
2043
|
|
2095
2044
|
def mouseClickEvent(self, ev: QtGui.QMouseEvent):
|
@@ -2098,7 +2047,10 @@ class UtteranceRegion(MfaRegion):
|
|
2098
2047
|
return
|
2099
2048
|
deselect = False
|
2100
2049
|
reset = True
|
2101
|
-
if ev.modifiers()
|
2050
|
+
if ev.modifiers() in [
|
2051
|
+
ev.modifiers().ControlModifier,
|
2052
|
+
ev.modifiers().ShiftModifier,
|
2053
|
+
]:
|
2102
2054
|
reset = False
|
2103
2055
|
if self.selected:
|
2104
2056
|
deselect = True
|
@@ -2107,7 +2059,7 @@ class UtteranceRegion(MfaRegion):
|
|
2107
2059
|
self.selected = True
|
2108
2060
|
else:
|
2109
2061
|
self.selected = True
|
2110
|
-
self.select_self(deselect=deselect, reset=reset
|
2062
|
+
self.select_self(deselect=deselect, reset=reset)
|
2111
2063
|
ev.accept()
|
2112
2064
|
|
2113
2065
|
def update_view_times(self):
|
@@ -2349,7 +2301,7 @@ class AudioPlots(pg.GraphicsObject):
|
|
2349
2301
|
def __init__(self, top_point, separator_point, bottom_point):
|
2350
2302
|
super().__init__()
|
2351
2303
|
self.settings = AnchorSettings()
|
2352
|
-
self.selection_model: typing.Optional[
|
2304
|
+
self.selection_model: typing.Optional[FileSelectionModel] = None
|
2353
2305
|
self.top_point = top_point
|
2354
2306
|
self.separator_point = separator_point
|
2355
2307
|
self.bottom_point = bottom_point
|
@@ -2434,7 +2386,45 @@ class AudioPlots(pg.GraphicsObject):
|
|
2434
2386
|
if ev.button() != QtCore.Qt.MouseButton.LeftButton:
|
2435
2387
|
ev.ignore()
|
2436
2388
|
return
|
2437
|
-
|
2389
|
+
if ev.modifiers() in [
|
2390
|
+
QtCore.Qt.KeyboardModifier.ControlModifier,
|
2391
|
+
QtCore.Qt.KeyboardModifier.ShiftModifier,
|
2392
|
+
]:
|
2393
|
+
time = ev.pos().x()
|
2394
|
+
if self.selection_model.selected_max_time is not None:
|
2395
|
+
if (
|
2396
|
+
self.selection_model.selected_min_time
|
2397
|
+
< time
|
2398
|
+
< self.selection_model.selected_max_time
|
2399
|
+
):
|
2400
|
+
if (
|
2401
|
+
time - self.selection_model.selected_min_time
|
2402
|
+
< self.selection_model.selected_max_time - time
|
2403
|
+
):
|
2404
|
+
min_time = time
|
2405
|
+
max_time = self.selection_model.selected_max_time
|
2406
|
+
else:
|
2407
|
+
min_time = self.selection_model.selected_min_time
|
2408
|
+
max_time = time
|
2409
|
+
else:
|
2410
|
+
min_time = min(
|
2411
|
+
time,
|
2412
|
+
self.selection_model.selected_min_time,
|
2413
|
+
self.selection_model.selected_max_time,
|
2414
|
+
)
|
2415
|
+
max_time = max(
|
2416
|
+
time,
|
2417
|
+
self.selection_model.selected_min_time,
|
2418
|
+
self.selection_model.selected_max_time,
|
2419
|
+
)
|
2420
|
+
else:
|
2421
|
+
min_time = min(time, self.selection_model.selected_min_time)
|
2422
|
+
max_time = max(time, self.selection_model.selected_min_time)
|
2423
|
+
self.selection_area.setRegion((min_time, max_time))
|
2424
|
+
self.selection_area.setVisible(True)
|
2425
|
+
self.selection_model.select_audio(min_time, max_time)
|
2426
|
+
else:
|
2427
|
+
self.selection_model.request_start_time(ev.pos().x())
|
2438
2428
|
ev.accept()
|
2439
2429
|
|
2440
2430
|
def hoverEvent(self, ev):
|
@@ -2476,9 +2466,9 @@ class AudioPlots(pg.GraphicsObject):
|
|
2476
2466
|
|
2477
2467
|
def update_plot(self):
|
2478
2468
|
if (
|
2479
|
-
self.selection_model.
|
2480
|
-
or self.selection_model.
|
2481
|
-
or not os.path.exists(self.selection_model.
|
2469
|
+
self.selection_model.model().file is None
|
2470
|
+
or self.selection_model.model().file.sound_file is None
|
2471
|
+
or not os.path.exists(self.selection_model.model().file.sound_file.sound_file_path)
|
2482
2472
|
):
|
2483
2473
|
return
|
2484
2474
|
self.rect.setLeft(self.selection_model.plot_min)
|
@@ -2490,48 +2480,68 @@ class AudioPlots(pg.GraphicsObject):
|
|
2490
2480
|
|
2491
2481
|
|
2492
2482
|
class SpeakerTier(pg.GraphicsObject):
|
2493
|
-
dragFinished = QtCore.Signal(object, object)
|
2494
2483
|
receivedWheelEvent = QtCore.Signal(object)
|
2495
2484
|
draggingLine = QtCore.Signal(object)
|
2496
2485
|
lineDragFinished = QtCore.Signal(object)
|
2497
2486
|
|
2498
2487
|
def __init__(
|
2499
|
-
self,
|
2488
|
+
self,
|
2489
|
+
top_point,
|
2490
|
+
bottom_point,
|
2491
|
+
speaker_id: int,
|
2492
|
+
speaker_name: str,
|
2493
|
+
corpus_model: CorpusModel,
|
2494
|
+
file_model: FileUtterancesModel,
|
2495
|
+
selection_model: FileSelectionModel,
|
2496
|
+
dictionary_model: DictionaryTableModel,
|
2497
|
+
search_term: str = None,
|
2500
2498
|
):
|
2501
2499
|
super().__init__()
|
2500
|
+
self.file_model = file_model
|
2501
|
+
self.corpus_model = corpus_model
|
2502
|
+
self.selection_model = selection_model
|
2503
|
+
self.dictionary_model = dictionary_model
|
2502
2504
|
self.settings = AnchorSettings()
|
2503
|
-
self.corpus_model: Optional[CorpusModel] = None
|
2504
|
-
self.selection_model: Optional[CorpusSelectionModel] = None
|
2505
2505
|
self.search_term = search_term
|
2506
2506
|
self.speaker_id = speaker_id
|
2507
2507
|
self.speaker_name = speaker_name
|
2508
2508
|
self.speaker_index = 0
|
2509
|
-
self.textgrid_top_point = top_point
|
2510
2509
|
self.top_point = top_point
|
2511
2510
|
self.speaker_label = pg.TextItem(self.speaker_name, color=self.settings.accent_base_color)
|
2512
2511
|
self.speaker_label.setFont(self.settings.font)
|
2513
2512
|
self.speaker_label.setParentItem(self)
|
2514
2513
|
self.speaker_label.setZValue(40)
|
2515
2514
|
self.bottom_point = bottom_point
|
2516
|
-
self.textgrid_bottom_point = bottom_point
|
2517
2515
|
self.annotation_range = self.top_point - self.bottom_point
|
2518
2516
|
self.extra_tiers = {}
|
2519
|
-
self.utterances = []
|
2520
2517
|
self.visible_utterances: dict[str, UtteranceRegion] = {}
|
2521
2518
|
self.background_brush = pg.mkBrush(self.settings.primary_very_dark_color)
|
2522
2519
|
self.border = pg.mkPen(self.settings.accent_light_color)
|
2523
2520
|
self.picture = QtGui.QPicture()
|
2521
|
+
self.has_visible_utterances = False
|
2522
|
+
self.has_selected_utterances = False
|
2523
|
+
self.rect = QtCore.QRectF(
|
2524
|
+
left=self.selection_model.plot_min,
|
2525
|
+
riht=self.selection_model.plot_max,
|
2526
|
+
top=self.top_point,
|
2527
|
+
bottom=self.bottom_point,
|
2528
|
+
)
|
2529
|
+
self._generate_picture()
|
2530
|
+
self.corpus_model.lockCorpus.connect(self.lock)
|
2531
|
+
self.corpus_model.refreshUtteranceText.connect(self.refreshTexts)
|
2532
|
+
self.selection_model.selectionChanged.connect(self.update_select)
|
2533
|
+
self.selection_model.model().utterancesReady.connect(self.refresh)
|
2524
2534
|
|
2525
2535
|
def wheelEvent(self, ev):
|
2526
2536
|
self.receivedWheelEvent.emit(ev)
|
2527
2537
|
|
2528
|
-
def
|
2529
|
-
if ev.button() != QtCore.Qt.MouseButton.
|
2538
|
+
def mouseClickEvent(self, ev):
|
2539
|
+
if ev.button() != QtCore.Qt.MouseButton.RightButton:
|
2530
2540
|
ev.ignore()
|
2531
2541
|
return
|
2532
2542
|
x = ev.pos().x()
|
2533
2543
|
begin = max(x - 0.5, 0)
|
2534
|
-
end = min(x + 0.5, self.selection_model.
|
2544
|
+
end = min(x + 0.5, self.selection_model.model().file.duration)
|
2535
2545
|
for x in self.visible_utterances.values():
|
2536
2546
|
if begin >= x.item_min and end <= x.item_max:
|
2537
2547
|
ev.accept()
|
@@ -2542,10 +2552,40 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2542
2552
|
end = x.item_min
|
2543
2553
|
break
|
2544
2554
|
if end - begin > 0.001:
|
2545
|
-
|
2546
|
-
|
2547
|
-
)
|
2548
|
-
|
2555
|
+
menu = QtWidgets.QMenu()
|
2556
|
+
|
2557
|
+
a = QtGui.QAction(menu)
|
2558
|
+
a.setText("Create utterance")
|
2559
|
+
a.triggered.connect(functools.partial(self.create_utterance, begin=begin, end=end))
|
2560
|
+
menu.addAction(a)
|
2561
|
+
menu.setStyleSheet(self.settings.menu_style_sheet)
|
2562
|
+
menu.exec_(ev.screenPos())
|
2563
|
+
|
2564
|
+
def contextMenuEvent(self, ev):
|
2565
|
+
x = ev.pos().x()
|
2566
|
+
begin = max(x - 0.5, 0)
|
2567
|
+
end = min(x + 0.5, self.selection_model.model().file.duration)
|
2568
|
+
for x in self.visible_utterances.values():
|
2569
|
+
if begin >= x.item_min and end <= x.item_max:
|
2570
|
+
ev.accept()
|
2571
|
+
return
|
2572
|
+
if begin < x.item_max and begin > x.item_max:
|
2573
|
+
begin = x.item_max
|
2574
|
+
if end > x.item_min and end < x.item_min:
|
2575
|
+
end = x.item_min
|
2576
|
+
break
|
2577
|
+
if end - begin > 0.001:
|
2578
|
+
menu = QtWidgets.QMenu()
|
2579
|
+
|
2580
|
+
a = QtGui.QAction(menu)
|
2581
|
+
a.setText("Create utterance")
|
2582
|
+
a.triggered.connect(functools.partial(self.create_utterance, begin=begin, end=end))
|
2583
|
+
menu.addAction(a)
|
2584
|
+
menu.setStyleSheet(self.settings.menu_style_sheet)
|
2585
|
+
menu.exec_(ev.screenPos())
|
2586
|
+
|
2587
|
+
def create_utterance(self, begin, end):
|
2588
|
+
self.file_model.create_utterance(self.speaker_id, begin, end)
|
2549
2589
|
|
2550
2590
|
def setSearchterm(self, term):
|
2551
2591
|
self.search_term = term
|
@@ -2558,22 +2598,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2558
2598
|
def paint(self, p, *args):
|
2559
2599
|
p.drawPicture(0, 0, self.picture)
|
2560
2600
|
|
2561
|
-
def set_speaker_index(self, index, num_speakers):
|
2562
|
-
self.speaker_index = index
|
2563
|
-
speaker_tier_range = self.annotation_range / num_speakers
|
2564
|
-
self.top_point = self.textgrid_top_point - (speaker_tier_range * self.speaker_index)
|
2565
|
-
self.bottom_point = self.top_point - speaker_tier_range
|
2566
|
-
self.rect = QtCore.QRectF(
|
2567
|
-
left=self.selection_model.plot_min,
|
2568
|
-
top=self.top_point,
|
2569
|
-
width=self.selection_model.plot_max - self.selection_model.plot_min,
|
2570
|
-
height=speaker_tier_range,
|
2571
|
-
)
|
2572
|
-
self.rect.setHeight(speaker_tier_range)
|
2573
|
-
self._generate_picture()
|
2574
|
-
|
2575
2601
|
def _generate_picture(self):
|
2576
|
-
self.speaker_label.setPos(self.selection_model.plot_min, self.top_point)
|
2577
2602
|
self.picture = QtGui.QPicture()
|
2578
2603
|
painter = QtGui.QPainter(self.picture)
|
2579
2604
|
painter.setPen(self.border)
|
@@ -2588,22 +2613,6 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2588
2613
|
def set_available_speakers(self, available_speakers):
|
2589
2614
|
self.available_speakers = available_speakers
|
2590
2615
|
|
2591
|
-
def set_models(
|
2592
|
-
self,
|
2593
|
-
corpus_model: CorpusModel,
|
2594
|
-
selection_model: CorpusSelectionModel,
|
2595
|
-
dictionary_model: DictionaryTableModel,
|
2596
|
-
):
|
2597
|
-
self.corpus_model = corpus_model
|
2598
|
-
self.selection_model = selection_model
|
2599
|
-
self.dictionary_model = dictionary_model
|
2600
|
-
for reg in self.visible_utterances.values():
|
2601
|
-
reg.highlighter.set_models(self.dictionary_model)
|
2602
|
-
# self.corpus_model.changeCommandFired.connect(self.refresh)
|
2603
|
-
self.corpus_model.lockCorpus.connect(self.lock)
|
2604
|
-
self.corpus_model.refreshUtteranceText.connect(self.refreshTexts)
|
2605
|
-
self.selection_model.selectionChanged.connect(self.update_select)
|
2606
|
-
|
2607
2616
|
def lock(self):
|
2608
2617
|
for utt in self.visible_utterances.values():
|
2609
2618
|
utt.setMovable(False)
|
@@ -2629,36 +2638,55 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2629
2638
|
if reg.scene() is not None:
|
2630
2639
|
reg.scene().removeItem(reg)
|
2631
2640
|
self.visible_utterances = {}
|
2632
|
-
self.other_intervals = []
|
2633
2641
|
|
2642
|
+
@profile
|
2634
2643
|
def refresh(self, *args):
|
2644
|
+
self.hide()
|
2635
2645
|
if self.selection_model.plot_min is None:
|
2636
2646
|
return
|
2637
|
-
self.rect.setLeft(self.selection_model.plot_min)
|
2638
|
-
self.rect.setRight(self.selection_model.plot_max)
|
2639
|
-
self._generate_picture()
|
2647
|
+
# self.rect.setLeft(self.selection_model.plot_min)
|
2648
|
+
# self.rect.setRight(self.selection_model.plot_max)
|
2649
|
+
# self._generate_picture()
|
2640
2650
|
self.has_visible_utterances = False
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
2647
|
-
|
2648
|
-
|
2651
|
+
self.has_selected_utterances = False
|
2652
|
+
self.speaker_label.setPos(self.selection_model.plot_min, self.top_point)
|
2653
|
+
cleanup_ids = []
|
2654
|
+
model_visible_utterances = self.selection_model.visible_utterances()
|
2655
|
+
visible_ids = [x.id for x in model_visible_utterances]
|
2656
|
+
for reg in self.visible_utterances.values():
|
2657
|
+
reg.hide()
|
2658
|
+
if (
|
2659
|
+
self.selection_model.min_time - reg.item.end > 15
|
2660
|
+
or reg.item.begin - self.selection_model.max_time > 15
|
2661
|
+
or (
|
2662
|
+
reg.item.id not in visible_ids
|
2663
|
+
and (
|
2664
|
+
reg.item.begin < self.selection_model.max_time
|
2665
|
+
or reg.item.end > self.selection_model.min_time
|
2666
|
+
)
|
2667
|
+
)
|
2668
|
+
):
|
2669
|
+
if reg.scene() is not None:
|
2670
|
+
reg.scene().removeItem(reg)
|
2671
|
+
cleanup_ids.append(reg.item.id)
|
2672
|
+
self.visible_utterances = {
|
2673
|
+
k: v for k, v in self.visible_utterances.items() if k not in cleanup_ids
|
2674
|
+
}
|
2675
|
+
for u in model_visible_utterances:
|
2676
|
+
if u.speaker_id != self.speaker_id:
|
2649
2677
|
continue
|
2650
|
-
self.has_visible_utterances = True
|
2651
2678
|
if u.id in self.visible_utterances:
|
2679
|
+
self.visible_utterances[u.id].setSelected(self.selection_model.checkSelected(u.id))
|
2652
2680
|
self.visible_utterances[u.id].show()
|
2653
2681
|
continue
|
2654
|
-
|
2682
|
+
self.has_visible_utterances = True
|
2655
2683
|
# Utterance region always at the top
|
2656
2684
|
reg = UtteranceRegion(
|
2657
2685
|
u,
|
2658
2686
|
self.corpus_model,
|
2687
|
+
self.file_model,
|
2659
2688
|
self.dictionary_model,
|
2660
2689
|
selection_model=self.selection_model,
|
2661
|
-
selected=selected,
|
2662
2690
|
extra_tiers=self.extra_tiers,
|
2663
2691
|
available_speakers=self.available_speakers,
|
2664
2692
|
bottom_point=self.bottom_point,
|
@@ -2667,7 +2695,6 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2667
2695
|
)
|
2668
2696
|
reg.sigRegionChanged.connect(self.check_utterance_bounds)
|
2669
2697
|
reg.sigRegionChangeFinished.connect(self.update_utterance)
|
2670
|
-
reg.dragFinished.connect(self.update_selected_speaker)
|
2671
2698
|
reg.lines[0].sigPositionChanged.connect(self.draggingLine.emit)
|
2672
2699
|
reg.lines[0].sigPositionChangeFinished.connect(self.lineDragFinished.emit)
|
2673
2700
|
reg.lines[1].sigPositionChanged.connect(self.draggingLine.emit)
|
@@ -2683,17 +2710,13 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2683
2710
|
reg.setParentItem(self)
|
2684
2711
|
self.visible_utterances[u.id] = reg
|
2685
2712
|
|
2686
|
-
|
2687
|
-
self.corpus_model.update_utterance_text(utterance, text=new_text)
|
2713
|
+
self.show()
|
2688
2714
|
|
2689
|
-
def
|
2690
|
-
|
2691
|
-
reg = self.sender()
|
2692
|
-
utterance = reg.item
|
2693
|
-
self.dragFinished.emit(utterance, pos)
|
2715
|
+
def update_utterance_text(self, utterance, new_text):
|
2716
|
+
self.selection_model.model().update_utterance_text(utterance, text=new_text)
|
2694
2717
|
|
2695
2718
|
def update_select(self):
|
2696
|
-
selected_rows = {x.id for x in self.selection_model.
|
2719
|
+
selected_rows = {x.id for x in self.selection_model.selected_utterances()}
|
2697
2720
|
for r in self.visible_utterances.values():
|
2698
2721
|
if r.item.id in selected_rows:
|
2699
2722
|
r.setSelected(True)
|
@@ -2708,15 +2731,21 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2708
2731
|
if end > 0:
|
2709
2732
|
reg.setRegion([beg, 0])
|
2710
2733
|
return
|
2711
|
-
if
|
2712
|
-
|
2734
|
+
if (
|
2735
|
+
self.selection_model.model().file is not None
|
2736
|
+
and -end > self.selection_model.model().file.duration
|
2737
|
+
):
|
2738
|
+
reg.setRegion([beg, self.selection_model.model().file.duration])
|
2713
2739
|
return
|
2714
2740
|
else:
|
2715
2741
|
if beg < 0:
|
2716
2742
|
reg.setRegion([0, end])
|
2717
2743
|
return
|
2718
|
-
if
|
2719
|
-
|
2744
|
+
if (
|
2745
|
+
self.selection_model.model().file is not None
|
2746
|
+
and end > self.selection_model.model().file.duration
|
2747
|
+
):
|
2748
|
+
reg.setRegion([beg, self.selection_model.model().file.duration])
|
2720
2749
|
return
|
2721
2750
|
for r in self.visible_utterances.values():
|
2722
2751
|
if r == reg:
|
@@ -2747,7 +2776,7 @@ class SpeakerTier(pg.GraphicsObject):
|
|
2747
2776
|
new_end = round(end, 4)
|
2748
2777
|
if new_begin == utt.begin and new_end == utt.end:
|
2749
2778
|
return
|
2750
|
-
self.
|
2779
|
+
self.selection_model.model().update_utterance_times(utt, begin=new_begin, end=new_end)
|
2751
2780
|
self.selection_model.select_audio(new_begin, None)
|
2752
2781
|
reg.text.begin = new_begin
|
2753
2782
|
reg.text.end = new_end
|