Noise Engineering: Engineering Yester Versio
We recently released another firmware for the Versio platform. If you are still learning the basics about the firmware/module, you can check out last week’s post. This week, Stephen and Kris are sitting down to do a bit of a technical discussion of the making of Yester.
What is Yester Versio and why did we make it?
Yester is the ninth firmware we’ve released for Versio. One of the early firmwares we made was an experimental delay called Imitor. With its 12 stereo taps, Imitor Versio is fantastic for sound design and wild landscapes but can be challenging to tame. We had a ton of fun with it but it was never really meant to be a basic delay. Imitor can get weird. So after Imitor came out, we got requests for a simple delay.
We had several competing ideas for what a Noise Engineering simple delay would look like; we didn’t want to put a delay out that didn’t have its own character. The one you now hold was far and away the winner.
Yester was built on three concepts. First, Stephen wanted to build a pitch-shift chorus. Second, our goal of making a simple delay since people asked for it. And finally, we wanted to bring this to Versio: this would allow us to develop it with no hardware expense (a win for us) and also to keep adding value to the platform (a win for you!).
The pitch-shifting chorus idea warrants a bit more detail because it’s fun. Many of the Juno synths use two bucket-brigade delays (BBDs) that are LFO-modulated by a triangle wave and its inverse to create that iconic chorus. This is an intriguing concept because this modulation makes the pitch shift constant; with the two LFOs opposing at any point in time, one of the BBDs is outputting a shift up while the other is outputting a shift down. Yester takes this to extreme levels as it allows the pitch shift up to be a full octave. For a chorus, this shift would normally be in tens of cents.
What are some of the stand-out features of Yester Versio?
We had a lot of fun discussions about a lot of these. Yester shares no delay-processing code with Imitor, so it was like starting from scratch in many ways.
We dabbled with options, but settled on three taps. There’s nothing really magical about this other than we found it more interesting than just one, but when you add the three delay taps to a dry signal, they total to four, which is a common meter. A simple delay was the goal, but limiting the number of taps to just a few was a requirement so we could do complicated LFO processing, which takes a lot of processor power (more on this later). We talked about making the number of taps switchable but with the limited number of switches on the platform, we opted instead for the Even/Triplet/Dotted functionality since this is hard to do even with external clock dividers.
The Chorus knob, when CCW, adds a pitch-shifting LFO. It uses a triangle wave and its inverse with slopes chosen so the rising edge pitch shifts up a maximum of an octave. The position of the LFO index knob controls the top pitch. The shift down pitch generated with this technique is not musically related to the shift up, but we really liked the fun, dissonant tones we got out of it. It’s basically a horror soundtrack in a module.
Turning the knob CW adds a more “normal” chorus LFO. This is created using the same structure as the pitch-shifting LFO, but with sine waves rather than inverted triangles. In this mode, the maximal modulation index is much lower. However, everything else is the same: both read from the non-modulated tap and then from the two modulated taps.
Imitor featured an Angle parameter that spaced the taps out. On Yester, Pan is a simplified version of Angle, designed to give a continuum of pans. On this figure, the three taps are represented by the lines. With the parameter centered, all taps are mono. To either extreme left or right, the panning is heavily weighted that direction. The result feels like a normal pan knob with various ping pongs in between the extremes.
We like to add wavefolders to things. Fold was an early feature we had specced, but when we put it in practice, it was just a bit too much. We decided to take a concept from the Imitor plugin and put the fold on the output, instead of within the feedback loop. The knob started out being just a wavefolder, but a wavefolder makes the low end drop out quickly. We knew we wanted to be able to add back in subharmonics, so we mapped Doom (from Ruina Versio) to the top ⅓ of the knob. Finding the right balance of timbral change and controllability on a multifunctional parameter was the next big challenge. Eventually, we added a slight saturator to the first ⅓ of the knob. The saturator sounded great on its own, but also had the added advantage of preconditioning the incoming signal for the wavefolder, making wavefolding sound better, too! After more testing we decided we needed to decrease the max number of folds, but, of course, Doom remained Doom.
Here we should also shout out Hans, who has been working with us as a tester for a while and came on board to help us get a few things across the finish line. Markus and Stephen initially shaped Yester’s distortion options, but by the end, we were all tired and Hans’s fresh ears allowed him to give us some wonderful feedback and really get the fold knob to a place where we were all happy with it.
The interpolation modes (Fade/Octave/Jump) are similar to those on Desmodus, but have been redesigned from the bottom up to fit Yester. In Fade mode, the goal is to make timing changes as smooth as possible even if it increases the latency of the transition. Here, Yester will not change the delay length until the new time has stabilized for 0.1s (which has some obvious implications for the use of an external LFO on the input). It uses a 5ms crossfade time.
In Lerp mode, the delay length changes quickly, but Yester rate limits the change so there is an apparent pitch shift limited to a maximum of one octave (up if shortening, down if lengthening). We used a similar concept in Imitor Versio, but it was redesigned for Yester.
Finally, in JMP mode, there is no rate limiting. This introduces interesting artifacts, and in some cases extreme effects if you’re really jamming on the Time knob. This mode was by far the most challenging part of developing Yester due to its occasional use of very sparse memory reads which is problematic for the external DRAM.
Challenges in developing Yester
The biggest issue we had was DRAM performance. We developed the Versio platform using the Daisy Seed, which is built with external DRAM. This works really well for us for a variety of reasons but one inherent challenge is that it’s slower to access external memory than internal RAM. This isn’t specific to the Seed, but rather something that applies to most external memory.
DRAM access is most efficient when reading sequential chunks of memory. Fade mode worked nicely here as even though it requires twice as many memory accesses for the crossfade, they are all linear. In contrast, the fastest delay mode (JMP) when changing delay-line length quickly can have a nearly random DRAM access pattern. This can increase the total amount of time to process the audio by as much as 30%.
We have a tradition where one person (generally Kris) stays largely hands off a product through development and tests as a fresh pair of eyes/ears near the end. And of course, when Kris plugged Yester in, she immediately found a bug caused by the DRAM read-speed issue that kicked us back substantially. When modulating delay time it generated an artifact that was just bad. Stephen spent a lot of time optimizing to solve issues relating to DRAM access speeds. The biggest change was to batch all reads before the DSP process and all writes to after. This allowed for much better cache coherence and avoided interleaved reads and writes which is particularly painful with our DRAM configuration.
Surprises in developing Yester
Yester was supposed to be a “simple delay.” And somehow it became one of the most technically challenging things we’ve made, and the amount of time spent on performance was substantially higher than we expected. Generally speaking, performance is an issue we need to work on with new or experimental ideas because we have a stable of mature code to pull from for common algorithms as well as more experience doing similar tasks.
Yester also came out a little weirder than we expected, though we’re happy about that. We were a little afraid of a simple delay not standing up to say what value it brings to the table given an already crowded playing field of delays. We aren’t afraid of that now.
Finally, a lot of effort went into polishing the “chorus as pitch shifter” idea . We wanted a less-weird chorus which remarkably worked nearly the first time by just changing the triangle LFOs to sine and reducing the index a bit.