A wavetable oscillator—Part 2

From Part 1, we have an oscillator. But we need to broaden it to allow scaling of harmonic content based on pitch so that we have all the harmonic content we need at the low frequency end, and, as we move up, eliminate those harmonics that would be above the the range of hearing and mirror (alias) back into the audible range.

How many harmonics do we need?

To start, we pick a lowest wavetable frequency. Let’s say 40 Hz (it could be 80 Hz, it could be 20 Hz—it could be 1 Hz). The highest harmonic that fits under half our sample rate is 551 (22050 / 40 is 551.25). So, we could make a sawtooth table of 551 harmonics. The top harmonic would be only 10 Hz from the aliasing threshold—Nyquist. If we shift that wavetable up one octave to 80 Hz, the top harmonic would double—which means it would alias back down to 20 Hz. And the top two hundred harmonics would be below 16 kHz…Ouch! That means as we glide the wavetable frequency from 40 Hz to 80 Hz, we’ll be inundated with harmonics aliasing downward throughout the audio range.

Of course, we could go the other direction, using that table from 40 Hz downward (and each higher table handling one octave downward similarly). But that means that as we shift down an octave, all of those harmonics at the top of the audio range will shift down to half the audio range—our highest harmonics would now top out at about 11 kHz before the next table takes over and restores harmonics to the top of the audio range. We’ll hear this shortcoming.

OK, we can cheat some and go for the middle ground. Most people don’t really hear to 20 kHz—adults are lucky if they can hear 14 kHz. If we go for 368 harmonics, that puts the top harmonic at 14.72 kHz for 40 Hz, and the alias would fold back to 14.66 kHz (44100 – 14720 x 2). I think this will work fine for me—I did a quick and dirty check a while back and could hear a 14 kHz tone, but not 15 kHz. The rest of you are on your own. Just kidding (and it ends up my hearing’s not that bad anyway—more later, in the “end notes” installment). Instead of requiring each subtable to cover an octave, we could use twice as many and have them cover half of an octave. Or an even smaller increment. Or we could just oversample the oscillator and expand our shallow frequency headroom greatly, from a few kHz to tens of kHz.

I’ll continue to develop this oscillator in octaves in order to keep the explanation simple (and because I’m going for “good” quality, to leave you to decide if you can sacrifice some quality for performance or memory, or whether you want to improve quality), but the extension to use more closely-spaces subtables is trivial. Oversampling 2x is also easy, but will complicate the explanation—you’re on your own if you want to go that way, but it’s a good learning exercise.

Wavetable size

First, let’s back up and figure out how long our tables need to be. Recalling that we need to sample a signal at greater than twice the highest frequency component, that means that for 368 harmonics, we need at least 368 x 2 + 1 samples, or a table length of at least 737 samples. But also remember that we’ll be using linear interpolation, so we need to oversample for good results. That means at least 2x, for 1474 samples.

We have good reasons to choose a table length that’s a power of two, however. There are optimizations we can do that take advantage of binary arithmetic, such as zero-cost wrapping of the table index for fixed-point indices, for instance. Plus, we get a huge boost in building these tables if we use the FFT, compared to summing sine waves individually. Also, we’ll definitely want to use the FFT if we let users define their own waves—and the FFT is best suited for tables whose lengths are a power of two. From 1474, our next highest power of two is 2048, which gives us a bit more oversampling as well. Memory’s cheap, so no problem going bigger, but let’s see where this gets us.

The bottom subtable will be used for that first octave and all pitches below. The second subtable takes over from 80 Hz to 160 Hz, and so on, as frequency doubles (and pitch goes up one octave). We use a suitable, progressively smaller range of harmonics for each table as we go up—dropping the upper half of our harmonics for each higher octave. The top table will be a sine wave, always, so we can just add tables until the last one has one harmonic.

Next: let’s hear the results in Part 3

This entry was posted in Aliasing, Digital Audio, Oscillators, Wavetable Oscillators. Bookmark the permalink.

12 Responses to A wavetable oscillator—Part 2

  1. A says:

    A probably better method is MinBLEPs, where the wavetable contains just the transition edge, anti-aliased, and then you sum it with the naively-generated square or sawtooth waves to effectively cancel out the aliasing. http://www.experimentalscene.com/articles/minbleps.php

    • Nigel Redmon says:

      I’m very familiar with MinBLEPs, and implemented them years ago. But “better”…they become more expensive at higher frequencies, and you can’t generate arbitrary waveforms. In part 1 I showed a sine wave from wavetable, and in part 3, a triangle—can you get those from a MinBLEP? No. And capturing (or computing) an arbitrary single cycle and translating that into an anti-aliased oscillator across the audio range…not with MinBLEPs. Sure, I realize you’re talking about saws and rectangles, but a MinBLEP oscillator is not “better”—just another way of doing a small subset of what a wavetable oscillator can do. But maybe it’s the only subset you care about, and it’s a valid choice.

      However, for adding hard sync to our wavetable oscillator…that’s where MinBLEPs become interesting for me. (And I had already planned to mention this before the oscillator series ends.)

      Thanks for reading!

      • Robert Bielik says:

        Actually that is not quite true. I have a MinBLEP based saw oscillator that is done with about 10 integer ALU operations that can generate totally aliasing free sawtooth, double that and you have a PWM capable square wave or a triangle wave, all hardsyncable, and the CPU demand is not related to generated frequency, plus is extremely low. Nonetheless, a wavetable oscillator is an extremely important part of a synth, so thanks for sharing the article.

        • Nigel Redmon says:

          Hi Robert,

          It’s not clear which part you’re saying is “not quite true”. The higher the frequency, the more often you need to generate minBLEPs, to the point that they overlap at high frequencies (in the general case). No?

          Indeed, hard sync was one of my favorite tools on the old modular analog synth, and naive (aliasing) sync on a digital oscillator doesn’t cut it for me. I do plan to write an article on the topic (but I have a couple already in the queue ahead of it).

          Thanks for the comments—and feel free to post links to audio or code of your oscillators if you’d like.

          Nigel

          • Robert Bielik says:

            You’re correct of course, with minBlep there is an added CPU cost with higher frequency, thus “minBlep” is a wrong term for what I’m doing. I’ve implemented the saw and triangle oscillators from this paper (see section 1.5), and I can generate arbitrary frequencies without any change in CPU cost, and with branchless code. For the time being, I’ll keep the actual implementation to myself, but it is (almost) self evident from the linked paper.

          • Nigel Redmon says:

            Thanks Robert, that sounds very interesting (and efficient). I came across that paper just recently, but haven’t yet read it yet. I might give it a try after try I finish my own thoughts on hard sync.

          • David says:

            How close to publishing your article on Hard Sync are you? I’d quite like to read that sometime…

          • Nigel Redmon says:

            I started down that path several months ago, but jumped off on different topics, including an article and code on envelope generators (mostly written late December!) that I need to finish editing and publish. But I’ll try to keep hard sync high on the list—thanks for the prod.

  2. aciddose says:

    “In part 1 I showed a sine wave from wavetable, and in part 3, a triangle—can you get those from a MinBLEP?”

    yes actually. you need minblamp – a ramp, and higher orders. 3,4,5 are good for sines although the usual implementation is just to use the squared parabolic approximation and only apply the higher order filter to sync which yields very close to perfect results.

    yes, any waveform can be generated with better results than wavetables. that doesn’t mean tables are useless. it only means they’re obsolete in most cases. the concern about expense at high frequency is justified in some cases. you have to also consider the lack of expense at low frequencies and question how often high frequencies occur.

    with a table of reasonable length you’ll tend to need at least eight samples, so that gives sr/8 as the threshold where you’ll start to expend equal and then more than one sample of filter per sample of output.

    by the way, it’s 5512.5hz for a ramp or other single transient waveshape at 44.1k. been playing many high frequency whistles lately? again it’s entirely justified but you must question exactly how reasonable it is to make the assumption a majority of content will be above that level. for the pulse we have two transients so our limit is 2756.25, a little more reasonable.

    yet still it’s quite clear that in general we’re dealing with frequencies in the range of 500hz, not 2500hz. at such frequencies the filter samples will occur with large spaces between and efficiency will quickly close to the naive case.

    • Nigel Redmon says:

      OK, but you’re changing the rules now when you answer “yes” (moving to relatives of MinBLEPs). I presented a wavetable oscillator for its generality. You can’t say “bah” into a mic, extract a cycle of it, and use that as your oscillator with MinBLEPs. Like I said, they are nice, and I especially like them for hard sync, but this is a tutorial on wavetable oscillators. And I disagree that “any waveform can be generated with better results than wavetables” and “they’re obsolete in most cases”—unless you are restricting yourself to “virtual analog” (with the classic waves).

      But even more importantly, I think that learning about how wavetable oscillators work, and why naive approaches fail, helps with the understanding of digital audio in general. And that’s the purpose of this blog.

  3. aciddose says:

    i should have also mentioned that it’s also possible to generate wavetables for blep oscillators. as you render your waveform at higher frequencies some information will be lost. if a specific transient does not contribute to the anti-aliased result at a particular frequency it can be replaced. for

    example let’s say we have a pulse wave with a +2octave pulse overlay on it. sort of like the alpha-juno waveforms, same idea. once we get to a frequency high enough that +2 octave is beyond nyquist we can completely drop these pulses. they’ll be replaced by a dc offset and ripple which can be made inconsequential.

    that is just a rare case, simply exceptional at best, it’s extremely rare! in the cases where it is needed the implementation is also like the rest of minblep definitely non-trivial. there are a lot of things to work out to have it perform as desired and many trade-offs to be made.

    it is possible though and it exists in a working state.

  4. Smashed Transistors says:

    Some variant of DPW is quite efficient for antialiasing of wavetables see http://forum.cockos.com/showthread.php?t=179974 for an implementation in Reaper jsfx.

Leave a Reply

Your email address will not be published. Required fields are marked *