tictacsync 0.3a3__py3-none-any.whl → 0.4a0__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.
Potentially problematic release.
This version of tictacsync might be problematic. Click here for more details.
- tictacsync/device_scanner.py +27 -35
- tictacsync/entry.py +8 -8
- tictacsync/timeline.py +350 -161
- tictacsync/yaltc.py +179 -171
- {tictacsync-0.3a3.dist-info → tictacsync-0.4a0.dist-info}/METADATA +1 -1
- tictacsync-0.4a0.dist-info/RECORD +15 -0
- tictacsync-0.3a3.dist-info/RECORD +0 -15
- {tictacsync-0.3a3.dist-info → tictacsync-0.4a0.dist-info}/LICENSE +0 -0
- {tictacsync-0.3a3.dist-info → tictacsync-0.4a0.dist-info}/WHEEL +0 -0
- {tictacsync-0.3a3.dist-info → tictacsync-0.4a0.dist-info}/entry_points.txt +0 -0
- {tictacsync-0.3a3.dist-info → tictacsync-0.4a0.dist-info}/top_level.txt +0 -0
tictacsync/yaltc.py
CHANGED
|
@@ -71,11 +71,11 @@ BPF_LOW_FRQ, BPF_HIGH_FRQ = (0.5*F1, 2*F2)
|
|
|
71
71
|
# utility for accessing pathnames
|
|
72
72
|
def _pathname(tempfile_or_path):
|
|
73
73
|
if isinstance(tempfile_or_path, type('')):
|
|
74
|
-
return tempfile_or_path
|
|
74
|
+
return tempfile_or_path ################################################
|
|
75
75
|
if isinstance(tempfile_or_path, Path):
|
|
76
|
-
return str(tempfile_or_path)
|
|
76
|
+
return str(tempfile_or_path) ###########################################
|
|
77
77
|
if isinstance(tempfile_or_path, tempfile._TemporaryFileWrapper):
|
|
78
|
-
return tempfile_or_path.name
|
|
78
|
+
return tempfile_or_path.name ###########################################
|
|
79
79
|
else:
|
|
80
80
|
raise Exception('%s should be Path or tempfile... is %s'%(
|
|
81
81
|
tempfile_or_path,
|
|
@@ -90,7 +90,7 @@ def to_precision(x,p):
|
|
|
90
90
|
"""
|
|
91
91
|
x = float(x)
|
|
92
92
|
if x == 0.:
|
|
93
|
-
return "0." + "0"*(p-1)
|
|
93
|
+
return "0." + "0"*(p-1) ################################################
|
|
94
94
|
out = []
|
|
95
95
|
if x < 0:
|
|
96
96
|
out.append("-")
|
|
@@ -243,7 +243,7 @@ class Decoder:
|
|
|
243
243
|
# return self.detected_pulse_position
|
|
244
244
|
if self.estimated_pulse_position:
|
|
245
245
|
logger.debug('returning cached estimated value')
|
|
246
|
-
return self.estimated_pulse_position
|
|
246
|
+
return self.estimated_pulse_position ###############################
|
|
247
247
|
_, silence_center_x = self._fit_triangular_signal_to_convoluted_env()
|
|
248
248
|
# symbol_width_samples = 1e-3*SYMBOL_LENGTH
|
|
249
249
|
self.estimated_pulse_position = silence_center_x + int(0.5*(
|
|
@@ -394,8 +394,9 @@ class Decoder:
|
|
|
394
394
|
v1 = self.cached_convolution_fit['chi_square']
|
|
395
395
|
v2 = self.cached_convolution_fit['minimum position']
|
|
396
396
|
v2_file = v2 + self.sound_extract_position
|
|
397
|
-
logger.debug('cached chi_sq: %s minimum position in file: %s'%
|
|
398
|
-
|
|
397
|
+
logger.debug('cached chi_sq: %s minimum position in file: %s'%
|
|
398
|
+
(v1, v2_file))
|
|
399
|
+
return (v1, v2) ####################################################
|
|
399
400
|
# cached!
|
|
400
401
|
x_shifted, convolution = self._get_square_convolution()
|
|
401
402
|
# see numpy.convolve(..., mode='valid')
|
|
@@ -419,7 +420,7 @@ class Decoder:
|
|
|
419
420
|
mp = pars['min_position']
|
|
420
421
|
model = 2*A*arcsin(abs(sin((x - mp)*2*pi/p)))/pi
|
|
421
422
|
if signal_data is None:
|
|
422
|
-
return model
|
|
423
|
+
return model ###################################################
|
|
423
424
|
return model - signal_data
|
|
424
425
|
fit_trig = lmfit.minimize(
|
|
425
426
|
trig_wave, trig_params,
|
|
@@ -430,7 +431,8 @@ class Decoder:
|
|
|
430
431
|
min_position = int(fit_trig.params['min_position'].value) + shift
|
|
431
432
|
logger.debug('chi_square %.1f minimum convolution position %i in file'%
|
|
432
433
|
(chi_square, min_position + self.sound_extract_position))
|
|
433
|
-
self.cached_convolution_fit['sound_extract_position'] =
|
|
434
|
+
self.cached_convolution_fit['sound_extract_position'] = \
|
|
435
|
+
self.sound_extract_position
|
|
434
436
|
self.cached_convolution_fit['chi_square'] = chi_square
|
|
435
437
|
self.cached_convolution_fit['minimum position'] = min_position
|
|
436
438
|
|
|
@@ -465,8 +467,9 @@ class Decoder:
|
|
|
465
467
|
|
|
466
468
|
"""
|
|
467
469
|
if self.silent_zone_indices:
|
|
468
|
-
return self.silent_zone_indices
|
|
469
|
-
_, silence_center_position =
|
|
470
|
+
return self.silent_zone_indices ####################################
|
|
471
|
+
_, silence_center_position = \
|
|
472
|
+
self._fit_triangular_signal_to_convoluted_env()
|
|
470
473
|
srate = self.samplerate
|
|
471
474
|
half_window = int(SAFE_SILENCE_WINDOW_WIDTH * 1e-3 * srate/2)
|
|
472
475
|
left_window_boundary = silence_center_position - half_window
|
|
@@ -711,7 +714,7 @@ class Decoder:
|
|
|
711
714
|
boundaries_OK, left_boundary, right_boundary = \
|
|
712
715
|
self._get_BFSK_word_boundaries()
|
|
713
716
|
if left_boundary is None:
|
|
714
|
-
return None, None, None
|
|
717
|
+
return None, None, None ############################################
|
|
715
718
|
symbol_width_samples = \
|
|
716
719
|
float(right_boundary - left_boundary)/N_SYMBOLS_SAMD21
|
|
717
720
|
symbol_positions = symbol_width_samples * \
|
|
@@ -911,7 +914,7 @@ class Decoder:
|
|
|
911
914
|
|
|
912
915
|
def get_time_in_sound_extract(self, plots):
|
|
913
916
|
if self.sound_extract is None:
|
|
914
|
-
return None
|
|
917
|
+
return None ########################################################
|
|
915
918
|
if plots:
|
|
916
919
|
self.make_silence_analysis_plot()
|
|
917
920
|
pulse_position = self._detect_sync_pulse_position()
|
|
@@ -928,7 +931,7 @@ class Decoder:
|
|
|
928
931
|
self._plot_slices(pulse_position, symbols_indices, word_lft,
|
|
929
932
|
word_rght, title)
|
|
930
933
|
if symbols_indices is None:
|
|
931
|
-
return None
|
|
934
|
+
return None ########################################################
|
|
932
935
|
sliced_data = self._slice_sound_extract(symbols_indices)
|
|
933
936
|
frequencies = [self._get_main_frequency(data_slice)
|
|
934
937
|
for data_slice
|
|
@@ -950,7 +953,7 @@ class Decoder:
|
|
|
950
953
|
symbols_indices[i],
|
|
951
954
|
symbols_indices[i+1]))
|
|
952
955
|
if None in bits:
|
|
953
|
-
return None
|
|
956
|
+
return None ########################################################
|
|
954
957
|
bits_string = ''.join(bits)
|
|
955
958
|
logger.debug('bits = %s'%bits_string)
|
|
956
959
|
time_values = self._values_from_bits(bits_string)
|
|
@@ -1011,25 +1014,26 @@ class Recording:
|
|
|
1011
1014
|
implicitly True for each video recordings (but not set)
|
|
1012
1015
|
|
|
1013
1016
|
device_relative_speed : float
|
|
1017
|
+
|
|
1014
1018
|
the ratio of the recording device clock speed relative to the
|
|
1015
|
-
|
|
1016
|
-
pysox tempo transform. If value < 1.0 then the recording is
|
|
1017
|
-
than
|
|
1018
|
-
instance so the value can change
|
|
1019
|
-
|
|
1019
|
+
video recorder clock device, in order to correct clock drift with
|
|
1020
|
+
pysox tempo transform. If value < 1.0 then the recording is
|
|
1021
|
+
slower than video recorder. Updated by each
|
|
1022
|
+
AudioStitcherVideoMerger instance so the value can change
|
|
1023
|
+
depending on the video recording . A mean is calculated for all
|
|
1020
1024
|
recordings of the same device in
|
|
1021
1025
|
AudioStitcherVideoMerger._get_concatenated_audiofile_for()
|
|
1022
1026
|
|
|
1023
1027
|
time_position : float
|
|
1024
1028
|
The time (in seconds) at which the recording starts relative to the
|
|
1025
|
-
|
|
1026
|
-
instance so the value can change depending on the
|
|
1029
|
+
video recording. Updated by each AudioStitcherVideoMerger
|
|
1030
|
+
instance so the value can change depending on the video
|
|
1027
1031
|
recording (a video or main sound).
|
|
1028
1032
|
|
|
1029
1033
|
final_synced_file : a pathlib.Path
|
|
1030
1034
|
contains the path of the merged video file after the call to
|
|
1031
1035
|
AudioStitcher.build_audio_and_write_video if the Recording is a
|
|
1032
|
-
|
|
1036
|
+
video recording, relative to the working directory
|
|
1033
1037
|
|
|
1034
1038
|
synced_audio : pathlib.Path
|
|
1035
1039
|
contains the path of audio only of self.final_synced_file. Absolute
|
|
@@ -1168,10 +1172,10 @@ class Recording:
|
|
|
1168
1172
|
if self.valid_sound:
|
|
1169
1173
|
val = sox.file_info.duration(_pathname(self.valid_sound))
|
|
1170
1174
|
logger.debug('duration of valid_sound %f'%val)
|
|
1171
|
-
return val
|
|
1175
|
+
return val #########################################################
|
|
1172
1176
|
else:
|
|
1173
1177
|
if self.probe is None:
|
|
1174
|
-
return 0
|
|
1178
|
+
return 0 #######################################################
|
|
1175
1179
|
try:
|
|
1176
1180
|
probed_duration = float(self.probe['format']['duration'])
|
|
1177
1181
|
except:
|
|
@@ -1292,7 +1296,7 @@ class Recording:
|
|
|
1292
1296
|
|
|
1293
1297
|
"""
|
|
1294
1298
|
if t1 == None or t2 == None:
|
|
1295
|
-
return False
|
|
1299
|
+
return False #######################################################
|
|
1296
1300
|
logger.debug('t1 : %s t2: %s'%(t1, t2))
|
|
1297
1301
|
datetime_1 = self._get_timedate_from_dict(t1)
|
|
1298
1302
|
datetime_2 = self._get_timedate_from_dict(t2)
|
|
@@ -1334,19 +1338,19 @@ class Recording:
|
|
|
1334
1338
|
to_precision(true_samplerate, 8))
|
|
1335
1339
|
return true_samplerate
|
|
1336
1340
|
|
|
1337
|
-
def set_time_position_to(self,
|
|
1341
|
+
def set_time_position_to(self, video_clip):
|
|
1338
1342
|
"""
|
|
1339
1343
|
Sets self.time_position, the time (in seconds) at which the recording
|
|
1340
|
-
starts relative to the
|
|
1341
|
-
instance so the value can change depending on the
|
|
1344
|
+
starts relative to the video recording. Updated by each AudioStitcherVideoMerger
|
|
1345
|
+
instance so the value can change depending on the video
|
|
1342
1346
|
recording (a video or main sound).
|
|
1343
1347
|
|
|
1344
1348
|
called by timeline.AudioStitcher._get_concatenated_audiofile_for()
|
|
1345
1349
|
|
|
1346
1350
|
"""
|
|
1347
|
-
|
|
1351
|
+
video_start_time = video_clip.get_start_time()
|
|
1348
1352
|
self.time_position = (self.get_start_time()
|
|
1349
|
-
-
|
|
1353
|
+
- video_start_time).total_seconds()
|
|
1350
1354
|
|
|
1351
1355
|
def get_Dt_with(self, later_recording):
|
|
1352
1356
|
"""
|
|
@@ -1366,14 +1370,14 @@ class Recording:
|
|
|
1366
1370
|
If successful AND self is audio, sets self.valid_sound
|
|
1367
1371
|
"""
|
|
1368
1372
|
if self.start_time is not None:
|
|
1369
|
-
return self.start_time
|
|
1373
|
+
return self.start_time #############################################
|
|
1370
1374
|
cached_times = {}
|
|
1371
1375
|
def find_time(t_sec, plots=False):
|
|
1372
1376
|
time_k = int(t_sec)
|
|
1373
1377
|
# if cached_times.has_key(time_k):
|
|
1374
1378
|
if CACHING and time_k in cached_times:
|
|
1375
1379
|
logger.debug('cache hit _find_time_around() for t=%s s'%time_k)
|
|
1376
|
-
return cached_times[time_k]
|
|
1380
|
+
return cached_times[time_k] ####################################
|
|
1377
1381
|
else:
|
|
1378
1382
|
logger.debug('_find_time_around() for t=%s s not cached'%time_k)
|
|
1379
1383
|
new_t = self._find_time_around(t_sec, plots)
|
|
@@ -1391,7 +1395,7 @@ class Recording:
|
|
|
1391
1395
|
# time_around_beginning = self._find_time_around(near_beg)
|
|
1392
1396
|
time_around_beginning = find_time(near_beg, plots)
|
|
1393
1397
|
if self.TicTacCode_channel is None:
|
|
1394
|
-
return None
|
|
1398
|
+
return None ####################################################
|
|
1395
1399
|
logger.debug('Trial #%i, end at %f'%(i+1, near_end))
|
|
1396
1400
|
# time_around_end = self._find_time_around(near_end)
|
|
1397
1401
|
time_around_end = find_time(near_end, plots)
|
|
@@ -1407,11 +1411,11 @@ class Recording:
|
|
|
1407
1411
|
break
|
|
1408
1412
|
if not coherence:
|
|
1409
1413
|
logger.warning('found times are incoherent')
|
|
1410
|
-
return None
|
|
1414
|
+
return None ########################################################
|
|
1411
1415
|
if None in [time_around_beginning, time_around_end]:
|
|
1412
1416
|
logger.warning('didnt find any time in file')
|
|
1413
1417
|
self.start_time = None
|
|
1414
|
-
return None
|
|
1418
|
+
return None ########################################################
|
|
1415
1419
|
true_sr = self._compute_true_samplerate(
|
|
1416
1420
|
time_around_beginning,
|
|
1417
1421
|
time_around_end)
|
|
@@ -1428,132 +1432,134 @@ class Recording:
|
|
|
1428
1432
|
self.start_time = start_UTC
|
|
1429
1433
|
self.sync_position = time_around_beginning['pulse at']
|
|
1430
1434
|
if self.is_audio():
|
|
1431
|
-
self.valid_sound = self._strip_TTC_and_Null()
|
|
1435
|
+
# self.valid_sound = self._strip_TTC_and_Null() # why now? :-)
|
|
1436
|
+
self.valid_sound = self.AVpath
|
|
1432
1437
|
return start_UTC
|
|
1433
1438
|
|
|
1434
|
-
def _strip_TTC_and_Null(self) -> tempfile.NamedTemporaryFile:
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1439
|
+
# def _strip_TTC_and_Null(self) -> tempfile.NamedTemporaryFile:
|
|
1440
|
+
# """
|
|
1441
|
+
# TTC is stripped from original audio and a tempfile.NamedTemporaryFile is
|
|
1442
|
+
# returned. If the original audio is stereo, this is simply the audio
|
|
1443
|
+
# without the TicTacCode channel, so this fct returns a mono wav
|
|
1444
|
+
# tempfile. But if the original audio is multitrack, two possibilities:
|
|
1445
|
+
|
|
1446
|
+
# A- there's a track.txt file declaring null channels (with '0' tags)
|
|
1447
|
+
# then those tracks are excluded too (a check is done those tracks
|
|
1448
|
+
# have low signal and warns the user otherwise)
|
|
1449
|
+
|
|
1450
|
+
# B- it's a multitrack recording but without track declaration
|
|
1451
|
+
# (no track.txt was found in the device folder): all the tracks are
|
|
1452
|
+
# returned into a multiwav tempfile (except TTC).
|
|
1453
|
+
|
|
1454
|
+
# Notes:
|
|
1455
|
+
# 'track.txt' is defined in device_scanner.TRACKSFN
|
|
1456
|
+
|
|
1457
|
+
# Beware of track indexing: sox starts indexing tracks at 1 but code
|
|
1458
|
+
# here uses zero based indexing.
|
|
1459
|
+
# """
|
|
1460
|
+
# tracks_file = self.device.folder/device_scanner.TRACKSFN
|
|
1461
|
+
# input_file = _pathname(self.AVpath)
|
|
1462
|
+
# # n_channels = sox.file_info.channels(input_file) # eg 2
|
|
1463
|
+
# n_channels = self.device.n_chan
|
|
1464
|
+
# sox_TicTacCode_channel = self.TicTacCode_channel + 1 # sox start at 1
|
|
1465
|
+
# if n_channels == 2:
|
|
1466
|
+
# logger.debug('stereo, so only excluding TTC (ZB idx) %i'%
|
|
1467
|
+
# self.TicTacCode_channel)
|
|
1468
|
+
# return self._sox_strip(input_file, [self.TicTacCode_channel]) ######
|
|
1469
|
+
# #
|
|
1470
|
+
# # First a check is done if the ttc tracks concur: the track detected
|
|
1471
|
+
# # by the Decoder class, stored in Recording.TicTacCode_channel VS the
|
|
1472
|
+
# # track declared by the user, Tracks.ttc (see device_scanner.py). If
|
|
1473
|
+
# # not, warn the user and exit.
|
|
1474
|
+
# trax = self.device.tracks # a Tracks dataclass instance, if any
|
|
1475
|
+
# logger.debug('trax %s'%trax)
|
|
1476
|
+
# if trax == None:
|
|
1477
|
+
# return self._sox_strip(input_file, [self.TicTacCode_channel]) ######
|
|
1478
|
+
# else:
|
|
1479
|
+
# logger.debug('ttc channel declared for the device: %i, ttc detected: %i, non zero base indexing'%
|
|
1480
|
+
# (trax.ttc, sox_TicTacCode_channel))
|
|
1481
|
+
# if trax.ttc != sox_TicTacCode_channel: # warn and quit
|
|
1482
|
+
# print('Error: TicTacCode channel detected is [gold1]%i[/gold1]'%
|
|
1483
|
+
# sox_TicTacCode_channel, end=' ')
|
|
1484
|
+
# print('and the file [gold1]%s[/gold1] specifies channel [gold1]%i[/gold1],'%
|
|
1485
|
+
# (tracks_file, trax.ttc))
|
|
1486
|
+
# print('Please correct the discrepancy and rerun. Quitting.')
|
|
1487
|
+
# sys.exit(1)
|
|
1488
|
+
# track_is_declared_audio = [ tag not in ['ttc','0','tc']
|
|
1489
|
+
# for tag in trax.rawtrx]
|
|
1490
|
+
# logger.debug('from tracks_file %s'%tracks_file)
|
|
1491
|
+
# logger.debug('track_is_declared_audio (not ttc or 0): %s'%
|
|
1492
|
+
# track_is_declared_audio)
|
|
1493
|
+
# # Now find out which files are silent, ie those with sox stats "RMS lev
|
|
1494
|
+
# # db" value inferior to DB_RMS_SILENCE_SOX (typ -50 -60 dbFS) from the
|
|
1495
|
+
# # sox "stat" command. Ex output belwow:
|
|
1496
|
+
# #
|
|
1497
|
+
# # sox input.wav -n channels stats -w 0.01
|
|
1498
|
+
# #
|
|
1499
|
+
# # Overall Ch1 Ch2 Ch3 Ch4
|
|
1500
|
+
# # DC offset -0.000047 -0.000047 -0.000047 -0.000016 -0.000031
|
|
1501
|
+
# # Min level -0.060913 -0.060913 -0.048523 -0.036438 -0.002777
|
|
1502
|
+
# # Max level 0.050201 0.050201 0.048767 0.039032 0.002838
|
|
1503
|
+
# # Pk lev dB -24.31 -24.31 -26.24 -28.17 -50.94
|
|
1504
|
+
# # RMS lev dB -40.33 -55.29 -53.70 -34.41 -59.75 <- this line
|
|
1505
|
+
# # RMS Pk dB -28.39 -28.39 -30.90 -31.20 -55.79
|
|
1506
|
+
# # RMS Tr dB -97.42 -79.66 -75.87 -97.42 -96.09
|
|
1507
|
+
# # Crest factor - 35.41 23.61 2.05 2.76
|
|
1508
|
+
# # Flat factor 6.93 0.00 0.00 0.97 10.63
|
|
1509
|
+
# # Pk count 10.2 2 2 17 20
|
|
1510
|
+
# # Bit-depth 12/16 12/16 12/16 12/16 8/16
|
|
1511
|
+
# # Num samples 11.2M
|
|
1512
|
+
# # Length s 232.780
|
|
1513
|
+
# # Scale max 1.000000
|
|
1514
|
+
# # Window s 0.010
|
|
1515
|
+
# args = ['sox', input_file, '-n', 'channels', 'stats', '-w', '0.01']
|
|
1516
|
+
# _, _, stat_output = sox.core.sox(args)
|
|
1517
|
+
# logger.debug('sox stat output: \n%s'%stat_output)
|
|
1518
|
+
# sox_RMS_lev_dB = stat_output.split('\n')[5].split()[4:]
|
|
1519
|
+
# logger.debug('Rec %s'%self)
|
|
1520
|
+
# logger.debug('Sox RMS %s, n_channels: %i'%(sox_RMS_lev_dB, n_channels))
|
|
1521
|
+
# # valid audio is non silent and not ttc
|
|
1522
|
+
# track_is_active = [float(db) > DB_RMS_SILENCE_SOX
|
|
1523
|
+
# if idx + 1 != sox_TicTacCode_channel else False
|
|
1524
|
+
# for idx, db in enumerate(sox_RMS_lev_dB)]
|
|
1525
|
+
# logger.debug('track_is_active %s'%track_is_active)
|
|
1526
|
+
# # Stored in self.device.tracks and as declared by the user, a track is
|
|
1527
|
+
# # either:
|
|
1528
|
+
# #
|
|
1529
|
+
# # - an active track (because a name was given to it)
|
|
1530
|
+
# # - the ttc track (as identified by the user)
|
|
1531
|
+
# # - a muted track (declared by a "0" in tracks.txt)
|
|
1532
|
+
# #
|
|
1533
|
+
# # the following checks active tracks are effectively non silent and
|
|
1534
|
+
# # muted tracks are effectively silent (warn the user if not but
|
|
1535
|
+
# # proceed, giving priority to status declared in the tracks.txt file.
|
|
1536
|
+
# # eg a non silent track will be discarded if the user tagged it with
|
|
1537
|
+
# # a "0")
|
|
1538
|
+
# declared_and_detected_are_same = all([a==b for a,b
|
|
1539
|
+
# in zip(track_is_declared_audio, track_is_active)])
|
|
1540
|
+
# logger.debug('declared_and_detected_are_same: %s'%
|
|
1541
|
+
# declared_and_detected_are_same)
|
|
1542
|
+
# if not declared_and_detected_are_same:
|
|
1543
|
+
# print('Warning, the file [gold1]%s[/gold1] specifies channel usage'%
|
|
1544
|
+
# (tracks_file))
|
|
1545
|
+
# print('and some muted tracks are not silent (or the inverse, see below),')
|
|
1546
|
+
# print('will proceed but if it\'s an error do necessary corrections and rerun.\n')
|
|
1547
|
+
# table = Table(title="Tracks status")
|
|
1548
|
+
# table.add_column("track #", justify="center", style='gold1')
|
|
1549
|
+
# table.add_column("RMS Level", justify="center", style='gold1')
|
|
1550
|
+
# table.add_column("Declared", justify="center", style='gold1')
|
|
1551
|
+
# for n in range(n_channels):
|
|
1552
|
+
# table.add_row(str(n+1), '%.0f dBFS'%float(sox_RMS_lev_dB[n]),
|
|
1553
|
+
# trax.rawtrx[n])
|
|
1554
|
+
# console = Console()
|
|
1555
|
+
# console.print(table)
|
|
1556
|
+
# if trax:
|
|
1557
|
+
# excluded_channels = [i for i in range(n_channels)
|
|
1558
|
+
# if not track_is_declared_audio[i]]
|
|
1559
|
+
# else:
|
|
1560
|
+
# excluded_channels = [self.TicTacCode_channel]
|
|
1561
|
+
# logger.debug('excluded_channels %s (ZB idx)'%excluded_channels)
|
|
1562
|
+
# return self._sox_strip(input_file, excluded_channels)
|
|
1557
1563
|
|
|
1558
1564
|
|
|
1559
1565
|
|
|
@@ -1631,13 +1637,13 @@ class Recording:
|
|
|
1631
1637
|
ppm = - (nominal/true - 1) * 1e6
|
|
1632
1638
|
return int(ppm)
|
|
1633
1639
|
|
|
1634
|
-
def get_speed_ratio(self,
|
|
1640
|
+
def get_speed_ratio(self, videoclip):
|
|
1635
1641
|
nominal = self.get_samplerate()
|
|
1636
1642
|
true = self.true_samplerate
|
|
1637
1643
|
ratio = true/nominal
|
|
1638
|
-
|
|
1639
|
-
true_ref =
|
|
1640
|
-
ratio_ref = true_ref/
|
|
1644
|
+
nominal_vid = videoclip.get_samplerate()
|
|
1645
|
+
true_ref = videoclip.true_samplerate
|
|
1646
|
+
ratio_ref = true_ref/nominal_vid
|
|
1641
1647
|
return ratio/ratio_ref
|
|
1642
1648
|
|
|
1643
1649
|
def get_samplerate(self):
|
|
@@ -1688,20 +1694,20 @@ class Recording:
|
|
|
1688
1694
|
|
|
1689
1695
|
def has_audio(self):
|
|
1690
1696
|
if not self.probe:
|
|
1691
|
-
return False
|
|
1697
|
+
return False #######################################################
|
|
1692
1698
|
streams = self.probe['streams']
|
|
1693
1699
|
codecs = [stream['codec_type'] for stream in streams]
|
|
1694
1700
|
return 'audio' in codecs
|
|
1695
1701
|
|
|
1696
1702
|
def get_audio_channels_nbr(self):
|
|
1697
1703
|
if not self.has_audio():
|
|
1698
|
-
return 0
|
|
1704
|
+
return 0 ###########################################################
|
|
1699
1705
|
audio_str = self._ffprobe_audio_stream()
|
|
1700
1706
|
return audio_str['channels']
|
|
1701
1707
|
|
|
1702
1708
|
def is_video(self):
|
|
1703
1709
|
if not self.probe:
|
|
1704
|
-
return False
|
|
1710
|
+
return False #######################################################
|
|
1705
1711
|
streams = self.probe['streams']
|
|
1706
1712
|
codecs = [stream['codec_type'] for stream in streams]
|
|
1707
1713
|
return 'video' in codecs
|
|
@@ -1742,7 +1748,7 @@ class Recording:
|
|
|
1742
1748
|
# decoder.cached_convolution_fit['is clean'] = False
|
|
1743
1749
|
if not self.has_audio():
|
|
1744
1750
|
self.TicTacCode_channel = None
|
|
1745
|
-
return
|
|
1751
|
+
return #############################################################
|
|
1746
1752
|
logger.debug('will read around %.2f sec'%time_where)
|
|
1747
1753
|
dryrun = (ffmpeg
|
|
1748
1754
|
.input(str(path), ss=time_where, t=chunk_length)
|
|
@@ -1775,9 +1781,10 @@ class Recording:
|
|
|
1775
1781
|
)
|
|
1776
1782
|
if decoder.extract_seems_TicTacCode():
|
|
1777
1783
|
self.TicTacCode_channel = i_chan
|
|
1784
|
+
self.device.ttc = i_chan
|
|
1778
1785
|
logger.debug('find TicTacCode channel, chan #%i'%
|
|
1779
1786
|
self.TicTacCode_channel)
|
|
1780
|
-
return self
|
|
1787
|
+
return self ####################################################
|
|
1781
1788
|
# end of loop: none found
|
|
1782
1789
|
self.TicTacCode_channel = None
|
|
1783
1790
|
logger.warning('found no TicTacCode channel')
|
|
@@ -1785,8 +1792,9 @@ class Recording:
|
|
|
1785
1792
|
|
|
1786
1793
|
def seems_to_have_TicTacCode_at_beginning(self):
|
|
1787
1794
|
if self.probe is None:
|
|
1788
|
-
return False
|
|
1789
|
-
self._read_sound_find_TicTacCode(TRIAL_TIMES[0][0],
|
|
1795
|
+
return False #######################################################
|
|
1796
|
+
self._read_sound_find_TicTacCode(TRIAL_TIMES[0][0],
|
|
1797
|
+
SOUND_EXTRACT_LENGTH)
|
|
1790
1798
|
return self.TicTacCode_channel is not None
|
|
1791
1799
|
|
|
1792
1800
|
def does_overlap_with_time(self, time):
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
tictacsync/LTCcheck.py,sha256=IEfpB_ZajWuRTWtqji0H-B2g7GQvWmGVjfT0Icumv7o,15704
|
|
2
|
+
tictacsync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
tictacsync/device_scanner.py,sha256=JmjwMFr6Jy6Jnl5sAycUSEXezF3ETLyF3TEXjn_orKs,27339
|
|
4
|
+
tictacsync/entry.py,sha256=oSDfa01wToQy6wyEw_IA1WeD7mFXTKbXmB4M3QD-ir4,11386
|
|
5
|
+
tictacsync/multi2polywav.py,sha256=Zl5EP2Yf-PKiZ8ewRSwqWsDULvKKjeWANK_-Yd5RAg4,7279
|
|
6
|
+
tictacsync/remergemix.py,sha256=BUtZ8YHw5Oz8VseTD-A4imNbtF7h391pw5yyl6v6OG4,4885
|
|
7
|
+
tictacsync/synciso.py,sha256=XmUcdUF9rl4VdCm7XW4PeYWYWM0vgAY9dC2hapoul9g,4821
|
|
8
|
+
tictacsync/timeline.py,sha256=HlCTnS48Z54t8DyplDLIKL2_uD952xulkTlDklzxGeM,56225
|
|
9
|
+
tictacsync/yaltc.py,sha256=n7ubnlcFDzCpvhZNIwMZMfijZq-ROEA-hS0dbcZgPtE,78490
|
|
10
|
+
tictacsync-0.4a0.dist-info/LICENSE,sha256=ZAOPXLh1zlQAnhHUd7oLslKM01YZ5UiAu3STYjwIxck,1068
|
|
11
|
+
tictacsync-0.4a0.dist-info/METADATA,sha256=3Ui70mGVLMKKO2hI32WUGXng-ZziDOiREYi8Qnt7jZU,5298
|
|
12
|
+
tictacsync-0.4a0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
13
|
+
tictacsync-0.4a0.dist-info/entry_points.txt,sha256=g3tdFFrVRcrKpuyKOCLUVBMgYfV65q9kpLZUOD_XCKg,139
|
|
14
|
+
tictacsync-0.4a0.dist-info/top_level.txt,sha256=eaCWG-BsYTRR-gLTJbK4RfcaXajr0gjQ6wG97MkGRrg,11
|
|
15
|
+
tictacsync-0.4a0.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
tictacsync/LTCcheck.py,sha256=IEfpB_ZajWuRTWtqji0H-B2g7GQvWmGVjfT0Icumv7o,15704
|
|
2
|
-
tictacsync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
tictacsync/device_scanner.py,sha256=-m2gd0XWXyJLNWfpLc_XQbMwFfNLJ4y3AmI4abz85W4,27558
|
|
4
|
-
tictacsync/entry.py,sha256=zyF8alGtJ57fmKm-_w1eCZber-T9VmeuKFL6yRyRofM,11385
|
|
5
|
-
tictacsync/multi2polywav.py,sha256=Zl5EP2Yf-PKiZ8ewRSwqWsDULvKKjeWANK_-Yd5RAg4,7279
|
|
6
|
-
tictacsync/remergemix.py,sha256=BUtZ8YHw5Oz8VseTD-A4imNbtF7h391pw5yyl6v6OG4,4885
|
|
7
|
-
tictacsync/synciso.py,sha256=XmUcdUF9rl4VdCm7XW4PeYWYWM0vgAY9dC2hapoul9g,4821
|
|
8
|
-
tictacsync/timeline.py,sha256=Qy37vFmFsGDSVpEio3ts_TmGeD96868qfioIevhp92U,45925
|
|
9
|
-
tictacsync/yaltc.py,sha256=eGCDzp5aTF4zqFN4wNfiESXRnaHEXtQB-u13gYBf8g8,76810
|
|
10
|
-
tictacsync-0.3a3.dist-info/LICENSE,sha256=ZAOPXLh1zlQAnhHUd7oLslKM01YZ5UiAu3STYjwIxck,1068
|
|
11
|
-
tictacsync-0.3a3.dist-info/METADATA,sha256=RLwLKCbmVfO1A1dBZL-wdF9I4nHk2km0c5j05N9mTIY,5298
|
|
12
|
-
tictacsync-0.3a3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
13
|
-
tictacsync-0.3a3.dist-info/entry_points.txt,sha256=g3tdFFrVRcrKpuyKOCLUVBMgYfV65q9kpLZUOD_XCKg,139
|
|
14
|
-
tictacsync-0.3a3.dist-info/top_level.txt,sha256=eaCWG-BsYTRR-gLTJbK4RfcaXajr0gjQ6wG97MkGRrg,11
|
|
15
|
-
tictacsync-0.3a3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|