[sdiy] Stupid Lookup Table Tricks - BLEPs when you can't divide (and can barely multiply)

rburnett at richieburnett.co.uk rburnett at richieburnett.co.uk
Mon Jul 2 12:42:24 CEST 2018


One way of avoiding the divide operation when implementing BLEP 
oscillators is to pre-calculate the reciprocal of the frequency of each 
MIDI note and store these in the same lookup table that stores the 
frequency of each MIDI note.  So when a new note is played you go to a 
LUT and pull out a frequency value and a "reciprocal of frequency" 
(period) value at the same time.  The frequency value is used to set the 
phase increment of the numerically controlled oscillator.  And the 
reciprocal value is used to multiply the residual after each overflow of 
the phase accumulator in the NCO, to determine the sub-sample location 
of whatever step correction you're going to apply for anti-aliasing, 
(BLIT, minBLEP, PolyBLEP, etc.)  (This replaces the usual operation of 
dividing the residual after overflow by the phase increment value, which 
can take a lot of CPU cycles on some low-end platforms.)

Obviously there are some limitations to this method.  You are only 
storing values for whole semi-tone increments, so you need to do linear 
interpolation to cater for pitch bends and modulation.  This adds error 
that is at it's maximum mid-way between semitone steps.  However, if ROM 
is a precious resource, you only need to store values for one octave of 
pitch range with values normalised to make best use of the available bit 
width of the storage memory.  Then range reduction can be used to map 
higher and lower octaves into this range with the appropriate number of 
left or right shifts being applied to the frequency and period values 
pulled from the LUT.

-Richie,


On 2018-07-02 10:47, Tom Wiltshire wrote:
> Don’t forget the golden rule on 8-bit processors:
> 
> “Don’t do hard sums!”
> 
> Look-up tables for anything even remotely taxing are essential. Then
> it’s just a question of working out how much accuracy you need in the
> table (both bit depth and table length) and whether you can manage
> with a simple table or whether it makes sense to interpolate. Even
> just reading two entries, summing and downshifting to create an extra
> table entry in-between every other one can help a lot - after all, you
> just doubled the effective size of the table.
> 
> Sometimes it is better to have excessive accuracy in the look-up
> table, especially if that gets you to a round number of bytes (e.g.
> using 16 bits when you only need 12). That would be my approach with
> these reciprocals. This also helps when interpolating, since you’re
> not introducing further error by having heavily quantised data to
> interpolate from.
> 
> Frankly, the errors introduced by simple linear interpolation have
> only very rarely been the cause of my worries. Usually the other
> limitations are more significant.
> 
> ==================
>        Electric Druid
> Synth & Stompbox DIY
> ==================
> 
>> On 2 Jul 2018, at 06:59, rsdio at audiobanshee.com wrote:
>> 
>> I didn’t look at any of this in detail. Does the Arduino sketch use 
>> interpolation of pre-computed table data? If so, wouldn’t that add 
>> distortion? ... and potentially aliasing?
>> 
>> Brian
>> 
>> 
>> On Jun 28, 2018, at 4:00 AM, rburnett at richieburnett.co.uk wrote:
>>> Neat!  The quality is not bad but there is still quite a bit of 
>>> audible aliasing even with the corrections enabled.
>>> 
>>> I think the problem is that your LUT of reciprocal values really 
>>> needs a lot more resolution.  It returns the same value for large 
>>> ranges of input index.  This heavily quantizes the positioning of the 
>>> polyBLEP corrections and ultimately limits their effectiveness for 
>>> the anti-aliasing.
>>> 
>>> You're only seeing about 20dB reduction in aliasing, and should be 
>>> able to do much better than this in practice.  But I think the 
>>> implementation is being limited by the resolution of the reciprocal 
>>> lookup.
>>> 
>>> The neat thing about polyBLEP is that the correction curves are 
>>> simple functions, so you would ideally calculate these on a more 
>>> capable platform, instead of using a pre-calculated lookup table.  
>>> Then you are only limited to the numerical precision of the 
>>> calculations and not the number of entries in a LUT.  But I 
>>> understand your motivations for doing it this way to see if it can be 
>>> made to work :-)
>>> 
>>> FWIW, if you just want to generate anti-aliased sawtooths and pulse 
>>> waveforms on a low-end 8-bit platform without oscillator-sync, then 
>>> the best option is probably just to use wavetables.  You store a 
>>> whole load of sawtooth renderings generated by additive synthesis 
>>> with progressively less harmonics in a lookup table.  Every time you 
>>> go up by one octave in pitch you switch to the next waveform from the 
>>> table.  Square an pulse can be generated by taking the difference of 
>>> two phase-shifted sawtooths.
>>> 
>>> -Richie,
>>> 
>>> On 2018-06-28 01:14, Gordonjcp wrote:
>>>> Why would you pick an avr8 to do bandlimited oscillators?
>>>> Because folk say it won't work, that's why!
>>>> https://github.com/ErroneousBosh/slttblep
>> 
>> 
>> _______________________________________________
>> Synth-diy mailing list
>> Synth-diy at synth-diy.org
>> http://synth-diy.org/mailman/listinfo/synth-diy
> 
> 
> _______________________________________________
> Synth-diy mailing list
> Synth-diy at synth-diy.org
> http://synth-diy.org/mailman/listinfo/synth-diy



More information about the Synth-diy mailing list