Skip to main content

The Hypergrowl Algorithm

I'm normally not a huge fan of variable wavetable synthesis found in synths such as Massive, Serum, or Vital. A big part of my electronic music philosophy is deriving everything parametrically from mathematical principles and not using samples, recorded material, or data mining (as in a lot of machine learning). As it turns out, many wavetables found in these plugins are cannibalized from recordings of other synthesizers, as Serum allows importing a sound file and chopping it up into pitch periods. I don't have an ethical objection to this, but it comes too close to sampling for me. As I've said before, I don't turn my nose up at sampling or anyone who uses it; I just personally like "pure" synthesis as an artistic constraint.

That said, more inventive users of these synths have found interesting ways to create wavetables that do have simple derivations. Serum not only offers an extensive set of operators for creating and editing wavetables, but also a "formula parser" that allows users to define wavetables with mathematical expressions. A tutorial by Busy Works Beats shows how to make a strange squelch effect by generating a harmonic series and using the "Bend +" warp operator to pinch the wavetables towards the middle. With a bit of math, it's not hard to port these sounds to DSP code that computes these waveforms on the fly, although proper antialiasing may be difficult to achieve without significant oversampling. [1]

The absolute crown jewel of fully parametric wavetable hacks is Au5's Hypergrowl. Go watch a few minutes of the video. As far as audio DSP algorithms go, I've never seen something so simple and elegant produce such fantastic-sounding results. The idea of the Hypergrowl is to begin with a square wave, configure the oscillator to output detuned copies, and then use Serum's "Resample" feature to render those to a buffer, chop it up into pitch periods, and load those wavetables back into the oscillator. The process is repeated several times to produce a variable wavetable with rapid modulation and deep notches. The sound is at this point extremely rich and minimal processing is needed to produce a professional-sounding brostep growl.

I don't own Serum, but I had to try this for myself. Due to its simplicity, it's not too hard to emulate this process in code. The following steps do the job:

  1. Start with a square waveform with period N repeated many times.

  2. Make several slightly detuned copies of this signal by resampling. The resampling quality isn't super important; linear interpolation is fine.

  3. Truncate the beginnings of these signals by random amounts so their phases are no longer aligned. This is critical, otherwise the wavetable will sound very boring.

  4. Truncate all signals from the end to match the length of the shortest signal, then sum the signals together.

  5. Repeat steps 2-4 several times.

  6. Chop the signal into N-sample wavetables.

  7. Remove dc bias from each wavetable.

  8. Optionally, remove even harmonics from each wavetable for a more "hollow" sound. This can be accomplished without FFT by subtracting a time-reversed version of each wavetable from itself, then dividing by 2.

  9. Normalize each wavetable so its peak amplitude is 1.

I initially did this in Python and NumPy, exporting the wavetables as an audio file and loading them in SuperCollider. I then decided to port this algorithm to sclang, since I like immediate feedback and convenient incorporation into patches, even though I'm not fond of the language. The code is available to Patreon subscribers.

Analysis

The Hypergrowl (or my version of it) can be characterized entirely mathematically, which can help us understand its behavior.

Define the square wave function as the function with period 1 such that:

\begin{equation*} \Pi(t) = \begin{cases} 1 & 0 \leq t < 1/2 \\ -1 & 1/2 \leq t < 1 \\ \end{cases} \end{equation*}

Let \(n\) be the number of detuned copies produced for each iteration. Let \(\omega_1, \ldots, \omega_n\) be the detuning ratios, which for simplicity's sake will be identical at each iteration. Let \(0 \leq \phi_1^{(i)}, \ldots, \phi_n^{(i)} < 1\) denote random phase offsets produced independently at iteration \(i\).

Define \(f_0(t) = \Pi(t)\) (or any waveform), and define the recurrence relation:

\begin{equation*} f_{i + 1}(t) = \sum_{k=1}^n f_{i}\left(\omega_k t + \phi_k^{(i)}\right) \end{equation*}

Then pick an iteration \(f_j\) and let \(v\) denote the number of wavetables. Then the \(v\) wavetables are defined as \(w_k(t) = f_j(k + t)\) where \(0 \leq t < 1\) and \(0 \leq k < v\). These are analog signals and require antialiasing to become sample digital wavetables. Aside from that, the Hypergrowl is now completely described.