I wish to all of you a happy 2018!
I am trying to use an FIR filter for reducing aliasing in JUCE
The main idea is based on this info.
http://www.willpirkle.com/Downloads/AN- ... yPhase.pdf (http://www.willpirkle.com/Downloads/AN-1MultiRateandPolyPhase.pdf)
and part of the implementation was based on this topic
https://forum.juce.com/t/basic-fir-filtering/24477/8 (https://forum.juce.com/t/basic-fir-filtering/24477/8)
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"
https://discourse-cdn-sjc1.com/business ... b009a6.png (https://discourse-cdn-sjc1.com/business/uploads/juce/original/2X/d/d64b82f867485f24e00519d14cae03506eb009a6.png)
Ande here is with it:
https://discourse-cdn-sjc1.com/business ... c724d3.png (https://discourse-cdn-sjc1.com/business/uploads/juce/original/2X/f/f73dc92b72ab0117b38bc7f05a7842a4bec724d3.png)
Any ideas will be very appreciated!!!
Thanks a lot!
Andy
JUCE CODE:
FIR_Filter.h
Code: Select all (#)
#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;
};
Code: Select all (#)
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
Code: Select all (#)
CFIR_Filter LPF_Filter;
Code: Select all (#)
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;
}
}
}