tictacsync 0.3a2__tar.gz → 0.3a4__tar.gz
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-0.3a2/tictacsync.egg-info → tictacsync-0.3a4}/PKG-INFO +1 -1
- {tictacsync-0.3a2 → tictacsync-0.3a4}/setup.py +1 -1
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/device_scanner.py +19 -18
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/entry.py +2 -2
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/timeline.py +88 -39
- {tictacsync-0.3a2 → tictacsync-0.3a4/tictacsync.egg-info}/PKG-INFO +1 -1
- {tictacsync-0.3a2 → tictacsync-0.3a4}/LICENSE +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/README.md +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/setup.cfg +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/__init__.py +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/multi2polywav.py +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/remergemix.py +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync/yaltc.py +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync.egg-info/SOURCES.txt +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync.egg-info/dependency_links.txt +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync.egg-info/entry_points.txt +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync.egg-info/not-zip-safe +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync.egg-info/requires.txt +0 -0
- {tictacsync-0.3a2 → tictacsync-0.3a4}/tictacsync.egg-info/top_level.txt +0 -0
|
@@ -31,7 +31,7 @@ setup(
|
|
|
31
31
|
'multi2polywav = tictacsync.multi2polywav:main',
|
|
32
32
|
]
|
|
33
33
|
},
|
|
34
|
-
version = '0.
|
|
34
|
+
version = '0.3a4',
|
|
35
35
|
description = "command for syncing audio video recordings",
|
|
36
36
|
long_description_content_type='text/markdown',
|
|
37
37
|
long_description = long_descr,
|
|
@@ -230,21 +230,6 @@ class Scanner:
|
|
|
230
230
|
Sets Scanner.input_structure = 'loose'|'folder_is_device'
|
|
231
231
|
|
|
232
232
|
"""
|
|
233
|
-
visible = [f for f in listdir(self.top_directory) if f[0] != '.']
|
|
234
|
-
logger.debug('visible: %s'%visible)
|
|
235
|
-
are_dir = all([isdir(join(self.top_directory, f)) for f in visible])
|
|
236
|
-
are_files = all([isfile(join(self.top_directory, f)) for f in visible])
|
|
237
|
-
logger.debug('dir: %s'%[isdir(join(self.top_directory, f)) for f
|
|
238
|
-
in visible])
|
|
239
|
-
if are_dir:
|
|
240
|
-
visible = [e for e in visible if e != 'SyncedMedia']
|
|
241
|
-
print('\nAssuming those are device folders: ',end='')
|
|
242
|
-
[print('[gold1]%s[/gold1]'%f, end=', ') for f in visible[:-1]]
|
|
243
|
-
print('[gold1]%s[/gold1].'%visible[-1])
|
|
244
|
-
self.input_structure = 'folder_is_device'
|
|
245
|
-
else: # are_files
|
|
246
|
-
self.input_structure = 'loose'
|
|
247
|
-
self.top_dir_has_multicam = False
|
|
248
233
|
files = Path(self.top_directory).rglob('*.*')
|
|
249
234
|
paths = [
|
|
250
235
|
p
|
|
@@ -252,17 +237,33 @@ class Scanner:
|
|
|
252
237
|
if p.suffix[1:] in av_file_extensions
|
|
253
238
|
and 'SyncedMedia' not in p.parts
|
|
254
239
|
]
|
|
240
|
+
logger.debug('found media files %s'%paths)
|
|
241
|
+
parents = [p.parent for p in paths]
|
|
242
|
+
logger.debug('found parents %s'%parents)
|
|
243
|
+
def _list_all_the_same(a_list):
|
|
244
|
+
return a_list.count(a_list[0]) == len(a_list)
|
|
245
|
+
all_parents_are_the_same = _list_all_the_same(parents)
|
|
246
|
+
logger.debug('all_parents_are_the_same %s'%all_parents_are_the_same)
|
|
247
|
+
if all_parents_are_the_same:
|
|
248
|
+
# all media (video + audio) are in a same folder, so this is loose
|
|
249
|
+
self.input_structure = 'loose'
|
|
250
|
+
# for now (TO DO?) 'loose' == no multi-cam
|
|
251
|
+
self.top_dir_has_multicam = False
|
|
252
|
+
else:
|
|
253
|
+
# check later if inside each folder, media have same device,
|
|
254
|
+
# for now, we'll guess structure is 'folder_is_device'
|
|
255
|
+
self.input_structure = 'folder_is_device'
|
|
255
256
|
for p in paths:
|
|
256
257
|
new_media = media_at_path(self.input_structure, p) # dev UID set here
|
|
257
258
|
self.found_media_files.append(new_media)
|
|
258
259
|
# files from devices without UID or name
|
|
259
|
-
def
|
|
260
|
-
|
|
260
|
+
# def _list_all_the_same(l):
|
|
261
|
+
# return all(e == l[0] for e in l)
|
|
261
262
|
def _try_name(medias):
|
|
262
263
|
# return common first strings in filename
|
|
263
264
|
names = [m.path.name for m in medias]
|
|
264
265
|
transposed_names = list(map(list, zip(*names)))
|
|
265
|
-
same = list(map(
|
|
266
|
+
same = list(map(_list_all_the_same, transposed_names))
|
|
266
267
|
try:
|
|
267
268
|
first_diff = same.index(False)
|
|
268
269
|
except:
|
|
@@ -126,8 +126,8 @@ def main():
|
|
|
126
126
|
# logger.add(sys.stdout, filter="__main__")
|
|
127
127
|
# logger.add(sys.stdout, filter="device_scanner")
|
|
128
128
|
# logger.add(sys.stdout, filter="yaltc") _extract_sound_to_merge
|
|
129
|
-
# logger.add(sys.stdout, filter=lambda r: r["function"] == "
|
|
130
|
-
# logger.add(sys.stdout, filter=lambda r: r["function"] == "
|
|
129
|
+
# logger.add(sys.stdout, filter=lambda r: r["function"] == "scan_media_and_build_devices_UID")
|
|
130
|
+
# logger.add(sys.stdout, filter=lambda r: r["function"] == "_sox_multi2mono")
|
|
131
131
|
# logger.add(sys.stdout, filter=lambda r: r["function"] == "_get_mix")
|
|
132
132
|
# logger.add(sys.stdout, filter=lambda r: r["function"] == "_sox_mix")
|
|
133
133
|
top_dir = args.directory[0]
|
|
@@ -66,24 +66,23 @@ def _sox_keep(audio_file, kept_channels) -> tempfile.NamedTemporaryFile:
|
|
|
66
66
|
"""
|
|
67
67
|
Returns a NamedTemporaryFile containing the selected kept_channels
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
eg: 4 channels with TicTacCode_channel at #2
|
|
72
|
-
returns {1: [1], 2: [3], 3: [4]}
|
|
73
|
-
ie the number of channels drops by one and chan 2 is missing
|
|
74
|
-
excluded_channels is a list of Zero Based indexing chan numbers
|
|
75
|
-
|
|
69
|
+
if len(kept_channels) == 1 then it's a mono mix on the specified track
|
|
70
|
+
if len(kept_channels) == 2 then it's a stereo mix on the specified tracks
|
|
76
71
|
"""
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
77
76
|
audio_file = _pathname(audio_file)
|
|
78
77
|
nchan = sox.file_info.channels(audio_file)
|
|
79
78
|
logger.debug('in file of %i chan, have to keep %s'%
|
|
80
79
|
(nchan, kept_channels))
|
|
81
80
|
all_channels = range(1, nchan + 1) # from 1 to nchan included
|
|
82
|
-
#
|
|
83
|
-
#
|
|
81
|
+
# Building dict according to pysox.remix format.
|
|
82
|
+
# https://pysox.readthedocs.io/en/latest/api.html#sox.transform.Transformer.remix
|
|
83
|
+
# eg: {1: [3], 2: [4]} to keep channels 3 & 4
|
|
84
84
|
kept_channels = [[n] for n in kept_channels]
|
|
85
85
|
sox_remix_dict = dict(zip(all_channels, kept_channels))
|
|
86
|
-
# {1: [1], 2: [3], 3: [4]} -> from 4 to 3 chan and chan 2 is dropped
|
|
87
86
|
output_fh = tempfile.NamedTemporaryFile(suffix='.wav', delete=DEL_TEMP)
|
|
88
87
|
out_file = _pathname(output_fh)
|
|
89
88
|
logger.debug('sox in and out files: %s %s'%(audio_file, out_file))
|
|
@@ -159,6 +158,26 @@ def _sox_combine(paths) -> Path:
|
|
|
159
158
|
(merged_duration, nchan))
|
|
160
159
|
return out_file_handle
|
|
161
160
|
|
|
161
|
+
def _sox_multi2mono(multichan_tmpfl) -> tempfile.NamedTemporaryFile:
|
|
162
|
+
# return a mono mix down
|
|
163
|
+
n_chan_input = sox.file_info.channels(_pathname(multichan_tmpfl))
|
|
164
|
+
logger.debug('n chan input: %s'%n_chan_input)
|
|
165
|
+
if n_chan_input == 1: # nothing to mix down
|
|
166
|
+
return multichan_tmpfl
|
|
167
|
+
mono_tpfl = tempfile.NamedTemporaryFile(suffix='.wav',
|
|
168
|
+
delete=DEL_TEMP)
|
|
169
|
+
tfm = sox.Transformer()
|
|
170
|
+
tfm.channels(1)
|
|
171
|
+
status = tfm.build(_pathname(multichan_tmpfl),_pathname(mono_tpfl))
|
|
172
|
+
logger.debug('n chan ouput: %s'%
|
|
173
|
+
sox.file_info.channels(_pathname(mono_tpfl)))
|
|
174
|
+
logger.debug('sox.build status for _sox_multi2mono(): %s'%status)
|
|
175
|
+
if status != True:
|
|
176
|
+
print('Error, sox did not normalize file in _sox_multi2mono()')
|
|
177
|
+
sys.exit(1)
|
|
178
|
+
return mono_tpfl
|
|
179
|
+
|
|
180
|
+
|
|
162
181
|
def _sox_mix(paths:list) -> tempfile.NamedTemporaryFile:
|
|
163
182
|
"""
|
|
164
183
|
mix files referred by the list of Path into a new temporary files passed on return
|
|
@@ -183,6 +202,8 @@ def _sox_mix(paths:list) -> tempfile.NamedTemporaryFile:
|
|
|
183
202
|
cbn.set_input_format(file_type=['wav']*N)
|
|
184
203
|
filenames = [_pathname(p) for p in paths]
|
|
185
204
|
logger.debug('%i files to mix %s'%(N, filenames))
|
|
205
|
+
logger.debug('nchan for each file %s'%[sox.file_info.channels(f) for
|
|
206
|
+
f in filenames])
|
|
186
207
|
mixed_tempf = tempfile.NamedTemporaryFile(suffix='.wav',delete=DEL_TEMP)
|
|
187
208
|
status = cbn.build(filenames,
|
|
188
209
|
_pathname(mixed_tempf),
|
|
@@ -580,35 +601,65 @@ class AudioStitcherVideoMerger:
|
|
|
580
601
|
stereo) mix track, returns a tmpfl containing the corresponding
|
|
581
602
|
tracks. If not, mix all the tracks with sox.
|
|
582
603
|
|
|
604
|
+
If no L-R tracks are declared in tracks.txt, a mono mix is returned;
|
|
605
|
+
If some
|
|
606
|
+
micL micR or mixL mixR
|
|
607
|
+
|
|
583
608
|
"""
|
|
584
|
-
if device.tracks
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
609
|
+
if device.tracks is None:
|
|
610
|
+
logger.debug('no tracks.txt, mixing all')
|
|
611
|
+
return _sox_multi2mono(multichan_tmpfl)
|
|
612
|
+
mix_tracks = device.tracks.mix
|
|
613
|
+
if mix_tracks == []:
|
|
614
|
+
logger.debug('tracks.txt present but no mix trx, mixing all')
|
|
615
|
+
return _sox_multi2mono(multichan_tmpfl)
|
|
616
|
+
# if here, mix exists
|
|
617
|
+
logger.debug('%s has mix %s'%(device.name, mix_tracks))
|
|
618
|
+
logger.debug('device %s'%device)
|
|
619
|
+
if 'ttc' in device.tracks.rawtrx:
|
|
620
|
+
sox_TTC_chan = device.tracks.rawtrx.index('ttc')
|
|
621
|
+
elif 'tc' in device.tracks.rawtrx:
|
|
622
|
+
sox_TTC_chan = device.tracks.rawtrx.index('tc')
|
|
623
|
+
else:
|
|
624
|
+
print('Error: no tc or ttc tag in track.txt')
|
|
625
|
+
sys.exit(1)
|
|
626
|
+
sox_TTC_chan += 1 # sox Not ZBIDX
|
|
627
|
+
logger.debug('TTC chan %i'%sox_TTC_chan)
|
|
628
|
+
# redo indexing since tracks.txt numbers refere to complete
|
|
629
|
+
# files and here audio file had TTC and muted channels
|
|
630
|
+
# removed:
|
|
631
|
+
if len(mix_tracks) == 2: # two tracks to shift
|
|
632
|
+
mixL_chan, mixR_chan = mix_tracks
|
|
633
|
+
# shifting left chan if necessary
|
|
634
|
+
shift = 0
|
|
635
|
+
if mixL_chan > sox_TTC_chan:
|
|
636
|
+
shift += 1
|
|
637
|
+
for unused_tr in device.tracks.unused:
|
|
638
|
+
if mixL_chan > unused_tr:
|
|
639
|
+
shift += 1
|
|
640
|
+
mixL_chan -= shift
|
|
641
|
+
# shifting right chan if necessary
|
|
642
|
+
shift = 0
|
|
643
|
+
if mixR_chan > sox_TTC_chan:
|
|
644
|
+
shift += 1
|
|
645
|
+
for unused_tr in device.tracks.unused:
|
|
646
|
+
if mixR_chan > unused_tr:
|
|
647
|
+
shift += 1
|
|
648
|
+
mixR_chan -= shift
|
|
649
|
+
mix_tracks = [mixL_chan, mixR_chan]
|
|
650
|
+
else: # mono, one track to shift
|
|
651
|
+
monomix_chan = mix_tracks[0]
|
|
652
|
+
shift = 0
|
|
653
|
+
if monomix_chan > sox_TTC_chan:
|
|
654
|
+
shift += 1
|
|
655
|
+
for unused_tr in device.tracks.unused:
|
|
656
|
+
if monomix_chan > unused_tr:
|
|
603
657
|
shift += 1
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return _sox_keep(multichan_tmpfl, mix_tracks)
|
|
610
|
-
else: # no tracks declaration, mix programmatically
|
|
611
|
-
return _sox_mix(_split_channels(multichan_tmpfl))
|
|
658
|
+
monomix_chan -= shift
|
|
659
|
+
mix_tracks = [monomix_chan]
|
|
660
|
+
logger.debug('new mix_tracks: %s'%mix_tracks)
|
|
661
|
+
return _sox_keep(multichan_tmpfl, mix_tracks)
|
|
662
|
+
|
|
612
663
|
|
|
613
664
|
def build_audio_and_write_video(self, top_dir, output_dir,
|
|
614
665
|
write_multicam_structure,
|
|
@@ -690,8 +741,6 @@ class AudioStitcherVideoMerger:
|
|
|
690
741
|
logger.debug('there are %i dev mixes'%len(mixes))
|
|
691
742
|
logger.debug('mixes %s'%mixes)
|
|
692
743
|
dev_mixes_mix = _sox_mix(mixes)
|
|
693
|
-
# dev_mixes_mix = _sox_combine([audio for _, audio
|
|
694
|
-
# in merged_audio_files_by_device]) # all devices
|
|
695
744
|
logger.debug('will merge with %s'%(_pathname(dev_mixes_mix)))
|
|
696
745
|
self.ref_recording.synced_audio = dev_mixes_mix
|
|
697
746
|
logger.debug('dev_mixes_mix n chan: %i'%
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|