Compare commits
3 Commits
8471db3ea1
...
8e5d9d9900
Author | SHA1 | Date | |
---|---|---|---|
8e5d9d9900 | |||
5eb6d2885f | |||
6716d5003b |
@ -10,7 +10,7 @@ import ffmpy
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
# multiprocessing stuff
|
# multiprocessing stuff
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool, Value, parent_process
|
||||||
|
|
||||||
# executing some commands
|
# executing some commands
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -27,6 +27,7 @@ from random import randint
|
|||||||
# typing hints
|
# typing hints
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
# temporary file/directory management
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
# working with sound files
|
# working with sound files
|
||||||
@ -38,6 +39,9 @@ import pyloudnorm
|
|||||||
# file copy
|
# file copy
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
# signal handling
|
||||||
|
import signal
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Normalize loudness of all music files in a given directory and its subdirectories.
|
Normalize loudness of all music files in a given directory and its subdirectories.
|
||||||
"""
|
"""
|
||||||
@ -45,6 +49,18 @@ Normalize loudness of all music files in a given directory and its subdirectorie
|
|||||||
musicfile_extensions = (".flac", ".wav", ".mp3", ".m4a", ".aac", ".opus")
|
musicfile_extensions = (".flac", ".wav", ".mp3", ".m4a", ".aac", ".opus")
|
||||||
|
|
||||||
|
|
||||||
|
class CleanupRequired(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def sigint_handler(signum, frame):
|
||||||
|
# set workers to clean up
|
||||||
|
cleanup_required.value = 1
|
||||||
|
# Output only once
|
||||||
|
if parent_process() is None:
|
||||||
|
print("\nReceived KeyboardInterrupt. Process cleaning up and stopping...")
|
||||||
|
|
||||||
|
|
||||||
def loudnorm(inputfile: str, outputfile: str):
|
def loudnorm(inputfile: str, outputfile: str):
|
||||||
"""
|
"""
|
||||||
Normalize audio to EBU R 128 standard using pyloudnorm
|
Normalize audio to EBU R 128 standard using pyloudnorm
|
||||||
@ -59,6 +75,10 @@ def loudnorm(inputfile: str, outputfile: str):
|
|||||||
meter = pyloudnorm.Meter(rate=rate)
|
meter = pyloudnorm.Meter(rate=rate)
|
||||||
loudness = meter.integrated_loudness(data=data)
|
loudness = meter.integrated_loudness(data=data)
|
||||||
|
|
||||||
|
# cleanup check
|
||||||
|
if bool(cleanup_required.value):
|
||||||
|
raise CleanupRequired()
|
||||||
|
|
||||||
# normalize audio
|
# normalize audio
|
||||||
file_normalized = pyloudnorm.normalize.loudness(
|
file_normalized = pyloudnorm.normalize.loudness(
|
||||||
data=data, input_loudness=loudness, target_loudness=-18.0
|
data=data, input_loudness=loudness, target_loudness=-18.0
|
||||||
@ -76,6 +96,9 @@ def ffmpeg_to_wav(inputfile: str, outputfile: str):
|
|||||||
inputfile (str): Path to input file
|
inputfile (str): Path to input file
|
||||||
outputfile (str): Path to output file
|
outputfile (str): Path to output file
|
||||||
"""
|
"""
|
||||||
|
# cleanup check
|
||||||
|
if bool(cleanup_required.value):
|
||||||
|
raise CleanupRequired()
|
||||||
|
|
||||||
# convert to wav in temporary directory
|
# convert to wav in temporary directory
|
||||||
with tempfile.TemporaryDirectory() as tempdir:
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
@ -99,6 +122,10 @@ def ffmpeg_to_wav(inputfile: str, outputfile: str):
|
|||||||
|
|
||||||
subprocess.run(ff.cmd, shell=True, capture_output=True)
|
subprocess.run(ff.cmd, shell=True, capture_output=True)
|
||||||
|
|
||||||
|
# cleanup check
|
||||||
|
if bool(cleanup_required.value):
|
||||||
|
raise CleanupRequired()
|
||||||
|
|
||||||
# normalize loudness
|
# normalize loudness
|
||||||
loudnorm(inputfile=temp_input, outputfile=temp_output)
|
loudnorm(inputfile=temp_input, outputfile=temp_output)
|
||||||
|
|
||||||
@ -107,6 +134,10 @@ def ffmpeg_to_wav(inputfile: str, outputfile: str):
|
|||||||
outputfile: "-c:a libopus" " " "-b:a 192k" " " "-compression_level 10"
|
outputfile: "-c:a libopus" " " "-b:a 192k" " " "-compression_level 10"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# cleanup check
|
||||||
|
if bool(cleanup_required.value):
|
||||||
|
raise CleanupRequired()
|
||||||
|
|
||||||
ff = ffmpy.FFmpeg(
|
ff = ffmpy.FFmpeg(
|
||||||
inputs={temp_output: None}, outputs=outputcmd, global_options=("-y")
|
inputs={temp_output: None}, outputs=outputcmd, global_options=("-y")
|
||||||
)
|
)
|
||||||
@ -123,6 +154,9 @@ def ffmpeg_copy_metadata(inputfile: str, outputfile: str):
|
|||||||
inputfile (str): Path to input file
|
inputfile (str): Path to input file
|
||||||
outputfile (str): Path to output file
|
outputfile (str): Path to output file
|
||||||
"""
|
"""
|
||||||
|
# cleanup check
|
||||||
|
if bool(cleanup_required.value):
|
||||||
|
raise CleanupRequired()
|
||||||
|
|
||||||
# store output file as temporary file. FFMPEG can't work on files in-place
|
# store output file as temporary file. FFMPEG can't work on files in-place
|
||||||
with tempfile.NamedTemporaryFile() as temp_audio:
|
with tempfile.NamedTemporaryFile() as temp_audio:
|
||||||
@ -154,10 +188,13 @@ def main(inputfile: str) -> Optional[list[Any]]:
|
|||||||
Output:
|
Output:
|
||||||
dynamically normalised audio files (list)
|
dynamically normalised audio files (list)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# set output folder to parent path + "normalized"
|
# set output folder to parent path + "normalized"
|
||||||
outputfolder = os.path.join(os.path.dirname(inputfile), "normalized")
|
outputfolder = os.path.join(os.path.dirname(inputfile), "normalized")
|
||||||
|
|
||||||
|
# cleanup check
|
||||||
|
if bool(cleanup_required.value):
|
||||||
|
raise CleanupRequired()
|
||||||
|
|
||||||
# NOTE create output folder
|
# NOTE create output folder
|
||||||
# because multiple parallel processes are at work here,
|
# because multiple parallel processes are at work here,
|
||||||
# there might be conflicts with one trying to create the directory although it already exists
|
# there might be conflicts with one trying to create the directory although it already exists
|
||||||
@ -201,6 +238,11 @@ if __name__ == "__main__":
|
|||||||
"""
|
"""
|
||||||
Handle arguments and other details for interactive usage
|
Handle arguments and other details for interactive usage
|
||||||
"""
|
"""
|
||||||
|
# global cleanup variable
|
||||||
|
cleanup_required = Value("i", 0)
|
||||||
|
|
||||||
|
# handle KeyboardInterrupt
|
||||||
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
|
||||||
# start time of program
|
# start time of program
|
||||||
starttime = time.time()
|
starttime = time.time()
|
||||||
@ -242,9 +284,6 @@ if __name__ == "__main__":
|
|||||||
# file where last run timestamp is stored
|
# file where last run timestamp is stored
|
||||||
timefile = os.path.join(srcfolder, "run.time")
|
timefile = os.path.join(srcfolder, "run.time")
|
||||||
|
|
||||||
# list of non-linear normalizations
|
|
||||||
nonlinear_all: Optional[list[Any]] = []
|
|
||||||
|
|
||||||
# get time of previous run
|
# get time of previous run
|
||||||
if reset:
|
if reset:
|
||||||
timeprev = 0
|
timeprev = 0
|
||||||
@ -265,8 +304,11 @@ if __name__ == "__main__":
|
|||||||
if os.path.getmtime(filepath) >= float(timeprev):
|
if os.path.getmtime(filepath) >= float(timeprev):
|
||||||
musicfiles.append(os.path.join(root, file))
|
musicfiles.append(os.path.join(root, file))
|
||||||
|
|
||||||
|
# process pool
|
||||||
with Pool(cpu) as p:
|
with Pool(cpu) as p:
|
||||||
nonlinear_all: Optional[list[Any]] = p.map(main, musicfiles)
|
result = p.map_async(main, musicfiles)
|
||||||
|
# wait for all processes to finish
|
||||||
|
result.wait()
|
||||||
|
|
||||||
# write this run's time into file
|
# write this run's time into file
|
||||||
with open(timefile, "w") as file:
|
with open(timefile, "w") as file:
|
||||||
|
Loading…
Reference in New Issue
Block a user