Ableton Live Set Real Export
Assume you want to be able to export your Ableton project's arrangement
into a machine readable format
to... do some things that machines are good at.
You start by opening a .als
file
in a text editor and - if your computer doesn't crash - get to see a lot of random characters.
Luckily, Ableton recently released a tool called Ableton Live Set Export.
It does exactly not what the name says:
The library only contains functionality for generating Ableton Live projects. It does not support reading or parsing Live Sets or other Ableton-generated files.
Sounds like Alice, doesn't it?
But the internet always has answers.
It turns out that .als
is just a gz
-compressed proprietary XML format - and that is pretty easy to use.
So, step one, rename your .als
to .als.gz
, decompress it and save the file as .xml
.
Step two, build a little Python (3.6) script - using the help of lxml -
and get the data you want!
Caveats (as found so far)
Some weird things when working with Ableton live set files:- Time is measured in beats. This kind of makes sense, but is also really annoying if you want to interact with other software.
The code
from lxml import etree import math
tree = etree.parse('ableton.xml') root = tree.getroot()
project_bpm = float(root.find('.//Tempo/Manual').get('Value'))
def beats_to_seconds(beats, bpm): return beats * 60 / bpm
def seconds_to_time_string(seconds): milliseconds = round((seconds % 1) * 1000) seconds = round(seconds) minutes = math.floor(seconds / 60) hours = math.floor(minutes / 60) minutes = minutes % 60 seconds = seconds % 60
return f'{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d}'
def beats_to_time_string(beats, bpm): return seconds_to_time_string(beats_to_seconds(beats, bpm))
tracks_xml = root.findall(".//AudioTrack") tracks = {} for track_xml in tracks_xml: track_id = track_xml.get('Id') track = { 'id': track_id, 'name': track_xml.find('Name/UserName').get('Value'), # it's handy to keep an XML element reference while debugging, but not necessary for 'production' '_xml': track_xml }
clips_xml = track_xml.findall('.//AudioClip') clips = [] for clip_xml in clips_xml: clip_path = '/' + '/'.join([path_xml.get('Dir') for path_xml in clip_xml.findall('.//SearchHint/PathHint/RelativePathElement')]) + '/' clip = { 'name': clip_xml.find('Name').get('Value'), 'file': clip_xml.find('SampleRef/FileRef/Name').get('Value'), 'path': clip_path, 'start_on_track': beats_to_seconds(float(clip_xml.find('CurrentStart').get('Value')), project_bpm), 'end_on_track': beats_to_seconds(float(clip_xml.find('CurrentEnd').get('Value')), project_bpm), 'start_in_file': beats_to_seconds(float(clip_xml.find('Loop/LoopStart').get('Value')), project_bpm), 'end_in_file': beats_to_seconds(float(clip_xml.find('Loop/LoopEnd').get('Value')), project_bpm), # it's handy to keep an XML element reference while debugging, but not necessary for 'production' '_xml': clip_xml } clips.append(clip)
track['clips'] = clips tracks[track_id] = track
use this to find the IDs of the tracks you're interested in
I don't think you can guess these from inside Ableton
for track_id, track in tracks.items():
print(track_id, track['name'])
track_id_filter = ['144'] for track_id in track_id_filter: track = tracks[track_id]
print("\n" + track['name'])
for clip in track- {seconds_to_time_string(clip['end_on_track'])} " f"| {clip| {clip['file']} (" f"{seconds_to_time_string(clip['start_in_file'])} - {seconds_to_time_string(clip['end_in_file'])})")
Sample output
I've redacted the actual values, but you get the idea:
TRACK NAME 00:00:00.000 - 00:00:02.500 | CLIP NAME | FILE NAME (00:00:10.500 - 00:00:13.1000) 00:00:03.508 - 00:00:04.027 | CLIP NAME | FILE NAME (00:02:59.625 - 00:03:00.144) 00:00:04.050 - 00:00:06.131 | CLIP NAME | FILE NAME (00:00:21.479 - 00:00:24.560) 00:00:06.131 - 00:00:07.335 | CLIP NAME | FILE NAME (00:00:09.459 - 00:00:11.663) 00:00:07.335 - 00:00:10.595 | CLIP NAME | FILE NAME (00:00:28.572 - 00:00:30.831) 00:00:10.595 - 00:00:12.998 | CLIP NAME | FILE NAME (00:00:15.439 - 00:00:18.842)The first time range indicates the place within your arrangement, whereas the latter one (in brackets) refers to the portion of the source file being used.
Ableton, Ableton Live and some other words in this text are probably protected by copyright and therefore (somehow) belong to someone or something. Also, Ableton hasn't publicly encouraged people to hack there file format so I assume this isn't endorsed by them.