expon
Overview
A (re)triggerable exponential line generator. Go from A to B in a exponential swell over some duration in seconds. When it reaches B, hold indefinitely until retriggered.
Note that values cannot be exactly 0.
Tangled files.
expon.h and expon.c. SK_EXPON_PRIV exposes the
sk_expon struct.
<<expon.h>>=
#ifndef SK_EXPON_H
#define SK_EXPON_H
#ifndef SKFLT
#define SKFLT float
#endif
<<typedefs>>
<<funcdefs>>
#ifdef SK_EXPON_PRIV
<<structs>>
#endif
#endif<<expon.c>>=
#include <math.h>
#define SK_EXPON_PRIV
#include "expon.h"
<<static_funcdefs>>
<<funcs>>Initialization
The expon state is managed in a struct called sk_expon,
and initialized  with sk_expon_init. The sampling rate
sr must be provided.
<<typedefs>>=
typedef struct sk_expon sk_expon;<<structs>>=
struct sk_expon {
    SKFLT a, dur, b;
    SKFLT val, incr;
    unsigned long sdur, stime;
    int init;
    int sr;
};<<funcdefs>>=
void sk_expon_init(sk_expon *e, int sr);<<funcs>>=
void sk_expon_init(sk_expon *e, int sr)
{
    sk_expon_a(e, 0.000001);
    sk_expon_b(e, 1);
    sk_expon_dur(e, 1);
    e->sr = sr;
    e->init = 1;
    expon_reinit(e);
}Setting Parameters
A and B
Go from value A to value B.
<<funcdefs>>=
void sk_expon_a(sk_expon *e, SKFLT val);
void sk_expon_b(sk_expon *e, SKFLT val);<<funcs>>=
void sk_expon_a(sk_expon *e, SKFLT val)
{
    if (val != 0) e->a = val;
}
void sk_expon_b(sk_expon *e, SKFLT val)
{
    if (val != 0) e->b = val;
}Duration
Set the duration of the segment with sk_expon_dur.
This is in units of seconds.
<<funcdefs>>=
void sk_expon_dur(sk_expon *e, SKFLT dur);<<funcs>>=
void sk_expon_dur(sk_expon *e, SKFLT dur)
{
    e->dur = dur;
}Calculating Multipler
The function expon_reinit will recalculate the multiplier
used to compute the exponential line.
<<static_funcdefs>>=
static void expon_reinit(sk_expon *e);<<funcs>>=
static void expon_reinit(sk_expon *e)
{
    SKFLT onedsr;
    e->stime = 0;
    e->sdur = e->dur * e->sr;
    onedsr = 1.0 / e->sr;
    if ((e->a * e->b) > 0.0) {
        e->incr = pow((SKFLT)(e->b / e->a), onedsr / e->dur);
    } else {
        e->incr = 1;
        e->val = e->a;
    }
    e->val = e->a;
}Computing a Sample
<<funcdefs>>=
SKFLT sk_expon_tick(sk_expon *e, SKFLT trig);<<funcs>>=
SKFLT sk_expon_tick(sk_expon *e, SKFLT trig)
{
    SKFLT out;
    out = 0;
    if (trig != 0) {
        expon_reinit(e);
        e->init = 0;
    }
    if (e->init) {
        out = 0;
    }
    if (e->stime < e->sdur) {
        SKFLT val = e->val;
        e->val *= e->incr;
        e->stime++;
        out = val;
    } else {
        out = e->b;
    }
    return out;
}