Single Cycle waves polyphase fir

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

Edit: This only worked for saw and square looks like other shapes like sin would show artifacts from the hard reset.


I have the following code snippet for single cycle wave interpolation and resampling.

if i hard reset the counter I get absolutely no aliasing.

It resamples perfectly 5 octaves up with no mip mapping required

if( counter >= len) {
counter = 0;
}

If i wrap the counter I get tons of artifacts like amplitude modulation and phasiness and need for mip mapping possibly

if( counter >= len) {
counter %= len;
}

Any idea which is correct?


I would prefer:

if( counter >= len) {
counter = 0;
}

as its so much easier


counter is 32.32 fixed point counter.

Code: Select all

        float up(Sample * sample) {
            
            
             
            auto len = static_cast<uint64_t>(sample->getLength()) << 32;
            
            auto buf = sample->getBuffer().getArrayOfReadPointers();
          
            
            
            int ixflt = ((counter) >> 26) & 0x3F;
            
            float t = ((counter) & 0x3FFFFFF) * 0x1p-26;

    
            float *y0 = imp + ixflt*12;
            
            float *y1 = y0 + 12;
            
           
            long long j = counter >> 32;
           
           
            float y = 0;
  
            float x0 = 0;
            float x1 = 0;

            

            
            for(int i=0; i < 12; i++)
            {
                long long idx = j+i-5;
                
                if(idx < 0) {
                    idx+=sample->getLength();
                }

                if(idx >= sample->getLength()) {
                    idx -= sample->getLength();
                }
                
                float se = buf[0][idx];
                float x = se;
                x0 += *y0++*x;
                x1 += *y1++*x;
                
            }
            
            
            y = x0 + (x1-x0)*t;
            
            counter += deltaup;
            
            if( counter >= len) {
                counter = 0;//counter%len;
            }
           
            
            return y;
            
            
        }
        

Post

if i hard reset the counter I get absolutely no aliasing.

It resamples perfectly 5 octaves up with no mip mapping required

if( counter >= len) {
counter = 0;
}

Have you checked the frequency of the osc with the hard reset? I would guess that you get a frequency error when your cycle length doesn't happen to be an integer multiple of the increment. That you don't get aliasing (or at least, no apparent aliasing, i.e. frequency components in between the desired harmonics) can be explained by the fact that each cycle will look exactly the same - so the waveform is perfectly periodic. But if you don't take into account the overshoot (over the cycle end) in a wraparound event, you'll mess with the fundamental frequency of the osc. You buy perfect periodicity (and hence a perfectly harmonic spectrum - although the spectral amplitudes might be slightly off, depending on the waveform) for the price of messing up your fundamental frequency. ...that's my guess, at least. I may be wrong.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

What I think happened is the aliasing just ended up matching harmonics of saw and square from the reset

When I tried a more sinusoidal wave the aliasing was more apparent

Mip mapping would remove the extra unnecessary samples which caused all my weird phasing and amplitude issues and just wrap as usual

But maybe it’s some sort of way to add blep to saw square

I’ll double check frequency error

Edit:

So for just saws an im assuming squares it can go about 2.5 octaves up with a sample of a saw wave cycle at 2048 before the error is too obvious with the hard reset.

Post

I'm not the best at fixed-point arithmetic, but if your into "Wrong" experiments :) try this. quantize the period itself and then derive the phase step from it.

period = round(len / desiredStep);
step = len / period;

Then:

counter += step;
if(counter >= len)
{ counter = 0;
}
www.solostuff.net
The 3rd law of thermo-dynamics states that: the 2nd law has two meanings, one of them is strictly wrong, the other is massively misunderstood.

Post

what is desiredStep frequency, 1.0/frequency, freq/sr ?

once you get hang of fixed point its super fun making your own float types. useful for ADSR as well as resampling, and im sure a bunch of other stuff.

Post

desiredStep should be something like: len * Freq/sr

I think its deltaUp in your code. but again fixed point, can confuse me.

on second thought. actually, i think you can just use period = round(sr/freq);
www.solostuff.net
The 3rd law of thermo-dynamics states that: the 2nd law has two meanings, one of them is strictly wrong, the other is massively misunderstood.

Post

Also, probably the better version is:

counter += step;
if(counter >= len)
{ counter -= len;
}
www.solostuff.net
The 3rd law of thermo-dynamics states that: the 2nd law has two meanings, one of them is strictly wrong, the other is massively misunderstood.

Post

I’ll give it a try right now deltaup is just resampling ratio * 2^31

Ratio of 1 becomes 1.0f step through 2048 samples

Post Reply

Return to “DSP and Plugin Development”