-
Notifications
You must be signed in to change notification settings - Fork 1
/
nistem.py
92 lines (82 loc) · 3 KB
/
nistem.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# Imports from standard distribution libs
import codecs, json, base64
import os, platform, subprocess, sys
# Imports from external dependencies
import mutagen
import mutagen.mp4
import mutagen.id3
_defaultMetadataJSON = '''
{
"mastering_dsp": {
"compressor": {
"enabled": false,
"ratio": 2,
"output_gain": 0.5,
"release": 0.1,
"attack": 0.01,
"input_gain": 0.5,
"threshold": 0,
"hp_cutoff": 300,
"dry_wet": 0
},
"limiter": {
"enabled": false,
"release": 0.05,
"threshold": 0,
"ceiling": 0
}
},
"version": 1,
"stems": [
{"color": "#009E73", "name": "Drums"},
{"color": "#D55E00", "name": "Bass"},
{"color": "#CC79A7", "name": "Other"},
{"color": "#56B4E9", "name": "Vox"}
]
}
'''
def encode(mixFilePath, drumFilePath, bassFilePath, otherFilePath, vocalFilePath, stemFilePath):
# make sure the ffmpeg is present in env
try:
subprocess.check_call(["ffmpeg", "-version"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
except FileNotFoundError:
raise RuntimeError("ffmpeg is not in the environment. Make sure that it is installed and on your PATH")
# make sure all of the input files exist
allFilesExist = True
for file in [mixFilePath, drumFilePath, bassFilePath, otherFilePath, vocalFilePath]:
if not os.path.exists(file):
print("ERROR - input file does not exist:", file)
allFilesExist = False
if not allFilesExist:
raise RuntimeError("Input files are missing! Cannot continue.")
# Use FFMPEG to mux all the files together including the original mix file's metadata/tags
ffmpegArgs = ["ffmpeg", "-y", "-nostats", "-loglevel", "error",
"-i", mixFilePath,
"-i", drumFilePath,
"-i", bassFilePath,
"-i", otherFilePath,
"-i", vocalFilePath,
"-map", "0", "-map", "1", "-map", "2", "-map", "3", "-map", "4",
# "-movflags", "+use_metadata_tags",
"-c", "copy", "-c:a", "aac", "-b:a", "320k",
stemFilePath
]
subprocess.check_call(ffmpegArgs)
sys.stdout.flush()
# Add on the NI required additional JSON encoded metadata to identify the stem tracks
metadata = base64.b64encode(_defaultMetadataJSON.encode("utf-8")).decode("utf-8")
metadata = "0:type=stem:src=base64," + metadata
mp4boxArgs = ["mp4box",
"-udta", metadata,
stemFilePath
]
subprocess.check_call(mp4boxArgs)
sys.stdout.flush()
# Do I need this tag? The reference files have it but... apparently no, not necessary.
# tags = mutagen.mp4.Open(stemFilePath)
# tags['----:com.apple.iTunes:AUDIOTYPE'] = [mutagen.mp4.MP4FreeForm(b'STEM', mutagen.mp4.AtomDataType.UTF8)]
# tags.save(stemFilePath)
def _test():
encode("02 Hatsune Miku's Counter Attack.mp3", "separated/mdx_extra/02 Hatsune Miku's Counter Attack/drums.wav", "separated/mdx_extra/02 Hatsune Miku's Counter Attack/bass.wav", "separated/mdx_extra/02 Hatsune Miku's Counter Attack/other.wav", "separated/mdx_extra/02 Hatsune Miku's Counter Attack/vocals.wav", "test.stem.mp4")
if __name__ == "__main__":
_test()