Show HN: Free AI-based music demixing in the browser (sevag.xyz)
Hi all,
I've spent some time working on music demixing or music source separation algorithms, which take in a mixed song and output estimates of isolated components (e.g. vocals, drums, bass, other).
I took a popular PyTorch model with good performance (Open-Unmix, UMX-L weights), reimplemented the inference steps in C++, and compiled it to WebAssembly for a free client-side music demixer.
48 comments
[ 3.6 ms ] story [ 105 ms ] threadI hoped to put together a system that compares the backs to the fronts and lists the output to find cool transitions, but I have no idea how to actually "grade" the similarities
Beyond basic BPM matching on the drums tracks, nothing I've tried has made for anything really compelling (sounds random... :( )
The script [1] uses Essentia Chromaprint [2] to "grade" the similarity of audio tracks, and combine the ones with the closest chromaprint. No crossfade or BPM matching, just yolo concatenation.
I have a track on Soundcloud which uses the above technique (mashing together short generated clips by their chromagram), trained on Cannibal Corpse [3]
1: https://github.com/sevagh/1000sharks.xyz/blob/master/sampler...
2: https://essentia.upf.edu/reference/std_Chromaprinter.html
3: https://soundcloud.com/user-167126026/1000sharks-domainal-sk...
However I did get sound similarity working using an audio tagging neural net [1]. I chopped off the first and last 15 seconds of every song in my collection and ran them all through this analysis which produces a ~520 dimensional vector. I then targeted specific endings I wanted to match and used Euclidian distance to find the closest matching song beginning.
YMMV but I thought it actually worked pretty well, I just never got to automating the BPM matching. I can try to look for my old script if you're interested :)
[1] https://github.com/fschmid56/EfficientAT
it separates the components of tracks that it can download (and process), not of a live audio feed
- select the best next song given a simple input (for example, a microphone or a camera looking into the crowd)
- mix it into the current song
- repeat
Using AI you could probably intuit the "pulse" of the music to find the first beat of the first bar of a measure, and sync tracks up so that they mix in a place that makes musical sense.
However… what if you want more than four components? What if you want to split a complex arrangement into a separate component for each individual instrument? Does anyone know of any interesting research in this area?
>We are also releasing an experimental 6 sources model, that adds a guitar and piano source. Quick testing seems to show okay quality for guitar, but a lot of bleeding and artifacts for the piano source.
I also believe Audioshake [2] (a company in the space) is doing guitar separation as well.
1: https://github.com/facebookresearch/demucs 2: https://www.audioshake.ai/
The companies doing AI mixing have a huge advantage in this area.
Does the developer console say something like "Aborted" or give a memory error in Firefox? If your clip is big enough that it uses >2GB but <4GB of memory, that could explain why it works in Chrome.
I believe the program he was using was djPROAI[0].
[0] https://www.algoriddim.com/djay-pro-mac
Console warning:
The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
Download Weights button also did nothing.
That's when I wrote umx.cpp [1] (which is what this site is based on).
On an unrelated project, a friend of mine mentioned WASM, and as I looked into it a bit more I thought trying to compile umx.cpp to WASM would be a great idea, since I only use Eigen (which is a header-only library that only depends on std).
1: https://github.com/sevagh/umx.cpp
is there a command line version of this tool ?
Of course, you can always run the upstream umxl model easily:
``` pip install openunmix # pulls in pytorch ```
Installing openunmix installs the `umx` cli:
``` $ umx --help usage: umx [-h] [--model MODEL] [--targets TARGETS [TARGETS ...]] [--outdir OUTDIR] [--ext EXT] [--start START] [--duration DURATION] [--no-cuda] [--audio-backend AUDIO_BACKEND] [--niter NITER] [--wiener-win-len WIENER_WIN_LEN] [--residual RESIDUAL] [--aggregate AGGREGATE] [--filterbank FILTERBANK] [--verbose] input [input ...]
UMX Inference
positional arguments: input List of paths to wav/flac files. ... ```
It will download the weights automatically for you and demix at a higher quality than my site, for two reasons: * Unquantized weights (small impact) * Post-processing step (bigger impact)
I tried to tackle the post-processing step in my C++ code (which would win ~1 dB in quality across all targets) but it's too tricky for now [2]. Maybe some other day.
1: https://github.com/sevagh/free-music-demixer/blob/main/examp...
2: https://github.com/sigsep/open-unmix-pytorch/blob/master/ope...
What about the ability to do separate out background noise? I'm thinking of a project like this where the Beatles Live album had screaming fans mixed down?
https://www.wired.com/2017/03/remastering-one-beatles-live-a...
"It doesn't exist as a software program that is easy to use," Clarke says. "It's a lot of Matlab, more like a research tool. There's no graphical front end where you can just load a piece of audio up, paint a track, and extract the audio. I write manual scripts, which I then put into the engine to process."
There are tons of recordings of live performances that could use a little AI TLC.
Hypothetically, this is how I would approach it.
I would start by forking Open-Unmix or another 4-stem model (Demucs, MDXNet). The code is oriented towards the 4 sources (vocals/drums/bass/other), which is dominant because the major datasets for training use these stems.
The Open-Unmix training code goes like: ``` x, y1, y2, y3, y4 = load_training_data()
y1_est, y2_est, y3_est, y4_est = unmix(x)
loss = loss([y1, y1_est, y2, y2_est, y3, y3_est, y4, y4_est]) ```
In your case it may be simpler like `noisy mix = clean mix + background noise`.
In that way, I don't even think you're constrained to using a dataset that has 4 stems available (which is a rare quality in a dataset).
Instead, you need a way to acquire or generate screaming and other concert noises.
Then, the new training code could look like: ``` x = load_training_data()
n_samples = x.shape[-1] # get length of music waveform
noise = generate_screams(n_samples)
x_noisy = x + noise
x_est = unmix(x_noisy)
loss = loss(x, x_est) ```
Well, anyway. That's my naive first idea of how I would approach it. But, this relies on having clean background noise/screams _without any music in it_. And I'm not aware of such datasets.
I have tried many sources and method over the years and settled on spleeter [0]. Works well even for 10+ minute songs, varying styles from flamenco to heavy metal.
[0] https://github.com/deezer/spleeter
I'm somewhat limited in what can run in a browser by the nature of the project.
Been really enjoying that one
VirtualDJ[0] software lets you do this with their Stems feature in real time and works really well, and it's free I believe.
[0] https://www.virtualdj.com/