Upload TMIDIX.py
Browse files
TMIDIX.py
CHANGED
|
@@ -51,7 +51,7 @@ r'''############################################################################
|
|
| 51 |
|
| 52 |
###################################################################################
|
| 53 |
|
| 54 |
-
__version__ = "25.
|
| 55 |
|
| 56 |
print('=' * 70)
|
| 57 |
print('TMIDIX Python module')
|
|
@@ -1513,6 +1513,9 @@ import hashlib
|
|
| 1513 |
|
| 1514 |
from array import array
|
| 1515 |
|
|
|
|
|
|
|
|
|
|
| 1516 |
###################################################################################
|
| 1517 |
#
|
| 1518 |
# Original TMIDI Tegridy helper functions
|
|
@@ -13132,7 +13135,7 @@ def fix_escore_notes_durations(escore_notes,
|
|
| 13132 |
elif len(g) == 2:
|
| 13133 |
|
| 13134 |
if g[0][times_idx]+g[0][durs_idx] >= g[1][times_idx]:
|
| 13135 |
-
g[0][durs_idx] = max(1, g[1][times_idx] - g[0][times_idx] -
|
| 13136 |
|
| 13137 |
merged_score.extend(g)
|
| 13138 |
|
|
@@ -13240,6 +13243,179 @@ def remove_duplicate_pitches_from_escore_notes(escore_notes,
|
|
| 13240 |
return new_escore
|
| 13241 |
|
| 13242 |
###################################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13243 |
|
| 13244 |
print('Module loaded!')
|
| 13245 |
print('=' * 70)
|
|
|
|
| 51 |
|
| 52 |
###################################################################################
|
| 53 |
|
| 54 |
+
__version__ = "25.7.5"
|
| 55 |
|
| 56 |
print('=' * 70)
|
| 57 |
print('TMIDIX Python module')
|
|
|
|
| 1513 |
|
| 1514 |
from array import array
|
| 1515 |
|
| 1516 |
+
from pathlib import Path
|
| 1517 |
+
from fnmatch import fnmatch
|
| 1518 |
+
|
| 1519 |
###################################################################################
|
| 1520 |
#
|
| 1521 |
# Original TMIDI Tegridy helper functions
|
|
|
|
| 13135 |
elif len(g) == 2:
|
| 13136 |
|
| 13137 |
if g[0][times_idx]+g[0][durs_idx] >= g[1][times_idx]:
|
| 13138 |
+
g[0][durs_idx] = max(1, g[1][times_idx] - g[0][times_idx] - min_notes_gap)
|
| 13139 |
|
| 13140 |
merged_score.extend(g)
|
| 13141 |
|
|
|
|
| 13243 |
return new_escore
|
| 13244 |
|
| 13245 |
###################################################################################
|
| 13246 |
+
|
| 13247 |
+
def chunks_shuffle(lst,
|
| 13248 |
+
min_len=1,
|
| 13249 |
+
max_len=3,
|
| 13250 |
+
seed=None
|
| 13251 |
+
):
|
| 13252 |
+
|
| 13253 |
+
rnd = random.Random(seed)
|
| 13254 |
+
chunks = []
|
| 13255 |
+
i, n = 0, len(lst)
|
| 13256 |
+
|
| 13257 |
+
while i < n:
|
| 13258 |
+
size = rnd.randint(min_len, max_len)
|
| 13259 |
+
size = min(size, n - i)
|
| 13260 |
+
chunks.append(lst[i : i + size])
|
| 13261 |
+
i += size
|
| 13262 |
+
|
| 13263 |
+
rnd.shuffle(chunks)
|
| 13264 |
+
|
| 13265 |
+
flattened = []
|
| 13266 |
+
for chunk in chunks:
|
| 13267 |
+
flattened.extend(chunk)
|
| 13268 |
+
|
| 13269 |
+
return flattened
|
| 13270 |
+
|
| 13271 |
+
###################################################################################
|
| 13272 |
+
|
| 13273 |
+
def convert_bytes_in_nested_list(lst,
|
| 13274 |
+
encoding='utf-8',
|
| 13275 |
+
errors='ignore',
|
| 13276 |
+
return_changed_events_count=False
|
| 13277 |
+
):
|
| 13278 |
+
|
| 13279 |
+
new_list = []
|
| 13280 |
+
|
| 13281 |
+
ce_count = 0
|
| 13282 |
+
|
| 13283 |
+
for item in lst:
|
| 13284 |
+
if isinstance(item, list):
|
| 13285 |
+
new_list.append(convert_bytes_in_nested_list(item))
|
| 13286 |
+
|
| 13287 |
+
elif isinstance(item, bytes):
|
| 13288 |
+
new_list.append(item.decode(encoding, errors=errors))
|
| 13289 |
+
ce_count += 1
|
| 13290 |
+
|
| 13291 |
+
else:
|
| 13292 |
+
new_list.append(item)
|
| 13293 |
+
|
| 13294 |
+
if return_changed_events_count:
|
| 13295 |
+
return new_list, ce_count
|
| 13296 |
+
|
| 13297 |
+
else:
|
| 13298 |
+
return new_list
|
| 13299 |
+
|
| 13300 |
+
###################################################################################
|
| 13301 |
+
|
| 13302 |
+
def find_deepest_midi_dirs(roots,
|
| 13303 |
+
marker_file="midi_score.mid",
|
| 13304 |
+
suffixes=None,
|
| 13305 |
+
randomize=False,
|
| 13306 |
+
seed=None,
|
| 13307 |
+
verbose=False
|
| 13308 |
+
):
|
| 13309 |
+
|
| 13310 |
+
try:
|
| 13311 |
+
iter(roots)
|
| 13312 |
+
if isinstance(roots, (str, Path)):
|
| 13313 |
+
root_list = [roots]
|
| 13314 |
+
else:
|
| 13315 |
+
root_list = list(roots)
|
| 13316 |
+
|
| 13317 |
+
except TypeError:
|
| 13318 |
+
root_list = [roots]
|
| 13319 |
+
|
| 13320 |
+
if isinstance(marker_file, (list, tuple)):
|
| 13321 |
+
patterns = [p.lower() for p in marker_file if p]
|
| 13322 |
+
|
| 13323 |
+
else:
|
| 13324 |
+
patterns = [marker_file.lower()] if marker_file else []
|
| 13325 |
+
|
| 13326 |
+
allowed = {s.lower() for s in (suffixes or ['.mid', '.midi', '.kar'])}
|
| 13327 |
+
|
| 13328 |
+
if verbose:
|
| 13329 |
+
print("Settings:")
|
| 13330 |
+
print(" Roots:", [str(r) for r in root_list])
|
| 13331 |
+
print(" Marker patterns:", patterns or "<no marker filter>")
|
| 13332 |
+
print(" Allowed suffixes:", allowed)
|
| 13333 |
+
print(f" Randomize={randomize}, Seed={seed}")
|
| 13334 |
+
|
| 13335 |
+
results = defaultdict(list)
|
| 13336 |
+
rng = random.Random(seed)
|
| 13337 |
+
|
| 13338 |
+
for root in root_list:
|
| 13339 |
+
|
| 13340 |
+
root_path = Path(root)
|
| 13341 |
+
|
| 13342 |
+
if not root_path.is_dir():
|
| 13343 |
+
print(f"Warning: '{root_path}' is not a valid directory, skipping.")
|
| 13344 |
+
continue
|
| 13345 |
+
|
| 13346 |
+
if verbose:
|
| 13347 |
+
print(f"\nScanning root: {str(root_path)}")
|
| 13348 |
+
|
| 13349 |
+
all_dirs = list(root_path.rglob("*"))
|
| 13350 |
+
dirs_iter = tqdm.tqdm(all_dirs, desc=f"Dirs in {root_path.name}", disable=not verbose)
|
| 13351 |
+
|
| 13352 |
+
for dirpath in dirs_iter:
|
| 13353 |
+
if not dirpath.is_dir():
|
| 13354 |
+
continue
|
| 13355 |
+
|
| 13356 |
+
children = list(dirpath.iterdir())
|
| 13357 |
+
if any(child.is_dir() for child in children):
|
| 13358 |
+
if verbose:
|
| 13359 |
+
print(f"Skipping non-leaf: {str(dirpath)}")
|
| 13360 |
+
continue
|
| 13361 |
+
|
| 13362 |
+
files = [f for f in children if f.is_file()]
|
| 13363 |
+
names = [f.name.lower() for f in files]
|
| 13364 |
+
|
| 13365 |
+
if patterns:
|
| 13366 |
+
matched = any(fnmatch(name, pat) for name in names for pat in patterns)
|
| 13367 |
+
if not matched:
|
| 13368 |
+
if verbose:
|
| 13369 |
+
print(f"No marker in: {str(dirpath)}")
|
| 13370 |
+
continue
|
| 13371 |
+
|
| 13372 |
+
if verbose:
|
| 13373 |
+
print(f"Marker found in: {str(dirpath)}")
|
| 13374 |
+
|
| 13375 |
+
else:
|
| 13376 |
+
if verbose:
|
| 13377 |
+
print(f"Including leaf (no marker): {str(dirpath)}")
|
| 13378 |
+
|
| 13379 |
+
for f in files:
|
| 13380 |
+
if f.suffix.lower() in allowed:
|
| 13381 |
+
results[str(dirpath)].append(str(f))
|
| 13382 |
+
|
| 13383 |
+
if verbose:
|
| 13384 |
+
print(f" Collected: {f.name}")
|
| 13385 |
+
|
| 13386 |
+
all_leaves = list(results.keys())
|
| 13387 |
+
if randomize:
|
| 13388 |
+
if verbose:
|
| 13389 |
+
print("\nShuffling leaf directories")
|
| 13390 |
+
|
| 13391 |
+
rng.shuffle(all_leaves)
|
| 13392 |
+
|
| 13393 |
+
else:
|
| 13394 |
+
all_leaves.sort()
|
| 13395 |
+
|
| 13396 |
+
final_dict = {}
|
| 13397 |
+
|
| 13398 |
+
for leaf in all_leaves:
|
| 13399 |
+
file_list = results[leaf][:]
|
| 13400 |
+
if randomize:
|
| 13401 |
+
if verbose:
|
| 13402 |
+
print(f"Shuffling files in: {leaf}")
|
| 13403 |
+
|
| 13404 |
+
rng.shuffle(file_list)
|
| 13405 |
+
|
| 13406 |
+
else:
|
| 13407 |
+
file_list.sort()
|
| 13408 |
+
|
| 13409 |
+
final_dict[leaf] = file_list
|
| 13410 |
+
|
| 13411 |
+
if verbose:
|
| 13412 |
+
print("\nScan complete. Found directories:")
|
| 13413 |
+
for d, fl in final_dict.items():
|
| 13414 |
+
print(f" {d} -> {len(fl)} files")
|
| 13415 |
+
|
| 13416 |
+
return final_dict
|
| 13417 |
+
|
| 13418 |
+
###################################################################################
|
| 13419 |
|
| 13420 |
print('Module loaded!')
|
| 13421 |
print('=' * 70)
|