tictacsync 0.97a0__py3-none-any.whl → 0.99a0__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,89 +266,149 @@ 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('*.*')
273
+ def _last4letters(part):
274
+ return
275
+
263
276
  paths = [
264
277
  p
265
278
  for p in files
266
279
  if p.suffix[1:] in av_file_extensions
267
- and 'SyncedMedia' not in p.parts
280
+ and SYNCEDFOLDER not in p.parts # SyncedMedia
281
+ and MCCDIR not in p.parts # SyncedMulticamClips
282
+ and '_ISO' not in [part[-4:] for part in p.parts] # exclude ISO wav files
268
283
  ]
269
284
  logger.debug('found media files %s'%paths)
270
285
  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:
286
+ logger.debug('found parents %s'%pformat(parents))
287
+ # True if all elements are identical
288
+ AV_files_have_same_parent = parents.count(parents[0]) == len(parents)
289
+ logger.debug('AV_files_have_same_parent %s'%AV_files_have_same_parent)
290
+ if AV_files_have_same_parent:
277
291
  # all media (video + audio) are in a same folder, so this is loose
278
292
  self.input_structure = 'loose'
279
293
  # for now (TO DO?) 'loose' == no multi-cam
280
- self.top_dir_has_multicam = False
294
+ # self.top_dir_has_multicam = False
281
295
  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'
296
+ # check later if inside each folder, media have same device
297
+ # for now, we'll guess structure is 'ordered'
298
+ self.input_structure = 'ordered'
285
299
  for p in paths:
286
300
  new_media = media_at_path(self.input_structure, p) # dev UID set here
287
301
  self.found_media_files.append(new_media)
288
- def _try_name(medias):
302
+ # for non UIDed try building UID from filenam
303
+ def _try_name_from_files(medias):
289
304
  # return common first strings in filename
305
+ def _all_identical(a_list):
306
+ return a_list.count(a_list[0]) == len(a_list)
290
307
  names = [m.path.name for m in medias]
291
308
  transposed_names = list(map(list, zip(*names)))
292
- same = list(map(_list_all_the_same, transposed_names))
309
+ same = list(map(_all_identical, transposed_names))
293
310
  try:
294
311
  first_diff = same.index(False)
295
312
  except:
296
313
  return names[0].split('.')[0]
297
314
  return names[0][:first_diff]
298
- no_device_UID_media = [m for m in self.found_media_files
315
+ no_device_UID_medias = [m for m in self.found_media_files
299
316
  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)
317
+ logger.debug('those media have no device UID %s'%no_device_UID_medias)
318
+ if no_device_UID_medias:
319
+ # will guess a device name from media filenames
320
+ logger.debug('no_device_UID_medias %s'%no_device_UID_medias)
321
+ start_string = _try_name_from_files(no_device_UID_medias)
303
322
  if len(start_string) < 2:
304
323
  print('\nError, cant identify the device for those files:')
305
- [print('%s, '%m.path.name, end='') for m in no_device_UID_media]
324
+ [print('%s, '%m.path.name, end='') for m in no_device_UID_medias]
306
325
  print('\n')
307
326
  sys.exit(1)
308
- one_device = no_device_UID_media[0].device
327
+ one_device = no_device_UID_medias[0].device
309
328
  one_device.name = start_string
310
329
  if not one_device.UID:
311
330
  one_device.UID = hash(start_string)
312
331
  print('\nWarning, guessing a device ID for those files:')
313
332
  [print('[gold1]%s[/gold1], '%m.path.name, end='') for m
314
- in no_device_UID_media]
333
+ in no_device_UID_medias]
315
334
  print('UID: [gold1]%s[/gold1]'%start_string)
316
- for m in no_device_UID_media:
335
+ for m in no_device_UID_medias:
317
336
  m.device = one_device
318
337
  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()
338
+ logger.debug('Scanner.found_media_files = %s'%pformat(self.found_media_files))
339
+ if self.input_structure == 'ordered':
340
+ self._confirm_folders_have_same_device()
322
341
  # self._use_folder_as_device_name()
323
342
  devices = set([m.device for m in self.found_media_files])
324
343
  audio_devices = [d for d in devices if d.dev_type == 'REC']
325
344
  for recorder in audio_devices:
345
+ # process tracks.txt for audio recorders
326
346
  recorder.tracks = self._get_tracks_from_file(recorder)
347
+ # logging only:
327
348
  if recorder.tracks:
328
349
  if not all([lv == None for lv in recorder.tracks.lag_values]):
329
350
  logger.debug('%s has lag_values %s'%(
330
351
  recorder.name, recorder.tracks.lag_values))
352
+ # check if device is in fact two parents up (and parent = ROLLxx):
353
+ # Group media by folder 2up and verify all media for each
354
+ # group have same device.
355
+ folder2up = lambda m: m.path.parent.parent
356
+ # logger.debug('folder2up: %s'%pformat([folder2up(m) for m
357
+ # in self.found_media_files]))
358
+ medias = sorted(self.found_media_files, key=folder2up)
359
+ # build lists for multiple reference of iterators
360
+ media_grouped_by_folder2up = [ (k, list(iterator)) for k, iterator
361
+ in groupby(medias, folder2up)]
362
+ logger.debug('media_grouped_by_folder2up: %s'%pformat(
363
+ media_grouped_by_folder2up))
364
+ folder_and_UIDs = [(f, [m.device.UID for m in medias])
365
+ for f, medias in media_grouped_by_folder2up]
366
+ logger.debug('devices: %s'%pformat(folder_and_UIDs))
367
+ def _multiple_and_same(a_list):
368
+ same = a_list.count(a_list[0]) == len(a_list)
369
+ return len(a_list) > 1 and same
370
+ folders_with_same_dev = [(f.name, UIDs[0]) for f, UIDs
371
+ in folder_and_UIDs
372
+ if _multiple_and_same(UIDs)]
373
+ logger.debug('folders_with_same_dev: %s'%pformat(folders_with_same_dev))
374
+ for name, UID in folders_with_same_dev:
375
+ for m in self.found_media_files:
376
+ if m.device.UID == UID:
377
+ m.device.name = name
378
+ # logger.debug('renamed device media: %s'%pformat(self.found_media_files))
331
379
  no_name_devices = [m.device for m in self.found_media_files
332
- if not m.device.name]
380
+ if not m.device.name]
381
+ # possible if self.input_structure == 'loose'
382
+ def _try_name_from_metadata(media):
383
+ # search model and make from fprobe
384
+ file = Path(media.path)
385
+ logger.debug('trying to find maker model for %s'%file)
386
+ try:
387
+ probe = ffmpeg.probe(file)
388
+ except ffmpeg.Error as e:
389
+ print('ffmpeg.probe error')
390
+ print(e.stderr, file)
391
+ return None, None #-----------------------------------------------------
392
+ # fall back to folder name
393
+ logger.debug('ffprobe %s'%pformat(probe))
394
+ # [TO BE COMPLETED]
395
+ # could reside in ['format','tags','com.apple.quicktime.model'],
396
+ # or ['format','tags','model'],
397
+ # or ['streams'][0]['tags']['vendor_id']) :-(
398
+
333
399
  for anon_dev in no_name_devices:
334
400
  medias = self.get_media_for_device(anon_dev)
335
- guess_name = _try_name(medias)
401
+ guess_name = _try_name_from_files(medias)
336
402
  # print('dev %s has no name, guessing %s'%(anon_dev, guess_name))
337
403
  logger.debug('dev %s has no name, guessing %s'%(anon_dev, guess_name))
338
404
  anon_dev.name = guess_name
339
405
  pprint_found_media_files = pformat(self.found_media_files)
340
406
  logger.debug('scanner.found_media_files = %s'%pprint_found_media_files)
341
407
  logger.debug('all devices %s'%[m.device for m in self.found_media_files])
408
+ dev_is_REC = [m.device.dev_type == 'REC' for m in self.found_media_files]
409
+ if not any(dev_is_REC): # no audio recordings!
410
+ print('\rNo audio recording found, nothing to sync, bye.')
411
+ sys.exit(0)
342
412
  # print('devices 312 %s'%set([m.device for m in self.found_media_files]))
343
413
 
344
414
  def _get_tracks_from_file(self, device) -> Tracks:
@@ -384,60 +454,69 @@ class Scanner:
384
454
  logger.debug('no tracks.txt file found')
385
455
  return None
386
456
 
387
- def _check_folders_have_same_device(self):
457
+ def _confirm_folders_have_same_device(self):
388
458
  """
389
- Since input_structure == 'folder_is_device,
459
+ Since input_structure == 'ordered',
390
460
  checks for files in self.found_media_files for structure as following.
391
461
 
392
462
  Warns user and quit program for:
393
463
  A- folders with mix of video and audio
394
464
  B- folders with mix of uniquely identified devices and unUIDied ones
395
- C- folders with mixed audio (or video) devices
465
+ C- folders with mixed audio an video files
396
466
 
397
467
  Warns user but proceeds for:
398
468
  D- folder with only unUIDied files (overlaps will be check later)
399
469
 
470
+ Changes self.input_structure to 'loose' if a folder contains files
471
+ from different devices.
472
+
400
473
  Proceeds silently if
401
474
  E- all files in the folder are from the same device
402
475
 
403
476
  Returns nothing
404
477
  """
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)
478
+ def _exit_on_folder_name_clash():
479
+ # Check media parent folders are unique
480
+ # returns media_grouped_by_folder
481
+ def _list_duplicates(seq):
482
+ seen = set()
483
+ seen_add = seen.add
484
+ # adds all elements it doesn't know yet to seen and all other to seen_twice
485
+ seen_twice = set( x for x in seq if x in seen or seen_add(x) )
486
+ # turn the set into a list (as requested)
487
+ return list( seen_twice )
488
+ folder_key = lambda m: m.path.parent
489
+ medias = sorted(self.found_media_files, key=folder_key)
490
+ # build lists for multiple reference of iterators
491
+ media_grouped_by_folder = [ (k, list(iterator)) for k, iterator
492
+ in groupby(medias, folder_key)]
493
+ logger.debug('media_grouped_by_folder %s'%pformat(
494
+ media_grouped_by_folder))
495
+ complete_path_folders = [e[0] for e in media_grouped_by_folder]
496
+ name_of_folders = [p.name for p in complete_path_folders]
497
+ logger.debug('complete_path_folders with media files %s'%
498
+ complete_path_folders)
499
+ logger.debug('name_of_folders with media files %s'%name_of_folders)
500
+ # unique_folder_names = set(name_of_folders) [TODO] is this useful ?
501
+ # repeated_folders = _list_duplicates(name_of_folders)
502
+ # logger.debug('repeated_folders %s'%repeated_folders)
503
+ # if repeated_folders:
504
+ # print('There are conflicts for some repeated folder names:')
505
+ # for f in [str(p) for p in repeated_folders]:
506
+ # print(' [gold1]%s[/gold1]'%f)
507
+ # print('Here are the complete paths:')
508
+ # for f in [str(p) for p in complete_path_folders]:
509
+ # print(' [gold1]%s[/gold1]'%f)
510
+ # print('please rename and rerun. Quitting..')
511
+ # sys.exit(1) ####################################################
512
+ return media_grouped_by_folder
513
+ media_grouped_by_folder = _exit_on_folder_name_clash()
435
514
  n_CAM_folder = 0
436
515
  for folder, list_of_medias_in_folder in media_grouped_by_folder:
437
516
  # check all medias are either video or audio recordings in folder
438
517
  # if not, warn user and quit.
439
518
  dev_types = set([m.device.dev_type for m in list_of_medias_in_folder])
440
- logger.debug('dev_types %s'%dev_types)
519
+ logger.debug('dev_types for folder%s: %s'%(folder,dev_types))
441
520
  if dev_types == {'CAM'}:
442
521
  n_CAM_folder += 1
443
522
  if len(dev_types) != 1:
@@ -446,14 +525,14 @@ class Scanner:
446
525
  [print('[gold1]%s[/gold1]'%m.path.name, end =', ')
447
526
  for m in list_of_medias_in_folder]
448
527
  print('\nplease move them in exclusive folders and rerun.\n')
449
- sys.exit(1)
528
+ sys.exit(1) ######################################################
450
529
  unidentified = [m for m in list_of_medias_in_folder
451
530
  if m.device.UID == None]
452
531
  UIDed = [m for m in list_of_medias_in_folder
453
532
  if m.device.UID != None]
454
533
  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)
534
+ logger.debug(' media with unknown devices %s'%pformat(unidentified))
535
+ logger.debug(' media with UIDed devices %s'%pformat(UIDed))
457
536
  if len(unidentified) != 0 and len(UIDed) != 0:
458
537
  print('\nProblem while grouping files in [gold1]%s[/gold1]:'%folder)
459
538
  print('There is a mix of unidentifiable and identified devices.')
@@ -466,16 +545,38 @@ class Scanner:
466
545
  elif answer.upper() in ["N", "NO"]:
467
546
  # Do action you need
468
547
  print('please move the following files in a folder named appropriately:\n')
469
- sys.exit(1)
548
+ sys.exit(1) ################################################
470
549
  # if, in a folder, there's a mix of different identified devices,
471
550
  # Warn user and quit.
551
+ UIDs = [m.device.UID for m in UIDed]
552
+ all_same_device = UIDs.count(UIDs[0]) == len(UIDs)
553
+ logger.debug('UIDs in %s: %s. all_same_device %s'%(folder,
554
+ pformat(UIDs), all_same_device))
555
+ if not all_same_device:
556
+ self.input_structure = 'loose'
557
+ # self.top_dir_has_multicam = False
558
+ logger.debug('changed input_structure to loose')
559
+ # device name should be generated (it isn't the folder name...)
560
+ distinct_UIDS = set(UIDs)
561
+ n_UIDs = len(distinct_UIDS)
562
+ logger.debug('There are %i UIDs: %s'%(n_UIDs, distinct_UIDS))
563
+ # Buid CAM01, CAM02 or REC01, REC02.
564
+ # Get dev type from first media in list
565
+ devT = UIDed[0].device.dev_type # 'CAM' or 'REC'
566
+ generic_names = [devT + str(i).zfill(2) for i in range(n_UIDs)]
567
+ devUIDs_names = dict(zip(distinct_UIDS, generic_names))
568
+ logger.debug('devUIDs_names %s'%pformat(devUIDs_names))
569
+ # rename
570
+ for m in UIDed:
571
+ m.device.name = devUIDs_names[m.device.UID]
572
+ logger.debug('new name %s'%m.device.name)
472
573
  if len(dev_types) != 1:
473
574
  print('\nProblem while scanning for media files. In [gold1]%s[/gold1]:'%folder)
474
575
  print('There is a mix of files from different devices:')
475
576
  [print('[gold1]%s[/gold1]'%m.path.name, end =', ')
476
577
  for m in list_of_medias_in_folder]
477
578
  print('\nplease move them in exclusive folders and rerun.\n')
478
- sys.exit(1)
579
+ sys.exit(1) ####################################################
479
580
  if len(unidentified) == len(list_of_medias_in_folder):
480
581
  # all unidentified
481
582
  if len(unidentified) > 1:
@@ -487,11 +588,6 @@ class Scanner:
487
588
  # all files in folder are from unidentified device or
488
589
  # all files in folder are from the same identified device
489
590
  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
591
  return
496
592
 
497
593
  def _parse_track_values(self, tracks_file) -> Tracks:
@@ -499,16 +595,16 @@ class Scanner:
499
595
  read track names for naming separated ISOs
500
596
  from tracks_file.
501
597
 
502
- tokens looked for: mix; L mix; R mix; 0 and TC
598
+ tokens looked for: mix; mix L; mix R; 0 and TC
503
599
 
504
600
  repeating "mic*" pattern signals a stereo track
505
601
  and entries will correspondingly panned into
506
- a stero mix named Lmix.wav and Rmix.wav
602
+ a stero mix named mixL.wav and mixL.wav
507
603
 
508
- L mic # spaces are ignored |
509
- R mic | stereo pair
510
- L micB
511
- R micB
604
+ mic L # spaces are ignored |
605
+ mic R | stereo pair
606
+ micB L
607
+ micB R
512
608
 
513
609
  Returns: a Tracks instance:
514
610
  # track numbers start at 1 for first track (as needed by sox)
@@ -523,22 +619,22 @@ class Scanner:
523
619
  unused=[],
524
620
  stereomics=[('mic', (4, 3)), ('mic2', (6, 5))],
525
621
  mix=[], others=[('clics', 1)],
526
- rawtrx=['clics', 'TC', 'L mic', 'R mic', 'L mic2;1000', 'R mic2;1000', 'Lmix', 'Rmix'],
622
+ rawtrx=['clics', 'TC', 'micL', 'micR', 'mic2L;1000', 'mic2R;1000', 'mixL', 'mixR'],
527
623
  error_msg=None, lag_values=[None, None, None, None, '1000', '1000', None, None])
528
624
  """
529
625
  def _WOspace(chaine):
530
626
  ch = [c for c in chaine if c != ' ']
531
627
  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'
628
+ # def _WO_LR(chaine):
629
+ # ch = [c for c in chaine if c not in 'LR']
630
+ # return ''.join(ch)
631
+ # def _seemsStereoMic(tag):
632
+ # # is tag likely a stereo pair tag?
633
+ # # should starts with 'mic' and ends with 'l' or 'r'
634
+ # return tag[1:4]=='mic' and tag[0] in 'lr'
539
635
  file=open(tracks_file,"r")
540
636
  whole_txt = file.read()
541
- logger.debug('all_lines:\n%s'%whole_txt)
637
+ logger.debug('file %s all_lines:\n%s'%(tracks_file, whole_txt))
542
638
  tracks_lines_wspaces = [l.split('#')[0] for l in whole_txt.splitlines()
543
639
  if len(l) > 0 ]
544
640
  tracks_lines = [_WOspace(l) for l in tracks_lines_wspaces if len(l) > 0 ]
@@ -552,7 +648,7 @@ class Scanner:
552
648
  splt += [None]
553
649
  if len(splt) != 2:
554
650
  # error
555
- print('Text error in %s, line %s has too many ";"'%(
651
+ print('\nText error in %s, line %s has too many ";"'%(
556
652
  tracks_file, line))
557
653
  return splt
558
654
  tracks_lines, lag_values = zip(*[_detach_lag_value(l) for l
@@ -563,11 +659,10 @@ class Scanner:
563
659
  logger.debug('tracks_lines lower case: %s'%tracks_lines)
564
660
  # print(lag_values)
565
661
  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)
662
+ tagsWOl_r = [e[:-1] for e in tracks_lines] # skip last letter
663
+ logger.debug('tags WO LR letter %s'%tagsWOl_r)
568
664
  # find idx of start of pairs
569
- # ['clics', 'TC', 'Lmic', 'Rmic', 'Lmic2', 'Lmic2', 'Lmix', 'Rmix']
570
- # ^ ^ ^
665
+ # ['clics', 'TC', 'micL', 'micR', 'mic2L', 'mic2R', 'mixL', 'mixR']
571
666
  def _micOrmix(a,b):
572
667
  # test if same and mic mic or mix mix
573
668
  if len(a) == 0:
@@ -577,9 +672,10 @@ class Scanner:
577
672
  in zip(tagsWOl_r,tagsWOl_r[1:])]) if same]
578
673
  logger.debug('pair_idx_start %s'%pair_idx_start)
579
674
  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]
675
+ # in tracks_lines, check if idx ends a LR pair
676
+ # delays, if any, have been removed
677
+ a = tracks_lines[idx][-1]
678
+ b = tracks_lines[idx+1][-1]
583
679
  return a+b in ['lr', 'rl']
584
680
  LR_OKs = [LR_OK(p) for p in pair_idx_start]
585
681
  logger.debug('LR_OKs %s'%LR_OKs)
@@ -625,11 +721,11 @@ class Scanner:
625
721
  def _findLR(i_first):
626
722
  # returns L R indexes (+1 for sox non zero based indexing)
627
723
  i_2nd = i_first + 1
628
- a = tracks_lines[i_first][0]
629
- b = tracks_lines[i_2nd][0]
724
+ a = tracks_lines[i_first][-1] # l|r at end
725
+ b = tracks_lines[i_2nd][-1] # l|r at end
630
726
  if a == 'l':
631
727
  if b == 'r':
632
- # sequence is Lmix Rmix
728
+ # sequence is mixL mixR
633
729
  return i_first+1, i_2nd+1
634
730
  else:
635
731
  print('\nError in %s'%tracks_file)
@@ -638,7 +734,7 @@ class Scanner:
638
734
  quit()
639
735
  elif a == 'r':
640
736
  if b == 'l':
641
- # sequence is Rmix Lmix
737
+ # sequence is mixR mixL
642
738
  return i_2nd+1, i_first+1
643
739
  else:
644
740
  print('\nError in %s'%tracks_file)
@@ -666,7 +762,7 @@ class Scanner:
666
762
  # those are stereo pairs
667
763
  stereo_pairs = []
668
764
  for first_in_pair in pair_idx_start:
669
- suffix = tracks_lines[first_in_pair][1:]
765
+ suffix = tracks_lines[first_in_pair][:-1]
670
766
  stereo_pairs.append((suffix, _findLR(first_in_pair)))
671
767
  logger.debug('stereo_pairs %s'%stereo_pairs)
672
768
  output_tracks.stereomics = stereo_pairs