Smoother
Overview.
smoother is a one-pole smoothing filter.
The smoothing filter, sometimes called a portamento filter is an indispensible tool for a sound designer. Mostly used to smooth out steppy control signals, smoothing filters are a particular kind of one-pole recurisve IIR filter, usually with parametric smoothing control amount. Signals that go through smoothing filters get a distinct syruppy responsiveness added to it (especially if you set the smoothing amount way up!).
While smoothing filters usually have an association with smoothing out control signals from things like MIDI CC knobs, there are a few other useful things you can do with them. If you put audio-rate signal with note values through it, you get a really lovely legato portamento effect. A gate signal put through a smoothing filter produces an envelope with the most beautiful exponential curves perfect for short percusive sounds.
Tangled Files
smoother.c and smoother.h. SK_SMOOTHER_PRIV exposes the
struct.
#ifndef SK_SMOOTHER_H
#define SK_SMOOTHER_H
#ifndef SKFLT
#define SKFLT float
#endif
<<typedefs>>
#ifdef SK_SMOOTHER_PRIV
<<structs>>
#endif
<<funcdefs>>
#endif
#include <math.h>
#define SK_SMOOTHER_PRIV
#include "smoother.h"
<<funcs>>
The Equation
The one pole smoothing filter employs the following difference equation:
Where
is
and
is
. The
variables
and
are the smoothing half time and
sampling rate, respectively.
is the input signal.
Struct Initialized
sk_smoother is the struct.
typedef struct sk_smoother sk_smoother;
It is initalized with sk_smoother_init.
void sk_smoother_init(sk_smoother *s, int sr);
void sk_smoother_init(sk_smoother *s, int sr)
{
<<init>>
}
Struct Contents
struct sk_smoother {
SKFLT smooth;
SKFLT a1, b0, y0, psmooth;
SKFLT onedsr;
};
smooth is the smoothing parameter, with psmooth being
a cached variable that is used to check when the smooth
parameter has changed.
smooth is set to a reasonable default value of 10ms.
psmooth is set to a different (and also invalid) value of
-1. This will caused the filter coefficients to be
calculated when the compute function is called for
the first time.
s->smooth = 0.01;
s->psmooth = -1;
a1 and b0 are filter coefficients computed from the
smooth time parameter, with y0 being the filter memory.
s->a1 = 0;
s->b0 = 0;
s->y0 = 0;
onedsr is the constant 1.0/sr. This might not actually
be all that helpful since a divide operation is still
happening. Hmm.
s->onedsr = 1.0 / sr;
Setting Smoothing Time
Set the smoothinb time parameter with sk_smoother_time.
void sk_smoother_time(sk_smoother *s, SKFLT t);
void sk_smoother_time(sk_smoother *s, SKFLT t)
{
s->smooth = t;
}
The smoothing time, also known as the half time, is the amount of time (in seconds) it takes to go to halfway to the trajectory value.
Resetting The Filter
sk_smoother_reset will reset the smoothing filter, causing
it to snap directly to the value in.
void sk_smoother_reset(sk_smoother *s, SKFLT in);
void sk_smoother_reset(sk_smoother *s, SKFLT in)
{
s->y0 = in;
}
Compute
Compute a sample with sk_smoother_tick. This expects an
input signal, and returns a single output signal.
SKFLT sk_smoother_tick(sk_smoother *s, SKFLT in);
This is implementing the equation displayed above. Parameter caching is used so that filter coefficients are only updated when the smoothing amount updates. Doing this shaves off a few redundant CPU instructions.
SKFLT sk_smoother_tick(sk_smoother *s, SKFLT in)
{
SKFLT out;
if (s->psmooth != s->smooth) {
s->a1 = pow(0.5, s->onedsr/s->smooth);
s->b0 = 1.0 - s->a1;
s->psmooth = s->smooth;
}
s->y0 = s->b0 * in + s->a1 * s->y0;
out = s->y0;
return out;
}