First post, by superfury
I'm currently using the following code for low-pass and high-pass filtering all my generated signals:
Header with all typedefs:
#ifndef FILTER_H
#define FILTER_H
#include "headers/types.h" //Basic types!
typedef struct
{
byte isInit; //Initialized filter?
byte isFirstSample; //First sample?
float sound_last_result; //Last result!
float sound_last_sample; //Last sample!
float alpha; //Solid value that doesn't change for the filter, until the filter is updated!
//General filter information and settings set for the filter!
byte isHighPass;
float cutoff_freq;
float samplerate;
} HIGHLOWPASSFILTER; //High or low pass filter!
//Global high and low pass filters support!
void initSoundFilter(HIGHLOWPASSFILTER *filter, byte ishighpass, float cutoff_freq, float samplerate); //Initialize the filter!
void updateSoundFilter(HIGHLOWPASSFILTER *filter, byte ishighpass, float cutoff_freq, float samplerate); //Update the filter information/type!
void applySoundFilter(HIGHLOWPASSFILTER *filter, float *currentsample); //Apply the filter to a sample stream!
#endif
Code for processing the selected filter:
#include "headers/support/filters.h" //Our filter definitions!
void updateSoundFilter(HIGHLOWPASSFILTER *filter, byte ishighpass, float cutoff_freq, float samplerate)
{
filter->isHighPass = ishighpass; //Highpass filter?
if (filter->isInit || (filter->cutoff_freq!=cutoff_freq) || (filter->samplerate!=samplerate) || (ishighpass!=filter->isHighPass)) //We're to update?
{
if (ishighpass) //High-pass filter?
{
float RC = (1.0f / (cutoff_freq * (2.0f * (float)PI))); //RC is used multiple times, calculate once!
filter->alpha = (RC / (RC + (1.0f / samplerate))); //Alpha value to use!
}
else //Low-pass filter?
{
float dt = (1.0f / samplerate); //DT is used multiple times, calculate once!
filter->alpha = (dt / ((1.0f / (cutoff_freq * (2.0f * (float)PI))) + dt)); //Alpha value to use!
}
}
filter->isHighPass = ishighpass; //Hi-pass filter?
filter->cutoff_freq = cutoff_freq; //New cutoff frequency!
filter->samplerate = samplerate; //New samplerate!
}
void initSoundFilter(HIGHLOWPASSFILTER *filter, byte ishighpass, float cutoff_freq, float samplerate)
{
filter->isInit = 1; //We're an Init!
filter->isFirstSample = 1; //We're the first sample!
updateSoundFilter(filter,ishighpass,cutoff_freq,samplerate); //Init our filter!
}
void applySoundFilter(HIGHLOWPASSFILTER *filter, float *currentsample)
{
INLINEREGISTER float last_result;
if (filter->isFirstSample) //No last? Only executed once when starting playback!
{
filter->sound_last_result = filter->sound_last_sample = *currentsample; //Save the current sample!
filter->isFirstSample = 0; //Not the first sample anymore!
return; //Abort: don't filter the first sample!
}
last_result = filter->sound_last_result; //Load the last result to process!
if (filter->isHighPass) //High-pass filter?
{
last_result = filter->alpha * (last_result + *currentsample - filter->sound_last_sample);
}
else //Low-pass filter?
{
last_result += (filter->alpha*(*currentsample-last_result));
}
filter->sound_last_sample = *currentsample; //The last sample that was processed!
*currentsample = filter->sound_last_result = last_result; //Give the new result!
}
But it's running very slowly, even on fast systems(Intel i7 4.0GHz processing a 3.57MHz(Game Blaster) PWM signal by low-pass filtering). Is there a way to optimize this to be fast? Or is this already as fast as it can be?
Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io