Loading...
Loading...
Control Ableton Live with AI agents via MCP - create MIDI clips, insert audio, add tracks/devices, analyze signals, automate mixing
npx skill4agent add aradotso/mcp-skills ableton-live-mcp-controlSkill by ara.so — MCP Skills collection.
Set up the https://github.com/bschoepke/ableton-live-mcp MCP server for megit clone https://github.com/bschoepke/ableton-live-mcp.git
cd ableton-live-mcppip install -r requirements.txtRemoteScripts/MCP~/Music/Ableton/User Library/Remote Scripts/%USERPROFILE%\Documents\Ableton\User Library\Remote Scripts\claude_desktop_config.json{
"mcpServers": {
"ableton-live": {
"command": "python",
"args": ["-m", "ableton_live_mcp"],
"cwd": "/path/to/ableton-live-mcp"
}
}
}# Example: Get the current tempo
result = evaluate_python("Live.Song.Song.tempo")
# Example: Create a new MIDI track
code = """
song = Live.Song.Song
track = song.create_midi_track(-1)
track.name = 'My New Track'
"""
evaluate_python(code)# Create a simple C major chord progression
create_midi_clip(
track_index=0,
clip_slot=0,
length_bars=4,
notes=[
{"pitch": 60, "start": 0.0, "duration": 1.0, "velocity": 100}, # C
{"pitch": 64, "start": 0.0, "duration": 1.0, "velocity": 100}, # E
{"pitch": 67, "start": 0.0, "duration": 1.0, "velocity": 100}, # G
]
)# Insert a vocal sample
insert_audio_file(
track_index=1,
clip_slot=0,
file_path="/path/to/vocal.wav"
)# Add a MIDI track with a synth
add_track(
track_type="midi",
name="Bass Synth",
devices=["Operator", "Reverb"]
)# Get full Live Set details
info = get_live_set_info()
# Returns: tracks, scenes, tempo, time signature, devices, etc.# Capture 10 seconds of audio from track 0
audio_data = capture_audio(
track_index=0,
device_index=0,
duration_seconds=10.0
)
# Returns: base64-encoded WAV data# Get parameters for the first device on track 0
params = get_device_parameters(
track_index=0,
device_index=0
)# Set the cutoff frequency of a filter
set_device_parameter(
track_index=0,
device_index=0,
parameter_name="Filter Freq",
value=1200.0
)# Create a bass track with Operator synth
code = """
song = Live.Song.Song
track = song.create_midi_track(-1)
track.name = 'Bass'
# Add Operator synth
operator = track.devices[0] # Default instrument
operator.name = 'Bass Synth'
# Create a bass pattern
clip = track.clip_slots[0].create_clip(4.0)
clip.name = 'Bass Pattern'
# Add notes
for i in range(16):
if i % 4 == 0:
clip.set_notes(((36, i * 0.25, 0.25, 100, False),)) # C1 on downbeats
"""
evaluate_python(code)# First, add Agent Audio Tap device to a track in Ableton
# Then capture and analyze audio
import base64
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
# Capture audio
audio_b64 = capture_audio(track_index=0, device_index=0, duration_seconds=10.0)
# Decode audio
audio_bytes = base64.b64decode(audio_b64)
# Generate spectrogram
code = """
import wave
import numpy as np
from scipy import signal
with wave.open('temp.wav', 'rb') as wf:
audio_data = np.frombuffer(wf.readframes(wf.getnframes()), dtype=np.int16)
sample_rate = wf.getframerate()
f, t, Sxx = signal.spectrogram(audio_data, sample_rate)
# Save or display spectrogram
"""# Create master processing chain
code = """
song = Live.Song.Song
master = song.master_track
# Add EQ Eight
eq = master.devices.append(song.create_device('EQ Eight'))
# Add Compressor
comp = master.devices.append(song.create_device('Compressor'))
comp.parameters[0].value = -12.0 # Threshold
# Add Limiter
limiter = master.devices.append(song.create_device('Limiter'))
limiter.parameters[1].value = -0.3 # Ceiling
"""
evaluate_python(code)# Generate a chord progression
code = """
import Live
song = Live.Song.Song
track = song.tracks[0]
clip = track.clip_slots[0].create_clip(8.0)
# Chord progression: C - Am - F - G
chords = [
[(60, 64, 67), 0.0], # C major
[(57, 60, 64), 2.0], # A minor
[(53, 57, 60), 4.0], # F major
[(55, 59, 62), 6.0], # G major
]
notes = []
for chord, start_beat in chords:
for pitch in chord:
notes.append((pitch, start_beat, 2.0, 100, False))
clip.set_notes(tuple(notes))
clip.name = 'Chord Progression'
"""
evaluate_python(code)# Create automation for volume fadeout
code = """
song = Live.Song.Song
track = song.tracks[0]
clip = track.clip_slots[0].clip
# Create volume automation
envelope = clip.automation_envelope(track.mixer_device.volume)
envelope.insert_step(0.0, 0, 1.0) # Start at full volume
envelope.insert_step(7.0, 0, 0.0) # Fade to silence at bar 7
"""
evaluate_python(code)# Add and configure a reverb chain
code = """
song = Live.Song.Song
track = song.tracks[1]
# Add Reverb
reverb = track.devices.append(song.create_device('Reverb'))
reverb.parameters[0].value = 3.5 # Decay time
reverb.parameters[1].value = 0.3 # Dry/Wet
# Add EQ after reverb
eq = track.devices.append(song.create_device('EQ Eight'))
# High-pass filter to clean up reverb
eq.parameters[1].value = 300.0 # Frequency
"""
evaluate_python(code)# Set up sidechain compression (kick to bass)
code = """
song = Live.Song.Song
bass_track = song.tracks[1]
kick_track = song.tracks[0]
# Add Compressor to bass track
comp = bass_track.devices.append(song.create_device('Compressor'))
# Enable sidechain
comp.parameters[9].value = 1.0 # Sidechain enabled
# Set sidechain source to kick track
available_routings = comp.available_input_routing_types
for routing in available_routings:
if 'Audio From' in routing.display_name and kick_track.name in routing.display_name:
comp.input_routing_type = routing
break
# Configure compression
comp.parameters[0].value = -18.0 # Threshold
comp.parameters[1].value = 4.0 # Ratio
comp.parameters[2].value = 0.1 # Attack
comp.parameters[3].value = 0.2 # Release
"""
evaluate_python(code)# Add VST/AU instruments
code = """
song = Live.Song.Song
track = song.tracks[0]
# Add Serum (example)
serum = track.devices.append(song.create_device('Serum'))
# Add Keyscape for piano
keyscape = track.devices.append(song.create_device('Keyscape'))
"""
evaluate_python(code)# Get detailed information about all tracks
info = get_live_set_info()
# The response includes:
# - tempo
# - time_signature
# - tracks (name, type, devices, clip_slots)
# - scenes
# - master_track info
# - return_tracks
# Example: Find all tracks with a specific device
code = """
song = Live.Song.Song
tracks_with_reverb = []
for i, track in enumerate(song.tracks):
for device in track.devices:
if 'Reverb' in device.name:
tracks_with_reverb.append((i, track.name))
break
result = tracks_with_reverb
"""
result = evaluate_python(code)# Analyze frequency content of a track
code = """
import numpy as np
from scipy import signal as sp_signal
# Assuming audio is captured via Agent Audio Tap
# (audio_data would be from capture_audio tool)
def analyze_frequency_content(audio_data, sample_rate=44100):
# Compute FFT
fft = np.fft.rfft(audio_data)
freqs = np.fft.rfftfreq(len(audio_data), 1/sample_rate)
magnitudes = np.abs(fft)
# Find dominant frequencies
peaks, _ = sp_signal.find_peaks(magnitudes, height=np.max(magnitudes)*0.1)
dominant_freqs = freqs[peaks]
return {
'dominant_frequencies': dominant_freqs.tolist(),
'frequency_range': [freqs[0], freqs[-1]],
'peak_magnitude': float(np.max(magnitudes))
}
# Use this function after capturing audio
"""# Always wrap risky code in try/except when using evaluate_python
code = """
try:
song = Live.Song.Song
# Your code here
except Exception as e:
result = f'Error: {str(e)}'
"""# List all devices on a track first
code = """
song = Live.Song.Song
track = song.tracks[0]
device_names = [d.name for d in track.devices]
result = device_names
"""
devices = evaluate_python(code)get_device_parameters()evaluate_pythoncode = """
import numpy as np
import math
# Generate MIDI notes based on harmonic series
fundamental = 220 # A3
harmonics = [fundamental * i for i in range(1, 9)]
# Convert to MIDI note numbers
midi_notes = [int(round(69 + 12 * math.log2(f / 440))) for f in harmonics]
result = midi_notes
"""
notes = evaluate_python(code)# Apply same effect chain to multiple tracks
code = """
song = Live.Song.Song
effect_chain = ['EQ Eight', 'Compressor', 'Reverb']
for i in range(4): # First 4 tracks
track = song.tracks[i]
for effect_name in effect_chain:
track.devices.append(song.create_device(effect_name))
"""
evaluate_python(code)