Sync: Complete project state with all MEGA SPRINT V1-V3 features and Codex stubs
This commit is contained in:
145
apply_phantom_patch.py
Normal file
145
apply_phantom_patch.py
Normal file
@@ -0,0 +1,145 @@
|
||||
import os
|
||||
|
||||
patch = ''' def _create_arrangement_audio_pattern(self, track_index, file_path, positions, name=""):
|
||||
"""Create one or more arrangement audio clips from an absolute file path."""
|
||||
try:
|
||||
if str(file_path).startswith('/mnt/'):
|
||||
parts = str(file_path)[5:].split('/', 1)
|
||||
file_path = parts[0].upper() + ":\\\\" + parts[1].replace('/', '\\\\')
|
||||
|
||||
if track_index < 0 or track_index >= len(self._song.tracks):
|
||||
raise IndexError("Track index out of range")
|
||||
|
||||
track = self._song.tracks[track_index]
|
||||
|
||||
resolved_path = os.path.abspath(str(file_path or ""))
|
||||
if not resolved_path or not os.path.isfile(resolved_path):
|
||||
raise IOError("Audio file not found: " + resolved_path)
|
||||
|
||||
if isinstance(positions, (int, float)):
|
||||
positions = [positions]
|
||||
elif not isinstance(positions, (list, tuple)):
|
||||
positions = [0.0]
|
||||
|
||||
cleaned_positions = []
|
||||
for position in positions:
|
||||
try:
|
||||
cleaned_positions.append(float(position))
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not cleaned_positions:
|
||||
cleaned_positions = [0.0]
|
||||
|
||||
created_positions = []
|
||||
for index, position in enumerate(cleaned_positions):
|
||||
success = False
|
||||
created_clip = None
|
||||
|
||||
for attempt in range(3):
|
||||
try:
|
||||
# Find an empty session slot
|
||||
temp_slot_index = self._find_or_create_empty_clip_slot(track)
|
||||
clip_slot = track.clip_slots[temp_slot_index]
|
||||
if clip_slot.has_clip:
|
||||
clip_slot.delete_clip()
|
||||
|
||||
# Load audio into session slot
|
||||
session_clip = None
|
||||
if hasattr(clip_slot, "create_audio_clip"):
|
||||
session_clip = clip_slot.create_audio_clip(resolved_path)
|
||||
elif hasattr(track, "create_audio_clip"):
|
||||
# Fallback if LOM uses track for this
|
||||
session_clip = track.create_audio_clip(resolved_path, float(position))
|
||||
if session_clip:
|
||||
self.log_message("Warning: created audio clip directly on track (fallback)")
|
||||
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
|
||||
# Duplicate to arrangement
|
||||
# If session_clip exists and we have the duplicate method
|
||||
if hasattr(self._song, "duplicate_clip_to_arrangement") and hasattr(clip_slot, "create_audio_clip"):
|
||||
self.log_message("Duplicating session audio clip to arrangement")
|
||||
self._song.duplicate_clip_to_arrangement(track, temp_slot_index, float(position))
|
||||
time.sleep(0.1)
|
||||
|
||||
if clip_slot.has_clip:
|
||||
clip_slot.delete_clip()
|
||||
|
||||
clip_persisted = False
|
||||
for clip in getattr(track, "arrangement_clips", getattr(track, "clips", [])):
|
||||
if hasattr(clip, "start_time") and abs(float(clip.start_time) - float(position)) < 0.05:
|
||||
clip_persisted = True
|
||||
created_clip = clip
|
||||
break
|
||||
|
||||
if clip_persisted:
|
||||
success = True
|
||||
break
|
||||
|
||||
self.log_message("Warning: Clip at " + str(position) + " not persisted on attempt " + str(attempt+1))
|
||||
time.sleep(0.1)
|
||||
|
||||
except Exception as e:
|
||||
self.log_message("Warning: Clip creation error at attempt " + str(attempt+1) + ": " + str(e))
|
||||
try:
|
||||
if 'clip_slot' in locals() and clip_slot.has_clip:
|
||||
clip_slot.delete_clip()
|
||||
except:
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
|
||||
if not success:
|
||||
self.log_message("Error: Failed to persist audio clip at " + str(position) + " after 3 attempts")
|
||||
continue
|
||||
|
||||
clip_name = str(name or "").strip()
|
||||
if clip_name:
|
||||
if len(cleaned_positions) > 1:
|
||||
clip_name = clip_name + " " + str(index + 1)
|
||||
try:
|
||||
if created_clip is not None and hasattr(created_clip, "name"):
|
||||
created_clip.name = clip_name
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
created_positions.append(float(position))
|
||||
|
||||
return {
|
||||
"track_index": int(track_index),
|
||||
"file_path": resolved_path,
|
||||
"created_count": len(created_positions),
|
||||
"positions": created_positions,
|
||||
"name": str(name or "").strip(),
|
||||
}
|
||||
except Exception as e:
|
||||
self.log_message("Error creating arrangement audio pattern: " + str(e))
|
||||
raise
|
||||
'''
|
||||
|
||||
def patch_file(p):
|
||||
with open(p, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
start_idx = -1
|
||||
end_idx = -1
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith(' def _create_arrangement_audio_pattern('):
|
||||
start_idx = i
|
||||
for j in range(i+1, len(lines)):
|
||||
if lines[j].startswith(' def '):
|
||||
end_idx = j
|
||||
break
|
||||
break
|
||||
|
||||
if start_idx != -1 and end_idx != -1:
|
||||
lines = lines[:start_idx] + [patch + '\n'] + lines[end_idx:]
|
||||
with open(p, 'w', encoding='utf-8') as f:
|
||||
f.writelines(lines)
|
||||
print("Patched", os.path.basename(p))
|
||||
else:
|
||||
print("Failed", os.path.basename(p))
|
||||
|
||||
patch_file(r'C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\abletonmcp_init.py')
|
||||
patch_file(r'C:\ProgramData\Ableton\Live 12 Suite\Resources\MIDI Remote Scripts\AbletonMCP_AI\abletonmcp_runtime.py')
|
||||
Reference in New Issue
Block a user