VirtualDJ Prepared Stems Format
As of the time of writing, Virutal DJ splits into 5 stems. Prepared stems
are stored in a .mp4 file with (no video and) 5 audio tracks. In order,
these are:
- Vocal
- Hihat
- Bass
- Instruments
- Kick
The .vdjstems file includes a title tag on each stream identifying what it is.
Extractor Script
This is a simple python script to extract the 5 stems.
This works on newer .vdjstems that include a title on each stem.
#!/usr/bin/env python
from subprocess import run
import json
import os
import argparse
def main():
parser = argparse.ArgumentParser(prog="vdj_extract_stems",
description="Extract VDJ Stems")
parser.add_argument("files",nargs="+")
ns = parser.parse_args()
os.makedirs("extract",exist_ok=True)
for ifn in ns.files:
proc(ifn)
def proc(ifn):
m = run(["ffprobe","-print_format","json","-show_streams",ifn],capture_output=True)
data = json.loads(m.stdout.decode())
streams = data["streams"]
for stream in streams:
title = stream["tags"]["title"]
index = stream["index"]
xs = ifn.split(".")
x = ".".join(xs[:-2])
ofn = f"extract/{x}_{title.upper()}.m4a"
run(["ffmpeg","-n","-i",ifn,"-c:a","copy","-map",f"0:{index}",ofn])
if __name__ == "__main__":
main()
Slightly More Robust
This defaults to naming each stem STEM00, STEM01 etc. if the stems are not tagged.
Most likely VDJ uses the same order.
#!/usr/bin/env python3
from subprocess import run
import json
import os
import argparse
def main():
parser = argparse.ArgumentParser(prog="vdj_extract_stems",
description="Extract VDJ Stems")
parser.add_argument("files",nargs="+")
ns = parser.parse_args()
os.makedirs("extract",exist_ok=True)
for ifn in ns.files:
proc(ifn)
def proc(ifn):
m = run(["ffprobe","-print_format","json","-show_streams",ifn],capture_output=True)
data = json.loads(m.stdout.decode())
streams = data["streams"]
mapping = []
try:
for stream in streams:
title = stream["tags"]["title"]
index = stream["index"]
xs = ifn.split(".")
x = ".".join(xs[:-2])
ofn = f"extract/{x}_{title.upper()}.m4a"
mapping.append((index,ofn))
except KeyError:
for i,stream in enumerate(streams):
index = stream["index"]
title = f"STEM{i:02d}"
xs = ifn.split(".")
x = ".".join(xs[:-2])
ofn = f"extract/{x}_{title.upper()}.m4a"
mapping.append((index,ofn))
for index,ofn in mapping:
run(["ffmpeg","-n","-i",ifn,"-c:a","copy","-map",f"0:{index}",ofn])
if __name__ == "__main__":
main()