Last active
January 20, 2025 20:44
-
-
Save joelotz/49d99e6c464825a0e551146bd92369a3 to your computer and use it in GitHub Desktop.
Convert a music .cue file into a label file. This module will accept an optional string attribute that specifies the input .cue file. If this file is not provided in the call then file-select box will be presented to the user. Output is a .txt file of labels that can be input into Audacity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
"""Convert a music .cue file into a label file. | |
This module will accept an optional string attribute that specifies the input | |
.cue file. If this file is not provided in the call then file-select box will | |
be presented to the user. Output is a .txt file of labels that can be input | |
into Audacity. | |
Examples: | |
$ python cue2labels.py | |
$ python cue2labels.py "InputFile.cue" | |
""" | |
def stringtime_to_millisec(stringtime): | |
""" | |
Parameters | |
---------- | |
stringtime : STRING | |
A string in the form of "HH:MM:SS:MS", where MS are millisecs. | |
Hours(HH) and Minutes(MM) are optional. | |
Seconds(SS) and Millisecs(MS) are mandatory. | |
Example: 10:05:12 = 10hrs, 5mins, 12ms | |
Returns | |
------- | |
FLOAT | |
Returns a the input stringtime as decimal seconds | |
""" | |
hours, minutes, seconds, milliseconds = (["00", "00"] + stringtime.split(":"))[-4:] | |
hours = int(hours[-2:])*360 | |
minutes = int(minutes[-2:])*60 | |
seconds = int(seconds[-2:]) | |
milliseconds = float(milliseconds[-2:])/60 | |
return hours + minutes + seconds + milliseconds | |
def parse_cue(cue_filename): | |
""" | |
Parameters | |
---------- | |
cue_filename : STRING | |
The name of the .cue file to be read and parsed. | |
Returns | |
------- | |
track_times : LIST | |
The time that the audio track starts, as given in the .cue file, | |
in decimal seconds | |
titles : LIST | |
The title of the track, as given in the .cue file. | |
""" | |
from re import findall | |
file = open(cue_filename, 'r') | |
track_times = [float(0)] | |
titles = [] | |
while True: | |
# Get next line from file | |
line = file.readline() | |
# if line is empty end of file is reached | |
if not line: | |
break | |
if line.strip()[:5] == 'INDEX 01': | |
stringtime = stringtime_to_millisec(line.strip()) | |
if stringtime != float(0): | |
track_times.append(stringtime) | |
elif line.strip()[:5] == 'TITLE': | |
track = findall(r'"([^"]*)"', line) | |
titles.append(track) | |
# I've had trouble in the past | |
if not titles or track_times[-1]==float(0): | |
warning_string = '''There is someting wrong with the .cue file, it\'s not formatted properly. | |
Unable to continue processing!''' | |
sys.exit(warning_string) | |
file.close() | |
return track_times, titles | |
def write_labels(label_filename, track_times, titles): | |
""" | |
Parameters | |
---------- | |
label_filename : STRING | |
The desired path/name of the output label file. | |
track_times : LIST | |
The time that the audio track starts, as given in the .cue file, | |
in decimal seconds | |
titles : LIST | |
The title of the track, as given in the .cue file. | |
Returns | |
------- | |
bool | |
""" | |
# Due to the format of the .cue file, the first track title may be the album title | |
if len(titles) > len(track_times): | |
titles.pop(0) | |
file = open(label_filename, "w") | |
# Write out in tab delimited format | |
for i in range(len(titles)): | |
line = f"{track_times[i]:.5f}\t{track_times[i]:.5f}\t{titles[i][0]}" | |
file.write(line) | |
file.write("\n") | |
file.close() | |
return True | |
if __name__ == "__main__": | |
import sys | |
import os | |
# Check if .cue file was given in the python call | |
try: | |
cue_filename = str(sys.argv[1]) | |
# If not, ask user to select | |
except: | |
from tkinter.filedialog import askopenfilename | |
cue_filename = askopenfilename(title="Select a cue file", filetypes=(("cue files",'*.cue'),)) | |
## EXIT if user selects cancel | |
# Read cue file and parse out the times and titles | |
track_times, titles = parse_cue(cue_filename) | |
# Make a label file name | |
label_filename = os.path.splitext(cue_filename)[0]+'_labels.txt' | |
# Write times and tracks to label file in proper format | |
write_labels(label_filename, track_times, titles) | |
print("File created") |
Thanks for the blog and for the scripts. I still had some problems running it. I had to change line 71 to get mine working. Also the titles were off due to the first "TITLE" field in the CUE header, so I had to omit the first element in the titles
list on line 139.
My fork: https://gist.github.com/allumik/7469c32c3e50724589ef9fb0efa1444d
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I can't find a way to comment in your blog article, so I will leave one here.
The "millisecond" part (last two digits) in an index is actually frame count, which each second has 75 (reference). So it should be
(Also there is an obvious typo in docstring:
Example: 10:05:12 = 10hrs, 5mins, 12ms
.)