Dup Ver Goto 📝

VirtualDJ Prepared Stems Format

DAW/dj/virtualdj virtualdj does not exist
To
96 lines, 279 words, 2657 chars Page 'PreparedStemsFormat' does not exist.

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:

  1. Vocal
  2. Hihat
  3. Bass
  4. Instruments
  5. 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()