Hiked The Enchantments for some unexplainable reason. Was supposed to be this great hike with views but we hit the rain/snow/snowstorm in August so was more sluggish than expected. The descent especially was hard as it was a lot of slippery granite.
Andrew Weatherall - Slow Electric Vol. 1 (Massive Mellow Mix)
Just before the COVID pandemic truly hit the world, Andrew Weatherall passed away at the age of 56 years. There is little value of rehashing the importance of his contributions to modern electronic music but to me personally he’s an icon of taste. I’m fascinated by Weatherall’s path in life, where he intentionally forfeited fame and glory (as a potential superstar DJ) for what he believed was the right path artistically for him. His view on music and broad taste is something I still use as a guiding star personally when exploring new music and the connections between tracks.
Weatherall produced and released a wide variety of mixes, ranging from 90s rave & breakbeat, onto the minimal techno era of the 2000s with Hypercity all the way to the throwback deep disco of the 2010s but one mix stands apart as different from most released work. “Slow Electric Vol.1” is a mix of mostly slower moving electronic music and for me this is one of the best expressions of Weatheralls broad and eclectic taste in music, many of the tracks on this mix are so obscure that they never even saw a digital release, let alone a streaming release. The mix “Slow Electric Vol.1” is also commonly called “Massive Mellow Mix” and was chronicled about by Kirk Degiorgio for ResidentAdvisor.
Kirk gets some facts wrong in the article but the thing he’s absolutely spot on about is the debate about the tracks which adds to the mysticism around this mix. Noone seems to have a good handle on when it was made or what tracks were on it. On top of that, the only available ripped version is a cassette recording that’s been spliced together at various points to mask over recording errors, coupled with aggressive audio compression and generational tape loss.
If you listen to the mix from YouTube you can clearly hear the degraded quality but spectrals also shows the 15KHz cutoff that is common with cassettes with the clear “hiss” being visible in the upper range of the spectrum. All of this has bothered me for reasons I can’t really explain:
The fact that I find it hard to enjoy this mix with the low audio quality.
Misinformation around the mix itself.
Disagreement on what tracks were used in the mix.
So what do we do about it?
This was one of these projects that I intentionally kept deferring, hoping that eventually my mind would lose interest as a way to pressure test if I really cared about working on this. After over a year of continuous flare ups of thought around this project I eventually accepted the fact that I for some reason did care about solving this and thus set out to solve it. So given the three things that bothered me, how do we go about fixing this? There is no way to access the source mix (he likely taped it directly from mix), the cassettes available for sale are of equally low quality and the recordings I’ve found all suck.
But what if we recreated the mix? As in we found the exact source tracks that Weatherall used, aligned it all to the cassette RIP and matched the transitions. It solves the problem of “what tracks were used” as only the right one will fit the source material and it also solves the quality issue as we can source the tracks from the highest quality source possible. If this mix was made later, this would be much harder as DJ mixers started incorporating looping and on-board effects but Weatherall likely spun this one on vinyl on an old 2 channel Vestax mixer with a 3 band EQ per channel, replicating this would not be hard!
The first step was sourcing all the tracks. It took a long time to find the tracks, as it was confusing what tracks were actually used. I was able to source some of the tracks digitally, as some of the artists have released these as part of compilations or anthologies. Some of the tracks however just never seem to have ever made it online, which was the case for a couple of tracks where the artist just seems to have made one album and never followed it by anything. Since I was set on actually recreating this mix, I had to source the vinyls from Discogs and rip them myself. One of them even came in the original plastic (Keyprocessor), for an artist that likely never sold much in the first place. I realize that the record exploring culture was different in the 90s and Weatherall likely sourcing these tracks from friends / shops but it is also sad that the only real discovery of this artist is through the fact that Weatherall at some point stumbled upon it and had the taste to include
it on his mix.
With that said and done, I laid out the version from YouTube into Ableton and started piecing it together. Ableton allows you to “Warp” tracks, as in adjust the tempo without affecting the pitch of the tracks. Contrary to most other Ableton users, this is actually not what we want. If we used Ableton’s global tempo and aligned the tracks as a modern DJ would, the mix would not be a pure recreation but rather just an imitation. You would lose the shifts in pitch that comes from vinyl mixing and the mix. Luckily we are able to use the “Re-Pitch” mode that instead of locking the pitch and adjusting the tempo by algorithmic modification we just speed up/slow down the track, exactly how a vinyl behaves when you tempo match to another deck. Hence when dragging these warp markers, we are adjusting the speed of which the track is playing between each marker.
Once I had laid out all tracks it was more obvious where the source taped had been spliced, as the rough alignment started gapping in certain places. Relistening to those specific spots one could easily hear where the person editing the tape had spliced it to fit the tempo of the track, likely cutting a bit more than what was lost to mask it better.
Lastly I had to align the mixes and tempo with what Weatherall mixed, something that wasn’t hard but time consuming. I really wanted to include the “feeling” of the mix, as in to capture the creative decisions and small mistakes that were in the source which meant basically tracking second by second to the source mix and aligning the warp markers. The fun part about this is you can really see where Weatherall was holding his finger on the spindle to slightly slow down the platter as the tempo lightly decreases in a non-linear fashion as the tempo dial on the vinyl decks would do it.
Result
Pressing “Export” in Ableton felt like closing a door to an obsession. After over 3 years of collecting, searching and thinking about this mix, being able to hear this in full quality tracking almost exactly to the source material feels great. Was this worth the effort?Unlikely for anyone else but me.Am I glad I did this?Absolutely.
So now that we have the mix, let’s help answering some of the questions that I were floating around on various music forums on the internet:
When was this mix recorded?
I am almost certain that this mix was recorded in May/June of 1994. Contrary to what the uploaded mix is titled as (1993). The reason for this is that many of the tracks on the mix were actually released in 1994 and not 1993. Since many of the tracks are from early Q2 in 1994, I’m guessing that these are fresh tracks that Weatherall included in the mix. There is also the Reddit user Donkeyshite who mentions being in the band “State of Flux” and their tracks being made and released early 1994, not 1993.
What is the actual tracklist?
00:00:00 Hole In One - Spiritual Ideas For Virtual Reality [unknown source]
Back again with yet another odd protocol to dive into. This time around we’re tackling a pixel protocol named DDP. DDP is another small homebrew protocol that aims to squeeze in as much pixel data as possible into one ethernet frame (1500 bytes) in order to maximize transmission efficiency over local networks. When you’re driving large scale LED installations, the overhead starts mattering as you have to introduce other complexity to deal with it (TCP, packet protocols etc). Especially in applications where lost data matters less than latency and throughput.
I ended up in this hole as I purchased the 8 Port LED Distro by Bong69 (what a name) which is a small ESP32 controller wired up with an ethernet port, level shifters, fuses and 8 output connectors for driving LED strips like WS2811/WS2812. The controller runs a piece of software called WLED, an open source project implementing a wide variety of different features to drive everything from holiday lights to installations. Reality is I just wanted a simple controller that solved the output problem so that I could stream pixel data to over wired ethernet. The alternative was that I would write software for a Teensy but given that life has changed to a degree, time is a precious resource these days.
WLED supports E1.13, ArtNet, DDP and tpm2.net and their own UDP realtime protocol. ArtNet and E1.31 are originally protocols to control light fixtures and suffers from those compromises (maximum 40FPS framerate for DMX compatibility, multicast) which ruled them out. I started out implementing tpm2.net but quickly realized that the only real user of this protocol seemed to be a German bespoke LED controller manufacturer. That left DDP as the preferred protocol to pursue.
DDP is defined by 3waylabs and seems to be their preferred protocol for their art installations. The webpage has some mentions of burning man so going to assume it’s yet another burning man LED installation developer. What I liked about DDP is that it’s extremely smart in how it packs the metadata into the bitstream. DDP makes use of every available bit, which yields a header no larger than 10 bytes. Compare this to E1.31 where the header is 126 bytes. Modern computers don’t care but for a small microcontroller parsing data, this ends up having an impact on the amount of frames per second you can push. DDP sits in the middle here as “sane” compromise. It doesn’t mandate a framerate, it’s spec agnostic to if you send it over UDP or TCP (although I suspect most vendors only accept UDP) and it’s open ended in that it relies on JSON for messaging. Only drawback is that clients needs to implement JSON parsing if they want to be smart but that’s
tablestakes at this point for anything connected.
Implementing DDP
I was set on trying leveraging Copilot and ChatGPT this time around to save time and bonged out a go implementation in an evening. Coming back to Go always makes me realize how good Rust is. If you took Go, added the Result type and enum pattern matching from Rust you would have the perfect language but sadly we’re bound by the C conventions imposed by Rob Pike and friends. After verifying that the Go implementation sent the right bytes, I hooked up the WLED controller which of course did not work. Turns out that WLED wants to open a return connection to the incoming address for it to accept DDP.
Having a working Go implementation helped in thinking about how to design the Rust version of this. With Go I took some architectural liberties that are forbidden in Rust. On top of that, the Go implementation only implements the subset that allows you to send pixels, not control the display. I took the same approach here, using ChatGPT to assist but it quickly turned out that I had to do a lot of manual work as ChatGPT struggled to understand the documentation. The documentation relies a lot on formatting to convey the spec and ChatGPT didn’t see that nuance.
After another couple of days of bashing, ddp-rs was now working. Since I cared a bit more about implementing the entire spec this time around, I wrote some more serious tests to both encode and parse DDP. To test my library, I used WLEDs “output mode” in which it can spit out a DDP stream and this is where it started getting weird. My test failed on parsing the bits per pixel from WLED, being offset by 2. As always when programming, I assumed it was my fault and started digging. After going back and forth on the spec for hours I could not understand how the value WLED was sending would be correct at which point it was time to jump into the WLED source code.
After digging a bit I was convinced that WLED had implemented it wrong. WLED just hard sets these values in config instead of calculating them (nothing wrong with this, faster for their use case) and the values were wrong, but why? I opened a pull request with changes and one of the maintainers immediately asked me to fix it upstream. After reviewing the upstream repo, it turns out that the WLED developers hacked DDP support on themselves and DDP isn’t in the upstream repo. The maintainer shares that the spec they implemented a while back was different. I used the waybackmachine and it turns out they were right, the spec actually has changed over time. At this point, the only way to clear this out is to email the person who wrote the spec and ask them what’s the actual story behind this value. I emailed and got an answer quickly and it
turns out that this field was initially “to be defined later” but a lot of people started wanting RGBW support in WLED, which pushed the author of the protocol to implement something quick that later changed. WLED was still on the “initial” implementation. After that, the pull request was accepted and I could return back to sanity.
What did we learn?
Please version your protocol and provide a historical list of the changes.
I am now firmly in the camp of “Go is not great”. Fantastic runtime, harsh language.
ChatGPT is amazing, you already knew that though.
Long story short, I implemented DDP for Rust. In case you ever need it, enjoy.