Repository navigation
Expand file tree
/
Copy pathableton-to-cues.py
More file actions
137 lines (118 loc) · 4.95 KB
/
Copy pathableton-to-cues.py
File metadata and controls
137 lines (118 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# usage: python3 ableton-to-cues.py $ALS_FILENAME $REKORDBOX_XML_FILENAME
# converts ableton warp markers to rekordbox cue points.
# use '--reverse' to convert rekordbox cues to ableton warp markers instead
# writes output to output.xml if converting ableton to rekordbox
# in reverse mode, it writes to output.als
import xml.etree.ElementTree as ET
import gzip
from urllib.parse import unquote
import argparse
parser = argparse.ArgumentParser(
description='convert between cues and warp markers')
parser.add_argument(
'als_file', type=str, help='path to ALS file')
parser.add_argument(
'rekordbox_file', type=str, help='path to Rekordbox xml file')
parser.add_argument(
'--reverse', type=bool, default=False,
help='set to true to convert Rekordbox to Ableton')
args = parser.parse_args()
def normalize_time(time):
if time == 0:
return "0.001"
else:
return "{0:.3f}".format(time)
def get_memcue(time):
child = ET.Element('POSITION_MARK')
child.set('Name', '')
child.set('Type', '0')
child.set('Num', '-1')
child.set('Start', normalize_time(time))
return child
def get_hotcue(time, num):
child = ET.Element('POSITION_MARK')
child.set('Name', '')
child.set('Type', '0')
child.set('Red', '40')
child.set('Green', '226')
child.set('Blue', '20')
child.set('Num', str(num))
child.set('Start', normalize_time(time))
return child
def get_warp_marker(time, num, bpm):
child = ET.Element('WarpMarker')
child.set('Id', str(num))
child.set('SecTime', time)
beat_time = float(time) * bpm / 60
child.set('BeatTime', str(beat_time))
return child
def get_rekordbox_filename(track):
parts = rekordbox_track.get('Location').split('/')
return unquote(parts[-1])
def get_ableton_filename(track):
return track.find('.//FileRef').find('./Name').get('Value')
# get ableton audio tracks
tree = ET.parse(gzip.GzipFile(args.als_file))
tracks = tree.getroot().findall('.//AudioClip')
# get rekordbox tracks
rekordbox_tree = ET.parse(args.rekordbox_file)
rekordbox_tracks = rekordbox_tree.getroot().findall('./COLLECTION/TRACK')
if not args.reverse:
outfile = 'output.xml'
print('Converting Ableton warp markers to Rekordbox cues.')
for track in tracks:
filename = get_ableton_filename(track)
warp_markers = track.findall('.//WarpMarkers/WarpMarker')
# Find the corresponding track in rekordbox
for rekordbox_track in rekordbox_tracks:
if (get_rekordbox_filename(rekordbox_track) == filename):
print('processing ' + filename)
# clear all existing cues
for element in rekordbox_track.findall('./POSITION_MARK'):
rekordbox_track.remove(element)
# create a hotcue and mem cue for each warp marker
num = 0
times = [float(marker.get('SecTime')) for marker in warp_markers]
times.sort()
# ignore last item cuz it gets duplicated for some reason
del times[-1]
for time in times:
hotcue = get_hotcue(time, num)
memcue = get_memcue(time)
num = num + 1
rekordbox_track.append(hotcue)
rekordbox_track.append(memcue)
rekordbox_tree.write(outfile, encoding='UTF-8', xml_declaration=True)
else:
outfile = 'output.als'
print('Converting Rekordbox cues to Ableton warp markers.')
for rekordbox_track in rekordbox_tracks:
filename = get_rekordbox_filename(rekordbox_track)
# find the corresponding ableton track
for track in tracks:
if (get_ableton_filename(track) == filename):
print('processing ' + filename)
# clear all existing warp markers
for markers in track.findall('./WarpMarkers'):
track.remove(markers)
# create new <WarpMarkers> group
child = ET.Element('WarpMarkers')
# ableton warp marker IDs seem to start at 2??
num = 2
# get rekordbox bpm
bpm = float(rekordbox_track.find('./TEMPO').get('Bpm'))
time = None
for element in rekordbox_track.findall('./POSITION_MARK'):
time = element.get('Start')
marker = get_warp_marker(time, num, bpm)
num = num + 1
child.append(marker)
# append the last marker a 2nd time; for some reason this seems
# needed otherwise it doesn't show up in ableton.
if time:
marker = get_warp_marker(str(float(time) + 0.1), num, bpm)
child.append(marker)
# attach the new WarpMarkers group
track.append(child)
tree.write(outfile, encoding='UTF-8', xml_declaration=True)
print('Finished writing ' + outfile)