Füge Unterstützung für die Erstellung von Tracklisten hinzu und verbessere Duplikat-Filterung in Audacity-Labels

This commit is contained in:
2025-07-03 10:49:36 +02:00
parent 223fa6ab0c
commit 2b564a6dd3
3 changed files with 74 additions and 17 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.cue
*.txt

View File

@ -1,15 +1,21 @@
# CUE to Audacity Label Converter # CUE to Audacity Label Converter
Ein Python-Script, das CUE-Dateien (von rekordbox DJ oder anderen Quellen) in Audacity-Label-Dateien umwandelt. Ein Python-Script, das CUE-Dateien (von rekordbox DJ oder anderen Quellen) in Audacity-Label-Dateien und schöne Tracklists umwandelt.
## Beschreibung ## Beschreibung
Dieses Tool liest CUE-Dateien und erstellt daraus Textdateien mit Zeitstempeln und Track-Titeln, die direkt in Audacity als Label-Track importiert werden können. Besonders nützlich für DJ-Sets oder lange Audio-Aufnahmen, die in einzelne Tracks unterteilt werden sollen. Dieses Tool liest CUE-Dateien und erstellt daraus zwei Ausgabe-Dateien:
1. **Audacity-Labels**: Textdateien mit Zeitstempeln für den Import in Audacity
2. **Tracklist**: Professionell formatierte Trackliste zum Teilen
Besonders nützlich für DJ-Sets oder lange Audio-Aufnahmen, die in einzelne Tracks unterteilt werden sollen.
## Features ## Features
- Unterstützt rekordbox CUE-Dateien im HH:MM:SS Format - Unterstützt rekordbox CUE-Dateien im HH:MM:SS Format
- Automatische Erkennung von Standard CUE-Formaten (MM:SS:FF mit CD-Frames) - Automatische Erkennung von Standard CUE-Formaten (MM:SS:FF mit CD-Frames)
- **Intelligente Duplikat-Filterung**: Entfernt Tracks, die innerhalb der letzten 2 Tracks bereits vorkamen
- **Zwei Ausgabe-Formate**: Audacity-Labels und professionelle Tracklist
- Flexible Regex-Pattern für verschiedene Einrückungen (Tabs/Leerzeichen) - Flexible Regex-Pattern für verschiedene Einrückungen (Tabs/Leerzeichen)
- UTF-8 Encoding für internationale Zeichen - UTF-8 Encoding für internationale Zeichen
- Plattformübergreifend (Windows, macOS, Linux) - Plattformübergreifend (Windows, macOS, Linux)
@ -57,6 +63,12 @@ TRACK 01 AUDIO
150.000000 150.000000 Song Title 150.000000 150.000000 Song Title
``` ```
### Ausgabe (Tracklist-Datei)
```
01. Artist Name - Song Title (02:30)
02. Another Artist - Another Song (05:15)
```
## Unterstützte CUE-Formate ## Unterstützte CUE-Formate
1. **rekordbox Format**: `HH:MM:SS` (Stunden:Minuten:Sekunden) 1. **rekordbox Format**: `HH:MM:SS` (Stunden:Minuten:Sekunden)
@ -68,21 +80,32 @@ Das Script erkennt automatisch das Format basierend auf den Zeitwerten.
1. Öffnen Sie Ihre Audio-Datei in Audacity 1. Öffnen Sie Ihre Audio-Datei in Audacity
2. Gehen Sie zu `Datei``Importieren``Labels...` 2. Gehen Sie zu `Datei``Importieren``Labels...`
3. Wählen Sie die generierte `.txt` Datei aus 3. Wählen Sie die generierte `*_audacity.txt` Datei aus
4. Die Zeitmarken erscheinen als Label-Track 4. Die Zeitmarken erscheinen als Label-Track
## Dateien ## Ausgabedateien
- `cue2auda.py` - Hauptscript Das Script erstellt automatisch zwei Dateien:
- `requirements.txt` - Python-Abhängigkeiten (leer, da nur Standard-Bibliotheken verwendet werden)
- `README.md` - Diese Datei - `filename_audacity.txt` - Audacity-Label-Datei für den Import
- `filename_tracklist.txt` - Professionelle Tracklist zum Teilen
## Beispiel-Workflow ## Beispiel-Workflow
1. Exportieren Sie ein DJ-Set aus rekordbox mit CUE-Datei 1. Exportieren Sie ein DJ-Set aus rekordbox mit CUE-Datei
2. Führen Sie das Script aus: `python cue2auda.py /pfad/zu/cue/dateien` 2. Führen Sie das Script aus: `python cue2auda.py /pfad/zu/cue/dateien`
3. Importieren Sie die generierte `.txt` Datei in Audacity 3. **Zwei Dateien werden erstellt:**
4. Nutzen Sie die Labels zum Schneiden oder Navigieren - `filename_audacity.txt` → Importieren Sie diese in Audacity als Labels
- `filename_tracklist.txt` → Teilen Sie diese schöne Tracklist
4. Nutzen Sie die Labels zum Schneiden oder Navigieren in Audacity
## Duplikat-Filterung
Das Script erkennt automatisch Duplikate in DJ-Mixes und filtert Tracks heraus, die innerhalb der letzten 2 Tracks bereits vorkamen. Dies ist besonders nützlich bei:
- **Blend-Übergängen**: Wenn Tracks überlappend gespielt werden
- **Loop-Rolls**: Wenn derselbe Track kurz wiederholt wird
- **DJ-Techniken**: Drop-outs, Cuts und Re-Entries
## Technische Details ## Technische Details

View File

@ -23,13 +23,19 @@ for cueFileName in glob.glob(os.path.join(thePath, "*.cue")):
#print(cueFileContent) #print(cueFileContent)
# Create label file # Create label file
labelFileName = os.path.splitext(cueFileName)[0] + ".txt" labelFileName = os.path.splitext(cueFileName)[0] + "_audacity.txt"
with open(labelFileName, "w", encoding="utf-8") as labelFile: tracklistFileName = os.path.splitext(cueFileName)[0] + "_tracklist.txt"
with open(labelFileName, "w", encoding="utf-8") as labelFile, \
open(tracklistFileName, "w", encoding="utf-8") as tracklistFile:
#print ("###" + labelFileName + "###") #print ("###" + labelFileName + "###")
# Process file # Process file
theTitle = "" # initialize title now in order to keep it available when scanning subsequent INDEX line theTitle = "" # initialize title now in order to keep it available when scanning subsequent INDEX line
thePerformer = "" # initialize performer
trackCount = 0 trackCount = 0
lastTitles = [] # Track the last few titles to avoid duplicates within a few tracks
maxTrackDistance = 2 # Filter duplicates within this many tracks
for lineNum, line in enumerate(cueFileContent, 1): for lineNum, line in enumerate(cueFileContent, 1):
originalLine = line originalLine = line
@ -40,6 +46,11 @@ for cueFileName in glob.glob(os.path.join(thePath, "*.cue")):
if theMatchTitle is not None: if theMatchTitle is not None:
theTitle = theMatchTitle.group(1) theTitle = theMatchTitle.group(1)
# Match PERFORMER - try multiple patterns for different indentation (tabs or spaces)
theMatchPerformer = re.search(r'PERFORMER\s+"([^"]+)"', line)
if theMatchPerformer is not None:
thePerformer = theMatchPerformer.group(1)
# Match INDEX 01 - try multiple patterns for different formats (tabs or spaces) # Match INDEX 01 - try multiple patterns for different formats (tabs or spaces)
theMatchIndex = re.search(r'INDEX\s+01\s+(\d{1,2}):(\d{2}):(\d{2})', line) theMatchIndex = re.search(r'INDEX\s+01\s+(\d{1,2}):(\d{2}):(\d{2})', line)
if theMatchIndex is not None: if theMatchIndex is not None:
@ -47,18 +58,39 @@ for cueFileName in glob.glob(os.path.join(thePath, "*.cue")):
theMinutes = int(theMatchIndex.group(2)) # Minutes theMinutes = int(theMatchIndex.group(2)) # Minutes
theSeconds = int(theMatchIndex.group(3)) # Seconds theSeconds = int(theMatchIndex.group(3)) # Seconds
trackCount += 1
# Convert HH:MM:SS to total seconds # Convert HH:MM:SS to total seconds
theStartTime = (theHours * 3600) + (theMinutes * 60) + theSeconds theStartTime = (theHours * 3600) + (theMinutes * 60) + theSeconds
# format theStartTime # Check for duplicates: skip if same title appears within the last few tracks
theStartTime = "{:.6f}".format(theStartTime) isDuplicate = theTitle in lastTitles[-maxTrackDistance:]
# Write time and title to label file if not isDuplicate:
labelFile.write(theStartTime + "\t" + theStartTime + "\t" + theTitle + "\n") trackCount += 1
# format theStartTime
theStartTimeFormatted = "{:.6f}".format(theStartTime)
# Format time for tracklist (MM:SS)
timeMinutes = theStartTime // 60
timeSeconds = theStartTime % 60
timeFormatted = f"{int(timeMinutes):02d}:{int(timeSeconds):02d}"
# Write time and title to Audacity label file
labelFile.write(theStartTimeFormatted + "\t" + theStartTimeFormatted + "\t" + theTitle + "\n")
# Write to tracklist file: TrackNr. Artist - Track (Time)
if thePerformer:
tracklistFile.write(f"{trackCount:02d}. {thePerformer} - {theTitle} ({timeFormatted})\n")
else:
tracklistFile.write(f"{trackCount:02d}. {theTitle} ({timeFormatted})\n")
# Add to title history
lastTitles.append(theTitle)
else:
print(f"Skipping duplicate: '{theTitle}' at {theHours:02d}:{theMinutes:02d}:{theSeconds:02d} (appeared within last {maxTrackDistance} tracks)")
print(f"Created {trackCount} labels in {labelFileName}") print(f"Created {trackCount} labels in {labelFileName}")
print(f"Created tracklist in {tracklistFileName}")
# end for line in cueFileContent # end for line in cueFileContent