Hi JUCE community!
I wish to all of you a happy 2018!
I am trying to use an FIR filter for reducing aliasing.
The main idea is based on this info.
http://www.willpirkle.com/Downloads/AN-1MultiRateandPolyPhase.pdf
and part of the implementation was based on this topic
Here is the problem. The filter seems to cut the desired frequencies, but the aliasing is not reduced at all.
Here is a sawtooth at 440 Hz without “oversampling”
Ande here is with it:
Any ideas will be very appreciated!!!
Thanks a lot!
FIR_Filter.h
#ifndef FIR_Filter_h
#define FIR_Filter_h
#include <iostream>
using namespace std;
#endif /* FIR_Filter_h */
class CFIR_Filter
{
public:
CFIR_Filter (void);
virtual ~CFIR_Filter(void);
void init ();
float processFilterBlock (float x);
int getOverSamplingRatio() { return m_nOverSamplingRatio;} ;
inline void setOverSamplingRatio(int m_nOverSamplingRatio) {this->m_nOverSamplingRatio = m_nOverSamplingRatio;
}
inline int getOffset() { return m_Offset;}
inline void setOffset(int m_Offset) {this->m_Offset = m_Offset;}
inline int getIRLength() {
return m_nIRLength;}
inline void setIRLength(int m_nIRLength) {this->m_nIRLength = m_nIRLength;}
inline void setDelayLength() {this->m_nDelayLineSize = this->m_nIRLength /this->m_nOverSamplingRatio;
}
inline void setDelayLineIndex() {this->DelayLineIndex = this->m_nDelayLineSize-1;
}
private:
// Set OverSampling ratio
int m_nOverSamplingRatio = 16;
// Set the IRLenght here
int m_nIRLength = 640;
// The IR Array here
float *m_FilterImpulseResponse;
// The Delay Line Array here
int m_nIRIndex = 0;
int m_nDelayLineSize = m_nIRLength/m_nOverSamplingRatio;
int m_Offset = m_nOverSamplingRatio-1;
float *m_DelayLine;
int DelayLineIndex= 0;
int DelayLineLoopCounter=0;
};
FIR_Filter.cpp
CFIR_Filter::CFIR_Filter (void)
{
//init array impulse response
m_FilterImpulseResponse = new float[m_nIRLength];
memset(m_FilterImpulseResponse, 0, m_nIRLength*sizeof(float));
// Add your impulse response here
m_FilterImpulseResponse[0] = -0.0000000396927433;
m_FilterImpulseResponse[1] = -0.0000000578565071;
m_FilterImpulseResponse[2] = -0.0000000987668898;
.....
m_FilterImpulseResponse[637] = -0.0000000987668898;
m_FilterImpulseResponse[638] = -0.0000000578565071;
m_FilterImpulseResponse[639] = -0.0000000396927433;
//Init array Delay Line, fill with zeros
m_DelayLine = new float[m_nIRLength/m_nOverSamplingRatio];
memset(m_DelayLine, 0, m_nIRLength*sizeof(float));
for (int i=0; i<m_nIRLength; i++) m_DelayLine[i] = 0.0;
}
CFIR_Filter::~CFIR_Filter(void)
{
if(m_DelayLine) delete m_DelayLine;
if(m_FilterImpulseResponse) delete m_FilterImpulseResponse;
}
void CFIR_Filter::init()
{
}
float CFIR_Filter::processFilterBlock(float x)
{
m_DelayLine[DelayLineIndex] = x;
DelayLineLoopCounter = DelayLineIndex;
float y = 0;
for (int i = m_Offset; i < m_nIRLength; i+=m_nOverSamplingRatio) // for each tap
{
y+= m_DelayLine[DelayLineLoopCounter] * m_FilterImpulseResponse[i];
if (--DelayLineLoopCounter < 0)
DelayLineLoopCounter += m_nDelayLineSize; // wrap buffer index
}
if (++DelayLineIndex >= m_nDelayLineSize)
DelayLineIndex -= m_nDelayLineSize; // wrap buffer index
return y*m_nOverSamplingRatio;
}
In PluginProcessor.h
CFIR_Filter LPF_Filter;
In PluginProcessor.cpp
OscAudioProcessor::OscAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor (BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", AudioChannelSet::stereo(), true)
#endif
)
#endif
{
LPF_Filter.setOverSamplingRatio(nOversamplingRatio);
LPF_Filter.setOffset(0);
LPF_Filter.setIRLength(640);
LPF_Filter.setDelayLength();
}
void OscAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels();
for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());
// This is the place where you'd normally do the guts of your plugin's
// audio processing...
float *monoBuffer = new float[ buffer.getNumSamples()];
for(int sample = 0; sample < buffer.getNumSamples(); ++sample)
{
monoBuffer [sample] = (float) 1 - (1 / M_PI * currentAngle ); //Saw
if(aliasProcessor)
{
monoBuffer [sample] =LPF_Filter.processFilterBlock((float) monoBuffer [sample]);
}
// Oversample
angleIncrement= (2 * M_PI * frequency ) / (samplingRate*nOversamplingRatio) ;
if (oscSwitch)
{
frequency+=0.01;
if(frequency> (samplingRate/2))
{
frequency=0;
oscSwitch=false;
}
}
#if 0
currentAngle+=angleIncrement*nOversamplingRatio;
#else
for (int i=0; i<nOversamplingRatio; i++ )
currentAngle+=angleIncrement;
#endif
if(currentAngle>(2 * M_PI)) currentAngle-= (2 * M_PI);
}
for (int channel = 0; channel < totalNumInputChannels; ++channel)
//*
{
float* channelData = buffer.getWritePointer (channel);
// ..do something to the data..
for (int sample = 0; sample < (buffer.getNumSamples()); sample++)
{
channelData[sample] = monoBuffer [sample]*onOff;
}
}
}