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/undo.py
CHANGED
@@ -6,7 +6,7 @@ import typing
|
|
6
6
|
import pynini.lib
|
7
7
|
import sqlalchemy
|
8
8
|
from montreal_forced_aligner.data import WordType
|
9
|
-
from montreal_forced_aligner.db import File, Pronunciation, Speaker, Utterance, Word
|
9
|
+
from montreal_forced_aligner.db import File, Pronunciation, Speaker, Utterance, Word
|
10
10
|
from PySide6 import QtCore, QtGui
|
11
11
|
from sqlalchemy.orm import make_transient
|
12
12
|
|
@@ -15,6 +15,7 @@ if typing.TYPE_CHECKING:
|
|
15
15
|
CorpusModel,
|
16
16
|
DiarizationModel,
|
17
17
|
DictionaryTableModel,
|
18
|
+
FileUtterancesModel,
|
18
19
|
SpeakerModel,
|
19
20
|
TextFilterQuery,
|
20
21
|
)
|
@@ -38,9 +39,8 @@ class CorpusCommand(QtGui.QUndoCommand):
|
|
38
39
|
|
39
40
|
def redo(self) -> None:
|
40
41
|
with self.corpus_model.edit_lock:
|
41
|
-
|
42
|
-
|
43
|
-
session.commit()
|
42
|
+
self._redo(self.corpus_model.session)
|
43
|
+
self.corpus_model.session.commit()
|
44
44
|
# while True:
|
45
45
|
# try:
|
46
46
|
# with self.corpus_model.session.begin_nested():
|
@@ -53,9 +53,8 @@ class CorpusCommand(QtGui.QUndoCommand):
|
|
53
53
|
|
54
54
|
def undo(self) -> None:
|
55
55
|
with self.corpus_model.edit_lock:
|
56
|
-
|
57
|
-
|
58
|
-
session.commit()
|
56
|
+
self._undo(self.corpus_model.session)
|
57
|
+
self.corpus_model.session.commit()
|
59
58
|
# while True:
|
60
59
|
# try:
|
61
60
|
# with self.corpus_model.session.begin_nested():
|
@@ -66,6 +65,12 @@ class CorpusCommand(QtGui.QUndoCommand):
|
|
66
65
|
self.update_data()
|
67
66
|
|
68
67
|
|
68
|
+
class FileCommand(CorpusCommand):
|
69
|
+
def __init__(self, file_model: FileUtterancesModel):
|
70
|
+
super().__init__(file_model.corpus_model)
|
71
|
+
self.file_model = file_model
|
72
|
+
|
73
|
+
|
69
74
|
class DictionaryCommand(QtGui.QUndoCommand):
|
70
75
|
def __init__(self, dictionary_model: DictionaryTableModel):
|
71
76
|
super().__init__()
|
@@ -127,9 +132,9 @@ class SpeakerCommand(QtGui.QUndoCommand):
|
|
127
132
|
self.update_data()
|
128
133
|
|
129
134
|
|
130
|
-
class DeleteUtteranceCommand(
|
131
|
-
def __init__(self, deleted_utterances: list[Utterance],
|
132
|
-
super().__init__(
|
135
|
+
class DeleteUtteranceCommand(FileCommand):
|
136
|
+
def __init__(self, deleted_utterances: list[Utterance], file_model: FileUtterancesModel):
|
137
|
+
super().__init__(file_model)
|
133
138
|
self.deleted_utterances = deleted_utterances
|
134
139
|
self.resets_tier = True
|
135
140
|
self.channels = [
|
@@ -147,7 +152,6 @@ class DeleteUtteranceCommand(CorpusCommand):
|
|
147
152
|
for i, utt in enumerate(self.deleted_utterances):
|
148
153
|
make_transient(utt)
|
149
154
|
for x in utt.phone_intervals:
|
150
|
-
x.duration = None
|
151
155
|
make_transient(x)
|
152
156
|
for x in utt.word_intervals:
|
153
157
|
make_transient(x)
|
@@ -158,95 +162,80 @@ class DeleteUtteranceCommand(CorpusCommand):
|
|
158
162
|
def redo(self) -> None:
|
159
163
|
super().redo()
|
160
164
|
self.corpus_model.delete_table_utterances(self.deleted_utterances)
|
165
|
+
self.file_model.delete_table_utterances(self.deleted_utterances)
|
161
166
|
self.corpus_model.changeCommandFired.emit()
|
162
167
|
|
163
168
|
def undo(self) -> None:
|
164
169
|
super().undo()
|
165
170
|
self.corpus_model.add_table_utterances(self.deleted_utterances)
|
171
|
+
self.file_model.add_table_utterances(self.deleted_utterances)
|
166
172
|
self.corpus_model.changeCommandFired.emit()
|
167
173
|
|
168
174
|
|
169
|
-
class SplitUtteranceCommand(
|
175
|
+
class SplitUtteranceCommand(FileCommand):
|
170
176
|
def __init__(
|
171
177
|
self,
|
172
|
-
|
173
|
-
|
178
|
+
merged_utterance: Utterance,
|
179
|
+
split_utterances: list[Utterance],
|
180
|
+
file_model: FileUtterancesModel,
|
174
181
|
update_table: bool = True,
|
175
182
|
):
|
176
|
-
super().__init__(
|
183
|
+
super().__init__(file_model)
|
184
|
+
self.merged_utterance = merged_utterance
|
177
185
|
self.split_utterances = split_utterances
|
178
186
|
self.resets_tier = True
|
179
187
|
self.update_table = update_table
|
180
|
-
self.channels = [
|
181
|
-
x[0].channel if x[0].channel is not None else 0 for x in self.split_utterances
|
182
|
-
]
|
188
|
+
self.channels = [x.channel if x.channel is not None else 0 for x in self.split_utterances]
|
183
189
|
self.setText(
|
184
190
|
QtCore.QCoreApplication.translate("SplitUtteranceCommand", "Split utterances")
|
185
191
|
)
|
186
192
|
|
187
193
|
def _redo(self, session) -> None:
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
for
|
193
|
-
if u.id is not None:
|
194
|
-
make_transient(u)
|
195
|
-
for x in u.phone_intervals:
|
196
|
-
x.duration = None
|
197
|
-
make_transient(x)
|
198
|
-
for x in u.word_intervals:
|
199
|
-
make_transient(x)
|
200
|
-
if u.channel is None:
|
201
|
-
u.channel = self.channels[i]
|
202
|
-
u.duration = None
|
203
|
-
u.kaldi_id = None
|
204
|
-
session.add(u)
|
205
|
-
|
206
|
-
def _undo(self, session) -> None:
|
207
|
-
for i, splits in enumerate(self.split_utterances):
|
208
|
-
old_utt = splits[0]
|
209
|
-
split_utts = splits[1:]
|
210
|
-
if old_utt.channel is None:
|
211
|
-
old_utt.channel = self.channels[i]
|
212
|
-
old_utt.duration = None
|
213
|
-
old_utt.kaldi_id = None
|
214
|
-
make_transient(old_utt)
|
215
|
-
for x in old_utt.phone_intervals:
|
216
|
-
x.duration = None
|
194
|
+
session.delete(self.merged_utterance)
|
195
|
+
for u in self.split_utterances:
|
196
|
+
if u.id is not None:
|
197
|
+
make_transient(u)
|
198
|
+
for x in u.phone_intervals:
|
217
199
|
make_transient(x)
|
218
|
-
for x in
|
200
|
+
for x in u.word_intervals:
|
219
201
|
make_transient(x)
|
220
|
-
|
221
|
-
|
222
|
-
|
202
|
+
if u.channel is None:
|
203
|
+
u.channel = self.merged_utterance.channel
|
204
|
+
session.add(u)
|
205
|
+
|
206
|
+
def _undo(self, session) -> None:
|
207
|
+
if self.merged_utterance.channel is None:
|
208
|
+
self.merged_utterance.channel = self.split_utterances[0].channel
|
209
|
+
make_transient(self.merged_utterance)
|
210
|
+
for x in self.merged_utterance.phone_intervals:
|
211
|
+
make_transient(x)
|
212
|
+
for x in self.merged_utterance.word_intervals:
|
213
|
+
make_transient(x)
|
214
|
+
session.add(self.merged_utterance)
|
215
|
+
for u in self.split_utterances:
|
216
|
+
session.delete(u)
|
223
217
|
|
224
218
|
def redo(self) -> None:
|
225
219
|
super().redo()
|
226
|
-
|
227
|
-
|
228
|
-
split_utts = splits[1:]
|
229
|
-
if self.update_table:
|
230
|
-
self.corpus_model.split_table_utterances(old_utt, split_utts)
|
220
|
+
self.corpus_model.split_table_utterances(self.merged_utterance, self.split_utterances)
|
221
|
+
self.file_model.split_table_utterances(self.merged_utterance, self.split_utterances)
|
231
222
|
self.corpus_model.changeCommandFired.emit()
|
232
223
|
|
233
224
|
def undo(self) -> None:
|
234
225
|
super().undo()
|
235
|
-
|
236
|
-
|
237
|
-
split_utts = splits[1:]
|
238
|
-
self.corpus_model.merge_table_utterances(old_utt, split_utts)
|
226
|
+
self.corpus_model.merge_table_utterances(self.merged_utterance, self.split_utterances)
|
227
|
+
self.file_model.merge_table_utterances(self.merged_utterance, self.split_utterances)
|
239
228
|
self.corpus_model.changeCommandFired.emit()
|
240
229
|
|
241
230
|
|
242
|
-
class MergeUtteranceCommand(
|
231
|
+
class MergeUtteranceCommand(FileCommand):
|
243
232
|
def __init__(
|
244
233
|
self,
|
245
234
|
unmerged_utterances: list[Utterance],
|
246
235
|
merged_utterance: Utterance,
|
247
|
-
|
236
|
+
file_model: FileUtterancesModel,
|
248
237
|
):
|
249
|
-
super().__init__(
|
238
|
+
super().__init__(file_model)
|
250
239
|
self.unmerged_utterances = unmerged_utterances
|
251
240
|
self.merged_utterance = merged_utterance
|
252
241
|
self.resets_tier = True
|
@@ -263,8 +252,6 @@ class MergeUtteranceCommand(CorpusCommand):
|
|
263
252
|
make_transient(self.merged_utterance)
|
264
253
|
if self.merged_utterance.channel is None:
|
265
254
|
self.merged_utterance.channel = self.channel
|
266
|
-
self.merged_utterance.kaldi_id = None
|
267
|
-
self.merged_utterance.duration = None
|
268
255
|
session.add(self.merged_utterance)
|
269
256
|
|
270
257
|
def _undo(self, session) -> None:
|
@@ -273,24 +260,22 @@ class MergeUtteranceCommand(CorpusCommand):
|
|
273
260
|
if old_utt.channel is None:
|
274
261
|
old_utt.channel = self.channel
|
275
262
|
for x in old_utt.phone_intervals:
|
276
|
-
x.duration = None
|
277
263
|
make_transient(x)
|
278
264
|
for x in old_utt.word_intervals:
|
279
265
|
make_transient(x)
|
280
|
-
old_utt.duration = None
|
281
|
-
old_utt.kaldi_id = None
|
282
266
|
session.add(old_utt)
|
283
|
-
# session.refresh(self.merged_utterance)
|
284
267
|
session.delete(self.merged_utterance)
|
285
268
|
|
286
269
|
def redo(self) -> None:
|
287
270
|
super().redo()
|
288
271
|
self.corpus_model.merge_table_utterances(self.merged_utterance, self.unmerged_utterances)
|
272
|
+
self.file_model.merge_table_utterances(self.merged_utterance, self.unmerged_utterances)
|
289
273
|
self.corpus_model.changeCommandFired.emit()
|
290
274
|
|
291
275
|
def undo(self) -> None:
|
292
276
|
super().undo()
|
293
277
|
self.corpus_model.split_table_utterances(self.merged_utterance, self.unmerged_utterances)
|
278
|
+
self.file_model.split_table_utterances(self.merged_utterance, self.unmerged_utterances)
|
294
279
|
self.corpus_model.changeCommandFired.emit()
|
295
280
|
|
296
281
|
|
@@ -350,11 +335,10 @@ class MergeSpeakersCommand(CorpusCommand):
|
|
350
335
|
).update({Speaker.modified: True})
|
351
336
|
|
352
337
|
|
353
|
-
class CreateUtteranceCommand(
|
354
|
-
def __init__(self, new_utterance: Utterance,
|
355
|
-
super().__init__(
|
338
|
+
class CreateUtteranceCommand(FileCommand):
|
339
|
+
def __init__(self, new_utterance: Utterance, file_model: FileUtterancesModel):
|
340
|
+
super().__init__(file_model)
|
356
341
|
self.new_utterance = new_utterance
|
357
|
-
self.resets_tier = True
|
358
342
|
self.channel = self.new_utterance.channel
|
359
343
|
if self.channel is None:
|
360
344
|
self.channel = 0
|
@@ -377,18 +361,22 @@ class CreateUtteranceCommand(CorpusCommand):
|
|
377
361
|
def redo(self) -> None:
|
378
362
|
super().redo()
|
379
363
|
self.corpus_model.add_table_utterances([self.new_utterance])
|
364
|
+
self.file_model.add_table_utterances([self.new_utterance])
|
380
365
|
self.corpus_model.changeCommandFired.emit()
|
381
366
|
|
382
367
|
def undo(self) -> None:
|
383
368
|
super().undo()
|
384
369
|
self.corpus_model.delete_table_utterances([self.new_utterance])
|
370
|
+
self.file_model.delete_table_utterances([self.new_utterance])
|
385
371
|
self.corpus_model.changeCommandFired.emit()
|
386
372
|
|
387
373
|
|
388
|
-
class UpdateUtteranceTimesCommand(
|
389
|
-
def __init__(
|
390
|
-
|
391
|
-
|
374
|
+
class UpdateUtteranceTimesCommand(FileCommand):
|
375
|
+
def __init__(
|
376
|
+
self, utterance: Utterance, begin: float, end: float, file_model: FileUtterancesModel
|
377
|
+
):
|
378
|
+
super().__init__(file_model)
|
379
|
+
self.utterance = utterance
|
392
380
|
self.new_begin = begin
|
393
381
|
self.old_begin = utterance.begin
|
394
382
|
self.new_end = end
|
@@ -400,37 +388,31 @@ class UpdateUtteranceTimesCommand(CorpusCommand):
|
|
400
388
|
)
|
401
389
|
|
402
390
|
def _redo(self, session) -> None:
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
Utterance.features: None,
|
410
|
-
}
|
411
|
-
)
|
391
|
+
self.utterance.begin = self.new_begin
|
392
|
+
self.utterance.end = self.new_end
|
393
|
+
self.utterance.xvector = None
|
394
|
+
self.utterance.ivector = None
|
395
|
+
self.utterance.features = None
|
396
|
+
session.merge(self.utterance)
|
412
397
|
|
413
398
|
def _undo(self, session) -> None:
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
Utterance.features: None,
|
421
|
-
}
|
422
|
-
)
|
399
|
+
self.utterance.begin = self.old_begin
|
400
|
+
self.utterance.end = self.old_end
|
401
|
+
self.utterance.xvector = None
|
402
|
+
self.utterance.ivector = None
|
403
|
+
self.utterance.features = None
|
404
|
+
session.merge(self.utterance)
|
423
405
|
|
424
406
|
def update_data(self):
|
425
407
|
super().update_data()
|
426
408
|
self.corpus_model.changeCommandFired.emit()
|
427
|
-
self.corpus_model.update_utterance_table_row(self.
|
409
|
+
self.corpus_model.update_utterance_table_row(self.utterance)
|
428
410
|
|
429
411
|
|
430
|
-
class UpdateUtteranceTextCommand(
|
431
|
-
def __init__(self, utterance: Utterance, new_text: str,
|
432
|
-
super().__init__(
|
433
|
-
self.
|
412
|
+
class UpdateUtteranceTextCommand(FileCommand):
|
413
|
+
def __init__(self, utterance: Utterance, new_text: str, file_model: FileUtterancesModel):
|
414
|
+
super().__init__(file_model)
|
415
|
+
self.utterance = utterance
|
434
416
|
self.speaker_id = utterance.speaker_id
|
435
417
|
self.old_text = utterance.text
|
436
418
|
self.new_text = new_text
|
@@ -445,40 +427,28 @@ class UpdateUtteranceTextCommand(CorpusCommand):
|
|
445
427
|
for w in self.new_text.split():
|
446
428
|
if not self.corpus_model.dictionary_model.check_word(w, self.speaker_id):
|
447
429
|
oovs.add(w)
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
Utterance.ignored: not self.new_text,
|
454
|
-
}
|
455
|
-
)
|
430
|
+
self.utterance.text = self.new_text
|
431
|
+
self.utterance.normalized_text = self.new_text # FIXME: Update this
|
432
|
+
self.utterance.oovs = " ".join(oovs)
|
433
|
+
self.utterance.ignored = not self.new_text
|
434
|
+
session.merge(self.utterance)
|
456
435
|
|
457
436
|
def _undo(self, session) -> None:
|
458
437
|
oovs = set()
|
459
438
|
for w in self.new_text.split():
|
460
439
|
if not self.corpus_model.dictionary_model.check_word(w, self.speaker_id):
|
461
440
|
oovs.add(w)
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
}
|
468
|
-
)
|
469
|
-
|
470
|
-
def update_data(self):
|
471
|
-
super().update_data()
|
472
|
-
try:
|
473
|
-
self.corpus_model.update_utterance_table_row(self.utterance_id)
|
474
|
-
except KeyError:
|
475
|
-
pass
|
441
|
+
self.utterance.text = self.old_text
|
442
|
+
self.utterance.normalized_text = self.old_text # FIXME: Update this
|
443
|
+
self.utterance.oovs = " ".join(oovs)
|
444
|
+
self.utterance.ignored = not self.old_text
|
445
|
+
session.merge(self.utterance)
|
476
446
|
|
477
447
|
def id(self) -> int:
|
478
448
|
return 1
|
479
449
|
|
480
450
|
def mergeWith(self, other: UpdateUtteranceTextCommand) -> bool:
|
481
|
-
if other.id() != self.id() or other.
|
451
|
+
if other.id() != self.id() or other.utterance.id != self.utterance.id:
|
482
452
|
return False
|
483
453
|
self.new_text = other.new_text
|
484
454
|
return True
|
@@ -627,16 +597,17 @@ class UpdateSpeakerCommand(SpeakerCommand):
|
|
627
597
|
)
|
628
598
|
|
629
599
|
|
630
|
-
class UpdateUtteranceSpeakerCommand(
|
600
|
+
class UpdateUtteranceSpeakerCommand(FileCommand):
|
631
601
|
def __init__(
|
632
602
|
self,
|
633
603
|
utterances: typing.Union[Utterance, typing.List[Utterance]],
|
634
604
|
new_speaker: typing.Union[Speaker, int],
|
635
|
-
|
605
|
+
file_model: FileUtterancesModel,
|
636
606
|
):
|
637
|
-
super().__init__(
|
607
|
+
super().__init__(file_model)
|
638
608
|
if not isinstance(utterances, list):
|
639
609
|
utterances = [utterances]
|
610
|
+
self.utterances = utterances
|
640
611
|
self.utterance_ids = [x.id for x in utterances]
|
641
612
|
self.file_ids = set([x.file_id for x in utterances])
|
642
613
|
self.old_speaker_ids = [x.speaker_id for x in utterances]
|
@@ -644,7 +615,6 @@ class UpdateUtteranceSpeakerCommand(CorpusCommand):
|
|
644
615
|
self.new_speaker_id = new_speaker
|
645
616
|
else:
|
646
617
|
self.new_speaker_id = new_speaker.id
|
647
|
-
self.resets_tier = True
|
648
618
|
self.setText(
|
649
619
|
QtCore.QCoreApplication.translate(
|
650
620
|
"UpdateUtteranceSpeakerCommand", "Update utterance speaker"
|
@@ -673,18 +643,15 @@ class UpdateUtteranceSpeakerCommand(CorpusCommand):
|
|
673
643
|
)
|
674
644
|
)
|
675
645
|
session.flush()
|
676
|
-
|
677
|
-
|
678
|
-
)
|
646
|
+
for u in self.utterances:
|
647
|
+
u.speaker_id = self.new_speaker_id
|
679
648
|
session.query(Speaker).filter(
|
680
649
|
Speaker.id.in_(self.old_speaker_ids + [self.new_speaker_id])
|
681
650
|
).update({Speaker.modified: True})
|
682
651
|
|
683
652
|
def _undo(self, session) -> None:
|
684
|
-
|
685
|
-
|
686
|
-
update_mappings.append({"id": u_id, "speaker_id": self.old_speaker_ids[i]})
|
687
|
-
bulk_update(self.corpus_model.session, Utterance, update_mappings)
|
653
|
+
for i, u in enumerate(self.utterances):
|
654
|
+
u.speaker_id = self.old_speaker_ids[i]
|
688
655
|
session.query(Speaker).filter(
|
689
656
|
Speaker.id.in_(self.old_speaker_ids + [self.new_speaker_id])
|
690
657
|
).update({Speaker.modified: True})
|
@@ -692,6 +659,8 @@ class UpdateUtteranceSpeakerCommand(CorpusCommand):
|
|
692
659
|
def update_data(self):
|
693
660
|
super().update_data()
|
694
661
|
self.corpus_model.set_file_modified(self.file_ids)
|
662
|
+
self.corpus_model.change_speaker_table_utterances(self.utterances)
|
663
|
+
self.file_model.change_speaker_table_utterances(self.utterances)
|
695
664
|
self.corpus_model.changeCommandFired.emit()
|
696
665
|
self.corpus_model.update_data()
|
697
666
|
self.corpus_model.runFunction.emit(
|
anchor/widgets.py
CHANGED
@@ -25,6 +25,8 @@ from anchor.models import (
|
|
25
25
|
CorpusSelectionModel,
|
26
26
|
DiarizationModel,
|
27
27
|
DictionaryTableModel,
|
28
|
+
FileSelectionModel,
|
29
|
+
FileUtterancesModel,
|
28
30
|
OovModel,
|
29
31
|
SpeakerModel,
|
30
32
|
TextFilterQuery,
|
@@ -61,7 +63,6 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
61
63
|
self.max_time = None
|
62
64
|
self.start_load_time = None
|
63
65
|
self.min_time = None
|
64
|
-
self.corpus_model = None
|
65
66
|
self.selection_model = None
|
66
67
|
self.timer = QtCore.QTimer(self)
|
67
68
|
self.timer.setInterval(1)
|
@@ -78,7 +79,6 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
78
79
|
self._audio_output.setDevice(self.devices.defaultAudioOutput())
|
79
80
|
self.setAudioOutput(self._audio_output)
|
80
81
|
self.playbackStateChanged.connect(self.reset_position)
|
81
|
-
self.mediaStatusChanged.connect(self.update_load)
|
82
82
|
self.fade_in_anim = QtCore.QPropertyAnimation(self._audio_output, b"volume")
|
83
83
|
self.fade_in_anim.setDuration(10)
|
84
84
|
self.fade_in_anim.setStartValue(0.1)
|
@@ -95,11 +95,6 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
95
95
|
self.fade_out_anim.finished.connect(super().pause)
|
96
96
|
self.file_path = None
|
97
97
|
|
98
|
-
def update_load(self, state):
|
99
|
-
if state == self.MediaStatus.LoadedMedia:
|
100
|
-
self.reset_position()
|
101
|
-
self.audioReady.emit(True)
|
102
|
-
|
103
98
|
def handle_error(self, *args):
|
104
99
|
print("ERROR")
|
105
100
|
print(args)
|
@@ -118,12 +113,22 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
118
113
|
self.fade_in_anim.start()
|
119
114
|
|
120
115
|
def startTime(self):
|
121
|
-
if
|
116
|
+
if (
|
117
|
+
self.selection_model.selected_min_time is not None
|
118
|
+
and self.selection_model.min_time
|
119
|
+
<= self.selection_model.selected_min_time
|
120
|
+
<= self.selection_model.max_time
|
121
|
+
):
|
122
122
|
return self.selection_model.selected_min_time
|
123
123
|
return self.selection_model.min_time
|
124
124
|
|
125
125
|
def maxTime(self):
|
126
|
-
if
|
126
|
+
if (
|
127
|
+
self.selection_model.selected_max_time is not None
|
128
|
+
and self.selection_model.min_time
|
129
|
+
<= self.selection_model.selected_max_time
|
130
|
+
<= self.selection_model.max_time
|
131
|
+
):
|
127
132
|
return self.selection_model.selected_max_time
|
128
133
|
return self.selection_model.max_time
|
129
134
|
|
@@ -149,14 +154,10 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
149
154
|
break
|
150
155
|
self._audio_output.setDevice(o)
|
151
156
|
|
152
|
-
def
|
153
|
-
|
154
|
-
):
|
155
|
-
self.corpus_model = corpus_model
|
156
|
-
self.selection_model = selection_model
|
157
|
-
if corpus_model is None:
|
157
|
+
def set_models(self, selection_model: Optional[FileSelectionModel]):
|
158
|
+
if selection_model is None:
|
158
159
|
return
|
159
|
-
|
160
|
+
self.selection_model = selection_model
|
160
161
|
self.selection_model.fileChanged.connect(self.loadNewFile)
|
161
162
|
self.selection_model.viewChanged.connect(self.update_times)
|
162
163
|
self.selection_model.selectionAudioChanged.connect(self.update_selection_times)
|
@@ -187,29 +188,27 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
187
188
|
self.setCurrentTime(self.startTime())
|
188
189
|
|
189
190
|
def update_times(self):
|
190
|
-
if (
|
191
|
-
self.
|
192
|
-
|
193
|
-
or self.currentTime() > self.maxTime()
|
194
|
-
):
|
191
|
+
if self.currentTime() < self.startTime() or self.currentTime() > self.maxTime():
|
192
|
+
self.stop()
|
193
|
+
if self.playbackState() != QtMultimedia.QMediaPlayer.PlaybackState.PlayingState:
|
195
194
|
self.setCurrentTime(self.startTime())
|
196
195
|
|
197
196
|
def loadNewFile(self, *args):
|
198
197
|
self.audioReady.emit(False)
|
199
198
|
self.stop()
|
200
199
|
try:
|
201
|
-
new_file = self.selection_model.
|
200
|
+
new_file = self.selection_model.model().file.sound_file.sound_file_path
|
202
201
|
except Exception:
|
203
202
|
self.setSource(QtCore.QUrl())
|
204
203
|
return
|
205
204
|
if (
|
206
205
|
self.selection_model.max_time is None
|
207
|
-
or self.selection_model.
|
208
|
-
or self.selection_model.
|
206
|
+
or self.selection_model.model().file is None
|
207
|
+
or self.selection_model.model().file.duration is None
|
209
208
|
):
|
210
209
|
self.setSource(QtCore.QUrl())
|
211
210
|
return
|
212
|
-
self.channels = self.selection_model.
|
211
|
+
self.channels = self.selection_model.model().file.num_channels
|
213
212
|
self.setSource(f"file:///{new_file}")
|
214
213
|
self.setPosition(0)
|
215
214
|
self.audioReady.emit(True)
|
@@ -218,19 +217,6 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
218
217
|
pos = self.position()
|
219
218
|
return pos / 1000
|
220
219
|
|
221
|
-
def setMaxTime(self, max_time):
|
222
|
-
if max_time is None:
|
223
|
-
return
|
224
|
-
self.max_time = max_time * 1000
|
225
|
-
|
226
|
-
def setMinTime(
|
227
|
-
self, min_time
|
228
|
-
): # Positions for MediaPlayer are in milliseconds, no SR required
|
229
|
-
if min_time is None:
|
230
|
-
min_time = 0
|
231
|
-
self.min_time = int(min_time * 1000)
|
232
|
-
self.setCurrentTime(min_time)
|
233
|
-
|
234
220
|
def setCurrentTime(self, time):
|
235
221
|
if time is None:
|
236
222
|
time = 0
|
@@ -245,7 +231,7 @@ class MediaPlayer(QtMultimedia.QMediaPlayer): # pragma: no cover
|
|
245
231
|
self.stop()
|
246
232
|
self.setSource(
|
247
233
|
QtCore.QUrl.fromLocalFile(
|
248
|
-
self.selection_model.
|
234
|
+
self.selection_model.model().file.sound_file.sound_file_path
|
249
235
|
)
|
250
236
|
)
|
251
237
|
self.play()
|
@@ -416,7 +402,7 @@ class UtteranceListTable(AnchorTableView):
|
|
416
402
|
def set_models(self, model: CorpusModel, selection_model: CorpusSelectionModel):
|
417
403
|
self.setModel(model)
|
418
404
|
self.setSelectionModel(selection_model)
|
419
|
-
self.doubleClicked.connect(self.selectionModel().
|
405
|
+
self.doubleClicked.connect(self.selectionModel().focus_utterance)
|
420
406
|
self.model().utteranceTextUpdated.connect(self.repaint)
|
421
407
|
self.refresh_settings()
|
422
408
|
model.corpusLoaded.connect(self.update_header)
|
@@ -793,6 +779,7 @@ class UtteranceDetailWidget(QtWidgets.QWidget): # pragma: no cover
|
|
793
779
|
self.settings = AnchorSettings()
|
794
780
|
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True)
|
795
781
|
self.corpus_model = None
|
782
|
+
self.file_model = None
|
796
783
|
self.selection_model = None
|
797
784
|
self.dictionary_model = None
|
798
785
|
self.plot_widget = UtteranceView(self)
|
@@ -829,24 +816,28 @@ class UtteranceDetailWidget(QtWidgets.QWidget): # pragma: no cover
|
|
829
816
|
def set_models(
|
830
817
|
self,
|
831
818
|
corpus_model: CorpusModel,
|
832
|
-
|
819
|
+
file_model: FileUtterancesModel,
|
820
|
+
selection_model: FileSelectionModel,
|
833
821
|
dictionary_model: DictionaryTableModel,
|
834
822
|
):
|
835
823
|
self.corpus_model = corpus_model
|
824
|
+
self.file_model = file_model
|
836
825
|
self.selection_model = selection_model
|
837
826
|
self.dictionary_model = dictionary_model
|
838
827
|
self.corpus_model.textFilterChanged.connect(self.plot_widget.set_search_term)
|
839
828
|
self.selection_model.viewChanged.connect(self.update_to_slider)
|
840
829
|
self.selection_model.fileChanged.connect(self.update_to_slider)
|
841
|
-
self.plot_widget.set_models(
|
830
|
+
self.plot_widget.set_models(
|
831
|
+
corpus_model, file_model, selection_model, self.dictionary_model
|
832
|
+
)
|
842
833
|
|
843
834
|
def update_to_slider(self):
|
844
835
|
with QtCore.QSignalBlocker(self.scroll_bar):
|
845
|
-
if self.selection_model.
|
836
|
+
if self.selection_model.model().file is None or self.selection_model.min_time is None:
|
846
837
|
return
|
847
838
|
if (
|
848
839
|
self.selection_model.min_time == 0
|
849
|
-
and self.selection_model.max_time == self.selection_model.
|
840
|
+
and self.selection_model.max_time == self.selection_model.model().file.duration
|
850
841
|
):
|
851
842
|
self.scroll_bar.setPageStep(10)
|
852
843
|
self.scroll_bar.setEnabled(False)
|
@@ -854,7 +845,7 @@ class UtteranceDetailWidget(QtWidgets.QWidget): # pragma: no cover
|
|
854
845
|
self.pan_right_button.setEnabled(False)
|
855
846
|
self.scroll_bar.setMaximum(0)
|
856
847
|
return
|
857
|
-
duration_ms = int(self.selection_model.
|
848
|
+
duration_ms = int(self.selection_model.model().file.duration * 1000)
|
858
849
|
begin = self.selection_model.min_time * 1000
|
859
850
|
end = self.selection_model.max_time * 1000
|
860
851
|
window_size_ms = int(end - begin)
|