Upload 2 files
Browse files- TMIDIX.py +106 -1
- midi_to_colab_audio.py +102 -13
TMIDIX.py
CHANGED
@@ -51,7 +51,7 @@ r'''############################################################################
|
|
51 |
|
52 |
###################################################################################
|
53 |
|
54 |
-
__version__ = "25.8.
|
55 |
|
56 |
print('=' * 70)
|
57 |
print('TMIDIX Python module')
|
@@ -14433,6 +14433,111 @@ def replace_chords_in_escore_notes(escore_notes,
|
|
14433 |
|
14434 |
###################################################################################
|
14435 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14436 |
print('Module loaded!')
|
14437 |
print('=' * 70)
|
14438 |
print('Enjoy! :)')
|
|
|
51 |
|
52 |
###################################################################################
|
53 |
|
54 |
+
__version__ = "25.8.29"
|
55 |
|
56 |
print('=' * 70)
|
57 |
print('TMIDIX Python module')
|
|
|
14433 |
|
14434 |
###################################################################################
|
14435 |
|
14436 |
+
class Cell:
|
14437 |
+
def __init__(self, cost, segments, gaps, prev_dir):
|
14438 |
+
self.cost = cost
|
14439 |
+
self.segments = segments
|
14440 |
+
self.gaps = gaps
|
14441 |
+
self.prev_dir = prev_dir
|
14442 |
+
|
14443 |
+
def align_integer_lists(seq1, seq2):
|
14444 |
+
|
14445 |
+
n, m = len(seq1), len(seq2)
|
14446 |
+
|
14447 |
+
if n == 0:
|
14448 |
+
return [None]*m, seq2.copy(), sum(abs(x) for x in seq2)
|
14449 |
+
if m == 0:
|
14450 |
+
return seq1.copy(), [None]*n, sum(abs(x) for x in seq1)
|
14451 |
+
|
14452 |
+
priority = {'diag': 0, 'up': 1, 'left': 2}
|
14453 |
+
|
14454 |
+
dp = [
|
14455 |
+
[Cell(cost=math.inf, segments=math.inf, gaps=math.inf, prev_dir='') for _ in range(m+1)]
|
14456 |
+
for _ in range(n+1)
|
14457 |
+
]
|
14458 |
+
dp[0][0] = Cell(cost=0, segments=0, gaps=0, prev_dir='')
|
14459 |
+
|
14460 |
+
for i in range(1, n+1):
|
14461 |
+
prev = dp[i-1][0]
|
14462 |
+
new_cost = prev.cost + abs(seq1[i-1])
|
14463 |
+
new_seg = prev.segments + (1 if prev.prev_dir != 'up' else 0)
|
14464 |
+
new_gaps = prev.gaps + 1
|
14465 |
+
dp[i][0] = Cell(new_cost, new_seg, new_gaps, 'up')
|
14466 |
+
|
14467 |
+
for j in range(1, m+1):
|
14468 |
+
prev = dp[0][j-1]
|
14469 |
+
new_cost = prev.cost + abs(seq2[j-1])
|
14470 |
+
new_seg = prev.segments + (1 if prev.prev_dir != 'left' else 0)
|
14471 |
+
new_gaps = prev.gaps + 1
|
14472 |
+
dp[0][j] = Cell(new_cost, new_seg, new_gaps, 'left')
|
14473 |
+
|
14474 |
+
for i in range(1, n+1):
|
14475 |
+
for j in range(1, m+1):
|
14476 |
+
a, b = seq1[i-1], seq2[j-1]
|
14477 |
+
|
14478 |
+
c0 = dp[i-1][j-1]
|
14479 |
+
cand_diag = Cell(
|
14480 |
+
cost = c0.cost + abs(a - b),
|
14481 |
+
segments = c0.segments,
|
14482 |
+
gaps = c0.gaps,
|
14483 |
+
prev_dir = 'diag'
|
14484 |
+
)
|
14485 |
+
|
14486 |
+
c1 = dp[i-1][j]
|
14487 |
+
seg1 = c1.segments + (1 if c1.prev_dir != 'up' else 0)
|
14488 |
+
cand_up = Cell(
|
14489 |
+
cost = c1.cost + abs(a),
|
14490 |
+
segments = seg1,
|
14491 |
+
gaps = c1.gaps + 1,
|
14492 |
+
prev_dir = 'up'
|
14493 |
+
)
|
14494 |
+
|
14495 |
+
c2 = dp[i][j-1]
|
14496 |
+
seg2 = c2.segments + (1 if c2.prev_dir != 'left' else 0)
|
14497 |
+
cand_left = Cell(
|
14498 |
+
cost = c2.cost + abs(b),
|
14499 |
+
segments = seg2,
|
14500 |
+
gaps = c2.gaps + 1,
|
14501 |
+
prev_dir = 'left'
|
14502 |
+
)
|
14503 |
+
|
14504 |
+
best = min(
|
14505 |
+
(cand_diag, cand_up, cand_left),
|
14506 |
+
key=lambda c: (c.cost, c.segments, c.gaps, priority[c.prev_dir])
|
14507 |
+
)
|
14508 |
+
dp[i][j] = best
|
14509 |
+
|
14510 |
+
aligned1 = []
|
14511 |
+
aligned2 = []
|
14512 |
+
i, j = n, m
|
14513 |
+
|
14514 |
+
while i > 0 or j > 0:
|
14515 |
+
cell = dp[i][j]
|
14516 |
+
|
14517 |
+
if cell.prev_dir == 'diag':
|
14518 |
+
aligned1.append(seq1[i-1])
|
14519 |
+
aligned2.append(seq2[j-1])
|
14520 |
+
i, j = i-1, j-1
|
14521 |
+
|
14522 |
+
elif cell.prev_dir == 'up':
|
14523 |
+
aligned1.append(seq1[i-1])
|
14524 |
+
aligned2.append(None)
|
14525 |
+
i -= 1
|
14526 |
+
|
14527 |
+
else:
|
14528 |
+
aligned1.append(None)
|
14529 |
+
aligned2.append(seq2[j-1])
|
14530 |
+
j -= 1
|
14531 |
+
|
14532 |
+
aligned1.reverse()
|
14533 |
+
aligned2.reverse()
|
14534 |
+
|
14535 |
+
total_cost = int(dp[n][m].cost)
|
14536 |
+
|
14537 |
+
return aligned1, aligned2, total_cost
|
14538 |
+
|
14539 |
+
###################################################################################
|
14540 |
+
|
14541 |
print('Module loaded!')
|
14542 |
print('=' * 70)
|
14543 |
print('Enjoy! :)')
|
midi_to_colab_audio.py
CHANGED
@@ -3233,14 +3233,27 @@ def normalize_audio(audio: np.ndarray,
|
|
3233 |
#===============================================================================
|
3234 |
|
3235 |
def midi_opus_to_colab_audio(midi_opus,
|
3236 |
-
|
3237 |
-
|
3238 |
-
|
3239 |
-
|
3240 |
-
|
3241 |
-
|
3242 |
-
|
3243 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3244 |
|
3245 |
if midi_opus[1]:
|
3246 |
|
@@ -3263,7 +3276,37 @@ def midi_opus_to_colab_audio(midi_opus,
|
|
3263 |
for chan in range(16):
|
3264 |
# channel 9 = percussion GM bank 128
|
3265 |
fl.program_select(chan, sfid, 128 if chan == 9 else 0, 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3266 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3267 |
# Playback vars
|
3268 |
tempo = int((60 / 120) * 1e6) # default 120bpm
|
3269 |
last_t = 0
|
@@ -3299,11 +3342,11 @@ def midi_opus_to_colab_audio(midi_opus,
|
|
3299 |
|
3300 |
elif name == "key_after_touch":
|
3301 |
chan, note, vel = data
|
3302 |
-
fl.key_pressure(chan, note, vel)
|
3303 |
|
3304 |
elif name == "channel_after_touch":
|
3305 |
chan, vel = data
|
3306 |
-
fl.channel_pressure(chan, vel)
|
3307 |
|
3308 |
elif name == "pitch_wheel_change":
|
3309 |
chan, wheel = data
|
@@ -3373,6 +3416,8 @@ def midi_opus_to_colab_audio(midi_opus,
|
|
3373 |
# Optionally write WAV to disk
|
3374 |
if write_audio_to_WAV:
|
3375 |
wav_name = midi_file.rsplit('.', 1)[0] + '.wav'
|
|
|
|
|
3376 |
pcm = np.int16(raw_audio.T / np.max(np.abs(raw_audio)) * 32767)
|
3377 |
with wave.open(wav_name, 'wb') as wf:
|
3378 |
wf.setframerate(sample_rate)
|
@@ -3393,8 +3438,21 @@ def midi_to_colab_audio(midi_file,
|
|
3393 |
volume_level_db=-1,
|
3394 |
trim_silence=True,
|
3395 |
silence_threshold=0.1,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3396 |
output_for_gradio=False,
|
3397 |
-
write_audio_to_WAV=False
|
|
|
3398 |
):
|
3399 |
"""
|
3400 |
Returns raw audio to pass to IPython.disaply.Audio func
|
@@ -3427,6 +3485,35 @@ def midi_to_colab_audio(midi_file,
|
|
3427 |
# channel 9 = percussion GM bank 128
|
3428 |
fl.program_select(chan, sfid, 128 if chan == 9 else 0, 0)
|
3429 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3430 |
# Playback vars
|
3431 |
tempo = int((60 / 120) * 1e6) # default 120bpm
|
3432 |
last_t = 0
|
@@ -3462,11 +3549,11 @@ def midi_to_colab_audio(midi_file,
|
|
3462 |
|
3463 |
elif name == "key_after_touch":
|
3464 |
chan, note, vel = data
|
3465 |
-
fl.key_pressure(chan, note, vel)
|
3466 |
|
3467 |
elif name == "channel_after_touch":
|
3468 |
chan, vel = data
|
3469 |
-
fl.channel_pressure(chan, vel)
|
3470 |
|
3471 |
elif name == "pitch_wheel_change":
|
3472 |
chan, wheel = data
|
@@ -3536,6 +3623,8 @@ def midi_to_colab_audio(midi_file,
|
|
3536 |
# Optionally write WAV to disk
|
3537 |
if write_audio_to_WAV:
|
3538 |
wav_name = midi_file.rsplit('.', 1)[0] + '.wav'
|
|
|
|
|
3539 |
pcm = np.int16(raw_audio.T / np.max(np.abs(raw_audio)) * 32767)
|
3540 |
with wave.open(wav_name, 'wb') as wf:
|
3541 |
wf.setframerate(sample_rate)
|
|
|
3233 |
#===============================================================================
|
3234 |
|
3235 |
def midi_opus_to_colab_audio(midi_opus,
|
3236 |
+
soundfont_path='/usr/share/sounds/sf2/FluidR3_GM.sf2',
|
3237 |
+
sample_rate=16000, # 44100
|
3238 |
+
volume_level_db=-1,
|
3239 |
+
trim_silence=True,
|
3240 |
+
silence_threshold=0.1,
|
3241 |
+
enable_reverb=False,
|
3242 |
+
reverb_param_dic={'roomsize': 0,
|
3243 |
+
'damping': 0,
|
3244 |
+
'width': 0,
|
3245 |
+
'level': 0
|
3246 |
+
},
|
3247 |
+
enable_chorus=False,
|
3248 |
+
chorus_param_dic={'nr': 0,
|
3249 |
+
'level': 0,
|
3250 |
+
'speed': 0.1,
|
3251 |
+
'depth': 0,
|
3252 |
+
'type': 0},
|
3253 |
+
output_for_gradio=False,
|
3254 |
+
write_audio_to_WAV=False,
|
3255 |
+
output_WAV_name=''
|
3256 |
+
):
|
3257 |
|
3258 |
if midi_opus[1]:
|
3259 |
|
|
|
3276 |
for chan in range(16):
|
3277 |
# channel 9 = percussion GM bank 128
|
3278 |
fl.program_select(chan, sfid, 128 if chan == 9 else 0, 0)
|
3279 |
+
|
3280 |
+
if enable_reverb:
|
3281 |
+
fl.set_reverb(roomsize=reverb_param_dic['roomsize'],
|
3282 |
+
damping=reverb_param_dic['damping'],
|
3283 |
+
width=reverb_param_dic['width'],
|
3284 |
+
level=reverb_param_dic['level']
|
3285 |
+
)
|
3286 |
+
|
3287 |
+
"""
|
3288 |
+
roomsize Reverb room size value (0.0-1.0)
|
3289 |
+
damping Reverb damping value (0.0-1.0)
|
3290 |
+
width Reverb width value (0.0-100.0)
|
3291 |
+
level Reverb level value (0.0-1.0)
|
3292 |
+
"""
|
3293 |
|
3294 |
+
if enable_chorus:
|
3295 |
+
fl.set_chorus(nr=chorus_param_dic['nr'],
|
3296 |
+
level=chorus_param_dic['level'],
|
3297 |
+
speed=chorus_param_dic['speed'],
|
3298 |
+
depth=chorus_param_dic['depth'],
|
3299 |
+
type=chorus_param_dic['type']
|
3300 |
+
)
|
3301 |
+
|
3302 |
+
"""
|
3303 |
+
nr Chorus voice count (0-99, CPU time consumption proportional to this value)
|
3304 |
+
level Chorus level (0.0-10.0)
|
3305 |
+
speed Chorus speed in Hz (0.29-5.0)
|
3306 |
+
depth_ms Chorus depth (max value depends on synth sample rate, 0.0-21.0 is safe for sample rate values up to 96KHz)
|
3307 |
+
type Chorus waveform type (0=sine, 1=triangle)
|
3308 |
+
"""
|
3309 |
+
|
3310 |
# Playback vars
|
3311 |
tempo = int((60 / 120) * 1e6) # default 120bpm
|
3312 |
last_t = 0
|
|
|
3342 |
|
3343 |
elif name == "key_after_touch":
|
3344 |
chan, note, vel = data
|
3345 |
+
# fl.key_pressure(chan, note, vel)
|
3346 |
|
3347 |
elif name == "channel_after_touch":
|
3348 |
chan, vel = data
|
3349 |
+
# fl.channel_pressure(chan, vel)
|
3350 |
|
3351 |
elif name == "pitch_wheel_change":
|
3352 |
chan, wheel = data
|
|
|
3416 |
# Optionally write WAV to disk
|
3417 |
if write_audio_to_WAV:
|
3418 |
wav_name = midi_file.rsplit('.', 1)[0] + '.wav'
|
3419 |
+
if output_WAV_name != '':
|
3420 |
+
wav_name = output_WAV_name
|
3421 |
pcm = np.int16(raw_audio.T / np.max(np.abs(raw_audio)) * 32767)
|
3422 |
with wave.open(wav_name, 'wb') as wf:
|
3423 |
wf.setframerate(sample_rate)
|
|
|
3438 |
volume_level_db=-1,
|
3439 |
trim_silence=True,
|
3440 |
silence_threshold=0.1,
|
3441 |
+
enable_reverb=False,
|
3442 |
+
reverb_param_dic={'roomsize': 0,
|
3443 |
+
'damping': 0,
|
3444 |
+
'width': 0,
|
3445 |
+
'level': 0
|
3446 |
+
},
|
3447 |
+
enable_chorus=False,
|
3448 |
+
chorus_param_dic={'nr': 0,
|
3449 |
+
'level': 0,
|
3450 |
+
'speed': 0.1,
|
3451 |
+
'depth': 0,
|
3452 |
+
'type': 0},
|
3453 |
output_for_gradio=False,
|
3454 |
+
write_audio_to_WAV=False,
|
3455 |
+
output_WAV_name=''
|
3456 |
):
|
3457 |
"""
|
3458 |
Returns raw audio to pass to IPython.disaply.Audio func
|
|
|
3485 |
# channel 9 = percussion GM bank 128
|
3486 |
fl.program_select(chan, sfid, 128 if chan == 9 else 0, 0)
|
3487 |
|
3488 |
+
if enable_reverb:
|
3489 |
+
fl.set_reverb(roomsize=reverb_param_dic['roomsize'],
|
3490 |
+
damping=reverb_param_dic['damping'],
|
3491 |
+
width=reverb_param_dic['width'],
|
3492 |
+
level=reverb_param_dic['level']
|
3493 |
+
)
|
3494 |
+
|
3495 |
+
"""
|
3496 |
+
roomsize Reverb room size value (0.0-1.0)
|
3497 |
+
damping Reverb damping value (0.0-1.0)
|
3498 |
+
width Reverb width value (0.0-100.0)
|
3499 |
+
level Reverb level value (0.0-1.0)
|
3500 |
+
"""
|
3501 |
+
|
3502 |
+
if enable_chorus:
|
3503 |
+
fl.set_chorus(nr=chorus_param_dic['nr'],
|
3504 |
+
level=chorus_param_dic['level'],
|
3505 |
+
speed=chorus_param_dic['speed'],
|
3506 |
+
depth=chorus_param_dic['depth'],
|
3507 |
+
type=chorus_param_dic['type']
|
3508 |
+
)
|
3509 |
+
|
3510 |
+
"""
|
3511 |
+
nr Chorus voice count (0-99, CPU time consumption proportional to this value)
|
3512 |
+
level Chorus level (0.0-10.0)
|
3513 |
+
speed Chorus speed in Hz (0.29-5.0)
|
3514 |
+
depth_ms Chorus depth (max value depends on synth sample rate, 0.0-21.0 is safe for sample rate values up to 96KHz)
|
3515 |
+
type Chorus waveform type (0=sine, 1=triangle)
|
3516 |
+
"""
|
3517 |
# Playback vars
|
3518 |
tempo = int((60 / 120) * 1e6) # default 120bpm
|
3519 |
last_t = 0
|
|
|
3549 |
|
3550 |
elif name == "key_after_touch":
|
3551 |
chan, note, vel = data
|
3552 |
+
# fl.key_pressure(chan, note, vel)
|
3553 |
|
3554 |
elif name == "channel_after_touch":
|
3555 |
chan, vel = data
|
3556 |
+
# fl.channel_pressure(chan, vel)
|
3557 |
|
3558 |
elif name == "pitch_wheel_change":
|
3559 |
chan, wheel = data
|
|
|
3623 |
# Optionally write WAV to disk
|
3624 |
if write_audio_to_WAV:
|
3625 |
wav_name = midi_file.rsplit('.', 1)[0] + '.wav'
|
3626 |
+
if output_WAV_name != '':
|
3627 |
+
wav_name = output_WAV_name
|
3628 |
pcm = np.int16(raw_audio.T / np.max(np.abs(raw_audio)) * 32767)
|
3629 |
with wave.open(wav_name, 'wb') as wf:
|
3630 |
wf.setframerate(sample_rate)
|