Tremolo audio effect (amplitude modulation)

Gabriel Rivas November 29, 2011 Coded in C
/************************Tremolo.c*************************/

#include "Tremolo.h"

static double dep;
static short counter_limit;
static short control;
static short mod;
static double offset;

void Tremolo_init(short effect_rate,double depth) {
    dep     = depth; 
    control = 1;
    mod     = 0;
    counter_limit = effect_rate;
    offset  = 1 - dep;
}

double Tremolo_process(double xin) {
    double yout;
    double m;

    m = (double)mod*dep/counter_limit;
    yout = (m + offset)*xin;
    return yout;
}

void Tremolo_sweep(void) {

	    mod += control;
  
	    if (mod > counter_limit) {
	        control = -1;
            } 
            else if(!mod) {
	        control = 1;
            }
}

/********************Tremolo.h****************************/
#ifndef __TREMOLO_H__
#define __TREMOLO_H__

extern void Tremolo_init(short effect_rate,double depth);
extern double Tremolo_process(double xin);
extern void Tremolo_sweep(void);

#endif

/*Usage example*/
#include "Tremolo.h"

void main(void) {
    double xin;
    double yout;
    Tremolo_init(4000,1);

    while(1) {
        if (new_sample_flag()) {
            /*When there's new sample at your ADC or CODEC input*/
            /*Read the sample*/
            xin = read_sample();
            /*Apply the Tremolo_process function to the sample*/
            yout = Tremolo_process(0.7*temp);

            /*Send the output value to your DAC or codec output*/
            write_output(yout);
            /*Makes LFO vary*/
            Tremolo_sweep();
        }                              
    }
}

Auto Wah and Envelope follower audio effect

Gabriel Rivas November 29, 2011 Coded in C
#include "bp_iir.h"
#include "AutoWah.h"

static short center_freq;
static short samp_freq;
static short counter;
static short counter_limit;
static short control;
static short max_freq;
static short min_freq;
static short f_step;
static struct bp_filter H;
static double a[3];
static double b[3];
double x[3],y[3];

void AutoWah_init(short effect_rate,short sampling,short maxf,short minf,short Q,double gainfactor,short freq_step) {
	double C;

	//Process variables
	center_freq = 0;
	samp_freq = sampling;
	counter = effect_rate;
	control = 0;

	//User Parametters
	counter_limit = effect_rate;
	
	//Convert frequencies to index ranges
	min_freq = 0;
	max_freq = (maxf - minf)/freq_step;

    bp_iir_init(sampling,gainfactor,Q,freq_step,minf);
	f_step = freq_step; 
        
	//Lowpass filter parameters	
	/*
	   C = 1/TAN(PI*Fc/Fs)
	*/
	C = 1018.59;

	b[0] = 1/(1+2*0.7071*C+pow(C,2));
	b[1] = 2*b[0];
	b[2] = b[0];

	a[1] = 2*b[0]*(1-pow(C,2));
	a[2] = b[0]*(1-2*0.7071*C+pow(C,2));
}

double AutoWah_process(double xin) {
	double yout;

	yout = bp_iir_filter(xin,&H);
	#ifdef INPUT_UNSIGNED
		yout += 32767;
	#endif
	
	return yout;
}

void AutoWah_sweep(double xin) {
	unsigned int filter_index;
	double yout;
        double detect;

	/*The input is 16 bit unsigned so it
	has to be centered to 0*/
	detect = (xin - 32767.0); 
	x[0] = x[1]; 
	x[1] = x[2]; 
	/*Here the input to the filter
	is half rectified*/
	x[2] = (detect > 0)?detect:0;
		
	y[0] = y[1]; 
	y[1] = y[2]; 
	
	y[2] =    b[0]*x[2];
	y[2] +=   b[1]*x[1];
	y[2] +=   b[2]*x[0];
	y[2] -=   a[1]*y[1];
	y[2] -=   a[2]*y[0];

	if (!--counter) {
		/*The output of the LPF (y[2]) is scaled by 0.1
		in order to be used as a LFO to control the band pass filter
		*/
	    filter_index = (double)min_freq + y[2]*0.1;
                        
            /*The scaling value is determined as a value
            that would keep the filter index within the
            range of max_freq
	    */
            if(filter_index > max_freq) {
                filter_index = max_freq;
            } 
            if(filter_index < 0) {
                filter_index = 0;
            }

	    bp_iir_setup(&H,filter_index);

	    counter = counter_limit; 
	}
}

Auto Wah audio effect (LFO control)

Gabriel Rivas September 24, 2011 Coded in C
/*************** AutoWah.c ********************************/

#include "bp_iir.h"
#include "AutoWah.h"

static short center_freq;
static short samp_freq;
static short counter;
static short counter_limit;
static short control;
static short max_freq;
static short min_freq;
static short f_step;
static struct bp_filter H;

/*
This is the auto wah effect initialization function. 
This initializes the band pass filter and the effect control variables
*/
void AutoWah_init(short effect_rate,short sampling,short maxf,short minf,short Q,double gainfactor,short freq_step) {
	double C;

	/*Process variables*/
	center_freq = 0;
	samp_freq = sampling;
	counter = effect_rate;
	control = 0;

	/*User Parametters*/
	counter_limit = effect_rate;
	
	/*Convert frequencies to index ranges*/
	min_freq = 0;
	max_freq = (maxf - minf)/freq_step;

        bp_iir_init(sampling,gainfactor,Q,freq_step,minf);
	f_step = freq_step; 
}

/*
This function generates the current output value
Note that if the input and output signal are integer
unsigned types, we need to add a half scale offset
*/
double AutoWah_process(int xin) {
	double yout;

	yout = bp_iir_filter(xin,&H);
	#ifdef INPUT_UNSIGNED
		yout += 32767;
	#endif
	
	return yout;
}

/*
This function will emulate a LFO that will vary according
to the effect_rate parameter set in the AutoWah_init function.
*/
void AutoWah_sweep(void) {
	double yout;
     
	if (!--counter) {
		if (!control) {
			bp_iir_setup(&H,(center_freq+=f_step));
			if (center_freq > max_freq) {
				control = 1;
			}
		}
		else if (control) {
			bp_iir_setup(&H,(center_freq-=f_step));
			if (center_freq == min_freq) {
				control = 0;
			}
		}

		counter = counter_limit; 
	}
}

/*************** AutoWah.h ****************************/

#ifndef __AUTOWAH_H__
#define __AUTOWAH_H__

extern void AutoWah_init(short effect_rate,short sampling,short maxf,short minf,short Q,double gainfactor,short freq_step);
extern double AutoWah_process(int xin);
extern void AutoWah_sweep(void);

#endif

/************** Usage Example **************************/

#include "AutoWah.h"

void main(void) {
    short xin;
    short yout;
    AutoWah_init(2000,  /*Effect rate 2000*/
                 16000, /*Sampling Frequency*/
                 1000,  /*Maximum frequency*/
                 500,   /*Minimum frequency*/
                 4,     /*Q*/
                 0.707, /*Gain factor*/
                 10     /*Frequency increment*/
                 );   

    while(1) {
        if (new_sample_flag()) {
            /*When there's new sample at your ADC or CODEC input*/
            /*Read the sample*/
            xin = read_sample();
            /*Apply AutoWah_process function to the sample*/
            yout =AutoWah_process(xin);

            /*Send the output value to your DAC or codec output*/
            write_output(yout);
            /*Makes the LFO vary*/
            AutoWah_sweep();
        }                              
    }
}

Phaser audio effect

Gabriel Rivas July 4, 20112 comments Coded in C
/*
Phaser audio effect:

Xin                                                                       Yout
-------------------------------[dir_mix]--------------------->[+]--------->
      |                                                        ^  
      |                                                        |
      |-->[VNS1]-->[VNS2]-->[VNS3]...-->[VNSN]-->[pha_mix]------      

            ^        ^        ^           ^ 
            |        |        |           |
            |--------|--------|---...------
            |
          [LFO]         

VNS = Variable notch stage

*/

#include "br_iir.h"
#include "Phaser.h"

/*This defines the phaser stages
that is the number of variable notch blocks
*/
#define PH_STAGES 20

static short center_freq;    /*Center frequency counter*/
static short samp_freq;      /*Sampling frequency*/
static short counter;        /*Smaple counter*/
static short counter_limit;  /*Smaple counter limit*/
static short control;        /*LFO Control*/
static short max_freq;       /*Maximum notch center frequency*/
static short min_freq;       /*Minimum notch center frequency*/ 
static double pha_mix;       /*Filtered signal mix*/
static short f_step;         /*Sweep frequency step*/ 
static double dir_mix;       /*Direct signal mix*/
static struct br_filter H[PH_STAGES]; /*Array of notch filters stages*/

/*
This funtion initializes the phaser control variables
and the variable notch filter coefficients array
*/
void Phaser_init(short effect_rate,short sampling,short maxf,short minf,short Q,double gainfactor,double pha_mixume,short freq_step, double dmix) {
    /*Initialize notch filter coefficients set array*/
    br_iir_init(sampling,gainfactor,Q,freq_step, minf);
   
    /*Initializes the phaser control variables*/
    center_freq = 0;
    samp_freq = sampling;
    counter = effect_rate;
    control = 0;
    counter_limit = effect_rate;

    /*Convert frequencies to integer indexes*/
    min_freq = 0;
    max_freq = (maxf - minf)/freq_step;

    pha_mix = pha_mixume;
    f_step = freq_step;
    dir_mix = dmix;
}

/*
This function does the actual phasing processing
1. It takes the input sample and pass it trough the
cascaded notch filter stages
2. It takes tha output of the cascaded notch filters
and scales it, scales the input sample and generate
the output effect sample.
*/
double Phaser_process(double xin) {
    double yout;
    int i;

    yout = br_iir_filter(xin,&H[0]);

    for(i = 1; i < PH_STAGES; i++) {
        yout = br_iir_filter(yout,&H[i]);
    }
     
    yout = dir_mix*xin + pha_mix*yout;
      
    return yout;
}

/*
This function makes vary the center notch frequency
in all the cascaded notch filter stages by a simulated
triangle wave LFO that goes up and down
*/
void Phaser_sweep(void) {
    int i;

    if (!--counter) {
        if (!control) {
            center_freq+=f_step;

            if (center_freq > max_freq) {
                control = 1;
            }
        }
        else if (control) {
            center_freq-=f_step;

            if (center_freq == min_freq) {               
                control = 0;
            }
        }
        for(i = 0; i < PH_STAGES; i++) {
            br_iir_setup(&H[i],center_freq);
        }       
        counter = counter_limit;
    }
}

/************

Phaser.h

***********/

#ifndef __PHASER_H__
#define __PHASER_H__

extern void Phaser_init(short effect_rate,short sampling,short maxf,short minf,short Q,double gainfactor,double mix_volume,short freq_step, double dmix);
extern double Phaser_process(double xin);
extern void Phaser_sweep(void);

#endif

Variable 2nd order band pass IIR filter

Gabriel Rivas July 4, 20112 comments Coded in C
#include "bp_iir.h"
#include <math.h>
#define BP_MAX_COEFS 120
#define PI 3.1415926

/*This is an array of the filter parameters object
defined in the br_iir.h file*/
static struct bp_coeffs bp_coeff_arr[BP_MAX_COEFS];

/*This initialization function will create the
band pass filter coefficients array, you have to specify:
fsfilt = Sampling Frequency
gb     = Gain at cut frequencies
Q      = Q factor, Higher Q gives narrower band
fstep  = Frequency step to increase center frequencies
in the array
fmin   = Minimum frequency for the range of center   frequencies
*/
void bp_iir_init(double fsfilt,double gb,double Q,short fstep, short fmin) {
      int i;
      double damp;
      double wo;
      
       damp = gb/sqrt(1 - pow(gb,2));

	for (i=0;i<BP_MAX_COEFS;i++) {
            wo = 2*PI*(fstep*i + fmin)/fsfilt;
		bp_coeff_arr[i].e = 1/(1 + damp*tan(wo/(Q*2)));
		bp_coeff_arr[i].p = cos(wo);
		bp_coeff_arr[i].d[0] = (1-bp_coeff_arr[i].e);
		bp_coeff_arr[i].d[1] = 2*bp_coeff_arr[i].e*bp_coeff_arr[i].p;
		bp_coeff_arr[i].d[2] = (2*bp_coeff_arr[i].e-1);
	}
}

/*This function loads a given set of band pass filter coefficients acording to a center frequency index
into a band pass filter object
H = filter object
ind = index of the array mapped to a center frequency
*/
void bp_iir_setup(struct bp_filter * H,int ind) {
	H->e = bp_coeff_arr[ind].e;
	H->p = bp_coeff_arr[ind].p;
	H->d[0] = bp_coeff_arr[ind].d[0];
	H->d[1] = bp_coeff_arr[ind].d[1];
	H->d[2] = bp_coeff_arr[ind].d[2];
}

/*This function loads a given set of band pass filter coefficients acording to a center frequency index
into a band pass filter object
H = filter object
ind = index of the array mapped to a center frequency
*/
double bp_iir_filter(double yin,struct bp_filter * H) {
	double yout;

	H->x[0] =  H->x[1]; 
	H->x[1] =  H->x[2]; 
	H->x[2] = yin;
	
	H->y[0] =  H->y[1]; 
	H->y[1] =  H->y[2]; 

	H->y[2] = H->d[0]* H->x[2] - H->d[0]* H->x[0] + (H->d[1]* H->y[1]) - H->d[2]* H->y[0];
	
	yout =  H->y[2];

	return yout;
}

/******************
bp_iir.h
**********************/

#ifndef __BP_IIR_H__
#define __BP_IIR_H__

struct bp_coeffs{
	double e;
	double p;
	double d[3];
};

struct bp_filter{
	double e;
	double p;
	double d[3];
	double x[3];
	double y[3];
};

extern void bp_iir_init(double fsfilt,double gb,double Q,short fstep, short fmin);
extern void bp_iir_setup(struct bp_filter * H,int index);
extern double bp_iir_filter(double yin,struct bp_filter * H);

#endif

Variable 2nd order Notch IIR filter

Gabriel Rivas June 21, 20112 comments Coded in C
#include "br_iir.h"
#include <math.h>

#define BR_MAX_COEFS 120
#define PI 3.1415926

/*This is an array of the filter parameters object
defined in the br_iir.h file*/
static struct br_coeffs br_coeff_arr[BR_MAX_COEFS];

/*This initialization function will create the
notch filter coefficients array, you have to specify:
fsfilt = Sampling Frequency
gb     = Gain at cut frequencies
Q      = Q factor, Higher Q gives narrower band
fstep  = Frequency step to increase center frequencies
in the array
fmin   = Minimum frequency for the range of center   frequencies
*/
void br_iir_init(double fsfilt,double gb,double Q,double fstep, short fmin) {
	int i;
      double damp;
      double wo;
      
      damp = sqrt(1 - pow(gb,2))/gb;

	for (i=0;i<BR_MAX_COEFS;i++) {
                wo = 2*PI*(fstep*i + fmin)/fsfilt;
		br_coeff_arr[i].e = 1/(1 + damp*tan(wo/(Q*2)));
		br_coeff_arr[i].p = cos(wo);
		br_coeff_arr[i].d[0] = br_coeff_arr[i].e;
		br_coeff_arr[i].d[1] = 2*br_coeff_arr[i].e*br_coeff_arr[i].p;
		br_coeff_arr[i].d[2] = (2*br_coeff_arr[i].e-1);
	}
}

/*This function loads a given set of notch filter coefficients acording to a center frequency index
into a notch filter object
H = filter object
ind = index of the array mapped to a center frequency
*/
void br_iir_setup(struct br_filter * H,int ind) {
	H->e = br_coeff_arr[ind].e;
	H->p = br_coeff_arr[ind].p;
	H->d[0] = br_coeff_arr[ind].d[0];
	H->d[1] = br_coeff_arr[ind].d[1];
	H->d[2] = br_coeff_arr[ind].d[2];
}

/*
This function does the actual notch filter processing
yin = input sample
H   = filter object 
*/
double br_iir_filter(double yin,struct br_filter * H) {
	double yout;

	H->x[0] = H->x[1]; 
	H->x[1] = H->x[2]; 
	H->x[2] = yin;
	
	H->y[0] = H->y[1]; 
	H->y[1] = H->y[2]; 

	H->y[2] = H->d[0]*H->x[2] - H->d[1]*H->x[1] + H->d[0]*H->x[0] + H->d[1]*H->y[1] - H->d[2]*H->y[0];
	
	yout = H->y[2];
	return yout;
}

/******************/
#ifndef __BR_IIR_H__
#define __BR_IIR_H__

/*
Notch filter coefficients object
*/
struct br_coeffs {
	double e;
	double p;
	double d[3];
};

/*
Notch filter object
*/
struct br_filter {
	double e;
	double p;
	double d[3];
	double x[3];
	double y[3];
};

extern void br_iir_init(double fsfilt,double gb,double Q,double fstep, short fmin);
extern void br_iir_setup(struct br_filter * H,int index);
extern double br_iir_filter(double yin,struct br_filter * H);

#endif

Flanger Audio Effect

Gabriel Rivas April 22, 2011 Coded in C
/*******************FLANGER.C******************************/

#include "Delay.h"
#include "Flanger.h"

static short samp_freq;
static double var_delay;
static short counter;
static short counter_limit;
static short control;
static short max_delay;
static short min_delay;
static double mix_vol;
static double delay_step;

/*
This is the initialization function, basically
it passes the initialization parameters to the delay block
and initializes the flanger control variables.
*/
void Flanger_init(short effect_rate,short sampling,short maxd,short mind,double fwv,double stepd,double fbv) {
	Delay_Init(2,fbv,fwv,1);
 
	samp_freq = sampling;
	counter = effect_rate;
	control = 1;
	var_delay = mind;

	//User Parameters
	counter_limit = effect_rate;
	max_delay =  maxd;
	min_delay = mind;
	mix_vol = 1;
	delay_step = stepd;
}

/*This is the flanging process task
that uses the delay task inside*/
double Flanger_process(double xin) {
	double yout;

	yout = Delay_task(xin); 	
	return yout;
}

/*
This sweep function creates a slow frequency
ramp that will go up and down changing the
delay value at the same time. The counter
variable is a counter of amount of samples that 
the function waits before it can change the delay.
*/
void Flanger_sweep(void) {
	if (!--counter) {			
	    var_delay+=control*delay_step;
  
	    if (var_delay > max_delay) {
	        control = -1;
            } 

            if (var_delay < min_delay) {
	        control = 1;
            }

	    Delay_set_delay(var_delay);
	    counter = counter_limit;
	}
}

/*****************FLANGER.H********************************/
#ifndef __FLANGER_H__
#define __FLANGER_H__

extern void Flanger_init(short effect_rate,short sampling,short maxd,short mind,double fwv,double stepd,double fbv);
extern double Flanger_process(double xin);
extern void Flanger_sweep(void);

#endif

/*****USAGE EXAMPLE****************************************/
#include "Flanger.h"

void main(void) {
    double xin;
    double yout;
    Flanger_init(500,16000,70,2,0.3,1,0.3);

    while(1) {
        if (new_sample_flag()) {
            /*When there's new sample at your ADC or CODEC input*/
            /*Read the sample*/
            xin = read_sample();
            /*Apply the Flanger_process function to the sample*/
            yout = Flanger_process(0.7*xin);

            /*Send the output value to your DAC or codec output*/
            write_output(yout);
            /*Makes the delay vary*/
            Flanger_sweep();
        }                              
    }
}

Template to develop audio DSP using the (OSS) API + GNU/Linux

Gabriel Rivas February 6, 2011 Coded in C
#include <stdio.h>
#include <fcntl.h>
#include <sys/soundcard.h>

#define BUF_SIZE 2

/*buffers for sound device*/
unsigned char devbuf[BUF_SIZE];

/*File descriptor for device*/
int audio_fd;

/*The sound card is known as the DSP*/
char DEVICE_NAME[]="/dev/dsp";

/*Device Settings*/
int format;
int channels;
int fs;
int len;
int frag;
int devcaps;

int main()
{
    unsigned int temp;
    unsigned int yout;

    /*Samples format is 16 bit unsigned*/
    format = AFMT_U16_LE;
    /*1 Channel, MONO*/
    channels = 1;
    /*Sampling Rate is 16 KHz*/
    fs = 16000;
    /*This is a parameter used to set the DSP for low latencies*/
    frag = 0x00020004;

	/******************************************************
          Set parameters in sound card device
    *****************************************************/

	/*Open sound card device*/
	if ((audio_fd = open(DEVICE_NAME,O_RDWR, 0)) == -1) {
		/* Open of device failed */
		perror(DEVICE_NAME);
		exit(1);
	}	

	if (ioctl (audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag) == -1)
	{
	    perror ("SNDCTL_DSP_SETFRAGMENT");
	    exit (-1);
	}

	/*Set audio format*/
	if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) {
		/* fatal error */
		perror("SNDCTL_DSP_SETFMT");
		exit(1);
	}
	/*Set number of channels*/
	if (ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
		/* Fatal error */
		perror("SNDCTL_DSP_CHANNELS");
		exit(1);
	}
	
	/*Set sampling rate*/
	if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &fs)==-1) {
		/* Fatal error */
		perror("SNDCTL_DSP_SPEED");
		exit(1);
	}

	if (ioctl(audio_fd, SNDCTL_DSP_SYNC) == -1) {
		/* fatal error */
		perror("SNDCTL_DSP_SYNC");
		exit(1);
	}	

	/******************************************************
          This is the infinite loop to:
          1. Read a sample
          2. Process the sample
          3. Write the sample to soundcard output
    *****************************************************/
    while(1) {
        /* This is a blocking read function, the application will wait
           until the sound card captures a sample
        */
        if ((len = read(audio_fd,devbuf, sizeof(devbuf))) == -1) {
	        perror("audio read");
	        exit(1);
	    }

        /* We can pass this variable to a temporary value, 
           in this case as unsigned 16 value, and then use this value 
           for processing
        */  
	    temp = (devbuf[0])|(devbuf[1]<<8);

        /* In this case no processing is done so the value is passed to the output. You can also use this sample to build an audio file, or send it trought a communications interface, etc.
        */
	    yout = temp;

	    devbuf[0] = yout&0xFF;
	    devbuf[1] = (yout>>8)&0xFF;
		
        /* This is the way the output samples are sent to the soundcard            
        */
        if ((len = write(audio_fd,devbuf,sizeof(devbuf)) == -1)) {
	        perror("audio write");
	        exit(1);
        }
    }	
    return 0;
}

Fractional Delay Line implementation

Gabriel Rivas January 27, 20113 comments Coded in C
/****************DELAY.C*******************************/
#include "delay.h"
#include "math.h"

#define MAX_BUF_SIZE 64000

/*****************************************************************************
*       Fractional delay line implementation in C:
*
*                    ---------[d_mix]--------------------------
*                    |                                         |
*                    |                                         |
*                    |x1                                       v
*     xin ------>[+]----->[z^-M]--[interp.]----[d_fw]-------->[+]-----> yout 
*                 ^                         |  
*                 |                         |
*                 |----------[d_fb]<--------|   
*******************************************************************************/

double d_buffer[MAX_BUF_SIZE];

/*
This interface defines the delay object
*/
static struct fract_delay {
    double d_mix;       /*delay blend parameter*/
    short d_samples;	/*delay duration in samples*/
    double d_fb;	    /*feedback volume*/
    double d_fw;	    /*delay tap mix volume*/
    double n_fract;     /*fractional part of the delay*/
    double *rdPtr;      /*delay read pointer*/
    double *wrtPtr;     /*delay write pointer*/
};

static struct fract_delay del;

/*
This function is used to initialize the delay object
*/
void Delay_Init(double delay_samples,double dfb,double dfw, double dmix) {
	Delay_set_delay(delay_samples);
	Delay_set_fb(dfb);
	Delay_set_fw(dfw);
	Delay_set_mix(dmix);	
	del.wrtPtr = &d_buffer[MAX_BUF_SIZE-1];
}

/*
These functions are used as interface to the delay object,
so there's not direct access to the delay object from
external modules
*/
void Delay_set_fb(double val) {
    del.d_fb = val;
}

void Delay_set_fw(double val) {
    del.d_fw = val;
}

void Delay_set_mix(double val) {
    del.d_mix = val;
}

void Delay_set_delay(double n_delay) {
    /*Get the integer part of the delay*/
    del.d_samples = (short)floor(n_delay);

    /*gets the fractional part of the delay*/
    del.n_fract = (n_delay - del.d_samples);	
}

double Delay_get_fb(void) {
    return del.d_fb;
}

double Delay_get_fw(void) {
    return del.d_fw;
}

double Delay_get_mix(void) {
    return del.d_mix;
}

/*
This is the main delay task,
*/
double Delay_task(double xin) {
	double yout;
	double * y0; 
	double * y1;
	double x1;
	double x_est;
    
    /*Calculates current read pointer position*/
	del.rdPtr = del.wrtPtr - (short)del.d_samples;
	
	/*Wraps read pointer*/
	if (del.rdPtr < d_buffer) {
		del.rdPtr += MAX_BUF_SIZE-1;
	}
	
	/*Linear interpolation to estimate the delay + the fractional part*/
	y0 = del.rdPtr-1;
	y1 = del.rdPtr;

	if (y0 < d_buffer) {
	    y0 += MAX_BUF_SIZE-1;
	}

	x_est = (*(y0) - *(y1))*del.n_fract + *(y1);

    /*Calculate next value to store in buffer*/
    x1 = xin + x_est*del.d_fb;
    
	/*Store value in buffer*/
	*(del.wrtPtr) = x1;
  
    /*Output value calculation*/
	yout = x1*del.d_mix + x_est*del.d_fw;

    /*Increment delat write pointer*/
	del.wrtPtr++;

    /*Wraps delay write pointer*/
	if ((del.wrtPtr-&d_buffer[0]) > MAX_BUF_SIZE-1) {
		del.wrtPtr = &d_buffer[0];
	}
	return yout;
}
/***********DELAY.h*************************************/
#ifndef __DELAY_H__
#define __DELAY_H__

void Delay_Init(double delay_samples,double dfb,double dfw, double dmix);
void Delay_set_fb(double val);
void Delay_set_fw(double val);
void Delay_set_mix(double val);
void Delay_set_delay(double n_delay);
double Delay_get_fb(void);
double Delay_get_fw(void);
double Delay_get_mix(void);
double Delay_task(double xin);

#endif
/*****USAGE EXAMPLE****************************************/
void main(void) {
    double xin;
    double yout;
    Delay_Init(85.6,0.7,0.7,1);

    while(1) { 
        if (new_sample_flag()) {
            /*When there's new sample at your ADC or CODEC input*/
            /*Read the sample*/
            xin = read_sample();
            /*Apply the Delay_task function to the sample*/
            yout = Delay_task(xin);

            /*Send the output value to your ADC or codec output*/
            write_output(yout);
        }				
    }
}