Skip to content

Instantly share code, notes, and snippets.

@danrossi
Last active November 8, 2023 10:41
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danrossi/5fe77e8b36768a6371572b5735a447b2 to your computer and use it in GitHub Desktop.
Save danrossi/5fe77e8b36768a6371572b5735a447b2 to your computer and use it in GitHub Desktop.
Flac2Wav - Converter and preparation script for Rekordbox and Pioneer CDJ players that don't support Flac.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# pip install sox
import json
from multiprocessing import Pool
import logging
import os
import sys
import subprocess
import shlex
import re
from subprocess import call
import sox
try:
from os import scandir, walk
except ImportError:
from scandir import scandir, walk
class Flac2Wav:
logger = ''
def __init__(self):
global logger
# create logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# create a file handler
# handler = logging.FileHandler('converter.log')
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
# create a logging format
formatter = \
logging.Formatter('''
%(asctime)s - %(levelname)s - %(message)s
''')
handler.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(handler)
def convert(self, src_dir, out_dir):
global logger
file_queue = []
ext = ['.flac', '.wav']
# collect files to be converted
for entry in os.scandir(src_dir):
if entry.name.endswith(tuple(ext)) and entry.is_file():
filename = entry.name
if entry.name.endswith('.flac'):
filename = filename.replace('.flac', '.wav')
file_queue.append({
'dir': os.path.dirname(entry.path),
'path': entry.path,
'filename': filename,
'dest': out_dir,
})
logger.info('Start converting: %s files',
str(len(file_queue)))
with Pool(1) as p:
p.map(self.process, file_queue)
def cleanWhiteSpace(self, value):
return value.replace(' ', '_').replace('/', '_').replace('|', '_').replace('"', '').replace('(', '').replace(')', '')
def cleanDirectoryName(self, value):
return value.replace('/', '_').replace('|', '_').replace('"', '')
def probe_file(self, filename):
cmnd = [
'ffprobe',
'-loglevel',
'quiet',
'-show_format',
'-show_streams',
'-select_streams',
'a',
'-print_format',
'json',
filename,
]
p = subprocess.Popen(cmnd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, err) = p.communicate()
if err:
print(err)
else:
return (out)
def process(self, queue):
while True:
global logger
filename = queue['filename']
isWav = filename.index('wav') > -1
info = self.probe_file(queue['path'])
if info:
data = json.loads(info.decode('utf-8'))
format = data['format']
stream = data['streams'][0]
if 'bits_per_raw_sample' in stream:
bits = stream['bits_per_raw_sample']
else:
bits = stream['bits_per_sample']
bits_per_sample = int(bits)
sample_rate = int(stream['sample_rate'])
if 'tags' in format and 'ARTIST' in format['tags']:
print(format['tags'])
print(filename)
tags = format['tags']
artist = tags['ARTIST']
title = tags['TITLE']
album = tags.get('ALBUM', '')
directory = os.path.join(queue['dest'], artist,
self.cleanDirectoryName(album))
if not os.path.exists(directory):
os.makedirs(directory)
filename = os.path.join(directory,
'{0}-{1}-{2}.wav'.format(self.cleanWhiteSpace(artist),
self.cleanWhiteSpace(
title),
self.cleanWhiteSpace(album)))
else:
filename = os.path.join(queue['dest'],
queue['filename'])
tfm = sox.Transformer()
if bits_per_sample != 16 or sample_rate > 48000:
# check for 24bit or higher sample rates than 48k but don't
# convert anything less than 48k
new_sample_rate = sample_rate
if sample_rate > 48000:
new_sample_rate = 48000
logger.info('Converting From bit_depth: {0} sample_rate: {1}'.format(bits_per_sample,
sample_rate))
tfm.convert(new_sample_rate, 2, 16)
logger.info('Converting {0} to {1} '.format(queue['filename'
], filename))
tfm.build(queue['path'], filename)
return True
converter = Flac2Wav()
converter.convert("/mnt/d/RekordBox/queue/", "/mnt/d/RekordBox/ElectroSet/")
@danrossi
Copy link
Author

danrossi commented Oct 25, 2017

Flac2Wav

Converter and preparation script for Rekordbox and Pioneer CDJ players that don't support Flac.

The "standard" CDJ-2000 do not support Flac. And even though it says it supports 24/48 it has trouble reading files randomly.

This script converts to the absolute lowest common denominator 16/44 where required. It has to check for bitdepth and samplerate of the original files before conversion. So the files will hopefully load without issues.

It also renames the wav filenames from the metadata in the format artist-title-album as this has no metadata like Flac. and this is the best way to read the tracks on the display. The files are placed into individual directories of "artist/release"

The entire target directory can be imported after into Rekordbox as a playlist.

The CDJ-2000 NXS play Flac and support 24/96. The XDJ-1000 decks support Flac and 24/48.

Requirements

python3 is required for the fast scandir directory walking.

sudo apt-get install python3

ffprobe is required for metadata and format checks. This can be installed with

sudo apt-get install ffmpeg

Sox is required for the audio conversions. and PySox is required as the python wrapper.

sudo apt-get install sox
pip install sox

This installation will work the same for Linux Ubuntu and Windows Linux Sub System.

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