Skip to content

[Experimental] Fast copy into Ableton live w/ Remote Scripts#41

Merged
mhrice merged 4 commits into
mainfrom
ableton-live-copy
May 27, 2026
Merged

[Experimental] Fast copy into Ableton live w/ Remote Scripts#41
mhrice merged 4 commits into
mainfrom
ableton-live-copy

Conversation

@mhrice
Copy link
Copy Markdown
Collaborator

@mhrice mhrice commented May 27, 2026

Uses Ableton Remote Scripts for a fast integration workflow

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an experimental Ableton Live integration for the MLX-optimized SA3 workflow by introducing an Ableton MIDI Remote Script + a companion CLI to insert generated audio at the playhead, and improves WAV ingestion robustness by falling back to ffmpeg for non-16-bit/44.1kHz files.

Changes:

  • Add Ableton Live “AudioInserter” Remote Script (socket server) to create a new audio track and insert audio into arrangement at the current playhead.
  • Add insert_audio.py CLI + README instructions for sending audio files (and watching a folder) to Ableton over localhost.
  • Update read_wav() to support more WAV formats via ffmpeg fallback.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
optimized/mlx/scripts/sa3_mlx.py Extends WAV reading to fall back to ffmpeg for non-native formats.
optimized/mlx/ableton/README.md Documents setup and usage for the new Ableton integration workflow.
optimized/mlx/ableton/insert_audio.py Implements a CLI client for sending insert/ping commands to Ableton.
optimized/mlx/ableton/AudioInserter/AudioInserter.py Implements the Ableton Remote Script socket server and audio insertion logic.
optimized/mlx/ableton/AudioInserter/init.py Provides create_instance() entrypoint for Ableton Remote Scripts.
.gitignore Ignores Ableton .asd analysis/metadata files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +255 to +256
except wave.Error:
pass # unsupported format (32-bit float, 24-bit PCM, etc.)
Comment thread optimized/mlx/ableton/insert_audio.py Outdated
Comment on lines +6 to +14
python insert_audio.py # insert latest file in ~/Desktop
python insert_audio.py /path/to/file.wav # insert specific file
python insert_audio.py --watch ~/renders # watch folder, auto-insert on new file
python insert_audio.py --ping # check if Ableton is connected

Options:
--dir DIR Directory to search for latest file (default: ~/Desktop)
--ext EXT File extension filter, e.g. wav, aiff, mp3 (default: wav aiff mp3 flac)
--watch Watch mode: monitor DIR and auto-insert new files as they appear
Comment on lines +39 to +52
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(TIMEOUT)
s.connect((HOST, PORT))
s.sendall((json.dumps(cmd) + "\n").encode("utf-8"))
response = b""
while True:
chunk = s.recv(4096)
if not chunk:
break
response += chunk
if b"\n" in chunk:
break
s.close()
return json.loads(response.decode("utf-8").strip())
Comment on lines +39 to +48
```bash
# Insert a specific file at the current playhead
python3 insert_audio.py /path/to/out.wav

# Insert whatever wav was most recently dropped on your Desktop
python3 insert_audio.py

# Watch a folder and auto-insert each new file as it appears
python3 insert_audio.py --watch ~/Desktop
```
Comment on lines +54 to +60
```bash
# Generate
./sa3 --prompt "driving techno loop" --dit medium --decoder same-l --out out.wav

# Insert
python3 ableton/insert_audio.py out.wav
```
Comment on lines +37 to +43
while self._running:
try:
conn, _ = srv.accept()
data = conn.recv(BUFFER_SIZE).decode("utf-8").strip()
response = self._handle_command(data)
conn.sendall((response + "\n").encode("utf-8"))
conn.close()
Comment on lines +84 to +90
event.wait(timeout=10.0)

if result["ok"]:
msg = result.get("error") or ("Inserted: %s" % os.path.basename(file_path))
return json.dumps({"ok": True, "message": msg})
else:
return json.dumps({"ok": False, "error": result.get("error", "Unknown error")})
Comment on lines +30 to +49
def _server_loop(self):
try:
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind((SOCKET_HOST, SOCKET_PORT))
srv.listen(5)
srv.settimeout(1.0)
while self._running:
try:
conn, _ = srv.accept()
data = conn.recv(BUFFER_SIZE).decode("utf-8").strip()
response = self._handle_command(data)
conn.sendall((response + "\n").encode("utf-8"))
conn.close()
except socket.timeout:
continue
except Exception as e:
self.log_message("AudioInserter socket error: %s" % str(e))
except Exception as e:
self.log_message("AudioInserter server error: %s" % str(e))
mhrice and others added 2 commits May 27, 2026 09:03
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@mhrice mhrice requested a review from Copilot May 27, 2026 16:36
@mhrice mhrice changed the title [Experimental] Integration into Ableton live [Experimental] Fast copy into Ableton live w/ Remote Scripts May 27, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.

Comment on lines +39 to +43
conn, _ = srv.accept()
data = conn.recv(BUFFER_SIZE).decode("utf-8").strip()
response = self._handle_command(data)
conn.sendall((response + "\n").encode("utf-8"))
conn.close()
Comment on lines +84 to +90
event.wait(timeout=10.0)

if result["ok"]:
msg = result.get("error") or ("Inserted: %s" % os.path.basename(file_path))
return json.dumps({"ok": True, "message": msg})
else:
return json.dumps({"ok": False, "error": result.get("error", "Unknown error")})
Comment on lines +111 to +116
# Copy file to a unique path so each generation is preserved independently
ext = os.path.splitext(file_path)[1]
unique_name = "%s_%s%s" % (clean_name.replace(" ", "_"), int(time.time()), ext)
dest_dir = os.path.dirname(file_path)
unique_path = os.path.join(dest_dir, unique_name)
shutil.copy2(file_path, unique_path)
Comment on lines +38 to +51
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(TIMEOUT)
s.connect((HOST, PORT))
s.sendall((json.dumps(cmd) + "\n").encode("utf-8"))
response = b""
while True:
chunk = s.recv(4096)
if not chunk:
break
response += chunk
if b"\n" in chunk:
break
s.close()
return json.loads(response.decode("utf-8").strip())
)
except FileNotFoundError:
raise RuntimeError(
f"{path}: unsupported WAV format. Install ffmpeg to handle 24-bit/32-bit/48kHz audio:\n"
@mhrice mhrice merged commit a9afb78 into main May 27, 2026
2 checks passed
@mhrice mhrice deleted the ableton-live-copy branch May 27, 2026 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants