Alias Free Oscs, band limiting, and downsampling

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

duncanparsons wrote:
MadBrain wrote:By the way, for "anti-aliased" FM there's an easier and faster way - if you do the FM synthesis at a sample rate that's a multiple of the note freq, the reflected frequencies should line up with the frequencies already present, so you won't get the "metallic" sound of alias. :) After that you just resample the output to the target sample rate (ie 44.1khz) using your favourite algo.
Nice idea, that.. might try it :)
Sounds like putting the horse *in* the cart and pulling it yourself to me. What if the carrier and modulator frequencies aren't related by small integers?
Image
Don't do it my way.

Post

..notice I only said 'might' :hihi:

Good point. I do have a few ideas on some synthesis to try. FM was on the list, and I was considering different approaches to it. This one will probably get struck of the list. I can be a bit of an idea tart at times, I guess!

DSP
Image

Post

duncanparsons wrote:I can be a bit of an idea tart at times, I guess!
Right there with you. :)
Image
Don't do it my way.

Post

How about the cpu-usage? i mean, when i use one wavetable per octave, i would have to do a branching in my audio loop like this (i assume to render one sample at a time):

Code: Select all

Osc::getSample()
{
 if(freq<55)
  //use table1
 else if(freq<110) 
  //use table2
 else if(freq<220)
  //use table3
 else if(freq<440)
  //use table4

 //and so on
}
wouldn't this if-branch be less efficient, than to render always -say- 4 samples and then lowpass-filtering and decimating them to one sample? especially for higher notes, where the function jumps out of the branch very late? i know, that one could choose the table not for each single sample for one block of samples. but in this case, no pitch modulation would be possible (i like synthesizers having pitch-envelopes - my Aggressor-synth for instance provides a pitch ramp for each of it's 3 oscillators - so i need to update the osc's freq each sample). also FM requires the freq to be updated sample by sample...
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

BrainDoc...

When you're using one table per octave... use an array of pointers to the wavetables. Use the exponent of a frequency value to determine the table.

;) Urs

Post

braindoc wrote:i know, that one could choose the table not for each single sample for one block of samples. but in this case, no pitch modulation would be possible (i like synthesizers having pitch-envelopes - my Aggressor-synth for instance provides a pitch ramp for each of it's 3 oscillators - so i need to update the osc's freq each sample).
Assuming you blend between wavetables as the pitch changes instead of doing a hard cut between them, you can select some compromise blocksize (32 or 64 samples) to select the table -- as long as your pitch modulation doesn't get very deep and very fast, you'll rarely have any audible aliasing. If the modulation is too fast for that to work, then you actually have FM, which leads me to...
also FM requires the freq to be updated sample by sample...
Strictly speaking, the spectrum generated by FM or PM always has unlimited harmonics of nonzero amplitude, so aliasing is guaranteed regardless of what wavetable you select. Yay!

The only way I can think of to avoid it is to synthesize one cycle of the modulated FM signal (either with brute force in the time domain or using Urs's IFFT strategy from the predicted spectrum) and use that as the wavetable; this doesn't allow you to have inharmonic partials. (It's also essentially equivalent to MadBrain's suggestion, now that I think about it.) So in fact if you want completely alias free FM, you may as well go straight to additive synthesis.

If instead you decide you can accept some aliasing in your FM, then pick a wavetable that is an acceptable compromise between aggressive brightness (more partials, more aliasing) and mellow dullness (fewer partials, less aliasing).
Image
Don't do it my way.

Post

Borogove wrote:
duncanparsons wrote:I can be a bit of an idea tart at times, I guess!
Right there with you. :)
..A true believer!!

DSP
Image

Post

Urs wrote:BrainDoc...

When you're using one table per octave... use an array of pointers to the wavetables. Use the exponent of a frequency value to determine the table.

;) Urs
the "exponent of a frequency value" value confused me a little bit at first and i was thinking like: 55^x - huh? ...110^y - häh? but after sleeping a night over it, i think understand now what you mean. i could do something like:

tableIndex = log2(increment)

where increment is the current increment in my lookup-table and tableIndex is the index of the table which should be used - as the result of the log2 is a noninteger, i could use floor(tableIndex) to determine the actual table or use the fractional part for a crossfade between two tables. when the increment is 1, i use table[0], when it is 2 - table[1], when it is 4 - table[2]... and so on, where each of the successive tables contains only half of the spectrum of the previous one. was that your idea? however, i will implement and test this procedure right now. if it works fine (which is, what i expect), i'll use it for my aggressor-synth.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

braindoc wrote: the "exponent of a frequency value" value confused me a little bit at first and i was thinking like: 55^x - huh? ...110^y - häh? but after sleeping a night over it, i think understand now what you mean. i could do something like:

tableIndex = log2(increment)

where increment is the current increment in my lookup-table and tableIndex is the index of the table which should be used - as the result of the log2 is a noninteger, i could use floor(tableIndex) to determine the actual table or use the fractional part for a crossfade between two tables. when the increment is 1, i use table[0], when it is 2 - table[1], when it is 4 - table[2]... and so on, where each of the successive tables contains only half of the spectrum of the previous one. was that your idea? however, i will implement and test this procedure right now. if it works fine (which is, what i expect), i'll use it for my aggressor-synth.
I think he meant that:

index = log2(frequency).

since a float is an exponent and a mantissa, you can extract the exponent directly as an integer and use it as a table index (with appropriate masking to prevent
out of bounds access etc). This gets rid of the log2, since you aren't interested in the significand. when calculating the table index:

Code: Select all

const int EXPONENT_BIAS   = 127;
const int EXPONENT_MASK   = 0x7C00000;
const int EXPONENT_OFFSET = 23;

const unsigned long ifrq = *(reinterpret_cast<unsigned long const* const>(&frequency));

index = ((ifrq & EXPONENT_MASK) >> EXPONENT_OFFSET) - EXPONENT_BIAS;
i think..

Post

texture wrote:
...
This gets rid of the log2, since you aren't interested in the significand. when calculating the table index:

Code: Select all

const int EXPONENT_BIAS   = 127;
const int EXPONENT_MASK   = 0x7C00000;
const int EXPONENT_OFFSET = 23;

const unsigned long ifrq = *(reinterpret_cast<unsigned long const* const>(&frequency));

index = ((ifrq & EXPONENT_MASK) >> EXPONENT_OFFSET) - EXPONENT_BIAS;
i think..
aha. makes sense, although it always seems quite complicated to me to deal with these low-level things. i'll try it with log2, and if i got that to work, i'll think about optimizing it with your suggestion.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Actually, my calc was slightly wrong, it shudl be:

Code: Select all

index = ((ifrq >> 23) & 0xFF) - 127

Post

i just wrote a little function, which can extract the exponent from a float-value - i think, it can be made more efficient, but for clarity of the code, i post it, as it is:

Code: Select all

unsigned long getExponentFromFloat(float valueFlt)
{
 static unsigned long bitMask = 0x7FFFFFFF;  //unsigned 32 bit integer 
                                             //leftmost bit is 0, all others are 1

 static unsigned long exponent = 0;  //this is the variable which should finally hold
                                     //the exponent

 static unsigned long *ptrInt; //pointer to a 32-bit integer
 static void          *ptr;    //pointer to to anything

 ptr      = &valueFlt;               //determine the adress of the float-variable
 ptrInt   = (unsigned long*) ptr;    //store this adress in the int-pointer

 exponent = *ptrInt;                 //get the value and interpret is as int

 //mask out the sign-bit via bitwise and:
 exponent = exponent & bitMask;

 //rightshift by 23 to shift the mantissa away:
 exponent =  exponent >> 23;

 //subtract the bias:
 exponent -= 127;

 return exponent;
}
...maybe someone will find it useful. i will now go on and write a similar thing for doubles (which is, what i need). ....i hate this low-level stuff!...

EDIT: it looks a little bit ugly-formatted here, because of the wraparounds of the comments
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

which can be reduced to:

Code: Select all

typedef unsigned int uint32;

inline uint32 getExponentFromFloat(float f) 
{
    return (((*(reinterpret_cast<uint32 const* const>(&f)) >> 23) & 0xFF) - 127;
}
By the way, the statics in your version could be made const, which means that the compiler will optinmize them away.

Post

yes. i just wanted to post something, where it can easily be seen, what actually happens. but for my synth, i think, i will aslo use such a reduced version.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Urs wrote:
Hard Sync doesn't need oversampling to keep aliasing inaudible, even when using wavetables. I posted the algorithm I use for hard sync (Zebra, FilterscapeVA) on musicdsp mailing list, roughly a year ago. In the end, clever tuning can do the trick ;-)
do you refer to this paper here?:

http://www.cs.cmu.edu/~eli/papers/icmc01-hardsync.pdf

if not, could you post a link here to the algorithm?

BTW: i have my osc's almost alias-free now with a one table per octave switch, where the table number is deteremined by the exponent of the phase-increment - the additional CPU-load is very low. i'm VERY happy with that! thanks for the hint! maybe it's now time to get the sync alias-free, too
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post Reply

Return to “DSP and Plugin Development”