tictacsync 1.1.0a0__py3-none-any.whl → 1.3.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.

@@ -3,8 +3,6 @@
3
3
  # while inotifywait --recursive -e close_write . ; do python entry.py tests/multi2/; done
4
4
  # above for linux
5
5
 
6
- TRACKSFILE = 'tracks.txt'
7
- SILENT_TRACK_TOKENS = '-0n'
8
6
 
9
7
  av_file_extensions = \
10
8
  """webm mkv flv flv vob ogv ogg drc gif gifv mng avi MTS M2TS TS mov qt
@@ -40,10 +38,12 @@ try:
40
38
  from . import multi2polywav
41
39
  from . import mamsync
42
40
  from . import mamconf
41
+ from . import yaltc
43
42
  except:
44
43
  import multi2polywav
45
44
  import mamsync
46
45
  import mamconf
46
+ import yaltc
47
47
 
48
48
  MCCDIR = 'SyncedMulticamClips'
49
49
  SYNCEDFOLDER = 'SyncedMedia'
@@ -64,10 +64,9 @@ def print_grby(grby):
64
64
  print('\ngrouped by %s:'%key)
65
65
  for e in keylist:
66
66
  print(' ', e)
67
-
68
67
  @dataclass
69
68
  class Tracks:
70
- # track numbers start at 1 for first track (as needed by sox)
69
+ # track numbers start at 1 for first track (as needed by sox,1 Based Index)
71
70
  ttc: int # track number of TicTacCode signal
72
71
  unused: list # of unused tracks
73
72
  stereomics: list # of stereo mics track tuples (Lchan#, Rchan#)
@@ -75,7 +74,9 @@ class Tracks:
75
74
  others: list #of all other tags: (tag, track#) tuples
76
75
  rawtrx: list # list of strings read from file
77
76
  error_msg: str # 'None' if none
78
- lag_values: list # list of lag in ms, entry is None if not specified.
77
+ lag_values: list # list of lags in ms, entry is None if not specified.
78
+ # UTC_timestamp: str # to the nearest minute ISO 8601 date and time e.g.: "2007-04-05T14:30Z"
79
+
79
80
 
80
81
  @dataclass
81
82
  class Device:
@@ -216,10 +217,8 @@ class Scanner:
216
217
  top_directory : string
217
218
  String of path where to start searching for media files.
218
219
 
219
- # top_dir_has_multicam : bool
220
- # If top dir is folder structures AND more than on cam
221
-
222
- found_media_files: list of Media objects
220
+ found_media_files: list of dataclass Media instances encapsulating
221
+ the pathlibPath and the device (of Device dataclass).
223
222
  """
224
223
 
225
224
  def __init__(
@@ -351,17 +350,19 @@ class Scanner:
351
350
  logger.debug('Scanner.found_media_files = %s'%pformat(self.found_media_files))
352
351
  if self.input_structure == 'ordered':
353
352
  self._confirm_folders_have_same_device()
354
- # self._use_folder_as_device_name()
355
- devices = set([m.device for m in self.found_media_files])
356
- audio_devices = [d for d in devices if d.dev_type == 'REC']
357
- for recorder in audio_devices:
358
- # process tracks.txt for audio recorders
359
- recorder.tracks = self._get_tracks_from_file(recorder)
360
- # logging only:
361
- if recorder.tracks:
362
- if not all([lv == None for lv in recorder.tracks.lag_values]):
363
- logger.debug('%s has lag_values %s'%(
364
- recorder.name, recorder.tracks.lag_values))
353
+ # [TODO] move this where Recordings have been TCed for any tracks timestamps
354
+ # <begin>
355
+ # devices = set([m.device for m in self.found_media_files])
356
+ # audio_devices = [d for d in devices if d.dev_type == 'REC']
357
+ # for recorder in audio_devices:
358
+ # # process tracks.txt for audio recorders
359
+ # recorder.tracks = self._get_tracks_from_file(recorder)
360
+ # # logging only:
361
+ # if recorder.tracks:
362
+ # if not all([lv == None for lv in recorder.tracks.lag_values]):
363
+ # logger.debug('%s has lag_values %s'%(
364
+ # recorder.name, recorder.tracks.lag_values))
365
+ # </end>
365
366
  # check if device is in fact two parents up (and parent = ROLLxx):
366
367
  # Group media by folder 2up and verify all media for each
367
368
  # group have same device.
@@ -388,7 +389,6 @@ class Scanner:
388
389
  for m in self.found_media_files:
389
390
  if m.device.UID == UID:
390
391
  m.device.name = name
391
- # logger.debug('renamed device media: %s'%pformat(self.found_media_files))
392
392
  no_name_devices = [m.device for m in self.found_media_files
393
393
  if not m.device.name]
394
394
  # possible if self.input_structure == 'loose'
@@ -421,50 +421,6 @@ class Scanner:
421
421
  if not any(dev_is_REC): # no audio recordings!
422
422
  print('\rNo audio recording found, nothing to sync, bye.')
423
423
  sys.exit(0)
424
- # print('devices 312 %s'%set([m.device for m in self.found_media_files]))
425
-
426
- def _get_tracks_from_file(self, device) -> Tracks:
427
- """
428
- Look for eventual track names in TRACKSFILE file, stored inside the
429
- recorder folder alongside the audio files. If there, returns a Tracks
430
- object, if not returns None.
431
- """
432
- source_audio_folder = device.folder
433
- tracks_file = source_audio_folder/TRACKSFILE
434
- track_names = False
435
- a_recording = [m for m in self.found_media_files
436
- if m.device == device][0]
437
- logger.debug('a_recording for device %s : %s'%(device, a_recording))
438
- nchan = sox.file_info.channels(str(a_recording.path))
439
- if os.path.isfile(tracks_file):
440
- logger.debug('found file: %s'%(TRACKSFILE))
441
- tracks = self._parse_track_values(tracks_file)
442
- if tracks.error_msg:
443
- print('\nError parsing [gold1]%s[/gold1] file: %s, quitting.\n'%
444
- (tracks_file, tracks.error_msg))
445
- sys.exit(1)
446
- logger.debug('parsed tracks %s'%tracks)
447
- ntracks = 2*len(tracks.stereomics)
448
- ntracks += len(tracks.mix)
449
- ntracks += len(tracks.unused)
450
- ntracks += len(tracks.others)
451
- ntracks += 1 # for ttc track
452
- logger.debug(' n chan: %i n tracks file: %i'%(nchan, ntracks))
453
- if ntracks != nchan:
454
- print('\nError parsing %s content'%tracks_file)
455
- print('incoherent number of tracks, %i vs %i quitting\n'%
456
- (nchan, ntracks))
457
- sys.exit(1)
458
- err_msg = tracks.error_msg
459
- if err_msg != None:
460
- print('\nError, quitting: in file %s, %s'%(tracks_file, err_msg))
461
- raise Exception
462
- else:
463
- logger.debug('tracks object%s'%tracks)
464
- return tracks
465
- else:
466
- logger.debug('no tracks.txt file found')
467
- return None
468
424
 
469
425
  def _confirm_folders_have_same_device(self):
470
426
  """
@@ -602,184 +558,6 @@ class Scanner:
602
558
  logger.debug('n_CAM_folder %i'%n_CAM_folder)
603
559
  return
604
560
 
605
- def _parse_track_values(self, tracks_file) -> Tracks:
606
- """
607
- read track names for naming separated ISOs
608
- from tracks_file.
609
-
610
- tokens looked for: mix; mix L; mix R; 0 and TC
611
-
612
- repeating "mic*" pattern signals a stereo track
613
- and entries will correspondingly panned into
614
- a stero mix named mixL.wav and mixL.wav
615
-
616
- mic L # spaces are ignored |
617
- mic R | stereo pair
618
- micB L
619
- micB R
620
-
621
- Returns: a Tracks instance:
622
- # track numbers start at 1 for first track (as needed by sox)
623
- ttc: int # track number of TicTacCode signal
624
- unused: list # of unused tracks
625
- stereomics: list # of stereo mics track tuples (Lchan#, Rchan#)
626
- mix: list # of mixed tracks, if a pair, order is L than R
627
- others: list #of all other tags: (tag, track#) tuples
628
- rawtrx: list # list of strings read from file
629
- error_msg: str # 'None' if none
630
- e.g.: Tracks( ttc=2,
631
- unused=[],
632
- stereomics=[('mic', (4, 3)), ('mic2', (6, 5))],
633
- mix=[], others=[('clics', 1)],
634
- rawtrx=['clics', 'TC', 'micL', 'micR', 'mic2L;1000', 'mic2R;1000', 'mixL', 'mixR'],
635
- error_msg=None, lag_values=[None, None, None, None, '1000', '1000', None, None])
636
- """
637
- def _WOspace(chaine):
638
- ch = [c for c in chaine if c != ' ']
639
- return ''.join(ch)
640
- # def _WO_LR(chaine):
641
- # ch = [c for c in chaine if c not in 'LR']
642
- # return ''.join(ch)
643
- # def _seemsStereoMic(tag):
644
- # # is tag likely a stereo pair tag?
645
- # # should starts with 'mic' and ends with 'l' or 'r'
646
- # return tag[1:4]=='mic' and tag[0] in 'lr'
647
- file=open(tracks_file,"r")
648
- whole_txt = file.read()
649
- logger.debug('file %s all_lines:\n%s'%(tracks_file, whole_txt))
650
- tracks_lines_wspaces = [l.split('#')[0] for l in whole_txt.splitlines()
651
- if len(l) > 0 ]
652
- tracks_lines = [_WOspace(l) for l in tracks_lines_wspaces if len(l) > 0 ]
653
- rawtrx = [l for l in tracks_lines_wspaces if len(l) > 0 ]
654
- # add index with tuples, starting at 1
655
- logger.debug('tracks_lines whole: %s'%tracks_lines)
656
- def _detach_lag_value(line):
657
- # look for ";number" ending any line, returns a two-list
658
- splt = line.split(';')
659
- if len(splt) == 1:
660
- splt += [None]
661
- if len(splt) != 2:
662
- # error
663
- print('\nText error in %s, line %s has too many ";"'%(
664
- tracks_file, line))
665
- return splt
666
- tracks_lines, lag_values = zip(*[_detach_lag_value(l) for l
667
- in tracks_lines])
668
- lag_values = [e for e in lag_values] # from tuple to list
669
- # logger.debug('tracks_lines WO lag: %s'%tracks_lines)
670
- tracks_lines = [l.lower() for l in tracks_lines]
671
- logger.debug('tracks_lines lower case: %s'%tracks_lines)
672
- # print(lag_values)
673
- logger.debug('lag_values: %s'%lag_values)
674
- tagsWOl_r = [e[:-1] for e in tracks_lines] # skip last letter
675
- logger.debug('tags WO LR letter %s'%tagsWOl_r)
676
- # find idx of start of pairs
677
- # ['clics', 'TC', 'micL', 'micR', 'mic2L', 'mic2R', 'mixL', 'mixR']
678
- def _micOrmix(a,b):
679
- # test if same and mic mic or mix mix
680
- if len(a) == 0:
681
- return False
682
- return (a == b) and (a in 'micmix')
683
- pair_idx_start =[i for i, same in enumerate([_micOrmix(a,b) for a,b
684
- in zip(tagsWOl_r,tagsWOl_r[1:])]) if same]
685
- logger.debug('pair_idx_start %s'%pair_idx_start)
686
- def LR_OK(idx):
687
- # in tracks_lines, check if idx ends a LR pair
688
- # delays, if any, have been removed
689
- a = tracks_lines[idx][-1]
690
- b = tracks_lines[idx+1][-1]
691
- return a+b in ['lr', 'rl']
692
- LR_OKs = [LR_OK(p) for p in pair_idx_start]
693
- logger.debug('LR_OKs %s'%LR_OKs)
694
- if not all(LR_OKs):
695
- print('\nError in %s'%tracks_file)
696
- print('Some tracks are paired but not L and R: %s'%rawtrx)
697
- print('quitting...')
698
- quit()
699
- complete_pairs_idx = pair_idx_start + [i + 1 for i in pair_idx_start]
700
- singles = set(range(len(tracks_lines))).difference(complete_pairs_idx)
701
- logger.debug('complete_pairs_idx %s'%complete_pairs_idx)
702
- logger.debug('singles %s'%singles)
703
- singles_tag = [tracks_lines[i] for i in singles]
704
- logger.debug('singles_tag %s'%singles_tag)
705
- n_tc_token = sum([t == 'tc' for t in singles_tag])
706
- logger.debug('n tc tags %s'%n_tc_token)
707
- if n_tc_token == 0:
708
- print('\nError in %s'%tracks_file)
709
- print('with %s'%rawtrx)
710
- print('no TC track found, quitting...')
711
- quit()
712
- if n_tc_token > 1:
713
- print('\nError in %s'%tracks_file)
714
- print('with %s'%rawtrx)
715
- print('more than one TC track, quitting...')
716
- quit()
717
- output_tracks = Tracks(None,[],[],[],[],rawtrx,None,[])
718
- output_tracks.ttc = tracks_lines.index('tc') + 1 # 1st = 1
719
- logger.debug('ttc_chan %s'%output_tracks.ttc)
720
- zeroed = [i+1 for i, t in enumerate(tracks_lines) if t == '0']
721
- logger.debug('zeroed %s'%zeroed)
722
- output_tracks.unused = zeroed
723
- output_tracks.others = [(st, tracks_lines.index(st)+1) for st
724
- in singles_tag if st not
725
- in ['tc', 'monomix', '0']]
726
- logger.debug('output_tracks.others %s'%output_tracks.others)
727
- # check for monomix
728
- if 'monomix' in tracks_lines:
729
- output_tracks.mix = [tracks_lines.index('monomix')+1]
730
- else:
731
- output_tracks.mix = []
732
- # check for stereo mix
733
- def _findLR(i_first):
734
- # returns L R indexes (+1 for sox non zero based indexing)
735
- i_2nd = i_first + 1
736
- a = tracks_lines[i_first][-1] # l|r at end
737
- b = tracks_lines[i_2nd][-1] # l|r at end
738
- if a == 'l':
739
- if b == 'r':
740
- # sequence is mixL mixR
741
- return i_first+1, i_2nd+1
742
- else:
743
- print('\nError in %s'%tracks_file)
744
- print('with %s'%rawtrx)
745
- print('can not find stereo mix')
746
- quit()
747
- elif a == 'r':
748
- if b == 'l':
749
- # sequence is mixR mixL
750
- return i_2nd+1, i_first+1
751
- else:
752
- print('\nError in %s'%tracks_file)
753
- print('with %s'%rawtrx)
754
- print('can not find stereo mix')
755
- quit()
756
- logger.debug('for now, output_tracks.mix %s'%output_tracks.mix)
757
- mix_pair = [p for p in pair_idx_start if tracks_lines[p][1:] == 'mix']
758
- if len(mix_pair) == 1:
759
- # one stereo mix, remove it from other pairs
760
- i = mix_pair[0]
761
- LR_pair = _findLR(i)
762
- logger.debug('LR_pair %s'%str(LR_pair))
763
- pair_idx_start.remove(i)
764
- # consistency check
765
- if output_tracks.mix != []:
766
- # already found a mono mix above!
767
- print('\nError in %s'%tracks_file)
768
- print('with %s'%rawtrx)
769
- print('found a mono mix AND a stereo mix')
770
- quit()
771
- output_tracks.mix = LR_pair
772
- logger.debug('finally, output_tracks.mix %s'%str(output_tracks.mix))
773
- logger.debug('remaining pairs %s'%pair_idx_start)
774
- # those are stereo pairs
775
- stereo_pairs = []
776
- for first_in_pair in pair_idx_start:
777
- suffix = tracks_lines[first_in_pair][:-1]
778
- stereo_pairs.append((suffix, _findLR(first_in_pair)))
779
- logger.debug('stereo_pairs %s'%stereo_pairs)
780
- output_tracks.stereomics = stereo_pairs
781
- logger.debug('finished: %s'%output_tracks)
782
- return output_tracks
783
561
 
784
562
 
785
563
 
tictacsync/entry.py CHANGED
@@ -84,7 +84,11 @@ def process_lag_adjustement(media_object):
84
84
  media_object.path.replace(backup_name)
85
85
  logger.debug('channels %s'%channels)
86
86
  def _trim(lag, chan_file):
87
- # for lag
87
+ # counter intuitive I know. if a file lags, there's too
88
+ # much samples at the start:
89
+ # ..................|.........
90
+ # .......................|....
91
+ # ^ play head ->
88
92
  if lag == None:
89
93
  return chan_file
90
94
  else:
@@ -110,7 +114,7 @@ def main():
110
114
  parser.add_argument(
111
115
  "path",
112
116
  type=str,
113
- nargs='*',
117
+ nargs=1,
114
118
  help="directory_name or media_file"
115
119
  )
116
120
  # parser.add_argument("directory", nargs="?", help="path of media directory")
@@ -165,14 +169,10 @@ def main():
165
169
  if args.verbose_output:
166
170
  logger.add(sys.stderr, level="DEBUG")
167
171
 
168
- # logger.add(sys.stdout, filter=lambda r: r["function"] == "_write_ISOs")
169
- logger.add(sys.stdout, filter=lambda r: r["function"] == "_build_and_write_audio")
170
- #
171
- # logger.add(sys.stdout, filter="__main__")
172
- # logger.add(sys.stdout, filter="yaltc")
173
-
174
172
  # logger.add(sys.stdout, filter=lambda r: r["function"] == "move_multicam_to_dir")
175
- # logger.add(sys.stdout, filter=lambda r: r["function"] == "_dev_type_for_name")
173
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "_build_audio_and_write_video")
174
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "main")
175
+ # logger.add(sys.stdout, filter=lambda r: r["function"] == "_build_from_tracks_txt")
176
176
  # logger.add(sys.stdout, filter=lambda r: r["function"] == "scan_media_and_build_devices_UID")
177
177
 
178
178
  top_dir = args.path[0]
@@ -241,7 +241,6 @@ def main():
241
241
  print('resulting in undefined results: quitting...')
242
242
  quit()
243
243
  print()
244
- # recordings, rec_with_TTC = process_files(scanner.found_media_files, args)
245
244
  recordings = [yaltc.Recording(m, do_plots=args.plotting) for m
246
245
  in scanner.found_media_files]
247
246
  recordings_with_time = [
@@ -249,6 +248,11 @@ def main():
249
248
  for rec in recordings
250
249
  if rec.get_start_time()
251
250
  ]
251
+ [r.load_track_info() for r in recordings_with_time if r.is_audio()]
252
+ for r in recordings:
253
+ # print(f'{r} device: #{id(r.device):x}')
254
+ logger.debug(f'{r} \nDevice instance id: #{id(r.device):x}')
255
+ logger.debug(f'device content: {r.device}')
252
256
  if audio_REC_only:
253
257
  for rec in recordings:
254
258
  # print(rec, rec.device == ref_device)