Skip to content

Instantly share code, notes, and snippets.

@joelotz
Last active April 5, 2024 13:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save joelotz/49d99e6c464825a0e551146bd92369a3 to your computer and use it in GitHub Desktop.
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.
#!/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")
@fireattack
Copy link

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

milliseconds = float(milliseconds[-2:])/75

(Also there is an obvious typo in docstring: Example: 10:05:12 = 10hrs, 5mins, 12ms.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment