Skip to content

Instantly share code, notes, and snippets.

@bleggett
Forked from hyperknot/dsd2flac.py
Last active April 23, 2022 23:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bleggett/f88618d14f6e906d751b9e3e641c5df4 to your computer and use it in GitHub Desktop.
Save bleggett/f88618d14f6e906d751b9e3e641c5df4 to your computer and use it in GitHub Desktop.
DSD to FLAC conversion using SoX DSD. Original by @hyperknot. Scans the file once to determine optimum gain, then converts using that. You can get SoX DSD binaries from https://audiodigitale.eu/repo/sox/
#!/usr/bin/env python3
import pathlib
import subprocess
import sys
import shutil
import math
root = pathlib.Path(__file__).parent.resolve()
target_root = root / 'dsd'
def convert_folder(folder):
files = folder.glob('*.dsf')
for file in files:
relative_dir = file.parent.relative_to(root)
target_dir = target_root / relative_dir
target_dir.mkdir(exist_ok=True, parents=True)
tmp_path = target_dir / 'tmp.flac'
tmp_path.unlink(missing_ok=True)
target_path = target_dir / (file.stem + '.flac')
if target_path.is_file():
continue
print(f' {target_path}')
cmdCalc = [
'sox',
'-V3',
file,
'--bits',
'24',
'-C',
'0',
tmp_path,
#
'rate',
'-ub74',
'176400',
'sinc',
'-25k',
'stats',
]
print("\nCalculating file levels...\n")
proc = subprocess.Popen(cmdCalc, stderr=subprocess.PIPE, text=True)
while True:
line = proc.stderr.readline()
if not line:
break
if 'Pk lev dB' in line:
levels = line.split()
detectedPeak = abs(float(levels[3]))
calcNorm = math.ceil(detectedPeak)
if calcNorm >= 6:
print("DSD appears to be mastered according to Scarlet Book loudness specs...")
gain = 6
elif calcNorm <= 5:
print(f"Found a weird one Bobby...detected peak was {detectedPeak}, using gain {calcNorm}")
gain = calcNorm
print(f"\nConverting file with gain level: {gain}...\n")
cmdConv = [
'sox',
'-V3',
file,
'--bits',
'24',
'-C',
'8',
tmp_path,
#
'rate',
'-ub74',
'176400',
#
'gain',
str(gain),
#
'sinc',
'-25k',
'stats',
]
subprocess.run(cmdConv, text=True, capture_output=True)
tmp_path.rename(target_path)
return dict(success=True, target_dir=target_dir)
def main():
dsd_folders = set()
dsd_files = root.glob('**/*.dsf')
for file in dsd_files:
folder = file.parent
dsd_folders.add(folder)
print(f"Got folders: {dsd_folders}")
for folder in sorted(dsd_folders):
print(f'\n\nProcessing {folder}')
r = convert_folder(folder)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment