Upload TMIDIX.py
Browse files
TMIDIX.py
CHANGED
|
@@ -51,7 +51,7 @@ r'''############################################################################
|
|
| 51 |
|
| 52 |
###################################################################################
|
| 53 |
|
| 54 |
-
__version__ = "26.2.
|
| 55 |
|
| 56 |
print('=' * 70)
|
| 57 |
print('TMIDIX Python module')
|
|
@@ -16094,6 +16094,391 @@ def squash_monophonic_escore_notes_pitches(escore_notes,
|
|
| 16094 |
|
| 16095 |
###################################################################################
|
| 16096 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16097 |
print('Module loaded!')
|
| 16098 |
print('=' * 70)
|
| 16099 |
print('Enjoy! :)')
|
|
|
|
| 51 |
|
| 52 |
###################################################################################
|
| 53 |
|
| 54 |
+
__version__ = "26.2.17"
|
| 55 |
|
| 56 |
print('=' * 70)
|
| 57 |
print('TMIDIX Python module')
|
|
|
|
| 16094 |
|
| 16095 |
###################################################################################
|
| 16096 |
|
| 16097 |
+
def humanize_velocities_in_escore_notes(escore_notes):
|
| 16098 |
+
|
| 16099 |
+
if not escore_notes:
|
| 16100 |
+
return []
|
| 16101 |
+
|
| 16102 |
+
notes = [list(n) for n in escore_notes]
|
| 16103 |
+
notes.sort(key=lambda x: (x[1], x[4])) # Sort by time, then pitch
|
| 16104 |
+
|
| 16105 |
+
# -----------------------------------------------------------
|
| 16106 |
+
# 1. GLOBAL ANALYSIS (Grid, Phrases, Arcs)
|
| 16107 |
+
# -----------------------------------------------------------
|
| 16108 |
+
|
| 16109 |
+
onset_times = sorted(list(set([n[1] for n in notes])))
|
| 16110 |
+
|
| 16111 |
+
# --- Grid Estimation ---
|
| 16112 |
+
estimated_grid = 120
|
| 16113 |
+
if len(onset_times) > 1:
|
| 16114 |
+
intervals = [onset_times[i+1] - onset_times[i] for i in range(len(onset_times)-1)]
|
| 16115 |
+
active_intervals = [i for i in intervals if i > 0 and i < 960]
|
| 16116 |
+
if active_intervals:
|
| 16117 |
+
rounded_intervals = [round(i / 10) * 10 for i in active_intervals]
|
| 16118 |
+
valid_intervals = [r for r in rounded_intervals if r > 0]
|
| 16119 |
+
if valid_intervals:
|
| 16120 |
+
estimated_grid = max(set(valid_intervals), key=valid_intervals.count)
|
| 16121 |
+
|
| 16122 |
+
# --- Beat Grid Calculation ---
|
| 16123 |
+
if estimated_grid <= 120:
|
| 16124 |
+
beat_grid = estimated_grid * 4
|
| 16125 |
+
elif estimated_grid <= 240:
|
| 16126 |
+
beat_grid = estimated_grid * 2
|
| 16127 |
+
else:
|
| 16128 |
+
beat_grid = estimated_grid
|
| 16129 |
+
|
| 16130 |
+
# --- Phrase Detection ---
|
| 16131 |
+
melodic_onsets = sorted(list(set([n[1] for n in notes if n[3] != 9])))
|
| 16132 |
+
phrase_gap_threshold = beat_grid * 3
|
| 16133 |
+
|
| 16134 |
+
phrases = []
|
| 16135 |
+
current_phrase = []
|
| 16136 |
+
|
| 16137 |
+
if not melodic_onsets: melodic_onsets = onset_times
|
| 16138 |
+
|
| 16139 |
+
for i, t in enumerate(melodic_onsets):
|
| 16140 |
+
if not current_phrase:
|
| 16141 |
+
current_phrase.append(t)
|
| 16142 |
+
else:
|
| 16143 |
+
prev_t = melodic_onsets[i-1]
|
| 16144 |
+
if t - prev_t > phrase_gap_threshold:
|
| 16145 |
+
phrases.append(current_phrase)
|
| 16146 |
+
current_phrase = [t]
|
| 16147 |
+
else:
|
| 16148 |
+
current_phrase.append(t)
|
| 16149 |
+
if current_phrase:
|
| 16150 |
+
phrases.append(current_phrase)
|
| 16151 |
+
|
| 16152 |
+
# --- Global Arc Calculation ---
|
| 16153 |
+
total_duration = onset_times[-1] - onset_times[0] if onset_times else 0
|
| 16154 |
+
global_progress_map = {}
|
| 16155 |
+
for t in onset_times:
|
| 16156 |
+
progress = (t - onset_times[0]) / total_duration if total_duration > 0 else 0
|
| 16157 |
+
global_arc = math.cos((progress - 0.5) * math.pi) * 6 # Range -6 to +6
|
| 16158 |
+
global_progress_map[t] = global_arc
|
| 16159 |
+
|
| 16160 |
+
# -----------------------------------------------------------
|
| 16161 |
+
# 2. INSTRUMENT SEPARATION & PROCESSING
|
| 16162 |
+
# -----------------------------------------------------------
|
| 16163 |
+
|
| 16164 |
+
instrument_tracks = defaultdict(list)
|
| 16165 |
+
for n in notes:
|
| 16166 |
+
instrument_tracks[(n[3], n[6])].append(n)
|
| 16167 |
+
|
| 16168 |
+
# Main Loop
|
| 16169 |
+
for key, track_notes in instrument_tracks.items():
|
| 16170 |
+
channel, inst_num = key
|
| 16171 |
+
|
| 16172 |
+
# --- Instrument Classification ---
|
| 16173 |
+
is_drum = (channel == 9) or (inst_num == 128)
|
| 16174 |
+
is_bass = (32 <= inst_num <= 39)
|
| 16175 |
+
is_keys = (inst_num <= 7) or (16 <= inst_num <= 23)
|
| 16176 |
+
is_plucked = (24 <= inst_num <= 31)
|
| 16177 |
+
is_solo_string = (40 <= inst_num <= 47)
|
| 16178 |
+
is_ensemble = (48 <= inst_num <= 55)
|
| 16179 |
+
is_synth_lead = (80 <= inst_num <= 87)
|
| 16180 |
+
is_synth_pad = (88 <= inst_num <= 95)
|
| 16181 |
+
|
| 16182 |
+
track_notes.sort(key=lambda x: (x[1], x[4]))
|
| 16183 |
+
|
| 16184 |
+
# ==========================================================
|
| 16185 |
+
# LOGIC A: DRUMS (UNIFORM & SEPARATED)
|
| 16186 |
+
# ==========================================================
|
| 16187 |
+
if is_drum:
|
| 16188 |
+
for n in track_notes:
|
| 16189 |
+
t, pitch = n[1], n[4]
|
| 16190 |
+
|
| 16191 |
+
is_kick = pitch in [35, 36]
|
| 16192 |
+
is_snare = pitch in [38, 40]
|
| 16193 |
+
is_hat = pitch in [42, 44, 46]
|
| 16194 |
+
is_tom = 41 <= pitch <= 50 and not is_hat and not is_snare
|
| 16195 |
+
|
| 16196 |
+
if is_kick:
|
| 16197 |
+
target_vel = 115
|
| 16198 |
+
elif is_snare:
|
| 16199 |
+
target_vel = 112
|
| 16200 |
+
elif is_hat:
|
| 16201 |
+
target_vel = 90
|
| 16202 |
+
elif is_tom:
|
| 16203 |
+
target_vel = 105
|
| 16204 |
+
else:
|
| 16205 |
+
target_vel = 100
|
| 16206 |
+
|
| 16207 |
+
position_in_beat = t % beat_grid
|
| 16208 |
+
if position_in_beat == 0:
|
| 16209 |
+
metric_mod = 0
|
| 16210 |
+
elif position_in_beat == (beat_grid // 2):
|
| 16211 |
+
metric_mod = -2
|
| 16212 |
+
else:
|
| 16213 |
+
metric_mod = -6
|
| 16214 |
+
|
| 16215 |
+
closest_t = min(onset_times, key=lambda x: abs(x - t))
|
| 16216 |
+
global_mod = global_progress_map.get(closest_t, 0)
|
| 16217 |
+
|
| 16218 |
+
final_vel = target_vel + metric_mod + global_mod + random.gauss(0, 2.0)
|
| 16219 |
+
n[5] = max(30, min(127, int(final_vel)))
|
| 16220 |
+
|
| 16221 |
+
continue
|
| 16222 |
+
|
| 16223 |
+
# ==========================================================
|
| 16224 |
+
# LOGIC B: BASS
|
| 16225 |
+
# ==========================================================
|
| 16226 |
+
elif is_bass:
|
| 16227 |
+
last_vel = 100
|
| 16228 |
+
for n in track_notes:
|
| 16229 |
+
t = n[1]
|
| 16230 |
+
|
| 16231 |
+
position_in_grid = t % beat_grid
|
| 16232 |
+
metric_strength = 4 if position_in_grid == 0 else (1 if position_in_grid == (beat_grid // 2) else -2)
|
| 16233 |
+
|
| 16234 |
+
target = 100 + metric_strength
|
| 16235 |
+
|
| 16236 |
+
smoothed = (target * 0.3) + (last_vel * 0.7)
|
| 16237 |
+
last_vel = smoothed
|
| 16238 |
+
|
| 16239 |
+
final_vel = smoothed + random.gauss(0, 2)
|
| 16240 |
+
n[5] = max(30, min(115, int(final_vel)))
|
| 16241 |
+
continue
|
| 16242 |
+
|
| 16243 |
+
# ==========================================================
|
| 16244 |
+
# LOGIC C: MELODIC INSTRUMENTS
|
| 16245 |
+
# ==========================================================
|
| 16246 |
+
else:
|
| 16247 |
+
# --- Role Detection (Base Velocity Target) ---
|
| 16248 |
+
# Determine the 'floor' velocity for this track
|
| 16249 |
+
|
| 16250 |
+
base_vel_target = 90 # Default
|
| 16251 |
+
|
| 16252 |
+
if is_solo_string or is_synth_lead:
|
| 16253 |
+
base_vel_target = 105 # Lead
|
| 16254 |
+
elif is_ensemble or is_synth_pad:
|
| 16255 |
+
base_vel_target = 80 # Pad/Backing
|
| 16256 |
+
elif is_plucked:
|
| 16257 |
+
# Check density for Guitar Solo vs Rhythm
|
| 16258 |
+
unique_onsets = set(nn[1] for nn in track_notes)
|
| 16259 |
+
avg_poly = len(track_notes) / len(unique_onsets) if unique_onsets else 1
|
| 16260 |
+
base_vel_target = 105 if avg_poly < 1.3 else 95
|
| 16261 |
+
elif is_keys:
|
| 16262 |
+
# Check if it looks like a Solo Piano piece or just a Piano track
|
| 16263 |
+
# If the whole score is basically this track -> Solo
|
| 16264 |
+
if len(track_notes) > (len(notes) * 0.8):
|
| 16265 |
+
base_vel_target = 100
|
| 16266 |
+
else:
|
| 16267 |
+
base_vel_target = 90
|
| 16268 |
+
|
| 16269 |
+
# --- Dispatch to specific logic ---
|
| 16270 |
+
|
| 16271 |
+
# CASE 1: PIANO / KEYS (RESTORED ORIGINAL LOGIC)
|
| 16272 |
+
if is_keys:
|
| 16273 |
+
last_vel_lh = base_vel_target
|
| 16274 |
+
last_vel_rh = base_vel_target
|
| 16275 |
+
prev_melody_pitch = None
|
| 16276 |
+
|
| 16277 |
+
time_slices = defaultdict(list)
|
| 16278 |
+
for n in track_notes:
|
| 16279 |
+
time_slices[n[1]].append(n)
|
| 16280 |
+
sorted_times = sorted(time_slices.keys())
|
| 16281 |
+
|
| 16282 |
+
for t_idx, t in enumerate(sorted_times):
|
| 16283 |
+
slice_notes = time_slices[t]
|
| 16284 |
+
slice_notes.sort(key=lambda x: x[4])
|
| 16285 |
+
|
| 16286 |
+
# Context Mods
|
| 16287 |
+
phrase_arc_mod = 0
|
| 16288 |
+
for p_times in phrases:
|
| 16289 |
+
if t in p_times:
|
| 16290 |
+
p_len = p_times[-1] - p_times[0]
|
| 16291 |
+
if p_len > 0:
|
| 16292 |
+
progress = (t - p_times[0]) / p_len
|
| 16293 |
+
phrase_arc_mod = math.cos((1.0 - progress) * math.pi) * 0.5 + 0.5
|
| 16294 |
+
phrase_arc_mod = (phrase_arc_mod - 0.5) * 10
|
| 16295 |
+
break
|
| 16296 |
+
|
| 16297 |
+
global_arc = global_progress_map.get(t, 0)
|
| 16298 |
+
|
| 16299 |
+
position_in_grid = t % beat_grid
|
| 16300 |
+
if position_in_grid == 0: metric_strength = 6
|
| 16301 |
+
elif position_in_grid == (beat_grid // 2): metric_strength = 2
|
| 16302 |
+
else: metric_strength = -3
|
| 16303 |
+
|
| 16304 |
+
# Hand Splitting Logic
|
| 16305 |
+
pitches = [n[4] for n in slice_notes]
|
| 16306 |
+
split_idx = 0
|
| 16307 |
+
max_gap = 0
|
| 16308 |
+
|
| 16309 |
+
if len(pitches) > 1:
|
| 16310 |
+
for i in range(len(pitches)-1):
|
| 16311 |
+
gap = pitches[i+1] - pitches[i]
|
| 16312 |
+
if gap > max_gap:
|
| 16313 |
+
max_gap = gap
|
| 16314 |
+
split_idx = i + 1
|
| 16315 |
+
|
| 16316 |
+
if max_gap < 12:
|
| 16317 |
+
avg_pitch = sum(pitches) / len(pitches)
|
| 16318 |
+
split_idx = 0 if avg_pitch >= 60 else len(pitches)
|
| 16319 |
+
|
| 16320 |
+
lh_notes = slice_notes[:split_idx]
|
| 16321 |
+
rh_notes = slice_notes[split_idx:]
|
| 16322 |
+
|
| 16323 |
+
# LH Processing
|
| 16324 |
+
if lh_notes:
|
| 16325 |
+
target_lh = base_vel_target + metric_strength + global_arc + phrase_arc_mod - 3
|
| 16326 |
+
smoothed_lh = (target_lh * 0.25) + (last_vel_lh * 0.75)
|
| 16327 |
+
last_vel_lh = smoothed_lh
|
| 16328 |
+
|
| 16329 |
+
for i, n in enumerate(lh_notes):
|
| 16330 |
+
offset = 0 if i == 0 else -5
|
| 16331 |
+
if n[2] < estimated_grid / 2: offset += 2
|
| 16332 |
+
vel = smoothed_lh + offset + random.gauss(0, 2)
|
| 16333 |
+
n[5] = max(30, min(115, int(vel)))
|
| 16334 |
+
|
| 16335 |
+
# RH Processing
|
| 16336 |
+
if rh_notes:
|
| 16337 |
+
target_rh = base_vel_target + metric_strength + global_arc + phrase_arc_mod + 3
|
| 16338 |
+
smoothed_rh = (target_rh * 0.35) + (last_vel_rh * 0.65)
|
| 16339 |
+
last_vel_rh = smoothed_rh
|
| 16340 |
+
|
| 16341 |
+
current_top_pitch = rh_notes[-1][4]
|
| 16342 |
+
num_rh = len(rh_notes)
|
| 16343 |
+
is_dense = num_rh >= 3
|
| 16344 |
+
|
| 16345 |
+
for i, n in enumerate(rh_notes):
|
| 16346 |
+
pitch = n[4]
|
| 16347 |
+
offset = 0
|
| 16348 |
+
|
| 16349 |
+
if i == num_rh - 1: # Top note melody
|
| 16350 |
+
offset = 12 if is_dense else 5
|
| 16351 |
+
if prev_melody_pitch is not None:
|
| 16352 |
+
diff = pitch - prev_melody_pitch
|
| 16353 |
+
if diff > 4: offset += 6
|
| 16354 |
+
elif diff > 0: offset += 3
|
| 16355 |
+
elif diff < -4: offset -= 4
|
| 16356 |
+
if pitch > 72: offset += (pitch - 72) * 0.2
|
| 16357 |
+
prev_melody_pitch = pitch
|
| 16358 |
+
elif i == 0:
|
| 16359 |
+
offset = -1
|
| 16360 |
+
else:
|
| 16361 |
+
offset = -8
|
| 16362 |
+
|
| 16363 |
+
if n[2] < estimated_grid / 2: offset += 2
|
| 16364 |
+
vel = smoothed_rh + offset + random.gauss(0, 2)
|
| 16365 |
+
n[5] = max(35, min(120, int(vel)))
|
| 16366 |
+
|
| 16367 |
+
# CASE 2: OTHER MELODIC (Generic Role-Based Logic)
|
| 16368 |
+
else:
|
| 16369 |
+
last_vel = base_vel_target
|
| 16370 |
+
prev_melody_pitch = None
|
| 16371 |
+
|
| 16372 |
+
time_slices = defaultdict(list)
|
| 16373 |
+
for n in track_notes:
|
| 16374 |
+
time_slices[n[1]].append(n)
|
| 16375 |
+
sorted_times = sorted(time_slices.keys())
|
| 16376 |
+
|
| 16377 |
+
for t_idx, t in enumerate(sorted_times):
|
| 16378 |
+
slice_notes = time_slices[t]
|
| 16379 |
+
slice_notes.sort(key=lambda x: x[4])
|
| 16380 |
+
|
| 16381 |
+
# Context
|
| 16382 |
+
phrase_arc_mod = 0
|
| 16383 |
+
for p_times in phrases:
|
| 16384 |
+
if t in p_times:
|
| 16385 |
+
p_len = p_times[-1] - p_times[0]
|
| 16386 |
+
if p_len > 0:
|
| 16387 |
+
progress = (t - p_times[0]) / p_len
|
| 16388 |
+
phrase_arc_mod = math.sin(progress * math.pi) * 6
|
| 16389 |
+
break
|
| 16390 |
+
|
| 16391 |
+
global_arc = global_progress_map.get(t, 0)
|
| 16392 |
+
|
| 16393 |
+
position_in_grid = t % beat_grid
|
| 16394 |
+
if position_in_grid == 0: metric_strength = 6
|
| 16395 |
+
elif position_in_grid == (beat_grid // 2): metric_strength = 2
|
| 16396 |
+
else: metric_strength = -3
|
| 16397 |
+
|
| 16398 |
+
core_vel = base_vel_target + metric_strength + global_arc + phrase_arc_mod
|
| 16399 |
+
smoothed = (core_vel * 0.35) + (last_vel * 0.65)
|
| 16400 |
+
last_vel = smoothed
|
| 16401 |
+
|
| 16402 |
+
num_notes = len(slice_notes)
|
| 16403 |
+
|
| 16404 |
+
for i, n in enumerate(slice_notes):
|
| 16405 |
+
pitch = n[4]
|
| 16406 |
+
offset = 0
|
| 16407 |
+
|
| 16408 |
+
if i == num_notes - 1:
|
| 16409 |
+
offset = 10
|
| 16410 |
+
if prev_melody_pitch is not None:
|
| 16411 |
+
diff = pitch - prev_melody_pitch
|
| 16412 |
+
if diff > 4: offset += 5
|
| 16413 |
+
prev_melody_pitch = pitch
|
| 16414 |
+
elif i == 0:
|
| 16415 |
+
offset = 0
|
| 16416 |
+
else:
|
| 16417 |
+
offset = -6
|
| 16418 |
+
|
| 16419 |
+
final_vel = smoothed + offset + random.gauss(0, 3)
|
| 16420 |
+
n[5] = max(30, min(127, int(final_vel)))
|
| 16421 |
+
|
| 16422 |
+
# -----------------------------------------------------------
|
| 16423 |
+
# 3. FINAL EXPRESSIVE SCALING
|
| 16424 |
+
# -----------------------------------------------------------
|
| 16425 |
+
for n in notes:
|
| 16426 |
+
if n[3] == 9:
|
| 16427 |
+
continue
|
| 16428 |
+
|
| 16429 |
+
v = n[5]
|
| 16430 |
+
center = 95
|
| 16431 |
+
|
| 16432 |
+
deviation = v - center
|
| 16433 |
+
final_v = center + (deviation * 1.1)
|
| 16434 |
+
final_v += random.randint(-1, 1)
|
| 16435 |
+
|
| 16436 |
+
n[5] = max(20, min(127, int(final_v)))
|
| 16437 |
+
|
| 16438 |
+
return notes
|
| 16439 |
+
|
| 16440 |
+
###################################################################################
|
| 16441 |
+
|
| 16442 |
+
def most_common_ordered_set(values):
|
| 16443 |
+
|
| 16444 |
+
freq = Counter(values)
|
| 16445 |
+
|
| 16446 |
+
top_vals = {v for v, _ in freq.most_common()}
|
| 16447 |
+
|
| 16448 |
+
result = []
|
| 16449 |
+
seen = set()
|
| 16450 |
+
|
| 16451 |
+
for v in values:
|
| 16452 |
+
if v in top_vals and v not in seen:
|
| 16453 |
+
result.append(v)
|
| 16454 |
+
seen.add(v)
|
| 16455 |
+
|
| 16456 |
+
return result
|
| 16457 |
+
|
| 16458 |
+
###################################################################################
|
| 16459 |
+
|
| 16460 |
+
def escore_notes_velocities(escore_notes, chan_idx=3, vels_idx=5):
|
| 16461 |
+
|
| 16462 |
+
output_list = []
|
| 16463 |
+
|
| 16464 |
+
all_vels = [e[vels_idx] for e in escore_notes]
|
| 16465 |
+
avg_vel = sum(all_vels) / len(all_vels)
|
| 16466 |
+
vels_span = max(all_vels) - min(all_vels)
|
| 16467 |
+
|
| 16468 |
+
output_list.append([-1, min(all_vels), avg_vel, max(all_vels), vels_span])
|
| 16469 |
+
|
| 16470 |
+
chan_groups = groupby(sorted(escore_notes, key=lambda x: x[chan_idx]), key=lambda x: x[chan_idx])
|
| 16471 |
+
|
| 16472 |
+
for cha, group in chan_groups:
|
| 16473 |
+
all_vels = [e[vels_idx] for e in list(group)]
|
| 16474 |
+
avg_vel = sum(all_vels) / len(all_vels)
|
| 16475 |
+
vels_span = max(all_vels) - min(all_vels)
|
| 16476 |
+
output_list.append([cha, min(all_vels), avg_vel, max(all_vels), vels_span])
|
| 16477 |
+
|
| 16478 |
+
return output_list
|
| 16479 |
+
|
| 16480 |
+
###################################################################################
|
| 16481 |
+
|
| 16482 |
print('Module loaded!')
|
| 16483 |
print('=' * 70)
|
| 16484 |
print('Enjoy! :)')
|