Youtube to Stems
Jul 30, 2020
2 minute read

After 5 (or is it 6?) months of social isolation, I realized I had an overflowing surplus of time. After a brief relapse into Warcraft III, I decided that surplus time could be better invested elsewhere. That “elsewhere” turned out to be music.

I wanted to get better at sound design and learn how to recreate song I like. Yesterday, I had an epiphany: I knew how to code. The following script takes a youtube URL and extracts the stems–vocals, bassline, drums, and other stuff–into a predetermined folder. I then added this folder to the “data” section of FL studio for easy sample searching.

Figure 1: I should probably learn Ableton…

Figure 1: I should probably learn Ableton…

This marks my first official foray into bash scripting since college (and also using my skills for something other than generating capital for my company).

Prereqs

  1. Install Spleeter, an ML model that splits stems. Follow the link’s instructions if you don’t have conda.

    conda install -c conda-forge spleeter
    
  2. Install ytdl, a script that downloads a youtube video

    npm -g install ytdl
    

The script

Copy the following into your .{zsh,bash}rc and source it.

spleet() {
    mkdir -p ~/Documents/Stems/
    spleeter separate -i $1 -p spleeter:4stems -o ~/Documents/Stems/
}

yt() {
    local name=`ytdl $1 -i | head -n 1 | awk -F ": " '{print $2}'`
    local ename=`printf '%q' "$name"`
    local defaultdir="$HOME/Music/ytdl"
    mkdir -p defaultdir
    local defaultloc="$defaultdir/$ename"
    local loc="${2:-$defaultloc}"
    echo "Downloading $ename from $1 to $loc"
    ytdl $1 | ffmpeg -i pipe:0 -b:a 192K -vn $loc.wav
    echo "$loc.wav"
}

ytd() {
    local loc = `yt $1`
    spleet $1
}

Usage

ytd <URL> - Downloads and split the URL

yt <URL> <OPTIONAL_DESTINATION> - Downloads the wav of a youtube URL

spleet <path_to_wav> - Splits a wav into 4 stems

Things I learned

  • Functions > aliases.
  • With $1,$2,...$n and ${2:-value} you can make full-featured CLI applications all within bash in a matter of seconds.
  • $* means all the arguments to a command.
  • Backticks (``) allow you to execute subcommands and store them in values.
  • awk is a swiss army knife for piping out of one command into another.

Notes

DM me if you’re interested in going crate-digging (AKA clicking on obscure youtube links and finding cool samples). Hope this was useful, please enjoy responsibly. More cool stuff to come.