Anchor-annotator 0.5.0__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/METADATA +1 -1
- Anchor_annotator-0.7.0.dist-info/RECORD +22 -0
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/WHEEL +1 -1
- anchor/_version.py +2 -2
- anchor/db.py +1 -0
- anchor/main.py +31 -10
- anchor/models.py +103 -58
- anchor/plot.py +383 -362
- anchor/resources_rc.py +331 -150
- anchor/settings.py +10 -4
- anchor/ui_main_window.py +10 -0
- anchor/undo.py +18 -18
- anchor/widgets.py +103 -38
- anchor/workers.py +2485 -2462
- Anchor_annotator-0.5.0.dist-info/RECORD +0 -22
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/LICENSE +0 -0
- {Anchor_annotator-0.5.0.dist-info → Anchor_annotator-0.7.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: Anchor_annotator
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.7.0
|
4
4
|
Summary: Anchor annotator is a program for inspecting corpora for the Montreal Forced Aligner and correcting transcriptions and pronunciations.
|
5
5
|
Home-page: https://github.com/MontrealCorpusTools/Anchor-annotator
|
6
6
|
Author: Montreal Corpus Tools
|
@@ -0,0 +1,22 @@
|
|
1
|
+
anchor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
anchor/__main__.py,sha256=5ufG8lcx2x1am-04xI991AG7saJd24dxPw5JzjmB878,45
|
3
|
+
anchor/_version.py,sha256=akvr8ObxvMF-aaLBzW41juT4_KL3BjQUrjbwkIuQXMk,411
|
4
|
+
anchor/command_line.py,sha256=EucG805HyWk_zkMO9RXv9Yj0I0JVdDLZb1_DX2_ISjM,503
|
5
|
+
anchor/db.py,sha256=LlZzAy4bjmJIu0v4ev5Qjg_Fh2n9sMsKI2nAY1pwd0A,5057
|
6
|
+
anchor/main.py,sha256=Lyr3ppr-nzxaU7ZmWXc-luMsOtRBbV4ebCzk3rygur4,127781
|
7
|
+
anchor/models.py,sha256=35l7Kw3LVy-_ozdV_0ApSkKyCPViBwBmAukoq-jw90o,97668
|
8
|
+
anchor/plot.py,sha256=imNRLI76VgEf4n9UGNvIaTsqn65hqnN396e4iwRTh70,113387
|
9
|
+
anchor/resources_rc.py,sha256=tzJHrJw3MpjAlnj-DtCmaR4A8gAaLF966XEXs5HNIjc,8464375
|
10
|
+
anchor/settings.py,sha256=N2gRFQEpY4pLYgcDz1Aq-2c7CfmbNxmRmVcPijrHsCo,52118
|
11
|
+
anchor/ui_corpus_manager.py,sha256=e3ybOd4UdYarrLBATxI8vIFnioa4R_BHrbsEz5mJ5eA,8564
|
12
|
+
anchor/ui_error_dialog.py,sha256=HKbjGT_jtdb9jfn9THQMbl1fmcdWyjYDazM4hCwZ5Yo,3931
|
13
|
+
anchor/ui_main_window.py,sha256=XK91lhFAIEURZ6nwxIA74X-8j-P76JuJsN-ahun65rw,37043
|
14
|
+
anchor/ui_preferences.py,sha256=g3tcjAMFKIAqUJNEke7ww4LkdeTFA1zb8_lrhF6k5fo,43271
|
15
|
+
anchor/undo.py,sha256=T8CJpSZVZbItpU7KMZU2F49mNv1wo0rvMWtNIEbieeo,32856
|
16
|
+
anchor/widgets.py,sha256=NjQAc02QVu97QClhXcylj_P6IP0DsxWae_eiZR5Bw3M,159300
|
17
|
+
anchor/workers.py,sha256=ciVOlK15MiDq7juAivcQB6PEiEs7DemP0BOrcpnm2to,182624
|
18
|
+
Anchor_annotator-0.7.0.dist-info/LICENSE,sha256=C0oIsblENEgWQ7XMNdYoXyXsIA5wa3YF0I9lK3H7A1s,1076
|
19
|
+
Anchor_annotator-0.7.0.dist-info/METADATA,sha256=hvYb1JLmhGJEfwyTNGckZl6tqtj407fmYYdPqPOgwcE,1500
|
20
|
+
Anchor_annotator-0.7.0.dist-info/WHEEL,sha256=FZ75kcLy9M91ncbIgG8dnpCncbiKXSRGJ_PFILs6SFg,91
|
21
|
+
Anchor_annotator-0.7.0.dist-info/top_level.txt,sha256=wX6ZKxImGRZKFQjs3f6XYw_TfbAp6Xs3SmbLfLbFAJ0,7
|
22
|
+
Anchor_annotator-0.7.0.dist-info/RECORD,,
|
anchor/_version.py
CHANGED
anchor/db.py
CHANGED
@@ -105,6 +105,7 @@ class AnchorCorpus(AnchorSqlBase):
|
|
105
105
|
custom_mapping_path = Column(PathType, nullable=True)
|
106
106
|
reference_directory = Column(PathType, nullable=True)
|
107
107
|
current = Column(Boolean, nullable=False, default=False, index=True)
|
108
|
+
# last_used = Column(DateTime, nullable=False, server_default=sqlalchemy.func.now(), index=True)
|
108
109
|
|
109
110
|
acoustic_model_id = Column(Integer, ForeignKey("acoustic_model.id"), index=True, nullable=True)
|
110
111
|
acoustic_model = relationship("AcousticModel", back_populates="corpora")
|
anchor/main.py
CHANGED
@@ -123,6 +123,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
123
123
|
self.media_player = MediaPlayer(self)
|
124
124
|
self.media_player.playbackStateChanged.connect(self.handleAudioState)
|
125
125
|
self.media_player.audioReady.connect(self.file_loaded)
|
126
|
+
self.media_player.playingChanged.connect(self.update_play_button)
|
126
127
|
self.media_player.timeChanged.connect(
|
127
128
|
self.ui.utteranceDetailWidget.plot_widget.audio_plot.update_play_line
|
128
129
|
)
|
@@ -345,14 +346,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
345
346
|
session.commit()
|
346
347
|
|
347
348
|
def file_loaded(self, ready):
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
self.ui.playAct.setChecked(False)
|
354
|
-
self.ui.muteAct.setChecked(False)
|
355
|
-
self.ui.muteAct.setEnabled(False)
|
349
|
+
self.ui.playAct.setEnabled(ready)
|
350
|
+
self.ui.muteAct.setEnabled(ready)
|
351
|
+
|
352
|
+
def update_play_button(self, playing):
|
353
|
+
self.ui.playAct.setChecked(playing)
|
356
354
|
|
357
355
|
def corpus_changed(self, clean):
|
358
356
|
if clean:
|
@@ -406,9 +404,15 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
406
404
|
elif function == "Diarizing utterances":
|
407
405
|
worker = workers.SpeakerDiarizationWorker(self.corpus_model.session, **extra_args[0])
|
408
406
|
worker.signals.result.connect(finished_function)
|
409
|
-
elif function == "
|
407
|
+
elif function == "Diarizing speakers":
|
408
|
+
worker = workers.SpeakerUtterancesWorker(self.corpus_model.session, **extra_args[0])
|
409
|
+
worker.signals.result.connect(finished_function)
|
410
|
+
elif function == "Counting utterance diarization results":
|
410
411
|
worker = workers.SpeakerDiarizationWorker(self.corpus_model.session, **extra_args[0])
|
411
412
|
worker.signals.result.connect(finished_function)
|
413
|
+
elif function == "Counting speaker diarization results":
|
414
|
+
worker = workers.SpeakerUtterancesWorker(self.corpus_model.session, **extra_args[0])
|
415
|
+
worker.signals.result.connect(finished_function)
|
412
416
|
elif function == "Merging speakers":
|
413
417
|
self.set_application_state("loading")
|
414
418
|
worker = workers.MergeSpeakersWorker(self.corpus_model.session, **extra_args[0])
|
@@ -720,7 +724,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
720
724
|
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
|
721
725
|
for worker in self.workers:
|
722
726
|
worker.stopped.set()
|
723
|
-
self.file_selection_model.clean_up_for_close()
|
724
727
|
self.file_utterances_model.clean_up_for_close()
|
725
728
|
self.settings.setValue(
|
726
729
|
AnchorSettings.UTTERANCES_VISIBLE, self.ui.utteranceDockWidget.isVisible()
|
@@ -765,6 +768,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
765
768
|
return
|
766
769
|
if self.thread_pool.activeThreadCount() > 0:
|
767
770
|
return
|
771
|
+
if self.file_selection_model.thread_pool.activeThreadCount() > 0:
|
772
|
+
return
|
768
773
|
if self.corpus_model.session is not None:
|
769
774
|
self.corpus_model.session = None
|
770
775
|
self.corpus_model.corpus.cleanup_connections()
|
@@ -851,8 +856,10 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
851
856
|
self.ui.transcriptionWidget.button.setDefaultAction(self.ui.transcribeCorpusAct)
|
852
857
|
self.ui.utteranceListWidget.oov_button.setDefaultAction(self.ui.oovsOnlyAct)
|
853
858
|
self.ui.alignmentWidget.button.setDefaultAction(self.ui.alignCorpusAct)
|
859
|
+
self.ui.alignmentWidget.verify_button.setDefaultAction(self.ui.verifyTranscriptsAct)
|
854
860
|
|
855
861
|
self.ui.alignCorpusAct.triggered.connect(self.begin_alignment)
|
862
|
+
self.ui.verifyTranscriptsAct.triggered.connect(self.begin_verify_transcripts)
|
856
863
|
self.ui.diarizationWidget.refresh_ivectors_action.triggered.connect(
|
857
864
|
self.begin_refresh_ivectors
|
858
865
|
)
|
@@ -1324,6 +1331,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
1324
1331
|
self.corpus_model.has_reference_alignments = True
|
1325
1332
|
elif w.workflow_type is WorkflowType.transcription:
|
1326
1333
|
self.corpus_model.has_transcribed_alignments = True
|
1334
|
+
elif w.workflow_type is WorkflowType.transcript_verification:
|
1335
|
+
self.corpus_model.has_transcribed_alignments = True
|
1336
|
+
self.corpus_model.has_transcript_verification_alignments = True
|
1327
1337
|
elif w.workflow_type is WorkflowType.per_speaker_transcription:
|
1328
1338
|
self.corpus_model.has_per_speaker_transcribed_alignments = True
|
1329
1339
|
|
@@ -1407,6 +1417,15 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
1407
1417
|
self.set_application_state("loading")
|
1408
1418
|
self.ui.loadingScreen.setCorpusName("Performing alignment...")
|
1409
1419
|
|
1420
|
+
def begin_verify_transcripts(self):
|
1421
|
+
self.enableMfaActions(False)
|
1422
|
+
self.alignment_worker.set_params(
|
1423
|
+
self.corpus_model.corpus, self.acoustic_model, self.ui.alignmentWidget.parameters()
|
1424
|
+
)
|
1425
|
+
self.alignment_worker.start()
|
1426
|
+
self.set_application_state("loading")
|
1427
|
+
self.ui.loadingScreen.setCorpusName("Verifying transcriptions...")
|
1428
|
+
|
1410
1429
|
def begin_refresh_ivectors(self):
|
1411
1430
|
self.enableMfaActions(False)
|
1412
1431
|
self.compute_ivectors_worker.set_params(self.corpus_model, reset=False)
|
@@ -1560,6 +1579,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
1560
1579
|
)
|
1561
1580
|
self.corpus_model.update_data()
|
1562
1581
|
self.check_actions()
|
1582
|
+
self.corpus_model.update_latest_alignment_workflow()
|
1563
1583
|
self.set_application_state("loaded")
|
1564
1584
|
|
1565
1585
|
def finalize_utterance_alignment(self, utterance_id: int):
|
@@ -2532,6 +2552,7 @@ class OptionsDialog(QtWidgets.QDialog):
|
|
2532
2552
|
self.ui.tabWidget.setCurrentIndex(0)
|
2533
2553
|
# self.setFont(self.settings.font)
|
2534
2554
|
# self.setStyleSheet(self.settings.style_sheet)
|
2555
|
+
self.update_preset_theme()
|
2535
2556
|
|
2536
2557
|
def set_theme(self, theme):
|
2537
2558
|
self.ui.primaryBaseEdit.set_color(theme[self.settings.PRIMARY_BASE_COLOR])
|
anchor/models.py
CHANGED
@@ -22,8 +22,8 @@ from montreal_forced_aligner.corpus.acoustic_corpus import (
|
|
22
22
|
AcousticCorpus,
|
23
23
|
AcousticCorpusWithPronunciations,
|
24
24
|
)
|
25
|
-
from montreal_forced_aligner.data import PhoneType, WordType
|
26
|
-
from montreal_forced_aligner.db import File, Phone, Speaker, Utterance
|
25
|
+
from montreal_forced_aligner.data import PhoneType, WordType, WorkflowType
|
26
|
+
from montreal_forced_aligner.db import CorpusWorkflow, File, Phone, Speaker, Utterance, Word
|
27
27
|
from montreal_forced_aligner.dictionary.mixins import (
|
28
28
|
DEFAULT_CLITIC_MARKERS,
|
29
29
|
DEFAULT_COMPOUND_MARKERS,
|
@@ -97,14 +97,13 @@ class TextFilterQuery:
|
|
97
97
|
if not text.endswith(word_break_set):
|
98
98
|
text += word_break_set
|
99
99
|
if posix:
|
100
|
-
text = text.replace(r"\b",
|
100
|
+
text = text.replace(r"\b", r"\y")
|
101
101
|
if text.startswith(r"\b"):
|
102
102
|
text = rf"((?<={WORD_BREAK_REGEX_SET})|(?<=^))" + text[2:]
|
103
103
|
if text.endswith(r"\b"):
|
104
104
|
text = text[:-2] + rf"((?={WORD_BREAK_REGEX_SET})|(?=$))"
|
105
|
-
if
|
106
|
-
|
107
|
-
text = "(?i)" + text
|
105
|
+
if not self.case_sensitive:
|
106
|
+
text = "(?i)" + text
|
108
107
|
return text
|
109
108
|
|
110
109
|
|
@@ -202,10 +201,10 @@ class FileUtterancesModel(QtCore.QAbstractListModel):
|
|
202
201
|
self.reversed_indices = {}
|
203
202
|
self.speaker_channel_mapping = {}
|
204
203
|
self.corpus_model: CorpusModel = None
|
205
|
-
self.
|
206
|
-
|
207
|
-
self.
|
208
|
-
self.
|
204
|
+
self.closing = False
|
205
|
+
|
206
|
+
self.thread_pool = QtCore.QThreadPool()
|
207
|
+
self.thread_pool.setMaxThreadCount(4)
|
209
208
|
|
210
209
|
def get_utterance(self, utterance_id: int) -> Utterance:
|
211
210
|
try:
|
@@ -217,8 +216,7 @@ class FileUtterancesModel(QtCore.QAbstractListModel):
|
|
217
216
|
self.corpus_model = corpus_model
|
218
217
|
|
219
218
|
def clean_up_for_close(self):
|
220
|
-
self.
|
221
|
-
self.speaker_tier_worker.stop()
|
219
|
+
self.closing = True
|
222
220
|
|
223
221
|
def set_file(self, file_id):
|
224
222
|
self.file = (
|
@@ -226,11 +224,13 @@ class FileUtterancesModel(QtCore.QAbstractListModel):
|
|
226
224
|
)
|
227
225
|
self.y = None
|
228
226
|
self.get_utterances()
|
229
|
-
self.
|
230
|
-
|
231
|
-
self.
|
227
|
+
waveform_worker = workers.WaveformWorker(self.file.sound_file.sound_file_path)
|
228
|
+
waveform_worker.signals.result.connect(self.finalize_loading_wave_form)
|
229
|
+
self.thread_pool.start(waveform_worker)
|
232
230
|
|
233
231
|
def finalize_loading_utterances(self, results):
|
232
|
+
if self.closing:
|
233
|
+
return
|
234
234
|
utterances, file_id = results
|
235
235
|
if file_id != self.file.id:
|
236
236
|
return
|
@@ -246,6 +246,8 @@ class FileUtterancesModel(QtCore.QAbstractListModel):
|
|
246
246
|
self.utterancesReady.emit()
|
247
247
|
|
248
248
|
def finalize_loading_wave_form(self, results):
|
249
|
+
if self.closing:
|
250
|
+
return
|
249
251
|
y, file_path = results
|
250
252
|
if self.file is None or file_path != self.file.sound_file.sound_file_path:
|
251
253
|
return
|
@@ -264,15 +266,17 @@ class FileUtterancesModel(QtCore.QAbstractListModel):
|
|
264
266
|
self.endRemoveRows()
|
265
267
|
if self.file is None:
|
266
268
|
return
|
267
|
-
|
268
|
-
|
269
|
-
self.
|
270
|
-
|
271
|
-
|
269
|
+
speaker_tier_worker = workers.SpeakerTierWorker(
|
270
|
+
self.corpus_model.session,
|
271
|
+
self.file.id,
|
272
|
+
query_alignment=(
|
273
|
+
self.corpus_model.has_alignments
|
274
|
+
or self.corpus_model.has_reference_alignments
|
275
|
+
or self.corpus_model.has_transcribed_alignments
|
276
|
+
),
|
272
277
|
)
|
273
|
-
|
274
|
-
self.
|
275
|
-
self.speaker_tier_worker.start()
|
278
|
+
speaker_tier_worker.signals.result.connect(self.finalize_loading_utterances)
|
279
|
+
self.thread_pool.start(speaker_tier_worker)
|
276
280
|
|
277
281
|
def create_utterance(self, speaker_id: Optional[int], begin: float, end: float):
|
278
282
|
if not self.corpus_model.editable:
|
@@ -602,18 +606,17 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
602
606
|
self.waveform_x = None
|
603
607
|
self.waveform_y = None
|
604
608
|
self.requested_utterance_id = None
|
605
|
-
self.
|
606
|
-
|
607
|
-
self.
|
608
|
-
self.
|
609
|
-
self.spectrogram_worker.signals.result.connect(self.finalize_loading_spectrogram)
|
610
|
-
self.pitch_track_worker.signals.result.connect(self.finalize_loading_pitch_track)
|
609
|
+
self.closing = False
|
610
|
+
|
611
|
+
self.thread_pool = QtCore.QThreadPool()
|
612
|
+
self.thread_pool.setMaxThreadCount(self.settings.value(self.settings.PLOT_THREAD_COUNT))
|
611
613
|
self.model().waveformReady.connect(self.load_audio_selection)
|
612
614
|
self.model().utterancesReady.connect(self.finalize_set_new_file)
|
613
615
|
self.viewChanged.connect(self.load_audio_selection)
|
614
616
|
self.model().selectionRequested.connect(self.update_selected_utterances)
|
615
617
|
self.view_change_timer = QtCore.QTimer()
|
616
|
-
self.view_change_timer.
|
618
|
+
self.view_change_timer.setSingleShot(True)
|
619
|
+
self.view_change_timer.setInterval(10)
|
617
620
|
self.view_change_timer.timeout.connect(self.send_selection_update)
|
618
621
|
|
619
622
|
def selected_utterances(self):
|
@@ -633,18 +636,17 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
633
636
|
y = self.model().y[begin_samp:end_samp, self.selected_channel]
|
634
637
|
else:
|
635
638
|
y = self.model().y[begin_samp:end_samp]
|
636
|
-
|
637
|
-
self.spectrogram_worker.set_params(
|
639
|
+
spectrogram_worker = workers.SpectrogramWorker(
|
638
640
|
y,
|
639
641
|
self.model().file.sound_file.sample_rate,
|
640
642
|
self.min_time,
|
641
643
|
self.max_time,
|
642
644
|
self.selected_channel,
|
643
645
|
)
|
644
|
-
|
646
|
+
spectrogram_worker.signals.result.connect(self.finalize_loading_spectrogram)
|
647
|
+
self.thread_pool.start(spectrogram_worker)
|
645
648
|
|
646
|
-
|
647
|
-
self.pitch_track_worker.set_params(
|
649
|
+
pitch_track_worker = workers.PitchWorker(
|
648
650
|
y,
|
649
651
|
self.model().file.sound_file.sample_rate,
|
650
652
|
self.min_time,
|
@@ -653,10 +655,10 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
653
655
|
self.bottom_point,
|
654
656
|
self.separator_point,
|
655
657
|
)
|
656
|
-
|
658
|
+
pitch_track_worker.signals.result.connect(self.finalize_loading_pitch_track)
|
659
|
+
self.thread_pool.start(pitch_track_worker)
|
657
660
|
|
658
|
-
|
659
|
-
self.auto_waveform_worker.set_params(
|
661
|
+
auto_waveform_worker = workers.AutoWaveformWorker(
|
660
662
|
y,
|
661
663
|
self.separator_point,
|
662
664
|
self.top_point,
|
@@ -664,12 +666,11 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
664
666
|
self.max_time,
|
665
667
|
self.selected_channel,
|
666
668
|
)
|
667
|
-
|
669
|
+
auto_waveform_worker.signals.result.connect(self.finalize_loading_auto_wave_form)
|
670
|
+
self.thread_pool.start(auto_waveform_worker)
|
668
671
|
|
669
672
|
def clean_up_for_close(self):
|
670
|
-
self.
|
671
|
-
self.pitch_track_worker.stop()
|
672
|
-
self.auto_waveform_worker.stop()
|
673
|
+
self.closing = True
|
673
674
|
|
674
675
|
@property
|
675
676
|
def plot_min(self):
|
@@ -684,6 +685,8 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
684
685
|
return self.max_time
|
685
686
|
|
686
687
|
def finalize_loading_spectrogram(self, results):
|
688
|
+
if self.closing:
|
689
|
+
return
|
687
690
|
if results is None:
|
688
691
|
self.spectrogram = None
|
689
692
|
self.min_db = None
|
@@ -691,28 +694,28 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
691
694
|
self.spectrogramReady.emit()
|
692
695
|
return
|
693
696
|
stft, channel, begin, end, min_db, max_db = results
|
697
|
+
if begin != self.min_time or end != self.max_time:
|
698
|
+
return
|
694
699
|
if self.settings.right_to_left:
|
695
700
|
stft = np.flip(stft, 1)
|
696
|
-
begin, end = -end, -begin
|
697
|
-
if begin != self.plot_min or end != self.plot_max:
|
698
|
-
return
|
699
701
|
self.spectrogram = stft
|
700
702
|
self.min_db = self.min_db
|
701
703
|
self.max_db = self.max_db
|
702
704
|
self.spectrogramReady.emit()
|
703
705
|
|
704
706
|
def finalize_loading_pitch_track(self, results):
|
707
|
+
if self.closing:
|
708
|
+
return
|
705
709
|
if results is None:
|
706
710
|
self.pitch_track_y = None
|
707
711
|
self.pitch_track_x = None
|
708
712
|
self.pitchTrackReady.emit()
|
709
713
|
return
|
710
714
|
pitch_track, voicing_track, channel, begin, end, min_f0, max_f0 = results
|
715
|
+
if begin != self.min_time or end != self.max_time:
|
716
|
+
return
|
711
717
|
if self.settings.right_to_left:
|
712
718
|
pitch_track = np.flip(pitch_track, 0)
|
713
|
-
begin, end = -end, -begin
|
714
|
-
if begin != self.plot_min or end != self.plot_max:
|
715
|
-
return
|
716
719
|
self.pitch_track_y = pitch_track
|
717
720
|
if pitch_track is None:
|
718
721
|
return
|
@@ -725,23 +728,24 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
725
728
|
self.pitchTrackReady.emit()
|
726
729
|
|
727
730
|
def finalize_loading_auto_wave_form(self, results):
|
731
|
+
if self.closing:
|
732
|
+
return
|
728
733
|
y, begin, end, channel = results
|
734
|
+
if begin != self.min_time or end != self.max_time:
|
735
|
+
return
|
729
736
|
if self.settings.right_to_left:
|
730
737
|
y = np.flip(y, 0)
|
731
|
-
begin, end = -end, -begin
|
732
|
-
if begin != self.plot_min or end != self.plot_max:
|
733
|
-
return
|
734
738
|
x = np.linspace(start=self.plot_min, stop=self.plot_max, num=y.shape[0])
|
735
739
|
self.waveform_x = x
|
736
740
|
self.waveform_y = y
|
737
741
|
self.waveformReady.emit()
|
738
742
|
|
739
743
|
def select_audio(self, begin, end):
|
740
|
-
if end is not None and end - begin < 0.
|
744
|
+
if end is not None and end - begin < 0.025:
|
741
745
|
end = None
|
742
746
|
self.selected_min_time = begin
|
743
747
|
self.selected_max_time = end
|
744
|
-
if self.selected_min_time != self.min_time:
|
748
|
+
if self.selected_min_time != self.min_time or end is not None:
|
745
749
|
self.selectionAudioChanged.emit(False)
|
746
750
|
|
747
751
|
def request_start_time(self, start_time, update=False):
|
@@ -881,7 +885,6 @@ class FileSelectionModel(QtCore.QItemSelectionModel):
|
|
881
885
|
self.view_change_timer.start()
|
882
886
|
|
883
887
|
def send_selection_update(self):
|
884
|
-
self.view_change_timer.stop()
|
885
888
|
self.viewChanged.emit(self.min_time, self.max_time)
|
886
889
|
|
887
890
|
def set_current_file(self, file_id, begin, end, utterance_id, speaker_id, force_update=False):
|
@@ -1916,14 +1919,30 @@ class DiarizationModel(TableModel):
|
|
1916
1919
|
self.runFunction.emit("Reassigning utterances for speaker", self.update_data, [kwargs])
|
1917
1920
|
|
1918
1921
|
def update_result_count(self):
|
1919
|
-
self.
|
1920
|
-
|
1921
|
-
|
1922
|
+
if self.in_speakers:
|
1923
|
+
self.runFunction.emit(
|
1924
|
+
"Counting speaker diarization results",
|
1925
|
+
self.finalize_result_count,
|
1926
|
+
[self.count_kwargs],
|
1927
|
+
)
|
1928
|
+
else:
|
1929
|
+
self.runFunction.emit(
|
1930
|
+
"Counting utterance diarization results",
|
1931
|
+
self.finalize_result_count,
|
1932
|
+
[self.count_kwargs],
|
1933
|
+
)
|
1922
1934
|
|
1923
1935
|
def update_data(self):
|
1924
1936
|
if not self.corpus_model.corpus.has_any_ivectors():
|
1925
1937
|
return
|
1926
|
-
|
1938
|
+
if self.in_speakers:
|
1939
|
+
self.runFunction.emit(
|
1940
|
+
"Diarizing speakers", self.finish_update_data, [self.query_kwargs]
|
1941
|
+
)
|
1942
|
+
else:
|
1943
|
+
self.runFunction.emit(
|
1944
|
+
"Diarizing utterances", self.finish_update_data, [self.query_kwargs]
|
1945
|
+
)
|
1927
1946
|
|
1928
1947
|
|
1929
1948
|
class CorpusModel(TableModel):
|
@@ -2040,6 +2059,31 @@ class CorpusModel(TableModel):
|
|
2040
2059
|
self.has_reference_alignments = False
|
2041
2060
|
self.has_transcribed_alignments = False
|
2042
2061
|
self.has_per_speaker_transcribed_alignments = False
|
2062
|
+
self.has_transcript_verification_alignments = False
|
2063
|
+
self.latest_alignment_workflow = None
|
2064
|
+
|
2065
|
+
def update_latest_alignment_workflow(self):
|
2066
|
+
with self.corpus.session() as session:
|
2067
|
+
query = (
|
2068
|
+
session.query(CorpusWorkflow.id)
|
2069
|
+
.filter(CorpusWorkflow.workflow_type.in_(WorkflowType.alignment_workflows()))
|
2070
|
+
.order_by(sqlalchemy.desc(CorpusWorkflow.time_stamp))
|
2071
|
+
.limit(1)
|
2072
|
+
).first()
|
2073
|
+
if query is not None:
|
2074
|
+
query = query[0]
|
2075
|
+
self.latest_alignment_workflow = query
|
2076
|
+
|
2077
|
+
def get_interjection_count(self):
|
2078
|
+
if self.corpus is None:
|
2079
|
+
return 0
|
2080
|
+
with self.corpus.session() as session:
|
2081
|
+
count = (
|
2082
|
+
session.query(sqlalchemy.func.count(Word.id))
|
2083
|
+
.filter(Word.word_type == WordType.interjection)
|
2084
|
+
.first()[0]
|
2085
|
+
)
|
2086
|
+
return count
|
2043
2087
|
|
2044
2088
|
def get_speaker_name(self, speaker_id: int):
|
2045
2089
|
if speaker_id not in self.speaker_id_mapping:
|
@@ -2326,6 +2370,7 @@ class CorpusModel(TableModel):
|
|
2326
2370
|
self.refresh_files()
|
2327
2371
|
self.refresh_speakers()
|
2328
2372
|
self.refresh_utterances()
|
2373
|
+
self.update_latest_alignment_workflow()
|
2329
2374
|
|
2330
2375
|
def search(
|
2331
2376
|
self,
|