Main Archive Specials IRC Wiki | FAQ Links Submit Forum
Search

Analysis

Effects

Filters

Other

Synthesis

All

Entries in this category

Beat Detector Class
Coefficients for Daubechies wavelets 1-38
DFT
Envelope detector
Envelope Detector class (C++)
Envelope follower with different attack and release
Fast in-place Walsh-Hadamard Transform
FFT
FFT classes in C++ and Object Pascal
Frequency response from biquad coefficients
Java FFT
Look ahead limiting
LPC analysis (autocorrelation + Levinson-Durbin recursion)
Magnitude and phase plot of arbitrary IIR function, up to 5th order
Measuring interpollation noise
QFT and DQFT (double precision) classes
Simple peak follower
tone detection with Goertzel
Tone detection with Goertzel (x86 ASM)
Vintage VU meters tutorial

Beat Detector Class

References : Posted by DSPMaster[at]free[dot]fr

Notes :
This class was designed for a VST plugin. Basically, it's just a 2nd order LP filter, followed by an enveloppe detector (thanks Bram), feeding a Schmitt trigger. The rising edge detector provides a 1-sample pulse each time a beat is detected. Code is self documented...
Note : The class uses a fixed comparison level, you may need to change it.


Code :
// ***** BEATDETECTOR.H *****
#ifndef BeatDetectorH
#define BeatDetectorH

class TBeatDetector
{
private:
  float KBeatFilter;        // Filter coefficient
  float Filter1Out, Filter2Out;
  float BeatRelease;        // Release time coefficient
  float PeakEnv;            // Peak enveloppe follower
  bool BeatTrigger;         // Schmitt trigger output
  bool PrevBeatPulse;       // Rising edge memory
public:
  bool BeatPulse;           // Beat detector output

  TBeatDetector();
  ~TBeatDetector();
  virtual void setSampleRate(float SampleRate);
  virtual void AudioProcess (float input);
};
#endif


// ***** BEATDETECTOR.CPP *****
#include "BeatDetector.h"
#include "math.h"

#define FREQ_LP_BEAT 150.0f    // Low Pass filter frequency
#define T_FILTER 1.0f/(2.0f*M_PI*FREQ_LP_BEAT)  // Low Pass filter time constant
#define BEAT_RTIME 0.02f  // Release time of enveloppe detector in second

TBeatDetector::TBeatDetector()
// Beat detector constructor
{
  Filter1Out=0.0;
  Filter2Out=0.0;
  PeakEnv=0.0;
  BeatTrigger=false;
  PrevBeatPulse=false;
  setSampleRate(44100);
}

TBeatDetector::~TBeatDetector()
{
  // Nothing specific to do...
}

void TBeatDetector::setSampleRate (float sampleRate)
// Compute all sample frequency related coeffs
{
  KBeatFilter=1.0/(sampleRate*T_FILTER);
  BeatRelease=(float)exp(-1.0f/(sampleRate*BEAT_RTIME));
}

void TBeatDetector::AudioProcess (float input)
// Process incoming signal
{
  float EnvIn;

  // Step 1 : 2nd order low pass filter (made of two 1st order RC filter)
  Filter1Out=Filter1Out+(KBeatFilter*(input-Filter1Out));
  Filter2Out=Filter2Out+(KBeatFilter*(Filter1Out-Filter2Out));

  // Step 2 : peak detector
  EnvIn=fabs(Filter2Out);
  if (EnvIn>PeakEnv) PeakEnv=EnvIn;  // Attack time = 0
  else
  {
    PeakEnv*=BeatRelease;
    PeakEnv+=(1.0f-BeatRelease)*EnvIn;
  }

  // Step 3 : Schmitt trigger
  if (!BeatTrigger)
  {
    if (PeakEnv>0.3) BeatTrigger=true;
  }
  else
  {
    if (PeakEnv<0.15) BeatTrigger=false;
  }

  // Step 4 : rising edge detector
  BeatPulse=false;
  if ((BeatTrigger)&&(!PrevBeatPulse))
    BeatPulse=true;
  PrevBeatPulse=BeatTrigger;
}


11 comment(s) | add a comment | nofrills version


Coefficients for Daubechies wavelets 1-38

Type : wavelet transform
References : Computed by Kazuo Hatano, Compiled and verified by Olli Niemitalo
Linked file : daub.h


no comments on this item | add a comment | nofrills version


DFT

Type : fourier transform
References : Posted by Andy Mucho
Code :
AnalyseWaveform(float *waveform, int framesize)
{
   float aa[MaxPartials];
   float bb[MaxPartials];
   for(int i=0;i<partials;i++)
   {
     aa[i]=0;
     bb[i]=0;
   }

   int hfs=framesize/2;
   float pd=pi/hfs;
   for (i=0;i<framesize;i++)
   {
     float w=waveform[i];
     int im = i-hfs;
     for(int h=0;h<partials;h++)
     {
        float th=(pd*(h+1))*im;
        aa[h]+=w*cos(th);
        bb[h]+=w*sin(th);
     }
   }
   for (int h=0;h<partials;h++)
       amp[h]= sqrt(aa[h]*aa[h]+bb[h]*bb[h])/hfs;
}


2 comment(s) | add a comment | nofrills version


Envelope detector

References : Posted by Bram

Notes :
Basicaly a one-pole LP filter with different coefficients for attack and release fed by the abs() of the signal. If you don't need different attack and decay settings, just use in->abs()->LP

Code :
//attack and release in milliseconds
float ga = (float) exp(-1/(SampleRate*attack));
float gr = (float) exp(-1/(SampleRate*release));

float envelope=0;

for(...)
{
  //get your data into 'input'
  EnvIn = abs(input);

  if(envelope < EnvIn)
  {
     envelope *= ga;
     envelope += (1-ga)*EnvIn;
  }
  else
  {
     envelope *= gr;
     envelope += (1-gr)*EnvIn;
  }
  //envelope now contains.........the envelope ;)
}


5 comment(s) | add a comment | nofrills version


Envelope Detector class (C++)

Type : envelope detector
References : Posted by Citizen Chunk
Linked file : http://www.chunkware.com/opensource/EnvelopeDetector.zip

Notes :
This is a C++ implementation of a simple envelope detector. The time constant (ms) represents the time it takes for the envelope to charge/discharge 63% (RC time constant).

(see linked files)




6 comment(s) | add a comment | nofrills version


Envelope follower with different attack and release

References : Posted by Bram

Notes :
xxxx_in_ms is xxxx in milliseconds ;-)

Code :
init::

attack_coef = exp(log(0.01)/( attack_in_ms * samplerate * 0.001));
release_coef = exp(log(0.01)/( release_in_ms * samplerate * 0.001));
envelope = 0.0;

loop::

tmp = fabs(in);
if(tmp > envelope)
    envelope = attack_coef * (envelope - tmp) + tmp;
else
    envelope = release_coef * (envelope - tmp) + tmp;


5 comment(s) | add a comment | nofrills version


Fast in-place Walsh-Hadamard Transform

Type : wavelet transform
References : Posted by Timo H Tossavainen

Notes :
IIRC, They're also called walsh-hadamard transforms.
Basically like Fourier, but the basis functions are squarewaves with different sequencies.
I did this for a transform data compression study a while back.
Here's some code to do a walsh hadamard transform on long ints in-place (you need to divide by n to get transform) the order is bit-reversed at output, IIRC.
The inverse transform is the same as the forward transform (expects bit-reversed input). i.e. x = 1/n * FWHT(FWHT(x)) (x is a vector)


Code :
void inline wht_bfly (long& a, long& b)
{
        long tmp = a;
        a += b;
        b = tmp - b;
}

// just a integer log2
int inline l2 (long x)
{
        int l2;
        for (l2 = 0; x > 0; x >>=1)
        {
                ++ l2;
        }

        return (l2);
}

////////////////////////////////////////////
// Fast in-place Walsh-Hadamard Transform //
////////////////////////////////////////////

void FWHT (std::vector& data)
{
  const int log2 = l2 (data.size()) - 1;
  for (int i = 0; i < log2; ++i)
  {
    for (int j = 0; j < (1 << log2); j += 1 << (i+1))
    {
       for (int k = 0; k < (1<<i); ++k)
       {
           wht_bfly (data [j + k], data [j + k + (1<<i)]);
       }
    }
  }
}


17 comment(s) | add a comment | nofrills version


FFT

References : Toth Laszlo
Linked file : rvfft.ps
Linked file : rvfft.cpp

Notes :
A paper (postscript) and some C++ source for 4 different fft algorithms, compiled by Toth Laszlo from the Hungarian Academy of Sciences Research Group on Artificial Intelligence.
Toth says: "I've found that Sorensen's split-radix algorithm was the fastest, so I use this since then (this means that you may as well delete the other routines in my source - if you believe my results)."




1 comment(s) | add a comment | nofrills version


FFT classes in C++ and Object Pascal

Type : Real-to-Complex FFT and Complex-to-Real IFFT
References : Laurent de Soras (Object Pascal translation by Frederic Vanmol)
Linked file : FFTReal.zip

Notes :
(see linkfile)



2 comment(s) | add a comment | nofrills version


Frequency response from biquad coefficients

Type : biquad
References : Posted by peter[AT]sonicreef[DOT]com

Notes :
Here is a formula for plotting the frequency response of a biquad filter. Depending on the coefficients that you have, you might have to use negative values for the b- coefficients.



Code :
//w = frequency (0 < w < PI)
//square(x) = x*x

y = 20*log((sqrt(square(a0*square(cos(w))-a0*square(sin(w))+a1*cos(w)+a2)+square(2*a0*cos(w)*sin(w)+a1*(sin(w))))/
                  sqrt(square(square(cos(w))-   square(sin(w))+b1*cos(w)+b2)+square(2*   cos(w)*sin(w)+b1*(sin(w))))));


2 comment(s) | add a comment | nofrills version


Java FFT

Type : FFT Analysis
References : Posted by Loreno Heer

Notes :
May not work correctly ;-)

Code :
// WTest.java
/*
    Copyright (C) 2003 Loreno Heer, (helohe at bluewin dot ch)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/
public class WTest{

    private static double[] sin(double step, int size){
        double f = 0;
        double[] ret = new double[size];
        for(int i = 0; i < size; i++){
            ret[i] = Math.sin(f);
            f += step;
        }
        return ret;
    }

    private static double[] add(double[] a, double[] b){
        double[] c = new double[a.length];
        for(int i = 0; i < a.length; i++){
            c[i] = a[i] + b[i];
        }
        return c;
    }

    private static double[] sub(double[] a, double[] b){
        double[] c = new double[a.length];
        for(int i = 0; i < a.length; i++){
            c[i] = a[i] - b[i];
        }
        return c;
    }

    private static double[] add(double[] a, double b){
        double[] c = new double[a.length];
        for(int i = 0; i < a.length; i++){
            c[i] = a[i] + b;
        }
        return c;
    }

    private static double[] cp(double[] a, int size){
        double[] c = new double[size];
        for(int i = 0; i < size; i++){
            c[i] = a[i];
        }
        return c;
    }

    private static double[] mul(double[] a, double b){
        double[] c = new double[a.length];
        for(int i = 0; i < a.length; i++){
            c[i] = a[i] * b;
        }
        return c;
    }

    private static void print(double[] value){
        for(int i = 0; i < value.length; i++){
            System.out.print(i + "," + value[i] + "\n");
        }
        System.out.println();
    }

    private static double abs(double[] a){
        double c = 0;
        for(int i = 0; i < a.length; i++){
            c = ((c * i) + Math.abs(a[i])) / (i + 1);
        }
        return c;
    }

    private static double[] fft(double[] a, int min, int max, int step){
        double[] ret = new double[(max - min) / step];
        int i = 0;
        for(int d = min; d < max; d = d + step){
            double[] f = sin(fc(d), a.length);
            double[] dif = sub(a, f);
            ret[i] = 1 - abs(dif);
            i++;
        }
        return ret;
    }

    private static double[] fft_log(double[] a){
        double[] ret = new double[1551];
        int i = 0;
        for(double d = 0; d < 15.5; d = d + 0.01){
            double[] f = sin(fc(Math.pow(2,d)), a.length);
            double[] dif = sub(a, f);
            ret[i] = Math.abs(1 - abs(dif));
            i++;
        }
        return ret;
    }

    private static double fc(double d){
        return d * Math.PI / res;
    }

    private static void print_log(double[] value){
        for(int i = 0; i < value.length; i++){
            System.out.print(Math.pow(2,((double)i/100d)) + "," + value[i] + "\n");
        }
        System.out.println();
    }

    public static void main(String[] args){
        double[] f_0 = sin(fc(440), sample_length); // res / pi =>14005
        //double[] f_1 = sin(.02, sample_length);
        double[] f_2 = sin(fc(520), sample_length);
        //double[] f_3 = sin(.25, sample_length);

        //double[] f = add( add( add(f_0, f_1), f_2), f_3);

        double[] f = add(f_0, f_2);

        //print(f);

        double[] d = cp(f,1000);
        print_log(fft_log(d));
    }

    static double length = .2; // sec
    static int res = 44000; // resoultion (pro sec)
    static int sample_length = res; // resoultion

}


2 comment(s) | add a comment | nofrills version


Look ahead limiting

References : Posted by Wilfried Welti

Notes :
use add_value with all values which enter the look-ahead area,
and remove_value with all value which leave this area. to get
the maximum value in the look-ahead area, use get_max_value.
in the very beginning initialize the table with zeroes.

If you always want to know the maximum amplitude in
your look-ahead area, the thing becomes a sorting
problem. very primitive approach using a look-up table


Code :
void lookup_add(unsigned section, unsigned size, unsigned value)
{
  if (section==value)
    lookup[section]++;
  else
  {
    size >>= 1;
    if (value>section)
    {
      lookup[section]++;
      lookup_add(section+size,size,value);
    }
    else
      lookup_add(section-size,size,value);
  }
}

void lookup_remove(unsigned section, unsigned size, unsigned value)
{
  if (section==value)
    lookup[section]--;
  else
  {
    size >>= 1;
    if (value>section)
    {
      lookup[section]--;
      lookup_remove(section+size,size,value);
    }
    else
      lookup_remove(section-size,size,value);
  }
}

unsigned lookup_getmax(unsigned section, unsigned size)
{
  unsigned max = lookup[section] ? section : 0;
  size >>= 1;
  if (size)
    if (max)
    {
      max = lookup_getmax((section+size),size);
      if (!max) max=section;
    }
    else
      max = lookup_getmax((section-size),size);
  return max;
}

void add_value(unsigned value)
{
  lookup_add(LOOKUP_VALUES>>1, LOOKUP_VALUES>>1, value);
}

void remove_value(unsigned value)
{
  lookup_remove(LOOKUP_VALUES>>1, LOOKUP_VALUES>>1, value);
}

unsigned get_max_value()
{
  return lookup_getmax(LOOKUP_VALUES>>1, LOOKUP_VALUES>>1);
}


no comments on this item | add a comment | nofrills version


LPC analysis (autocorrelation + Levinson-Durbin recursion)

References : Posted by mail[AT]mutagene[DOT]net

Notes :
The autocorrelation function implements a warped autocorrelation, so that frequency resolution can be specified by the variable 'lambda'. Levinson-Durbin recursion calculates autoregression coefficients a and reflection coefficients (for lattice filter implementation) K. Comments for Levinson-Durbin function implement matlab version of the same function.

No optimizations.


Code :
//find the order-P autocorrelation array, R, for the sequence x of length L and warping of lambda
//wAutocorrelate(&pfSrc[stIndex],siglen,R,P,0);
wAutocorrelate(float * x, unsigned int L, float * R, unsigned int P, float lambda)
{
    double    * dl = new double [L];
    double    * Rt = new double [L];
    double r1,r2,r1t;
    R[0]=0;
    Rt[0]=0;
    r1=0;
    r2=0;
    r1t=0;
    for(unsigned int k=0; k<L;k++)
    {
            Rt[0]+=double(x[k])*double(x[k]);

            dl[k]=r1-double(lambda)*double(x[k]-r2);
            r1 = x[k];
            r2 = dl[k];
    }
    for(unsigned int i=1; i<=P; i++)
    {
        Rt[i]=0;
        r1=0;
        r2=0;
        for(unsigned int k=0; k<L;k++)
        {
            Rt[i]+=double(dl[k])*double(x[k]);
            
            r1t = dl[k];
            dl[k]=r1-double(lambda)*double(r1t-r2);
            r1 = r1t;
            r2 = dl[k];
        }
    }
    for(i=0; i<=P; i++)
        R[i]=float(Rt[i]);
    delete[] dl;
    delete[] Rt;
}

// Calculate the Levinson-Durbin recursion for the autocorrelation sequence R of length P+1 and return the autocorrelation coefficients a and reflection coefficients K
LevinsonRecursion(unsigned int P, float *R, float *A, float *K)
{
    double Am1[62];

    if(R[0]==0.0) {
        for(unsigned int i=1; i<=P; i++)
        {
            K[i]=0.0;
            A[i]=0.0;
        }}
    else {
        double km,Em1,Em;
        unsigned int k,s,m;
        for (k=0;k<=P;k++){
            A[0]=0;
            Am1[0]=0; }
        A[0]=1;
        Am1[0]=1;
        km=0;
        Em1=R[0];
        for (m=1;m<=P;m++)                    //m=2:N+1
        {
            double err=0.0f;                    //err = 0;
            for (k=1;k<=m-1;k++)            //for k=2:m-1
                err += Am1[k]*R[m-k];        // err = err + am1(k)*R(m-k+1);
            km = (R[m]-err)/Em1;            //km=(R(m)-err)/Em1;
            K[m-1] = -float(km);
            A[m]=(float)km;                        //am(m)=km;
            for (k=1;k<=m-1;k++)            //for k=2:m-1
                A[k]=float(Am1[k]-km*Am1[m-k]);  // am(k)=am1(k)-km*am1(m-k+1);
            Em=(1-km*km)*Em1;                //Em=(1-km*km)*Em1;
            for(s=0;s<=P;s++)                //for s=1:N+1
                Am1[s] = A[s];                // am1(s) = am(s)
            Em1 = Em;                        //Em1 = Em;
        }
    }
    return 0;
}


3 comment(s) | add a comment | nofrills version


Magnitude and phase plot of arbitrary IIR function, up to 5th order

Type : magnitude and phase at any frequency
References : Posted by George Yohng

Notes :
Amplitude and phase calculation of IIR equation
run at sample rate "sampleRate" at frequency "F".

AMPLITUDE
-----------
cf_mag(F,sampleRate,
a0,a1,a2,a3,a4,a5,
b0,b1,b2,b3,b4,b5)
-----------

PHASE
-----------
cf_phi(F,sampleRate,
a0,a1,a2,a3,a4,a5,
b0,b1,b2,b3,b4,b5)
-----------

If you need a frequency diagram, draw a plot for
F=0...sampleRate/2

If you need amplitude in dB, use cf_lin2db(cf_mag(.......))

Set b0=-1 if you have such function:

y[n] = a0*x[n] + a1*x[n-1] + a2*x[n-2] + a3*x[n-3] + a4*x[n-4] + a5*x[n-5] +
+ b1*y[n-1] + b2*y[n-2] + b3*y[n-3] + b4*y[n-4] + b5*y[n-5];

Set b0=1 if you have such function:

y[n] = a0*x[n] + a1*x[n-1] + a2*x[n-2] + a3*x[n-3] + a4*x[n-4] + a5*x[n-5] +
- b1*y[n-1] - b2*y[n-2] - b3*y[n-3] - b4*y[n-4] - b5*y[n-5];

Do not try to reverse engineer these formulae - they don't give any sense
other than they are derived from transfer function, and they work. :)


Code :
/*
C file can be downloaded from
http://www.yohng.com/dsp/cfsmp.c
*/


#define C_PI 3.14159265358979323846264

double cf_mag(double f,double rate,
              double a0,double a1,double a2,double a3,double a4,double a5,
              double b0,double b1,double b2,double b3,double b4,double b5)
{
    return
        sqrt((a0*a0 + a1*a1 + a2*a2 + a3*a3 + a4*a4 + a5*a5 +
              2*(a0*a1 + a1*a2 + a2*a3 + a3*a4 + a4*a5)*cos((2*f*C_PI)/rate) +
              2*(a0*a2 + a1*a3 + a2*a4 + a3*a5)*cos((4*f*C_PI)/rate) +
              2*a0*a3*cos((6*f*C_PI)/rate) + 2*a1*a4*cos((6*f*C_PI)/rate) +
              2*a2*a5*cos((6*f*C_PI)/rate) + 2*a0*a4*cos((8*f*C_PI)/rate) +
              2*a1*a5*cos((8*f*C_PI)/rate) + 2*a0*a5*cos((10*f*C_PI)/rate))/
              (b0*b0 + b1*b1 + b2*b2 + b3*b3 + b4*b4 + b5*b5 +
              2*(b0*b1 + b1*b2 + b2*b3 + b3*b4 + b4*b5)*cos((2*f*C_PI)/rate) +
              2*(b0*b2 + b1*b3 + b2*b4 + b3*b5)*cos((4*f*C_PI)/rate) +
              2*b0*b3*cos((6*f*C_PI)/rate) + 2*b1*b4*cos((6*f*C_PI)/rate) +
              2*b2*b5*cos((6*f*C_PI)/rate) + 2*b0*b4*cos((8*f*C_PI)/rate) +
              2*b1*b5*cos((8*f*C_PI)/rate) + 2*b0*b5*cos((10*f*C_PI)/rate)));
}


double cf_phi(double f,double rate,
              double a0,double a1,double a2,double a3,double a4,double a5,
              double b0,double b1,double b2,double b3,double b4,double b5)
{
        atan2((a0*b0 + a1*b1 + a2*b2 + a3*b3 + a4*b4 + a5*b5 +
              (a0*b1 + a1*(b0 + b2) + a2*(b1 + b3) + a5*b4 + a3*(b2 + b4) +
              a4*(b3 + b5))*cos((2*f*C_PI)/rate) +
              ((a0 + a4)*b2 + (a1 + a5)*b3 + a2*(b0 + b4) +
              a3*(b1 + b5))*cos((4*f*C_PI)/rate) + a3*b0*cos((6*f*C_PI)/rate) +
              a4*b1*cos((6*f*C_PI)/rate) + a5*b2*cos((6*f*C_PI)/rate) +
              a0*b3*cos((6*f*C_PI)/rate) + a1*b4*cos((6*f*C_PI)/rate) +
              a2*b5*cos((6*f*C_PI)/rate) + a4*b0*cos((8*f*C_PI)/rate) +
              a5*b1*cos((8*f*C_PI)/rate) + a0*b4*cos((8*f*C_PI)/rate) +
              a1*b5*cos((8*f*C_PI)/rate) +
              (a5*b0 + a0*b5)*cos((10*f*C_PI)/rate))/
              (b0*b0 + b1*b1 + b2*b2 + b3*b3 + b4*b4 + b5*b5 +
              2*((b0*b1 + b1*b2 + b3*(b2 + b4) + b4*b5)*cos((2*f*C_PI)/rate) +
              (b2*(b0 + b4) + b3*(b1 + b5))*cos((4*f*C_PI)/rate) +
              (b0*b3 + b1*b4 + b2*b5)*cos((6*f*C_PI)/rate) +
              (b0*b4 + b1*b5)*cos((8*f*C_PI)/rate) +
              b0*b5*cos((10*f*C_PI)/rate))),

             ((a1*b0 + a3*b0 + a5*b0 - a0*b1 + a2*b1 + a4*b1 - a1*b2 +
              a3*b2 + a5*b2 - a0*b3 - a2*b3 + a4*b3 -
              a1*b4 - a3*b4 + a5*b4 - a0*b5 - a2*b5 - a4*b5 +
              2*(a3*b1 + a5*b1 - a0*b2 + a4*(b0 + b2) - a1*b3 + a5*b3 +
              a2*(b0 - b4) - a0*b4 - a1*b5 - a3*b5)*cos((2*f*C_PI)/rate) +
              2*(a3*b0 + a4*b1 + a5*(b0 + b2) - a0*b3 - a1*b4 - a0*b5 - a2*b5)*
              cos((4*f*C_PI)/rate) + 2*a4*b0*cos((6*f*C_PI)/rate) +
              2*a5*b1*cos((6*f*C_PI)/rate) - 2*a0*b4*cos((6*f*C_PI)/rate) -
              2*a1*b5*cos((6*f*C_PI)/rate) + 2*a5*b0*cos((8*f*C_PI)/rate) -
              2*a0*b5*cos((8*f*C_PI)/rate))*sin((2*f*C_PI)/rate))/
              (b0*b0 + b1*b1 + b2*b2 + b3*b3 + b4*b4 + b5*b5 +
              2*(b0*b1 + b1*b2 + b2*b3 + b3*b4 + b4*b5)*cos((2*f*C_PI)/rate) +
              2*(b0*b2 + b1*b3 + b2*b4 + b3*b5)*cos((4*f*C_PI)/rate) +
              2*b0*b3*cos((6*f*C_PI)/rate) + 2*b1*b4*cos((6*f*C_PI)/rate) +
              2*b2*b5*cos((6*f*C_PI)/rate) + 2*b0*b4*cos((8*f*C_PI)/rate) +
              2*b1*b5*cos((8*f*C_PI)/rate) + 2*b0*b5*cos((10*f*C_PI)/rate)));
}

double cf_lin2db(double lin)
{
    if (lin<9e-51) return -1000; /* prevent invalid operation */
    return 20*log10(lin);
}



9 comment(s) | add a comment | nofrills version


Measuring interpollation noise

References : Posted by Jon Watte

Notes :
You can easily estimate the error by evaluating the actual function and
evaluating your interpolator at each of the mid-points between your
samples. The absolute difference between these values, over the absolute
value of the "correct" value, is your relative error. log10 of your relative
error times 20 is an estimate of your quantization noise in dB. Example:

You have a table for every 0.5 "index units". The value at index unit 72.0
is 0.995 and the value at index unit 72.5 is 0.999. The interpolated value
at index 72.25 is 0.997. Suppose the actual function value at that point was
0.998; you would have an error of 0.001 which is a relative error of 0.001002004..
log10(error) is about -2.99913, which times 20 is about -59.98. Thus, that's
your quantization noise at that position in the table. Repeat for each pair of
samples in the table.

Note: I said "quantization noise" not "aliasing noise". The aliasing noise will,
as far as I know, only happen when you start up-sampling without band-limiting
and get frequency aliasing (wrap-around), and thus is mostly independent of
what specific interpolation mechanism you're using.




no comments on this item | add a comment | nofrills version


QFT and DQFT (double precision) classes

References : Posted by Joshua Scholar
Linked file : qft.tar_1.gz

Notes :
Since it's a Visual C++ project (though it has relatively portable C++) I
guess the main audience are PC users. As such I'm including a zip file.
Some PC users wouldn't know what to do with a tgz file.

The QFT and DQFT (double precision) classes supply the following functions:

1. Real valued FFT and inverse FFT functions. Note that separate arraysare used
for real and imaginary component of the resulting spectrum.

2. Decomposition of a spectrum into a separate spectrum of the evensamples
and a spectrum of the odd samples. This can be useful for buildingfilter banks.

3. Reconstituting a spectrum from separate spectrums of the even samples
and odd samples. This can be useful for building filter banks.

4. A discrete Sin transform (a QFT decomposes an FFT into a DST and DCT).

5. A discrete Cos transfrom.

6. Since a QFT does it's last stage calculating from the outside in thelast part
can be left unpacked and only calculated as needed in the case wherethe entire
spectrum isn't needed (I used this for calculating correlations andconvolutions
where I only needed half of the results).
ReverseNoUnpack()
UnpackStep()
and NegUnpackStep()
implement this functionality

NOTE Reverse() normalizes its results (divides by one half the blocklength), but
ReverseNoUnpack() does not.

7. Also if you only want the first half of the results you can call ReverseHalf()

NOTE Reverse() normalizes its results (divides by one half the blocklength), but
ReverseHalf() does not.

8. QFT is less numerically stable than regular FFTs. With singleprecision calculations,
a block length of 2^15 brings the accuracy down to being barelyaccurate enough.
At that size, single precision calculations tested sound files wouldoccasionally have
a sample off by 2, and a couple off by 1 per block. Full volume whitenoise would generate
a few samples off by as much as 6 per block at the end, beginning and middle.

No matter what the inputs the errors are always at the same positions in the block.
There some sort of cancelation that gets more delicate as the block size gets bigger.

For the sake of doing convolutions and the like where the forward transform is
done only once for one of the inputs, I created a AccurateForward() function.
It uses a regular FFT algorithm for blocks larger than 2^12, and decomposes into even and
odd FFTs recursively.

In any case you can always use the double precision routines to get more accuracy.
DQFT even has routines that take floats as inputs and return double precision
spectrum outputs.

As for portability:

1. The files qft.cpp and dqft.cpp start with defines:
#define _USE_ASM

If you comment those define out, then what's left is C++ with no assembly language.

2. There is unnecessary windows specific code in "criticalSection.h"
I used a critical section because objects are not reentrant (each object has
permanent scratch pad memory), but obviously critical sections are operating
system specific. In any case that code can easily be taken out.


If you look at my code and see that there's an a test built in the examples
that makes sure that the results are in the ballpark of being right. It
wasn't that I expected the answers to be far off, it was that I uncommenting
the "no assembly language" versions of some routines and I wanted to make
sure that they weren't broken.




no comments on this item | add a comment | nofrills version


Simple peak follower

Type : amplitude analysis
References : Posted by Phil Burk

Notes :
This simple peak follower will give track the peaks of a signal. It will rise rapidly when the input is rising, and then decay exponentially when the input drops. It can be used to drive VU meters, or used in an automatic gain control circuit.

Code :
// halfLife = time in seconds for output to decay to half value after an impulse

static float output = 0.0;

float scalar = pow( 0.5, 1.0/(halfLife * sampleRate)));

if( input < 0.0 )
  input = -input;  /* Absolute value. */

if ( input >= output )
{
   /* When we hit a peak, ride the peak to the top. */
   output = input;
}
else
{
   /* Exponential decay of output when signal is low. */
   output = output * scalar;
   /*
   ** When current gets close to 0.0, set current to 0.0 to prevent FP underflow
   ** which can cause a severe performance degradation due to a flood
   ** of interrupts.
   */
   if( output < VERY_SMALL_FLOAT ) output = 0.0;
}


2 comment(s) | add a comment | nofrills version


tone detection with Goertzel

Type : Goertzel
References : Posted by espenr[AT]ii[DOT]uib[DOT]no
Linked file : http://www.ii.uib.no/~espenr/tonedetect.zip

Notes :
Goertzel is basically DFT of parts of a spectrum not the total spectrum as you normally do with FFT. So if you just want to check out the power for some frequencies this could be better. Is good for DTFM detection I've heard.

The WNk isn't calculated 100% correctly, but it seems to work so ;) Yeah and the code is C++ so you might have to do some small adjustment to compile it as C.


Code :
/** Tone detect by Goertzel algorithm
*
* This program basically searches for tones (sines) in a sample and reports the different dB it finds for
* different frequencies. Can easily be extended with some thresholding to report true/false on detection.
* I'm far from certain goertzel it implemented 100% correct, but it works :)
*
* Hint, the SAMPLERATE, BUFFERSIZE, FREQUENCY, NOISE and SIGNALVOLUME all affects the outcome of the reported dB. Tweak
* em to find the settings best for your application. Also, seems to be pretty sensitive to noise (whitenoise anyway) which
* is a bit sad. Also I don't know if the goertzel really likes float values for the frequency ... And using 44100 as
* samplerate for detecting 6000 Hz tone is kinda silly I know :)
*
* Written by: Espen Riskedal, espenr@ii.uib.no, july-2002
*/

#include <iostream>
#include <cmath>
#include <cstdlib>

using std::rand;
// math stuff
using std::cos;
using std::abs;
using std::exp;
using std::log10;
// iostream stuff
using std::cout;
using std::endl;

#define PI 3.14159265358979323844
// change the defines if you want to
#define SAMPLERATE 44100
#define BUFFERSIZE 8820
#define FREQUENCY 6000
#define NOISE 0.05
#define SIGNALVOLUME 0.8

/**  The Goertzel algorithm computes the k-th DFT coefficient of the input signal using a second-order filter.
*   http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/www/node3.html.
*   Basiclly it just does a DFT of the frequency we want to check, and none of the others (FFT calculates for all frequencies).
*/
float goertzel(float *x, int N, float frequency, int samplerate) {
    float Skn, Skn1, Skn2;
    Skn = Skn1 = Skn2 = 0;
    
    for (int i=0; i<N; i++) {
    Skn2 = Skn1;
    Skn1 = Skn;
    Skn = 2*cos(2*PI*frequency/samplerate)*Skn1 - Skn2 + x[i];
    }
    
    float WNk = exp(-2*PI*frequency/samplerate); // this one ignores complex stuff
    //float WNk = exp(-2*j*PI*k/N);
    return (Skn - WNk*Skn1);
}

/** Generates a tone of the specified frequency
*  Gotten from: http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3c641e%243jn%40uicsl.csl.uiuc.edu
*/
float *makeTone(int samplerate, float frequency, int length, float gain=1.0) {
    //y(n) = 2 * cos(A) * y(n-1) - y(n-2)
    //A= (frequency of interest) * 2 * PI / (sampling frequency)
    //A is in radians.
    // frequency of interest MUST be <= 1/2 the sampling frequency.
    float *tone = new float[length];
    float A = frequency*2*PI/samplerate;
    
    for (int i=0; i<length; i++) {
    if (i > 1) tone[i]= 2*cos(A)*tone[i-1] - tone[i-2];
    else if (i > 0) tone[i] = 2*cos(A)*tone[i-1] - (cos(A));
    else tone[i] = 2*cos(A)*cos(A) - cos(2*A);
    }

    for (int i=0; i<length; i++) tone[i] = tone[i]*gain;
    
    return tone;
}

/** adds whitenoise to a sample */
void *addNoise(float *sample, int length, float gain=1.0) {
    for (int i=0; i<length; i++) sample[i] += (2*(rand()/(float)RAND_MAX)-1)*gain;
}

/** returns the signal power/dB */
float power(float value) {
    return 20*log10(abs(value));
}

int main(int argc, const char* argv) {
    cout << "Samplerate: " << SAMPLERATE << "Hz\n";
    cout << "Buffersize: " << BUFFERSIZE << " samples\n";
    cout << "Correct frequency is: " << FREQUENCY << "Hz\n";
    cout << " - signal volume: " << SIGNALVOLUME*100 << "%\n";
    cout << " - white noise: " << NOISE*100 << "%\n";
    
    float *tone = makeTone(SAMPLERATE, FREQUENCY, BUFFERSIZE, SIGNALVOLUME);
    addNoise(tone, BUFFERSIZE,NOISE);

    int stepsize = FREQUENCY/5;

    for (int i=0; i<10; i++) {
    int freq = stepsize*i;
    cout << "Trying freq: " << freq << "Hz  ->  dB: " << power(goertzel(tone, BUFFERSIZE, freq, SAMPLERATE)) << endl;
    }
    delete tone;
    
    return 0;
}


14 comment(s) | add a comment | nofrills version


Tone detection with Goertzel (x86 ASM)

Type : Tone detection with Goertzel in x86 assembly
References : Posted by Christian[AT]savioursofsoul[DOT]de

Notes :
This is an "assemblified" version of the Goertzel Tone Detector. It is about 2 times faster than the original code.

The code has been tested and it works fine.

Hope you can use it. I'm gonna try to build a Tuner (as VST-Plugin). I hope, that this will work :-\ If anyone is intrested, please let me know.

Christian


Code :
function Goertzel_x87(Buffer :Psingle; BLength:Integer; frequency: Single; samplerate: Single):Single;
asm
mov ecx,BLength
mov eax,Buffer
fld x2
fldpi
fmulp
fmul frequency
fdiv samplerate
fld st(0)
fcos
fld x2
fmulp
fxch st(1)
fldz
fsub st(0),st(1)
fstp st(1)

fldl2e
fmul
fld st(0)
frndint
fsub st(1),st(0)
fxch st(1)
f2xm1
fld1
fadd
fscale
fstp st(1)

fldz
fldz
fldz
@loopStart:
fxch st(1)
fxch st(2)
fstp st(0)
fld st(3)
fmul st(0),st(1)
fsub st(0),st(2)
fld [eax].Single
faddp
add eax,4
loop @loopStart
@loopEnd:

fxch st(3)
fmulp st(2), st(0)
fsub st(0),st(1)
fstp result
ffree st(2)
ffree st(1)
ffree st(0)
end;


28 comment(s) | add a comment | nofrills version


Vintage VU meters tutorial

References : Posted by neolit123 at gmail dot com

Notes :
Here is a short tutorial about vintage-styled VU meters:

http://neolit123.blogspot.com/2009/03/designing-analog-vu-meter-in-dsp.html




1 comment(s) | add a comment | nofrills version