The aliasing thread

Sampler and Sampling discussion (techniques, tips and tricks, etc.)
Post Reply New Topic
RELATED
PRODUCTS

Post

This has been a very interesting thread :D A little question (easy to answer :wink:) what software are you using to display the .wavs in the frequency domain - i.e. to get the images?

Shif.

Post

i believe it's cooledit (?)

Post

Now is named "Adobe Audition".

http://www.adobe.com/products/audition/

Wk

Post

hmm. i wish audacity had a better spectrogram view, though it is definitely improving.

Post

What I consider 'useable realtime' is something that allows me do the same as an average hardware sampler: playing 48~64 voices realtime before the CPU explodes. If I can't play a decent piano realtime, it's not for me. I feel it like what CSound is to a VSTi.
It's not 'realtime' here, but I also don't do anything below 128 points (64 on each side that is). With 128 points (& stereo) it uses 15% of my AMD 1700. That's without any SSE or 3DNow, and without optimizations of the loop points checks.

So this is arguru's sinc with an added groetzthing for the sines. I first tried a huge non-interpolated sine table but it didn't work.


Code: Select all

function StretchWave_Sinc_16IS_32FS(var StretchParams:TStretchParams;DestBuffer:PWAV32FS;Length:Integer):Integer;
const DivAdd:Single=Pi;
var   n,e,l,PtNum,x:Integer;
      LSum,RSum,k_fcpi,SinCB:Single;
      DivV,Sin1,Sin2,Cos1,Cos2:Array[0..1] of Single;
      v,v2:Double;
      p:PWAV16IS;
      SampleP:PWORD;
      b:Boolean;
Label NoBefore,NoAfter;
Begin
with StretchParams do
  Begin
  v:=1/(IntAdd+LongWord(FracAdd)*MaxDWORDToFloat);
  if v>1 then v:=1;
  k_fcpi:=v*Pi;
  SinCB:=2*Cos(k_fcpi);

  e:=LoopStart;
  l:=LoopEnd-e+1;

  for n:=0 to Length-1 do
    Begin
    // process
    p:=Pointer(WAVP+IntPos shl 2);
    LSum:=0;
    RSum:=0;
    b:=LoopCount<=0;

    if FracPos=0 then v:=MaxDWORDToFloat
                 else v:=LongWord(FracPos)*MaxDWORDToFloat;

    // cos
    v2      :=v*SincDiv;
    Cos1 [0]:=Cos(v2+SincDiv);
    Cos2 [0]:=Cos(v2);
    v2      :=v2-SincDiv;
    Cos1 [1]:=Cos(v2-SincDiv);
    Cos2 [1]:=Cos(v2);
    // sin
    v2      :=v*k_fcpi;
    Sin1 [0]:=Sin(v2+k_fcpi);
    Sin2 [0]:=Sin(v2);
    v2      :=v2-k_fcpi;
    Sin1 [1]:=Sin(v2-k_fcpi);
    Sin2 [1]:=Sin(v2);
    // div (none should be zero if written that way)
    DivV [0]:=v*DivAdd;
    DivV [1]:=(v-1)*DivAdd;


    // calc the sum
    for PtNum:=0 to Sinc_nPoints-1 do
      Begin
      // before
      x:=-PtNum;
      if b then
         Begin
         if x+IntPos<0 then GoTo NoBefore;
         End
           else
         while x+IntPos<e do inc(x,l);
      SampleP:=@p^[x,0];

      {
      s:=Sin2[0]*Cos2[0]*Cos2[0]/DivV[0];
      LSum:=LSum+p^[x,0]*s;
      RSum:=RSum+p^[x,1]*s;
      // cos
      s      :=CosCB*Cos1[0]-Cos2[0];
      Cos2[0]:=Cos1[0];
      Cos1[0]:=s;
      // sin
      s      :=SinCB*Sin1[0]-Sin2[0];
      Sin2[0]:=Sin1[0];
      Sin1[0]:=s;
      // div
      DivV[0]:=DivV[0]+DivAdd;
      }
      asm
          // cos
          FLD   DWORD PTR Cos2[0]
          FLD   DWORD PTR Cos1[0]
          FST   DWORD PTR Cos2[0]
          FMUL  DWORD PTR CosCB
          FSUB  ST(0),ST(1)
          FSTP  DWORD PTR Cos1[0]
          FMUL  ST(0),ST(0)  // s (Cos2*Cos2)
          // sin
          FLD   DWORD PTR Sin2[0]
          FLD   DWORD PTR Sin1[0]
          FST   DWORD PTR Sin2[0]
          FMUL  DWORD PTR SinCB
          FSUB  ST(0),ST(1)
          FSTP  DWORD PTR Sin1[0]
          FMULP ST(1),ST(0)  // s (*Sin2)
          // div
          FLD   DWORD PTR DivV[0]
          FDIV  ST(1),ST(0)  // s (/DivV)
          FADD  DivAdd
          FSTP  DWORD PTR DivV[0]
          //FSTP  s

          // LSum
          MOV   EAX,SampleP
          FILD  WORD PTR [EAX]
          FMUL  ST(0),ST(1)
          FADD  LSum
          FSTP  LSum
          // RSum
          FILD  WORD PTR [EAX+2]
          FMUL  ST(0),ST(1)
          FADD  RSum
          FSTP  RSum

          FSTP  ST(0)
        End;

      NoBefore:

      // after
      x:=PtNum+1;
      if x+IntPos>EndPos then
         Begin
         if LoopLength<=0 then GoTo NoAfter
                          else
            Repeat
                dec(x,LoopLength);
             Until x+IntPos<=EndPos;
         End;
      SampleP:=@p^[x,0];

      {
      s:=Sin2[1]*Cos2[1]*Cos2[1]/DivV[1];
      LSum:=LSum+p^[x,0]*s;
      RSum:=RSum+p^[x,1]*s;
      // cos
      s      :=CosCB*Cos1[1]-Cos2[1];
      Cos2[1]:=Cos1[1];
      Cos1[1]:=s;
      // sin
      s      :=SinCB*Sin1[1]-Sin2[1];
      Sin2[1]:=Sin1[1];
      Sin1[1]:=s;
      // div
      DivV[1]:=DivV[1]-DivAdd;
      }
      asm
          // cos
          FLD   DWORD PTR Cos2[4]
          FLD   DWORD PTR Cos1[4]
          FST   DWORD PTR Cos2[4]
          FMUL  DWORD PTR CosCB
          FSUB  ST(0),ST(1)
          FSTP  DWORD PTR Cos1[4]
          FMUL  ST(0),ST(0)  // s (Cos2*Cos2)
          // sin
          FLD   DWORD PTR Sin2[4]
          FLD   DWORD PTR Sin1[4]
          FST   DWORD PTR Sin2[4]
          FMUL  DWORD PTR SinCB
          FSUB  ST(0),ST(1)
          FSTP  DWORD PTR Sin1[4]
          FMULP ST(1),ST(0)  // s (*Sin2)
          // div
          FLD   DWORD PTR DivV[4]
          FDIV  ST(1),ST(0)  // s (/DivV)
          FSUB  DivAdd
          FSTP  DWORD PTR DivV[4]
          //FSTP  s

          // LSum
          MOV   EAX,SampleP
          FILD  WORD PTR [EAX]
          FMUL  ST(0),ST(1)
          FADD  LSum
          FSTP  LSum
          // RSum
          FILD  WORD PTR [EAX+2]
          FMUL  ST(0),ST(1)
          FADD  RSum
          FSTP  RSum

          FSTP  ST(0)
        End;

      NoAfter:
      End;

    // store it
    DestBuffer^[n,0]:=LSum*IntToFloatVar;
    DestBuffer^[n,1]:=RSum*IntToFloatVar;

    // inc the position
    StretchParams_Inc(StretchParams);
    // check the loop points
    while IntPos>EndPos do
      if LoopLength<=0 then
         Begin
         Result:=n+1;
         Exit;
         End
                       else
         Begin
         dec(IntPos,LoopLength);
         inc(LoopCount);
         End;
    End;
  End;

Result:=Length;
End;
Last edited by tony tony chopper on Mon Sep 20, 2004 5:08 am, edited 1 time in total.

Post

Here's another implementation of sinc resampler
is it new? (not that I understand it)

Post

Another funny idea:

One keeps 2 tables of precalculated, pre-windowed sines and cosines for the sinc, at arbitrary frequency. With Goertzl (or a look at Musicdsp) you can just phaseshift these to fit the fractional position.

Dunno how to do the reciprocal part of the sinc though. I guess I need another coffee first... :oops:

Cheers,

;) Urs

Post

I may be insane :shock: (both medically and legally) but I think I have a new (as far as I can tell) way to resample inside a sampler plugin. It's backwards because I oversample, resample and interpolate in one step, then I filter with a windowed sinc FIR filter with cutoff fixed at the nyquist frequency of the non-oversampled data. So, even if a sample's rate is not changed, I will be removing aliasing. I also only need one FIR per plugin, not per voice, as each voice can output oversampled data, the plugin mixes these and then brick wall filters them, then downsamples.

Neat huh? What do you think :?:
I have tried plotting what happens to a naive (aliased) square wave, and it looks great, I just need to implement my soundfont loader and my sampler and I will be able to hear how useful it is. (I like playing with sfz loaded into my host DarkWave Studio, maybe I'll use that for ear comparisons).

Post

dwerner wrote:I oversample, resample and interpolate in one step, then I filter with a windowed sinc FIR filter with cutoff fixed at the nyquist frequency of the non-oversampled data. So, even if a sample's rate is not changed, I will be removing aliasing. I also only need one FIR per plugin, not per voice, as each voice can output oversampled data, the plugin mixes these and then brick wall filters them, then downsamples.
But how do you oversample ? With a FIR too ?

Post

dwerner , is your host available for download ?
never heard of it before.

Post

Fire Sledge - Ohm Force wrote:But how do you oversample ? With a FIR too ?
Basically I resample and oversample at the same time (unless oversampling is disabled in which case I just resample) using linear or 4-point lagrange interpolation, no FIR yet. This will of course introduce aliasing (especially for linear) so I then hope to filter it out with the FIR. Haven't heard it working yet but I think it should be good.

Post

Scr1pt3r wrote:dwerner , is your host available for download ?
never heard of it before.
Hmmm... It's in the alpha stage, it is missing a LOT of features and some features only half work, but what the hell I think I'll put it up for download, go to my site it should be up for download when you read this . :P

Post

dwerner wrote: Basically I resample and oversample at the same time (unless oversampling is disabled in which case I just resample) using linear or 4-point lagrange interpolation, no FIR yet. This will of course introduce aliasing (especially for linear) so I then hope to filter it out with the FIR. Haven't heard it working yet but I think it should be good.
Maybe I wasn't too clear in that post: There is only a FIR filtering at the higher samplerate *after* interpolation, no FIR during the interpolation process.

Post

just curious: anybody tested cm DS404 ? why not?

Post

I oversample, resample and interpolate in one step, then I filter with a windowed sinc FIR filter with cutoff fixed at the nyquist frequency of the non-oversampled data. So, even if a sample's rate is not changed, I will be removing aliasing. I also only need one FIR per plugin, not per voice, as each voice can output oversampled data, the plugin mixes these and then brick wall filters them, then downsamples.
It does work, and that's how it's implemented in several synthesizers (including Pentagon I and z3ta+). The plugins process everything at an 'internal' oversample rate, then a single fir is used at the end of the chain after voice mixing.

The major drawback of the system is that every dsp process after sample playing must be processed at Nx the samplerate, and some of those processes won't get any benefit from the oversampling process.

For instance, the amp envelope control, the filters, etc. have to be processed at Nx the original samplerate. Depending on how many of those processes follow the sample playback, this might cost much more than having a per-voice resampler in terms of CPU usage.

The requirements for the output fir can be minimized by using the Nyquist - 20kHz area as passband area.

-René

Post Reply

Return to “Samplers, Sampling & Sample Libraries”