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)
|