tictacsync 0.97a0__py3-none-any.whl → 0.98a0__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.

@@ -6,7 +6,6 @@
6
6
  TRACKSFN = 'tracks.txt'
7
7
  SILENT_TRACK_TOKENS = '-0n'
8
8
 
9
-
10
9
  av_file_extensions = \
11
10
  """webm mkv flv flv vob ogv ogg drc gif gifv mng avi MTS M2TS TS mov qt
12
11
  wmv yuv rm rmvb viv asf amv mp4 m4p m4v mpg mp2 mpeg mpe mpv mpg mpeg m2v
@@ -40,6 +39,8 @@ try:
40
39
  except:
41
40
  import multi2polywav
42
41
 
42
+ MCCDIR = 'SyncedMulticamClips'
43
+ SYNCEDFOLDER = 'SyncedMedia'
43
44
 
44
45
  # utility for accessing pathnames
45
46
  def _pathname(tempfile_or_path):
@@ -73,7 +74,7 @@ class Tracks:
73
74
  @dataclass
74
75
  class Device:
75
76
  UID: int
76
- folder: Path
77
+ folder: Path # media's parent folder
77
78
  name: str
78
79
  dev_type: str # CAM or REC
79
80
  n_chan: int
@@ -97,7 +98,7 @@ def media_at_path(input_structure, p):
97
98
  dev_UID, dt, sf = get_device_ffprobe_UID(p)
98
99
  dev_name = None
99
100
  logger.debug('ffprobe dev_UID:%s dt:%s sf:%s'%(dev_UID, dt,sf))
100
- if input_structure == 'folder_is_device':
101
+ if input_structure == 'ordered':
101
102
  dev_name = p.parent.name
102
103
  if dev_UID is None:
103
104
  dev_UID = hash(dev_name)
@@ -132,7 +133,7 @@ def get_device_ffprobe_UID(file):
132
133
  """
133
134
  Tries to find an unique hash integer identifying the device that produced
134
135
  the file based on the string inside ffprobe metadata without any
135
- reference to date nor length nor time. Find out with ffprobe the type
136
+ reference to date, location, length or time. Find out with ffprobe the type
136
137
  of device: CAM or REC for videocamera or audio recorder.
137
138
 
138
139
  Device UIDs are used later in Montage._get_concatenated_audiofile_for()
@@ -192,7 +193,7 @@ def get_device_ffprobe_UID(file):
192
193
  class Scanner:
193
194
  """
194
195
  Class that encapsulates scanning of the directory given as CLI argument.
195
- Depending on the input_structure detected (loose|folder_is_device), enforce
196
+ Depending on the input_structure detected (loose|ordered), enforce
196
197
  some directory structure (or not). Build a list of media files found and a
197
198
  try to indentify uniquely the device used to record each media file.
198
199
 
@@ -202,15 +203,15 @@ class Scanner:
202
203
  Any of:
203
204
  'loose'
204
205
  all files audio + video are in top folder
205
- 'folder_is_device'
206
+ 'ordered'
206
207
  eg for multicam on Davinci Resolve
207
208
  input_structure is set in scan_media_and_build_devices_UID()
208
209
 
209
210
  top_directory : string
210
211
  String of path where to start searching for media files.
211
212
 
212
- top_dir_has_multicam : bool
213
- If top dir is folder structures AND more than on cam
213
+ # top_dir_has_multicam : bool
214
+ # If top dir is folder structures AND more than on cam
214
215
 
215
216
  found_media_files: list of Media objects
216
217
  """
@@ -243,6 +244,15 @@ class Scanner:
243
244
  CAMs = [d for d in devices if d.dev_type == 'CAM']
244
245
  return len(set(CAMs))
245
246
 
247
+ def get_device_in_path(self, a_media):
248
+ """
249
+ Return a device name taken from folders in path of a_media if and only
250
+ if all media files below it are from the same device. Goes up max two
251
+ levels from media; e.g., in /FOLDER2/FOLDER1/DSC00234.MOV will test up
252
+ to FOLDER2 as candidate.
253
+ """
254
+
255
+
246
256
  def scan_media_and_build_devices_UID(self, recursive=True):
247
257
  """
248
258
  Scans Scanner.top_directory recursively for files with known audio-video
@@ -256,7 +266,7 @@ class Scanner:
256
266
 
257
267
  Populates Scanner.found_media_files, a list of Media objects
258
268
 
259
- Sets Scanner.input_structure = 'loose'|'folder_is_device'
269
+ Sets Scanner.input_structure = 'loose'|'ordered'
260
270
 
261
271
  """
262
272
  files = Path(self.top_directory).rglob('*.*')
@@ -264,81 +274,137 @@ class Scanner:
264
274
  p
265
275
  for p in files
266
276
  if p.suffix[1:] in av_file_extensions
267
- and 'SyncedMedia' not in p.parts
277
+ and SYNCEDFOLDER not in p.parts # SyncedMedia
278
+ and MCCDIR not in p.parts # SyncedMulticamClips
268
279
  ]
269
280
  logger.debug('found media files %s'%paths)
270
281
  parents = [p.parent for p in paths]
271
- logger.debug('found parents %s'%parents)
272
- def _list_all_the_same(a_list):
273
- return a_list.count(a_list[0]) == len(a_list)
274
- all_parents_are_the_same = _list_all_the_same(parents)
275
- logger.debug('all_parents_are_the_same %s'%all_parents_are_the_same)
276
- if all_parents_are_the_same:
282
+ logger.debug('found parents %s'%pformat(parents))
283
+ # True if all elements are identical
284
+ AV_files_have_same_parent = parents.count(parents[0]) == len(parents)
285
+ logger.debug('AV_files_have_same_parent %s'%AV_files_have_same_parent)
286
+ if AV_files_have_same_parent:
277
287
  # all media (video + audio) are in a same folder, so this is loose
278
288
  self.input_structure = 'loose'
279
289
  # for now (TO DO?) 'loose' == no multi-cam
280
- self.top_dir_has_multicam = False
290
+ # self.top_dir_has_multicam = False
281
291
  else:
282
- # check later if inside each folder, media have same device,
283
- # for now, we'll guess structure is 'folder_is_device'
284
- self.input_structure = 'folder_is_device'
292
+ # check later if inside each folder, media have same device
293
+ # for now, we'll guess structure is 'ordered'
294
+ self.input_structure = 'ordered'
285
295
  for p in paths:
286
296
  new_media = media_at_path(self.input_structure, p) # dev UID set here
287
297
  self.found_media_files.append(new_media)
288
- def _try_name(medias):
298
+ # for non UIDed try building UID from filenam
299
+ def _try_name_from_files(medias):
289
300
  # return common first strings in filename
301
+ def _all_identical(a_list):
302
+ return a_list.count(a_list[0]) == len(a_list)
290
303
  names = [m.path.name for m in medias]
291
304
  transposed_names = list(map(list, zip(*names)))
292
- same = list(map(_list_all_the_same, transposed_names))
305
+ same = list(map(_all_identical, transposed_names))
293
306
  try:
294
307
  first_diff = same.index(False)
295
308
  except:
296
309
  return names[0].split('.')[0]
297
310
  return names[0][:first_diff]
298
- no_device_UID_media = [m for m in self.found_media_files
311
+ no_device_UID_medias = [m for m in self.found_media_files
299
312
  if not m.device.UID]
300
- if no_device_UID_media:
301
- logger.debug('no_device_UID_media %s'%no_device_UID_media)
302
- start_string = _try_name(no_device_UID_media)
313
+ logger.debug('those media have no device UID %s'%no_device_UID_medias)
314
+ if no_device_UID_medias:
315
+ # will guess a device name from media filenames
316
+ logger.debug('no_device_UID_medias %s'%no_device_UID_medias)
317
+ start_string = _try_name_from_files(no_device_UID_medias)
303
318
  if len(start_string) < 2:
304
319
  print('\nError, cant identify the device for those files:')
305
- [print('%s, '%m.path.name, end='') for m in no_device_UID_media]
320
+ [print('%s, '%m.path.name, end='') for m in no_device_UID_medias]
306
321
  print('\n')
307
322
  sys.exit(1)
308
- one_device = no_device_UID_media[0].device
323
+ one_device = no_device_UID_medias[0].device
309
324
  one_device.name = start_string
310
325
  if not one_device.UID:
311
326
  one_device.UID = hash(start_string)
312
327
  print('\nWarning, guessing a device ID for those files:')
313
328
  [print('[gold1]%s[/gold1], '%m.path.name, end='') for m
314
- in no_device_UID_media]
329
+ in no_device_UID_medias]
315
330
  print('UID: [gold1]%s[/gold1]'%start_string)
316
- for m in no_device_UID_media:
331
+ for m in no_device_UID_medias:
317
332
  m.device = one_device
318
333
  logger.debug('new device added %s'%self.found_media_files)
319
- logger.debug('Scanner.found_media_files = %s'%self.found_media_files)
320
- if self.input_structure == 'folder_is_device':
321
- self._check_folders_have_same_device()
334
+ logger.debug('Scanner.found_media_files = %s'%pformat(self.found_media_files))
335
+ if self.input_structure == 'ordered':
336
+ self._confirm_folders_have_same_device()
322
337
  # self._use_folder_as_device_name()
323
338
  devices = set([m.device for m in self.found_media_files])
324
339
  audio_devices = [d for d in devices if d.dev_type == 'REC']
325
340
  for recorder in audio_devices:
341
+ # process tracks.txt for audio recorders
326
342
  recorder.tracks = self._get_tracks_from_file(recorder)
343
+ # logging only:
327
344
  if recorder.tracks:
328
345
  if not all([lv == None for lv in recorder.tracks.lag_values]):
329
346
  logger.debug('%s has lag_values %s'%(
330
347
  recorder.name, recorder.tracks.lag_values))
348
+ # check if device is in fact two parents up (and parent = ROLLxx):
349
+ # Group media by folder 2up and verify all media for each
350
+ # group have same device.
351
+ folder2up = lambda m: m.path.parent.parent
352
+ # logger.debug('folder2up: %s'%pformat([folder2up(m) for m
353
+ # in self.found_media_files]))
354
+ medias = sorted(self.found_media_files, key=folder2up)
355
+ # build lists for multiple reference of iterators
356
+ media_grouped_by_folder2up = [ (k, list(iterator)) for k, iterator
357
+ in groupby(medias, folder2up)]
358
+ logger.debug('media_grouped_by_folder2up: %s'%pformat(
359
+ media_grouped_by_folder2up))
360
+ folder_and_UIDs = [(f, [m.device.UID for m in medias])
361
+ for f, medias in media_grouped_by_folder2up]
362
+ logger.debug('devices: %s'%pformat(folder_and_UIDs))
363
+ def _multiple_and_same(a_list):
364
+ same = a_list.count(a_list[0]) == len(a_list)
365
+ return len(a_list) > 1 and same
366
+ folders_with_same_dev = [(f.name, UIDs[0]) for f, UIDs
367
+ in folder_and_UIDs
368
+ if _multiple_and_same(UIDs)]
369
+ logger.debug('folders_with_same_dev: %s'%pformat(folders_with_same_dev))
370
+ for name, UID in folders_with_same_dev:
371
+ for m in self.found_media_files:
372
+ if m.device.UID == UID:
373
+ m.device.name = name
374
+ # logger.debug('renamed device media: %s'%pformat(self.found_media_files))
331
375
  no_name_devices = [m.device for m in self.found_media_files
332
- if not m.device.name]
376
+ if not m.device.name]
377
+ # possible if self.input_structure == 'loose'
378
+ def _try_name_from_metadata(media):
379
+ # search model and make from fprobe
380
+ file = Path(media.path)
381
+ logger.debug('trying to find maker model for %s'%file)
382
+ try:
383
+ probe = ffmpeg.probe(file)
384
+ except ffmpeg.Error as e:
385
+ print('ffmpeg.probe error')
386
+ print(e.stderr, file)
387
+ return None, None #-----------------------------------------------------
388
+ # fall back to folder name
389
+ logger.debug('ffprobe %s'%pformat(probe))
390
+ # [TO BE COMPLETED]
391
+ # could reside in ['format','tags','com.apple.quicktime.model'],
392
+ # or ['format','tags','model'],
393
+ # or ['streams'][0]['tags']['vendor_id']) :-(
394
+
333
395
  for anon_dev in no_name_devices:
334
396
  medias = self.get_media_for_device(anon_dev)
335
- guess_name = _try_name(medias)
397
+ guess_name = _try_name_from_files(medias)
336
398
  # print('dev %s has no name, guessing %s'%(anon_dev, guess_name))
337
399
  logger.debug('dev %s has no name, guessing %s'%(anon_dev, guess_name))
338
400
  anon_dev.name = guess_name
339
401
  pprint_found_media_files = pformat(self.found_media_files)
340
402
  logger.debug('scanner.found_media_files = %s'%pprint_found_media_files)
341
403
  logger.debug('all devices %s'%[m.device for m in self.found_media_files])
404
+ dev_is_REC = [m.device.dev_type == 'REC' for m in self.found_media_files]
405
+ if not any(dev_is_REC): # no audio recordings!
406
+ print('\rNo audio recording found, nothing to sync, bye.')
407
+ sys.exit(0)
342
408
  # print('devices 312 %s'%set([m.device for m in self.found_media_files]))
343
409
 
344
410
  def _get_tracks_from_file(self, device) -> Tracks:
@@ -384,60 +450,69 @@ class Scanner:
384
450
  logger.debug('no tracks.txt file found')
385
451
  return None
386
452
 
387
- def _check_folders_have_same_device(self):
453
+ def _confirm_folders_have_same_device(self):
388
454
  """
389
- Since input_structure == 'folder_is_device,
455
+ Since input_structure == 'ordered',
390
456
  checks for files in self.found_media_files for structure as following.
391
457
 
392
458
  Warns user and quit program for:
393
459
  A- folders with mix of video and audio
394
460
  B- folders with mix of uniquely identified devices and unUIDied ones
395
- C- folders with mixed audio (or video) devices
461
+ C- folders with mixed audio an video files
396
462
 
397
463
  Warns user but proceeds for:
398
464
  D- folder with only unUIDied files (overlaps will be check later)
399
465
 
466
+ Changes self.input_structure to 'loose' if a folder contains files
467
+ from different devices.
468
+
400
469
  Proceeds silently if
401
470
  E- all files in the folder are from the same device
402
471
 
403
472
  Returns nothing
404
473
  """
405
- def _list_duplicates(seq):
406
- seen = set()
407
- seen_add = seen.add
408
- # adds all elements it doesn't know yet to seen and all other to seen_twice
409
- seen_twice = set( x for x in seq if x in seen or seen_add(x) )
410
- # turn the set into a list (as requested)
411
- return list( seen_twice )
412
- folder_key = lambda m: m.path.parent
413
- medias = sorted(self.found_media_files, key=folder_key)
414
- # build lists for multiple reference of iterators
415
- media_grouped_by_folder = [ (k, list(iterator)) for k, iterator
416
- in groupby(medias, folder_key)]
417
- logger.debug('media_grouped_by_folder %s'%media_grouped_by_folder)
418
- complete_path_folders = [e[0] for e in media_grouped_by_folder]
419
- name_of_folders = [p.name for p in complete_path_folders]
420
- logger.debug('complete_path_folders with media files %s'%complete_path_folders)
421
- logger.debug('name_of_folders with media files %s'%name_of_folders)
422
- # unique_folder_names = set(name_of_folders)
423
- repeated_folders = _list_duplicates(name_of_folders)
424
- logger.debug('repeated_folders %s'%repeated_folders)
425
- if repeated_folders:
426
- print('There are conflicts for some repeated folder names:')
427
- for f in [str(p) for p in repeated_folders]:
428
- print(' [gold1]%s[/gold1]'%f)
429
- print('Here are the complete paths:')
430
- for f in [str(p) for p in complete_path_folders]:
431
- print(' [gold1]%s[/gold1]'%f)
432
- print('please rename and rerun. Quitting..')
433
- sys.exit(1)
434
- # print(media_grouped_by_folder)
474
+ def _exit_on_folder_name_clash():
475
+ # Check media parent folders are unique
476
+ # returns media_grouped_by_folder
477
+ def _list_duplicates(seq):
478
+ seen = set()
479
+ seen_add = seen.add
480
+ # adds all elements it doesn't know yet to seen and all other to seen_twice
481
+ seen_twice = set( x for x in seq if x in seen or seen_add(x) )
482
+ # turn the set into a list (as requested)
483
+ return list( seen_twice )
484
+ folder_key = lambda m: m.path.parent
485
+ medias = sorted(self.found_media_files, key=folder_key)
486
+ # build lists for multiple reference of iterators
487
+ media_grouped_by_folder = [ (k, list(iterator)) for k, iterator
488
+ in groupby(medias, folder_key)]
489
+ logger.debug('media_grouped_by_folder %s'%pformat(
490
+ media_grouped_by_folder))
491
+ complete_path_folders = [e[0] for e in media_grouped_by_folder]
492
+ name_of_folders = [p.name for p in complete_path_folders]
493
+ logger.debug('complete_path_folders with media files %s'%
494
+ complete_path_folders)
495
+ logger.debug('name_of_folders with media files %s'%name_of_folders)
496
+ # unique_folder_names = set(name_of_folders) [TODO] is this useful ?
497
+ # repeated_folders = _list_duplicates(name_of_folders)
498
+ # logger.debug('repeated_folders %s'%repeated_folders)
499
+ # if repeated_folders:
500
+ # print('There are conflicts for some repeated folder names:')
501
+ # for f in [str(p) for p in repeated_folders]:
502
+ # print(' [gold1]%s[/gold1]'%f)
503
+ # print('Here are the complete paths:')
504
+ # for f in [str(p) for p in complete_path_folders]:
505
+ # print(' [gold1]%s[/gold1]'%f)
506
+ # print('please rename and rerun. Quitting..')
507
+ # sys.exit(1) ####################################################
508
+ return media_grouped_by_folder
509
+ media_grouped_by_folder = _exit_on_folder_name_clash()
435
510
  n_CAM_folder = 0
436
511
  for folder, list_of_medias_in_folder in media_grouped_by_folder:
437
512
  # check all medias are either video or audio recordings in folder
438
513
  # if not, warn user and quit.
439
514
  dev_types = set([m.device.dev_type for m in list_of_medias_in_folder])
440
- logger.debug('dev_types %s'%dev_types)
515
+ logger.debug('dev_types for folder%s: %s'%(folder,dev_types))
441
516
  if dev_types == {'CAM'}:
442
517
  n_CAM_folder += 1
443
518
  if len(dev_types) != 1:
@@ -446,14 +521,14 @@ class Scanner:
446
521
  [print('[gold1]%s[/gold1]'%m.path.name, end =', ')
447
522
  for m in list_of_medias_in_folder]
448
523
  print('\nplease move them in exclusive folders and rerun.\n')
449
- sys.exit(1)
524
+ sys.exit(1) ######################################################
450
525
  unidentified = [m for m in list_of_medias_in_folder
451
526
  if m.device.UID == None]
452
527
  UIDed = [m for m in list_of_medias_in_folder
453
528
  if m.device.UID != None]
454
529
  logger.debug('devices in folder %s:'%folder)
455
- logger.debug(' media with unknown devices %s'%unidentified)
456
- logger.debug(' media with UIDed devices %s'%UIDed)
530
+ logger.debug(' media with unknown devices %s'%pformat(unidentified))
531
+ logger.debug(' media with UIDed devices %s'%pformat(UIDed))
457
532
  if len(unidentified) != 0 and len(UIDed) != 0:
458
533
  print('\nProblem while grouping files in [gold1]%s[/gold1]:'%folder)
459
534
  print('There is a mix of unidentifiable and identified devices.')
@@ -466,16 +541,38 @@ class Scanner:
466
541
  elif answer.upper() in ["N", "NO"]:
467
542
  # Do action you need
468
543
  print('please move the following files in a folder named appropriately:\n')
469
- sys.exit(1)
544
+ sys.exit(1) ################################################
470
545
  # if, in a folder, there's a mix of different identified devices,
471
546
  # Warn user and quit.
547
+ UIDs = [m.device.UID for m in UIDed]
548
+ all_same_device = UIDs.count(UIDs[0]) == len(UIDs)
549
+ logger.debug('UIDs in %s: %s. all_same_device %s'%(folder,
550
+ pformat(UIDs), all_same_device))
551
+ if not all_same_device:
552
+ self.input_structure = 'loose'
553
+ # self.top_dir_has_multicam = False
554
+ logger.debug('changed input_structure to loose')
555
+ # device name should be generated (it isn't the folder name...)
556
+ distinct_UIDS = set(UIDs)
557
+ n_UIDs = len(distinct_UIDS)
558
+ logger.debug('There are %i UIDs: %s'%(n_UIDs, distinct_UIDS))
559
+ # Buid CAM01, CAM02 or REC01, REC02.
560
+ # Get dev type from first media in list
561
+ devT = UIDed[0].device.dev_type # 'CAM' or 'REC'
562
+ generic_names = [devT + str(i).zfill(2) for i in range(n_UIDs)]
563
+ devUIDs_names = dict(zip(distinct_UIDS, generic_names))
564
+ logger.debug('devUIDs_names %s'%pformat(devUIDs_names))
565
+ # rename
566
+ for m in UIDed:
567
+ m.device.name = devUIDs_names[m.device.UID]
568
+ logger.debug('new name %s'%m.device.name)
472
569
  if len(dev_types) != 1:
473
570
  print('\nProblem while scanning for media files. In [gold1]%s[/gold1]:'%folder)
474
571
  print('There is a mix of files from different devices:')
475
572
  [print('[gold1]%s[/gold1]'%m.path.name, end =', ')
476
573
  for m in list_of_medias_in_folder]
477
574
  print('\nplease move them in exclusive folders and rerun.\n')
478
- sys.exit(1)
575
+ sys.exit(1) ####################################################
479
576
  if len(unidentified) == len(list_of_medias_in_folder):
480
577
  # all unidentified
481
578
  if len(unidentified) > 1:
@@ -487,11 +584,6 @@ class Scanner:
487
584
  # all files in folder are from unidentified device or
488
585
  # all files in folder are from the same identified device
489
586
  logger.debug('n_CAM_folder %i'%n_CAM_folder)
490
- if n_CAM_folder > 1 :
491
- self.top_dir_has_multicam = True
492
- else:
493
- self.top_dir_has_multicam = False
494
- logger.debug('top_dir_has_multicam: %s'%self.top_dir_has_multicam)
495
587
  return
496
588
 
497
589
  def _parse_track_values(self, tracks_file) -> Tracks:
@@ -499,16 +591,16 @@ class Scanner:
499
591
  read track names for naming separated ISOs
500
592
  from tracks_file.
501
593
 
502
- tokens looked for: mix; L mix; R mix; 0 and TC
594
+ tokens looked for: mix; mix L; mix R; 0 and TC
503
595
 
504
596
  repeating "mic*" pattern signals a stereo track
505
597
  and entries will correspondingly panned into
506
- a stero mix named Lmix.wav and Rmix.wav
598
+ a stero mix named mixL.wav and mixL.wav
507
599
 
508
- L mic # spaces are ignored |
509
- R mic | stereo pair
510
- L micB
511
- R micB
600
+ mic L # spaces are ignored |
601
+ mic R | stereo pair
602
+ micB L
603
+ micB R
512
604
 
513
605
  Returns: a Tracks instance:
514
606
  # track numbers start at 1 for first track (as needed by sox)
@@ -523,22 +615,22 @@ class Scanner:
523
615
  unused=[],
524
616
  stereomics=[('mic', (4, 3)), ('mic2', (6, 5))],
525
617
  mix=[], others=[('clics', 1)],
526
- rawtrx=['clics', 'TC', 'L mic', 'R mic', 'L mic2;1000', 'R mic2;1000', 'Lmix', 'Rmix'],
618
+ rawtrx=['clics', 'TC', 'micL', 'micR', 'mic2L;1000', 'mic2R;1000', 'mixL', 'mixR'],
527
619
  error_msg=None, lag_values=[None, None, None, None, '1000', '1000', None, None])
528
620
  """
529
621
  def _WOspace(chaine):
530
622
  ch = [c for c in chaine if c != ' ']
531
623
  return ''.join(ch)
532
- def _WO_LR(chaine):
533
- ch = [c for c in chaine if c not in 'LR']
534
- return ''.join(ch)
535
- def _seemsStereoMic(tag):
536
- # is tag likely a stereo pair tag?
537
- # should ends with 'mic' and starts with 'l' or 'r'
538
- return tag[1:4]=='mic' and tag[0] in 'lr'
624
+ # def _WO_LR(chaine):
625
+ # ch = [c for c in chaine if c not in 'LR']
626
+ # return ''.join(ch)
627
+ # def _seemsStereoMic(tag):
628
+ # # is tag likely a stereo pair tag?
629
+ # # should starts with 'mic' and ends with 'l' or 'r'
630
+ # return tag[1:4]=='mic' and tag[0] in 'lr'
539
631
  file=open(tracks_file,"r")
540
632
  whole_txt = file.read()
541
- logger.debug('all_lines:\n%s'%whole_txt)
633
+ logger.debug('file %s all_lines:\n%s'%(tracks_file, whole_txt))
542
634
  tracks_lines_wspaces = [l.split('#')[0] for l in whole_txt.splitlines()
543
635
  if len(l) > 0 ]
544
636
  tracks_lines = [_WOspace(l) for l in tracks_lines_wspaces if len(l) > 0 ]
@@ -552,7 +644,7 @@ class Scanner:
552
644
  splt += [None]
553
645
  if len(splt) != 2:
554
646
  # error
555
- print('Text error in %s, line %s has too many ";"'%(
647
+ print('\nText error in %s, line %s has too many ";"'%(
556
648
  tracks_file, line))
557
649
  return splt
558
650
  tracks_lines, lag_values = zip(*[_detach_lag_value(l) for l
@@ -563,11 +655,10 @@ class Scanner:
563
655
  logger.debug('tracks_lines lower case: %s'%tracks_lines)
564
656
  # print(lag_values)
565
657
  logger.debug('lag_values: %s'%lag_values)
566
- tagsWOl_r = [e[1:] for e in tracks_lines] # skip first letter
567
- logger.debug('tags WO 1st letter %s'%tagsWOl_r)
658
+ tagsWOl_r = [e[:-1] for e in tracks_lines] # skip last letter
659
+ logger.debug('tags WO LR letter %s'%tagsWOl_r)
568
660
  # find idx of start of pairs
569
- # ['clics', 'TC', 'Lmic', 'Rmic', 'Lmic2', 'Lmic2', 'Lmix', 'Rmix']
570
- # ^ ^ ^
661
+ # ['clics', 'TC', 'micL', 'micR', 'mic2L', 'mic2R', 'mixL', 'mixR']
571
662
  def _micOrmix(a,b):
572
663
  # test if same and mic mic or mix mix
573
664
  if len(a) == 0:
@@ -577,9 +668,10 @@ class Scanner:
577
668
  in zip(tagsWOl_r,tagsWOl_r[1:])]) if same]
578
669
  logger.debug('pair_idx_start %s'%pair_idx_start)
579
670
  def LR_OK(idx):
580
- # in tracks_lines, check if idx start a LR pair
581
- a = tracks_lines[idx][0]
582
- b = tracks_lines[idx+1][0]
671
+ # in tracks_lines, check if idx ends a LR pair
672
+ # delays, if any, have been removed
673
+ a = tracks_lines[idx][-1]
674
+ b = tracks_lines[idx+1][-1]
583
675
  return a+b in ['lr', 'rl']
584
676
  LR_OKs = [LR_OK(p) for p in pair_idx_start]
585
677
  logger.debug('LR_OKs %s'%LR_OKs)
@@ -625,11 +717,11 @@ class Scanner:
625
717
  def _findLR(i_first):
626
718
  # returns L R indexes (+1 for sox non zero based indexing)
627
719
  i_2nd = i_first + 1
628
- a = tracks_lines[i_first][0]
629
- b = tracks_lines[i_2nd][0]
720
+ a = tracks_lines[i_first][-1] # l|r at end
721
+ b = tracks_lines[i_2nd][-1] # l|r at end
630
722
  if a == 'l':
631
723
  if b == 'r':
632
- # sequence is Lmix Rmix
724
+ # sequence is mixL mixR
633
725
  return i_first+1, i_2nd+1
634
726
  else:
635
727
  print('\nError in %s'%tracks_file)
@@ -638,7 +730,7 @@ class Scanner:
638
730
  quit()
639
731
  elif a == 'r':
640
732
  if b == 'l':
641
- # sequence is Rmix Lmix
733
+ # sequence is mixR mixL
642
734
  return i_2nd+1, i_first+1
643
735
  else:
644
736
  print('\nError in %s'%tracks_file)
@@ -666,7 +758,7 @@ class Scanner:
666
758
  # those are stereo pairs
667
759
  stereo_pairs = []
668
760
  for first_in_pair in pair_idx_start:
669
- suffix = tracks_lines[first_in_pair][1:]
761
+ suffix = tracks_lines[first_in_pair][:-1]
670
762
  stereo_pairs.append((suffix, _findLR(first_in_pair)))
671
763
  logger.debug('stereo_pairs %s'%stereo_pairs)
672
764
  output_tracks.stereomics = stereo_pairs