tictacsync 1.0.2a0__py3-none-any.whl → 1.2.0b0__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 +5 -24
- tictacsync/entry.py +35 -38
- tictacsync/mamconf.py +175 -0
- tictacsync/mamsync.py +99 -172
- tictacsync/multi2polywav.py +3 -1
- tictacsync/newmix.py +217 -57
- tictacsync/timeline.py +137 -84
- tictacsync/yaltc.py +2 -2
- {tictacsync-1.0.2a0.dist-info → tictacsync-1.2.0b0.dist-info}/METADATA +4 -4
- tictacsync-1.2.0b0.dist-info/RECORD +19 -0
- {tictacsync-1.0.2a0.dist-info → tictacsync-1.2.0b0.dist-info}/entry_points.txt +2 -0
- tictacsync-1.0.2a0.dist-info/RECORD +0 -18
- {tictacsync-1.0.2a0.dist-info → tictacsync-1.2.0b0.dist-info}/LICENSE +0 -0
- {tictacsync-1.0.2a0.dist-info → tictacsync-1.2.0b0.dist-info}/WHEEL +0 -0
- {tictacsync-1.0.2a0.dist-info → tictacsync-1.2.0b0.dist-info}/top_level.txt +0 -0
tictacsync/timeline.py
CHANGED
|
@@ -9,7 +9,7 @@ from rich import print
|
|
|
9
9
|
from itertools import groupby
|
|
10
10
|
# import opentimelineio as otio
|
|
11
11
|
from datetime import timedelta
|
|
12
|
-
import shutil, os, sys, stat
|
|
12
|
+
import shutil, os, sys, stat, subprocess
|
|
13
13
|
from subprocess import Popen, PIPE
|
|
14
14
|
from pprint import pformat
|
|
15
15
|
|
|
@@ -401,6 +401,7 @@ class AudioStitcherVideoMerger:
|
|
|
401
401
|
Returns audio recordings that overlap self.videoclip.
|
|
402
402
|
Simply keys of self.soxed_audio dict
|
|
403
403
|
"""
|
|
404
|
+
logger.debug(f'soxed_audio {pformat(self.soxed_audio)}')
|
|
404
405
|
return list(self.soxed_audio.keys())
|
|
405
406
|
|
|
406
407
|
def _get_audio_devices(self):
|
|
@@ -411,15 +412,16 @@ class AudioStitcherVideoMerger:
|
|
|
411
412
|
return devices
|
|
412
413
|
|
|
413
414
|
def _get_secondary_audio_devices(self):
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
return devices
|
|
415
|
+
# when only audio devices are synced.
|
|
416
|
+
# identical to _get_audio_devices()...
|
|
417
|
+
# name changed for clarity
|
|
418
|
+
return self._get_audio_devices()
|
|
419
419
|
|
|
420
420
|
def _get_all_recordings_for(self, device):
|
|
421
421
|
# return recordings for a particular device, sorted by time
|
|
422
|
-
recs =
|
|
422
|
+
recs = self.get_matched_audio_recs()
|
|
423
|
+
logger.debug(f'device: {device.name} matched audio recs: {recs}')
|
|
424
|
+
recs = [a for a in recs if a.device == device]
|
|
423
425
|
recs.sort(key=lambda r: r.start_time)
|
|
424
426
|
return recs
|
|
425
427
|
|
|
@@ -652,14 +654,16 @@ class AudioStitcherVideoMerger:
|
|
|
652
654
|
self.soxed_audio[audio_rec] = output_fh
|
|
653
655
|
return output_fh
|
|
654
656
|
|
|
655
|
-
def _write_ISOs(self, edited_audio_all_devices
|
|
657
|
+
def _write_ISOs(self, edited_audio_all_devices,
|
|
658
|
+
snd_root=None, synced_root=None, raw_root=None, audio_only=False):
|
|
656
659
|
"""
|
|
660
|
+
[TODO: this multiline doc is obsolete]
|
|
657
661
|
Writes isolated audio files that were synced to synced_clip_file,
|
|
658
662
|
each track will have its dedicated monofile, named sequentially or with
|
|
659
663
|
the name find in TRACKSFILE if any, see Scanner._get_tracks_from_file()
|
|
660
664
|
|
|
661
665
|
edited_audio_all_devices:
|
|
662
|
-
a list of (name, mono_tempfile)
|
|
666
|
+
a list of (name, mono_tempfile, dev) -------------------------------------------> add argument for device for calling _get_all_recordings_for() for file for metada
|
|
663
667
|
|
|
664
668
|
Returns nothing, output is written to filesystem as below.
|
|
665
669
|
ISOs subfolders structure when user invokes the --isos flag:
|
|
@@ -671,7 +675,7 @@ class AudioStitcherVideoMerger:
|
|
|
671
675
|
canon24fps01.MOV ━━━━┓ name of clip is name of folder
|
|
672
676
|
canon24fps01_ISO/ <━━┛
|
|
673
677
|
chan_1.wav
|
|
674
|
-
chan_2.wav
|
|
678
|
+
chan_2.wav [UPDATE FOR MAM mode]
|
|
675
679
|
canon24fps02.MOV
|
|
676
680
|
canon24fps01_ISO/
|
|
677
681
|
chan_1.wav
|
|
@@ -708,8 +712,30 @@ class AudioStitcherVideoMerger:
|
|
|
708
712
|
logger.debug('video duration %.2f s'%
|
|
709
713
|
self.videoclip.get_duration())
|
|
710
714
|
return out_tf
|
|
711
|
-
|
|
712
|
-
|
|
715
|
+
def _meta_wav_dest(p1, p2, p3):
|
|
716
|
+
"""
|
|
717
|
+
takes metadata from p1, sound from p2 and combine them to create p3.
|
|
718
|
+
arguments are pathlib.Path or string;
|
|
719
|
+
returns nothing.
|
|
720
|
+
"""
|
|
721
|
+
f1, f2, f3 = [_pathname(p) for p in [p1, p2, p3]]
|
|
722
|
+
process_list = ['ffmpeg', '-y', '-loglevel', 'quiet', '-nostats', '-hide_banner',
|
|
723
|
+
'-i', f1, '-i', f2, '-map', '1',
|
|
724
|
+
'-map_metadata', '0', '-c', 'copy', f3]
|
|
725
|
+
proc = subprocess.run(process_list)
|
|
726
|
+
logger.debug(f'synced_clip_file raw')
|
|
727
|
+
if snd_root == None:
|
|
728
|
+
# alongside mode
|
|
729
|
+
synced_clip_file = self.videoclip.final_synced_file
|
|
730
|
+
logger.debug('alongside mode')
|
|
731
|
+
synced_clip_dir = synced_clip_file.parent
|
|
732
|
+
else:
|
|
733
|
+
# MAM mode
|
|
734
|
+
synced_clip_file = self.videoclip.AVpath
|
|
735
|
+
logger.debug('MAM mode')
|
|
736
|
+
rel = synced_clip_file.parent.relative_to(raw_root)
|
|
737
|
+
synced_clip_dir = Path(snd_root)/Path(raw_root).name/rel
|
|
738
|
+
logger.debug(f'synced_clip_dir: {synced_clip_dir}')
|
|
713
739
|
# build ISOs subfolders structure, see comment string below
|
|
714
740
|
video_stem_WO_suffix = synced_clip_file.stem
|
|
715
741
|
# ISOdir = synced_clip_dir/(video_stem_WO_suffix + 'ISO')
|
|
@@ -717,10 +743,17 @@ class AudioStitcherVideoMerger:
|
|
|
717
743
|
os.makedirs(ISOdir, exist_ok=True)
|
|
718
744
|
logger.debug('edited_audio_all_devices %s'%edited_audio_all_devices)
|
|
719
745
|
logger.debug('ISOdir %s'%ISOdir)
|
|
720
|
-
for name, mono_tmpfl in edited_audio_all_devices:
|
|
721
|
-
|
|
746
|
+
for name, mono_tmpfl, device in edited_audio_all_devices:
|
|
747
|
+
logger.debug(f'name:{name} mono_tmpfl:{mono_tmpfl} device:{pformat(device)}')
|
|
748
|
+
destination = ISOdir/(f'{video_stem_WO_suffix}_{name}.wav')
|
|
722
749
|
mono_tmpfl_trimpad = _fit_length(mono_tmpfl)
|
|
723
|
-
|
|
750
|
+
# if audio_only, self.ref_audio does not have itself as matching audio
|
|
751
|
+
if audio_only and device == self.ref_audio.device:
|
|
752
|
+
first_rec = self.ref_audio
|
|
753
|
+
else:
|
|
754
|
+
first_rec = self._get_all_recordings_for(device)[0]
|
|
755
|
+
logger.debug(f'will use {first_rec} for metadata source to copy over {destination}')
|
|
756
|
+
_meta_wav_dest(first_rec.AVpath, mono_tmpfl_trimpad, destination)
|
|
724
757
|
# remove_write_permissions(destination)
|
|
725
758
|
logger.debug('destination:%s'%destination)
|
|
726
759
|
|
|
@@ -867,19 +900,21 @@ class AudioStitcherVideoMerger:
|
|
|
867
900
|
stereo_files = mic_stereo_files + new_stereo_files
|
|
868
901
|
return _sox_mix_files(stereo_files)
|
|
869
902
|
|
|
870
|
-
def build_audio_and_write_merged_media(self, top_dir,
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
903
|
+
# def build_audio_and_write_merged_media(self, top_dir,
|
|
904
|
+
# dont_write_cam_folder, asked_ISOs, audio_REC_only):
|
|
905
|
+
# # simply bifurcates depending if ref media is video (prob 99%)
|
|
906
|
+
# # (then audio_REC_only == False)
|
|
907
|
+
# # or if ref media is audio (no camera detected, 1% of cases)
|
|
908
|
+
# # (with audio_REC_only == True)
|
|
909
|
+
# if not audio_REC_only:
|
|
910
|
+
# # almost always syncing audio to video clips
|
|
911
|
+
# self._build_audio_and_write_video(top_dir,
|
|
912
|
+
# dont_write_cam_folder, asked_ISOs)
|
|
913
|
+
# else:
|
|
914
|
+
# # rare
|
|
915
|
+
# self._build_and_write_audio(top_dir, anchor_dir)
|
|
916
|
+
|
|
917
|
+
def _build_and_write_audio(self, top_dir, anchor_dir=None):
|
|
883
918
|
"""
|
|
884
919
|
This is called when only audio recorders were found (no cam).
|
|
885
920
|
|
|
@@ -911,8 +946,7 @@ class AudioStitcherVideoMerger:
|
|
|
911
946
|
self.synced_clip_dir = synced_clip_dir
|
|
912
947
|
os.makedirs(synced_clip_dir, exist_ok=True)
|
|
913
948
|
logger.debug('synced_clip_dir is: %s'%synced_clip_dir)
|
|
914
|
-
synced_clip_file = synced_clip_dir
|
|
915
|
-
Path(self.videoclip.new_rec_name).name
|
|
949
|
+
synced_clip_file = synced_clip_dir/self.videoclip.AVpath.name
|
|
916
950
|
logger.debug('editing files for synced_clip_file%s'%synced_clip_file)
|
|
917
951
|
self.ref_audio.final_synced_file = synced_clip_file # relative path
|
|
918
952
|
# Collecting edited audio by device, in (Device, tempfile) pairs:
|
|
@@ -972,14 +1006,15 @@ class AudioStitcherVideoMerger:
|
|
|
972
1006
|
logger.debug('track_name %s'%track_name)
|
|
973
1007
|
if track_name[0] == '0': # muted, skip
|
|
974
1008
|
continue
|
|
975
|
-
names_audio_tempfiles.append((track_name, monotf))
|
|
976
|
-
logger.debug('names_audio_tempfiles %s'%names_audio_tempfiles)
|
|
977
|
-
self._write_ISOs(names_audio_tempfiles)
|
|
1009
|
+
names_audio_tempfiles.append((track_name, monotf, dev))
|
|
1010
|
+
logger.debug('names_audio_tempfiles %s'%pformat(names_audio_tempfiles))
|
|
1011
|
+
self._write_ISOs(names_audio_tempfiles, audio_only=True)
|
|
978
1012
|
logger.debug('merged_audio_files_by_device %s'%
|
|
979
1013
|
merged_audio_files_by_device)
|
|
980
1014
|
|
|
981
1015
|
def _build_audio_and_write_video(self, top_dir, dont_write_cam_folder,
|
|
982
|
-
asked_ISOs
|
|
1016
|
+
asked_ISOs, synced_root = None,
|
|
1017
|
+
snd_root = None, raw_root = None):
|
|
983
1018
|
"""
|
|
984
1019
|
top_dir: Path, directory where media were looked for
|
|
985
1020
|
|
|
@@ -1004,22 +1039,22 @@ class AudioStitcherVideoMerger:
|
|
|
1004
1039
|
(top_dir, dont_write_cam_folder, asked_ISOs))
|
|
1005
1040
|
logger.debug('device for rec %s: %s'%(self.videoclip,
|
|
1006
1041
|
self.videoclip.device))
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1042
|
+
if synced_root == None:
|
|
1043
|
+
# alongside, within SyncedMedia dirs
|
|
1044
|
+
synced_clip_dir = self.videoclip.AVpath.parent/OUT_DIR_DEFAULT
|
|
1045
|
+
logger.debug('"alongside mode" for clip: %s'%self.videoclip.AVpath)
|
|
1046
|
+
logger.debug(f'will save in {synced_clip_dir}')
|
|
1047
|
+
else:
|
|
1048
|
+
# MAM mode
|
|
1049
|
+
logger.debug('MAM mode')
|
|
1050
|
+
synced_clip_dir = Path(synced_root)/str(self.videoclip.AVpath.parent)[1:] # strip leading /
|
|
1051
|
+
rel = self.videoclip.AVpath.parent.relative_to(raw_root).parent
|
|
1052
|
+
logger.debug(f'relative path {rel}')
|
|
1053
|
+
synced_clip_dir = Path(synced_root)/Path(raw_root).name/rel
|
|
1054
|
+
logger.debug(f'will save in {synced_clip_dir}')
|
|
1020
1055
|
self.synced_clip_dir = synced_clip_dir
|
|
1021
1056
|
os.makedirs(synced_clip_dir, exist_ok=True)
|
|
1022
|
-
logger.debug('synced_clip_dir is: %s'%synced_clip_dir)
|
|
1057
|
+
# logger.debug('synced_clip_dir is: %s'%synced_clip_dir)
|
|
1023
1058
|
synced_clip_file = synced_clip_dir/self.videoclip.AVpath.name
|
|
1024
1059
|
logger.debug('editing files for synced_clip_file %s'%synced_clip_file)
|
|
1025
1060
|
self.videoclip.final_synced_file = synced_clip_file # relative path
|
|
@@ -1132,9 +1167,10 @@ class AudioStitcherVideoMerger:
|
|
|
1132
1167
|
logger.debug('track_name %s'%track_name)
|
|
1133
1168
|
if track_name[0] == '0': # muted, skip
|
|
1134
1169
|
continue
|
|
1135
|
-
names_audio_tempfiles.append((track_name, monotf))
|
|
1170
|
+
names_audio_tempfiles.append((track_name, monotf, dev))
|
|
1136
1171
|
logger.debug('names_audio_tempfiles %s'%pformat(names_audio_tempfiles))
|
|
1137
|
-
self._write_ISOs(names_audio_tempfiles
|
|
1172
|
+
self._write_ISOs(names_audio_tempfiles,
|
|
1173
|
+
snd_root=snd_root, synced_root=synced_root, raw_root=raw_root)
|
|
1138
1174
|
logger.debug('merged_audio_files_by_device %s'%
|
|
1139
1175
|
merged_audio_files_by_device)
|
|
1140
1176
|
# This loop below for logging purpose only:
|
|
@@ -1268,21 +1304,6 @@ class Matcher:
|
|
|
1268
1304
|
self.recordings = recordings_list
|
|
1269
1305
|
self.mergers = []
|
|
1270
1306
|
|
|
1271
|
-
# def _rename_all_recs(self):
|
|
1272
|
-
# """
|
|
1273
|
-
# Add _synced to filenames of synced video files. Change stored name only:
|
|
1274
|
-
# files have yet to be written to.
|
|
1275
|
-
# """
|
|
1276
|
-
# # match IO_structure:
|
|
1277
|
-
# # case 'foldercam':
|
|
1278
|
-
# for rec in self.recordings:
|
|
1279
|
-
# rec_extension = rec.AVpath.suffix
|
|
1280
|
-
# rel_path_new_name = '%s%s'%(rec.AVpath.stem, rec_extension)
|
|
1281
|
-
# rec.new_rec_name = Path(rel_path_new_name)
|
|
1282
|
-
# logger.debug('for %s new name: %s'%(
|
|
1283
|
-
# _pathname(rec.AVpath),
|
|
1284
|
-
# _pathname(rec.new_rec_name)))
|
|
1285
|
-
|
|
1286
1307
|
def scan_audio_for_each_videoclip(self):
|
|
1287
1308
|
"""
|
|
1288
1309
|
For each video (and for the Main Sound) in self.recordings, this finds
|
|
@@ -1294,10 +1315,11 @@ class Matcher:
|
|
|
1294
1315
|
V3 checked against ...
|
|
1295
1316
|
Main Sound checked against A1, A2, A3, A4
|
|
1296
1317
|
"""
|
|
1297
|
-
video_recordings = [r for r in self.recordings
|
|
1298
|
-
|
|
1318
|
+
video_recordings = [r for r in self.recordings
|
|
1319
|
+
if r.is_video() or r.is_audio_reference]
|
|
1320
|
+
# if r.is_audio_reference then audio, and will pass as video
|
|
1299
1321
|
audio_recs = [r for r in self.recordings if r.is_audio()
|
|
1300
|
-
and not r.
|
|
1322
|
+
and not r.is_audio_reference]
|
|
1301
1323
|
if not audio_recs:
|
|
1302
1324
|
print('\nNo audio recording found, syncing of videos only not implemented yet, exiting...\n')
|
|
1303
1325
|
sys.exit(1)
|
|
@@ -1453,7 +1475,7 @@ class Matcher:
|
|
|
1453
1475
|
vid.write_file_timecode(tc)
|
|
1454
1476
|
return
|
|
1455
1477
|
|
|
1456
|
-
def move_multicam_to_dir(self):
|
|
1478
|
+
def move_multicam_to_dir(self, raw_root=None, synced_root=None):
|
|
1457
1479
|
# creates a dedicated multicam directory and move clusters there
|
|
1458
1480
|
# e.g., for "top/day01/camA/roll02"
|
|
1459
1481
|
# ^ at that level
|
|
@@ -1462,6 +1484,7 @@ class Matcher:
|
|
|
1462
1484
|
#
|
|
1463
1485
|
# check for consistency: are all clips at the same level from topdir?
|
|
1464
1486
|
# Only for video, not audio (which doesnt fill up cards)
|
|
1487
|
+
logger.debug(f'synced_root: {synced_root}')
|
|
1465
1488
|
video_medias = [m for m in self.recordings if m.device.dev_type == 'CAM']
|
|
1466
1489
|
video_paths = [m.AVpath.parts for m in video_medias]
|
|
1467
1490
|
AV_path_lengths = [len(p) for p in video_paths]
|
|
@@ -1480,32 +1503,62 @@ class Matcher:
|
|
|
1480
1503
|
sys.exit(0)
|
|
1481
1504
|
# pick first
|
|
1482
1505
|
CAM_level, avp = CAM_levels[0], video_medias[0].AVpath
|
|
1483
|
-
logger.debug('CAM_levels: %s for
|
|
1506
|
+
logger.debug('CAM_levels: %s for %s\n'%(CAM_level, avp))
|
|
1484
1507
|
# MCCDIR = 'SyncedMulticamClips'
|
|
1485
|
-
parts_up_a_level = avp.parts[:CAM_level]
|
|
1486
|
-
|
|
1508
|
+
parts_up_a_level = [prt for prt in avp.parts[:CAM_level] if prt != '/']
|
|
1509
|
+
logger.debug(f'parts_up_a_level: {parts_up_a_level}')
|
|
1510
|
+
if synced_root == None:
|
|
1511
|
+
# alongside mode
|
|
1512
|
+
logger.debug('alongside mode')
|
|
1513
|
+
multicam_dir = Path('').joinpath(*parts_up_a_level)/MCCDIR
|
|
1514
|
+
else:
|
|
1515
|
+
# MAM mode
|
|
1516
|
+
logger.debug('MAM mode')
|
|
1517
|
+
abs_path_up = Path('/').joinpath(*parts_up_a_level)/MCCDIR
|
|
1518
|
+
logger.debug(f'abs_path_up: {abs_path_up}')
|
|
1519
|
+
rel_up = abs_path_up.relative_to(raw_root)
|
|
1520
|
+
logger.debug(f'rel_up: {rel_up}')
|
|
1521
|
+
multicam_dir = Path(synced_root)/Path(raw_root).name/rel_up
|
|
1522
|
+
# multicam_dir = Path(synced_root).joinpath(*parts_up_a_level)/MCCDIR
|
|
1487
1523
|
logger.debug('multicam_dir: %s'%multicam_dir)
|
|
1488
1524
|
Path.mkdir(multicam_dir, exist_ok=True)
|
|
1489
1525
|
cam_clips = []
|
|
1490
1526
|
[cam_clips.append(cl['vids']) for cl in self.multicam_clips_clusters]
|
|
1491
1527
|
cam_clips = _flatten(cam_clips)
|
|
1492
|
-
logger.debug('cam_clips: %s'%cam_clips)
|
|
1528
|
+
logger.debug('cam_clips: %s'%pformat(cam_clips))
|
|
1493
1529
|
cam_names = set([r.device.name for r in cam_clips])
|
|
1494
1530
|
# create new dirs for each CAM
|
|
1495
1531
|
[Path.mkdir(multicam_dir/cam_name, exist_ok=True)
|
|
1496
1532
|
for cam_name in cam_names]
|
|
1497
1533
|
# move clips there
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1534
|
+
if synced_root == None:
|
|
1535
|
+
# alongside mode
|
|
1536
|
+
for r in cam_clips:
|
|
1537
|
+
cam = r.device.name
|
|
1538
|
+
clip_name = r.AVpath.name
|
|
1539
|
+
dest = r.final_synced_file.replace(multicam_dir/cam/clip_name)
|
|
1540
|
+
logger.debug('dest: %s'%dest)
|
|
1541
|
+
origin_folder = r.final_synced_file.parent
|
|
1542
|
+
folder_now_empty = len(list(origin_folder.glob('*'))) == 0
|
|
1543
|
+
if folder_now_empty:
|
|
1544
|
+
logger.debug('after moving %s, folder is now empty, removing it'%dest)
|
|
1545
|
+
origin_folder.rmdir()
|
|
1546
|
+
print('\nMoved %i multicam clips in %s'%(len(cam_clips), multicam_dir))
|
|
1547
|
+
else:
|
|
1548
|
+
# MAM mode
|
|
1549
|
+
for r in cam_clips:
|
|
1550
|
+
cam = r.device.name
|
|
1551
|
+
clip_name = r.AVpath.name
|
|
1552
|
+
dest = r.final_synced_file.replace(multicam_dir/cam/clip_name)
|
|
1553
|
+
# leave a symlink behind
|
|
1554
|
+
os.symlink(multicam_dir/cam/clip_name, r.final_synced_file)
|
|
1555
|
+
logger.debug('dest: %s'%dest)
|
|
1556
|
+
origin_folder = r.final_synced_file.parent
|
|
1557
|
+
# folder_now_empty = len(list(origin_folder.glob('*'))) == 0
|
|
1558
|
+
# if folder_now_empty:
|
|
1559
|
+
# logger.debug('after moving %s, folder is now empty, removing it'%dest)
|
|
1560
|
+
# origin_folder.rmdir()
|
|
1561
|
+
print('\nMoved %i multicam clips in %s'%(len(cam_clips), multicam_dir))
|
|
1509
1562
|
|
|
1510
1563
|
|
|
1511
1564
|
|
tictacsync/yaltc.py
CHANGED
|
@@ -561,7 +561,7 @@ class Recording:
|
|
|
561
561
|
sync_position : int
|
|
562
562
|
position of first detected syn pulse
|
|
563
563
|
|
|
564
|
-
|
|
564
|
+
is_audio_reference : bool (True for ref rec only)
|
|
565
565
|
in multi recorders set-ups, user decides if a sound-only recording
|
|
566
566
|
is the time reference for all other audio recordings. By
|
|
567
567
|
default any video recording is the time reference for other audio,
|
|
@@ -647,7 +647,7 @@ class Recording:
|
|
|
647
647
|
self.decoder = None
|
|
648
648
|
self.probe = None
|
|
649
649
|
self.TicTacCode_channel = None
|
|
650
|
-
self.
|
|
650
|
+
self.is_audio_reference = False
|
|
651
651
|
self.device_relative_speed = 1.0
|
|
652
652
|
# self.valid_sound = None
|
|
653
653
|
self.final_synced_file = None
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tictacsync
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.2.0b0
|
|
4
|
+
Summary: commands for syncing audio video recordings
|
|
5
5
|
Home-page: https://tictacsync.org/
|
|
6
6
|
Author: Raymond Lutz
|
|
7
7
|
Author-email: lutzrayblog@mac.com
|
|
8
|
-
Classifier: Development Status ::
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
9
|
Classifier: Environment :: Console
|
|
10
10
|
Classifier: Intended Audience :: End Users/Desktop
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -68,7 +68,7 @@ Then pip install the syncing program:
|
|
|
68
68
|
This should install python dependencies _and_ the `tictacsync` command.
|
|
69
69
|
## Usage
|
|
70
70
|
|
|
71
|
-
Download multiple sample files [here](https://nuage.lutz.quebec/s/
|
|
71
|
+
Download multiple sample files [here](https://nuage.lutz.quebec/s/4jw4xgqysLPS8EQ/download/dailies1_3.zip) (700+ MB, sorry) unzip and run:
|
|
72
72
|
|
|
73
73
|
> tictacsync dailies/loose
|
|
74
74
|
The program `tictacsync` will recursively scan the directory given as argument, find all audio that coincide with any video and merge them into a subfolder named `SyncedMedia`. When the argument is an unique media file (not a directory), no syncing will occur but the decoded starting time will be printed to stdout:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
tictacsync/LTCcheck.py,sha256=IEfpB_ZajWuRTWtqji0H-B2g7GQvWmGVjfT0Icumv7o,15704
|
|
2
|
+
tictacsync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
tictacsync/device_scanner.py,sha256=ZF4ufRQGUv-6zMFW4fzNZpcFYGr8uUPKRK6jM9_b-P4,36435
|
|
4
|
+
tictacsync/entry.py,sha256=xwqziTH1M1m1-6ZUOVO_B7xht9zRZ22G_6ITBtRsEXE,15911
|
|
5
|
+
tictacsync/mamconf.py,sha256=FCgwsAadFzrhEUHa7IFSA0nBJV1SyKK55iSTAFR5Nwc,6974
|
|
6
|
+
tictacsync/mamsync.py,sha256=2XPhlw2P6IBUoNFUjBhpV4eKP3JqD501zy0iZFXXEjo,16696
|
|
7
|
+
tictacsync/multi2polywav.py,sha256=78W5yzKBfWy4nmD837VKwmcHAUZm10zRNe8ARUBJWCI,7439
|
|
8
|
+
tictacsync/newmix.py,sha256=-zDxr6_O-rjyo1QfgktvHgwqy_un07eFI4zKi8nygIQ,19188
|
|
9
|
+
tictacsync/remergemix.py,sha256=bRyi1hyNcyM1rTkHh8DmSsIQjYpwPprxSyyVipnxz30,9909
|
|
10
|
+
tictacsync/remrgmx.py,sha256=FxaAo5qqynpj6O56ekQGD31YP6X2g-kEdwVpHSCoh4Q,4265
|
|
11
|
+
tictacsync/synciso.py,sha256=XmUcdUF9rl4VdCm7XW4PeYWYWM0vgAY9dC2hapoul9g,4821
|
|
12
|
+
tictacsync/timeline.py,sha256=wcj3n5nAWavJlrZ5Ia-WFmdI2lflU8V1uL13yhrUI7s,75836
|
|
13
|
+
tictacsync/yaltc.py,sha256=1XlOmdz-8ZUKF97A30MEkIA0F5oThqDgWPV8Ik3CHn4,53179
|
|
14
|
+
tictacsync-1.2.0b0.dist-info/LICENSE,sha256=ZAOPXLh1zlQAnhHUd7oLslKM01YZ5UiAu3STYjwIxck,1068
|
|
15
|
+
tictacsync-1.2.0b0.dist-info/METADATA,sha256=SzpJguMsyz9ZRg6uhP7Csw-oa2URSuCNKjj4kWVj66E,5694
|
|
16
|
+
tictacsync-1.2.0b0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
17
|
+
tictacsync-1.2.0b0.dist-info/entry_points.txt,sha256=EZrwgJ0nlXDdVUDcMEijMnha5lb1YCkkg4DY9iz97BE,199
|
|
18
|
+
tictacsync-1.2.0b0.dist-info/top_level.txt,sha256=eaCWG-BsYTRR-gLTJbK4RfcaXajr0gjQ6wG97MkGRrg,11
|
|
19
|
+
tictacsync-1.2.0b0.dist-info/RECORD,,
|
|
@@ -1,18 +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=GtAlL1pKj32S-I7Uo2fCi5pWRNNYJ2mmRkKPPEdV76A,37611
|
|
4
|
-
tictacsync/entry.py,sha256=7qrPmxW0cwK2k4OWWkL9nOoCgww6aiYNdZDKKPUBNLE,15936
|
|
5
|
-
tictacsync/mamsync.py,sha256=v8krJ0OSgh9WkdAZa9vFrKpEKSw9cMb5SBSC1rrCbYs,20005
|
|
6
|
-
tictacsync/multi2polywav.py,sha256=Tt1xWfvQtuAi3aAVcXPDRu9ZGgDk2gmYyCRBSi6pTgk,7296
|
|
7
|
-
tictacsync/newmix.py,sha256=HB5lThhSr1oVtUyIordaB-lwAxm4bbuijRr-MBdZWhA,13161
|
|
8
|
-
tictacsync/remergemix.py,sha256=bRyi1hyNcyM1rTkHh8DmSsIQjYpwPprxSyyVipnxz30,9909
|
|
9
|
-
tictacsync/remrgmx.py,sha256=FxaAo5qqynpj6O56ekQGD31YP6X2g-kEdwVpHSCoh4Q,4265
|
|
10
|
-
tictacsync/synciso.py,sha256=XmUcdUF9rl4VdCm7XW4PeYWYWM0vgAY9dC2hapoul9g,4821
|
|
11
|
-
tictacsync/timeline.py,sha256=aMu1ntVrpFtH1YfyIgp80k7DT2RFo5B0E-BlMWE8wAs,72723
|
|
12
|
-
tictacsync/yaltc.py,sha256=xbMucI19UJKrEvIzyfpOsi3piSWzqM1gKgooeT9DV8g,53167
|
|
13
|
-
tictacsync-1.0.2a0.dist-info/LICENSE,sha256=ZAOPXLh1zlQAnhHUd7oLslKM01YZ5UiAu3STYjwIxck,1068
|
|
14
|
-
tictacsync-1.0.2a0.dist-info/METADATA,sha256=pkMWne2OEJ_m4gxeOXxpF2ww_0SXqTT43z4X4OUmJyo,5673
|
|
15
|
-
tictacsync-1.0.2a0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
16
|
-
tictacsync-1.0.2a0.dist-info/entry_points.txt,sha256=bMsk7T_7fwCtAOUbFyvECvHOzCJb2fmWjkUKQTkwbsc,131
|
|
17
|
-
tictacsync-1.0.2a0.dist-info/top_level.txt,sha256=eaCWG-BsYTRR-gLTJbK4RfcaXajr0gjQ6wG97MkGRrg,11
|
|
18
|
-
tictacsync-1.0.2a0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|