I have a low pass and high pass filter in my program and i have a problem where it is hard to accurately filter lower and mid frequencies. As 10KHz is halfway it means most of the filter is just occurring on the treble. I have noticed in many eq’s (shown below) 10khz is near the end with greater ranges at the lower frequencies. How do I recreate this in my IIR filters as i am currently just using the raw value from the slider.
to get a nice “linear” sounding feel to my filter frequency control I used this :
auto freqHz = std::pow(2.71828182846, (frequencyKnob * 5.0) + 4.0);
where frequencyKnob
value ranges between 0 and 1.
It’s using the “natural logarithm” e (2.718…etc), you might want to tweak the * 5.0
and + 4.0
to your liking (the multiplier controls the range, the addition controls the offset from 0 Hz, iirc I played about feeding it whitenoise and looking at the results in an analyser to just see how it was responding, as I couldn’t be bothered to fully understand the mathematics behind it in order to know how it would respond! I really ought not to be so lazy!)
edit: pretty obvious I’ve no idea about the mathematics, or at least misunderstood what e is
// start - start frequency (typically 20Hz)
// end - end frequency (typically 20000Hz)
// perc - proportion from start to end (range 0 - 1)
float logspace(float start, float end, float prop)
{
return start * std::powf(end / start, prop);
}
This spaces powers of ten evenly so there’s an equal step between 20-200, 200-2000, etc. With this function, 10’000Hz is placed ~90% along the logarithmic scale.
DBG(logspace(20.f, 20000.f, 0.f)); // 20
DBG(logpsace(20.f, 20000.f, 0.33f)); // ~200
DBG(logspace(20.f, 20000.f, 0.67f)); // ~2000
DBG(logspace(20.f, 20000.f, 1.f)); // 20000
DBG(logpsace(20.f, 20000.f, 0.9f)); // 10000
sorry for the late reply, the algorithm worked fine with some changes, this is the code i have to display and read exact values,
some reason
lpKnob->valueFromTextFunction = (const String &text)
{
auto freq = text.removeCharacters(“Hz”).getDoubleValue();
return std::pow(2.71828182846, (1 / ((freq - 4) / 5.903487553f)));
};
lpKnob->textFromValueFunction = (double value)
{
double freq = (value);
return (juce::String(std::pow(2.71828182846, (freq * 5.903487553f) + 4)) + “Hz”);
};
log(2.7182818…)=1, so just use exp(value). It’s going to be faster.
pow(t, p) = exp(p * log(t))
im really not sure how to implement that, whenever i chose a value it either sets it to 20000hz (1) or crashes the program. i want a way to reverse the function (below) for when i type a value it is one between 0 and 1
converting from 0-1 to 0hz-20000hz
return (juce::String(std::pow(2.71828182846, (freq * 5.903487553f) + 4)) + “Hz”);
return (juce::String(std::exp(freq * 5.903487553f + 4)) + “Hz”);
dont think thats entirely correct, prehaps its something wrong on my side but 5 returns 272.99
It is, or you need to show what you mean by not correct:
exp(5)
148.4131591025766
pow(2.72, 5)
148.88279736320004
i got a perfect formula worked out (one that goes from exactly 20 to 20000 with 500 in the middle.
the second function is its inverse and the slider must have a range of 0 to 1. this is so other people can use it if they need.
lpKnob->textFromValueFunction = [](double value)
{
double freq = (value);
return (juce::String(20 * (std::pow(10, (3 * freq)))) + "Hz");
};
lpKnob->valueFromTextFunction = [](const String &text)
{
auto freq = text.removeCharacters("Hz").getDoubleValue();
return ((log10(freq / 20)) / 3);
};