Upload TMIDIX.py
Browse files
TMIDIX.py
CHANGED
|
@@ -51,7 +51,7 @@ r'''############################################################################
|
|
| 51 |
|
| 52 |
###################################################################################
|
| 53 |
|
| 54 |
-
__version__ = "26.4.
|
| 55 |
|
| 56 |
print('=' * 70)
|
| 57 |
print('TMIDIX Python module')
|
|
@@ -18321,6 +18321,204 @@ def rle_toks_to_binary_matrix(rle_toks,
|
|
| 18321 |
|
| 18322 |
###################################################################################
|
| 18323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18324 |
print('Module loaded!')
|
| 18325 |
print('=' * 70)
|
| 18326 |
print('Enjoy! :)')
|
|
|
|
| 51 |
|
| 52 |
###################################################################################
|
| 53 |
|
| 54 |
+
__version__ = "26.4.15"
|
| 55 |
|
| 56 |
print('=' * 70)
|
| 57 |
print('TMIDIX Python module')
|
|
|
|
| 18321 |
|
| 18322 |
###################################################################################
|
| 18323 |
|
| 18324 |
+
class SAM:
|
| 18325 |
+
def __init__(self):
|
| 18326 |
+
self.len = [0]
|
| 18327 |
+
self.link = [-1]
|
| 18328 |
+
self.next = [dict()]
|
| 18329 |
+
self.last = 0
|
| 18330 |
+
|
| 18331 |
+
def add(self, c):
|
| 18332 |
+
cur = len(self.len)
|
| 18333 |
+
self.len.append(self.len[self.last] + 1)
|
| 18334 |
+
self.link.append(0)
|
| 18335 |
+
self.next.append(dict())
|
| 18336 |
+
p = self.last
|
| 18337 |
+
while p != -1 and c not in self.next[p]:
|
| 18338 |
+
self.next[p][c] = cur
|
| 18339 |
+
p = self.link[p]
|
| 18340 |
+
if p == -1:
|
| 18341 |
+
self.link[cur] = 0
|
| 18342 |
+
else:
|
| 18343 |
+
q = self.next[p][c]
|
| 18344 |
+
if self.len[p] + 1 == self.len[q]:
|
| 18345 |
+
self.link[cur] = q
|
| 18346 |
+
else:
|
| 18347 |
+
clone = len(self.len)
|
| 18348 |
+
self.len.append(self.len[p] + 1)
|
| 18349 |
+
self.link.append(self.link[q])
|
| 18350 |
+
self.next.append(self.next[q].copy())
|
| 18351 |
+
while p != -1 and self.next[p].get(c) == q:
|
| 18352 |
+
self.next[p][c] = clone
|
| 18353 |
+
p = self.link[p]
|
| 18354 |
+
self.link[q] = self.link[cur] = clone
|
| 18355 |
+
self.last = cur
|
| 18356 |
+
|
| 18357 |
+
###################################################################################
|
| 18358 |
+
|
| 18359 |
+
def common_subpatterns(lists):
|
| 18360 |
+
if not lists:
|
| 18361 |
+
return []
|
| 18362 |
+
# Build SAM from first list
|
| 18363 |
+
sam = SAM()
|
| 18364 |
+
for x in lists[0]:
|
| 18365 |
+
sam.add(x)
|
| 18366 |
+
|
| 18367 |
+
m = len(sam.len)
|
| 18368 |
+
# For each state, store minimal matched length across all other lists
|
| 18369 |
+
min_match = [sam.len[i] for i in range(m)]
|
| 18370 |
+
|
| 18371 |
+
# For each other list, compute for every state the longest match ending at that state
|
| 18372 |
+
for arr in lists[1:]:
|
| 18373 |
+
cur = 0
|
| 18374 |
+
l = 0
|
| 18375 |
+
best = [0]*m
|
| 18376 |
+
for x in arr:
|
| 18377 |
+
if x in sam.next[cur]:
|
| 18378 |
+
cur = sam.next[cur][x]
|
| 18379 |
+
l += 1
|
| 18380 |
+
else:
|
| 18381 |
+
while cur != -1 and x not in sam.next[cur]:
|
| 18382 |
+
cur = sam.link[cur]
|
| 18383 |
+
if cur == -1:
|
| 18384 |
+
cur = 0
|
| 18385 |
+
l = 0
|
| 18386 |
+
else:
|
| 18387 |
+
l = sam.len[cur] + 1
|
| 18388 |
+
cur = sam.next[cur][x]
|
| 18389 |
+
best[cur] = max(best[cur], l)
|
| 18390 |
+
# propagate best values along suffix links in decreasing len order
|
| 18391 |
+
order = sorted(range(m), key=lambda i: sam.len[i], reverse=True)
|
| 18392 |
+
for v in order:
|
| 18393 |
+
p = sam.link[v]
|
| 18394 |
+
if p != -1:
|
| 18395 |
+
best[p] = max(best[p], min(best[v], sam.len[p]))
|
| 18396 |
+
for i in range(m):
|
| 18397 |
+
min_match[i] = min(min_match[i], best[i])
|
| 18398 |
+
|
| 18399 |
+
# collect all distinct substrings: each state contributes lengths (link.len+1 .. min_match[state])
|
| 18400 |
+
res = set()
|
| 18401 |
+
for v in range(1, m):
|
| 18402 |
+
low = sam.len[sam.link[v]] + 1
|
| 18403 |
+
high = min_match[v]
|
| 18404 |
+
for L in range(low, high+1):
|
| 18405 |
+
# recover one substring of length L ending at this state by walking back from a position:
|
| 18406 |
+
# To avoid expensive reconstruction for every L, we reconstruct by scanning the first list.
|
| 18407 |
+
pass
|
| 18408 |
+
|
| 18409 |
+
# Efficient reconstruction: collect all end positions for each state by walking the first list
|
| 18410 |
+
# Build transitions to find substrings by scanning first list and recording (state, length) pairs
|
| 18411 |
+
cur = 0; l = 0
|
| 18412 |
+
pos_states = []
|
| 18413 |
+
for x in lists[0]:
|
| 18414 |
+
if x in sam.next[cur]:
|
| 18415 |
+
cur = sam.next[cur][x]; l += 1
|
| 18416 |
+
else:
|
| 18417 |
+
while cur != -1 and x not in sam.next[cur]:
|
| 18418 |
+
cur = sam.link[cur]
|
| 18419 |
+
if cur == -1:
|
| 18420 |
+
cur = 0; l = 0
|
| 18421 |
+
else:
|
| 18422 |
+
l = sam.len[cur] + 1
|
| 18423 |
+
cur = sam.next[cur][x]
|
| 18424 |
+
pos_states.append((cur, l))
|
| 18425 |
+
|
| 18426 |
+
# For each position, enumerate valid substring lengths and add actual slices
|
| 18427 |
+
n0 = len(lists[0])
|
| 18428 |
+
for i,(state, length) in enumerate(pos_states):
|
| 18429 |
+
maxlen = min(length, min_match[state])
|
| 18430 |
+
minlen = sam.len[sam.link[state]] + 1
|
| 18431 |
+
for L in range(minlen, maxlen+1):
|
| 18432 |
+
start = i - L + 1
|
| 18433 |
+
res.add(tuple(lists[0][start:start+L]))
|
| 18434 |
+
|
| 18435 |
+
return [list(t) for t in sorted(res, key=lambda x:(len(x), x))]
|
| 18436 |
+
|
| 18437 |
+
###################################################################################
|
| 18438 |
+
|
| 18439 |
+
def extract_non_overlapping_chords(escore_notes, max_dur=-1):
|
| 18440 |
+
|
| 18441 |
+
cscore = chordify_score([1000, escore_notes])
|
| 18442 |
+
|
| 18443 |
+
no_chords = []
|
| 18444 |
+
|
| 18445 |
+
for i, c in enumerate(cscore[:-1]):
|
| 18446 |
+
ntime = cscore[i+1][0][1]
|
| 18447 |
+
|
| 18448 |
+
if max_dur > 0:
|
| 18449 |
+
cval = max_dur
|
| 18450 |
+
|
| 18451 |
+
else:
|
| 18452 |
+
cval = closest_avg_val([e[2] for e in c])
|
| 18453 |
+
|
| 18454 |
+
if c[0][1]+cval <= ntime:
|
| 18455 |
+
no_chords.append(c)
|
| 18456 |
+
|
| 18457 |
+
no_chords.append(cscore[-1])
|
| 18458 |
+
|
| 18459 |
+
return no_chords
|
| 18460 |
+
|
| 18461 |
+
###################################################################################
|
| 18462 |
+
|
| 18463 |
+
def escore_chord_to_chord_token(escore_chord,
|
| 18464 |
+
use_full_chords=False,
|
| 18465 |
+
shift_chords=False
|
| 18466 |
+
):
|
| 18467 |
+
|
| 18468 |
+
if use_full_chords:
|
| 18469 |
+
CHORDS = ALL_CHORDS_FULL
|
| 18470 |
+
|
| 18471 |
+
else:
|
| 18472 |
+
CHORDS = ALL_CHORDS_SORTED
|
| 18473 |
+
|
| 18474 |
+
pitches = sorted(set([e[4] for e in escore_chord if e[3] != 9]))
|
| 18475 |
+
|
| 18476 |
+
if len(pitches) > 1:
|
| 18477 |
+
tones_chord = sorted(set([p % 12 for p in pitches]))
|
| 18478 |
+
|
| 18479 |
+
if tones_chord not in CHORDS:
|
| 18480 |
+
tones_chord = check_and_fix_tones_chord(tones_chord, use_full_chords=use_full_chords)
|
| 18481 |
+
|
| 18482 |
+
if shift_chords:
|
| 18483 |
+
return CHORDS.index(tones_chord)+12
|
| 18484 |
+
|
| 18485 |
+
else:
|
| 18486 |
+
return CHORDS.index(tones_chord)
|
| 18487 |
+
|
| 18488 |
+
elif len(pitches) == 1:
|
| 18489 |
+
if shift_chords:
|
| 18490 |
+
return pitches[0] % 12
|
| 18491 |
+
|
| 18492 |
+
else:
|
| 18493 |
+
return CHORDS.index([pitches[0] % 12])
|
| 18494 |
+
|
| 18495 |
+
else:
|
| 18496 |
+
return -1
|
| 18497 |
+
|
| 18498 |
+
###################################################################################
|
| 18499 |
+
|
| 18500 |
+
def transpose_chord_token(chord_token, transpose_value, use_full_chords=False):
|
| 18501 |
+
|
| 18502 |
+
if use_full_chords:
|
| 18503 |
+
CHORDS = ALL_CHORDS_FULL
|
| 18504 |
+
|
| 18505 |
+
else:
|
| 18506 |
+
CHORDS = ALL_CHORDS_SORTED
|
| 18507 |
+
|
| 18508 |
+
if 0 <= chord_token < len(CHORDS):
|
| 18509 |
+
tchord = CHORDS[chord_token]
|
| 18510 |
+
|
| 18511 |
+
t_tchord = transpose_tones_chord(tchord, transpose_value)
|
| 18512 |
+
|
| 18513 |
+
if t_tchord in CHORDS:
|
| 18514 |
+
return CHORDS.index(t_tchord)
|
| 18515 |
+
|
| 18516 |
+
return chord_token
|
| 18517 |
+
|
| 18518 |
+
return chord_token
|
| 18519 |
+
|
| 18520 |
+
###################################################################################
|
| 18521 |
+
|
| 18522 |
print('Module loaded!')
|
| 18523 |
print('=' * 70)
|
| 18524 |
print('Enjoy! :)')
|