66 lines
1.8 KiB
C
66 lines
1.8 KiB
C
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "config.h"
|
|
#include "interp.c"
|
|
|
|
struct stfu_envelope stfu_pump_envelope(struct stfu_envelope envelope);
|
|
float stfu_get_envelope_duration(struct stfu_envelope envelope);
|
|
struct stfu_envelope stfu_trigger_envelope(struct stfu_envelope envelope);
|
|
|
|
/* Basic linear envelope generator with up to 16 points max.
|
|
* First virtual point is always silent (0.0f).
|
|
*
|
|
* todo: Sustain?
|
|
*/
|
|
struct stfu_envelope {
|
|
/* Initial volume is assumed from previous point */
|
|
struct stfu_envelope_point {
|
|
float dur, vol;
|
|
} pnts[16];
|
|
uint8_t n_pnts;
|
|
float p, v;
|
|
} stfu_init_envelope(struct stfu_envelope_point *points, uint8_t n_points) {
|
|
struct stfu_envelope r = {0};
|
|
memcpy(&r.pnts, points, sizeof(struct stfu_envelope_point) * n_points);
|
|
r.n_pnts = n_points;
|
|
r = stfu_trigger_envelope(r);
|
|
return r;
|
|
}
|
|
|
|
struct stfu_envelope stfu_pump_envelope(struct stfu_envelope envelope) {
|
|
envelope.p += 1.0f / STFU_AUDIO_FRAME_RATE;
|
|
float d = stfu_get_envelope_duration(envelope);
|
|
if (envelope.p >= d)
|
|
/* Needs retriggering after that point */
|
|
return envelope;
|
|
|
|
float p = 0.0f;
|
|
for (uint8_t i = 0;; ++i) {
|
|
float ends = p + envelope.pnts[i].dur;
|
|
if (envelope.p < ends) {
|
|
float pv = i == 0 ? 0.0f : envelope.pnts[i - 1].vol;
|
|
envelope.v = stfu_linear_interpolate(p, pv, ends, envelope.pnts[i].vol,
|
|
envelope.p);
|
|
break;
|
|
}
|
|
p += envelope.pnts[i].dur;
|
|
}
|
|
|
|
return envelope;
|
|
}
|
|
|
|
float stfu_get_envelope_duration(struct stfu_envelope envelope) {
|
|
float r = 0.0f;
|
|
for (uint8_t i = 0; i < envelope.n_pnts; ++i) {
|
|
r += envelope.pnts[i].dur;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
struct stfu_envelope stfu_trigger_envelope(struct stfu_envelope envelope) {
|
|
envelope.p = 0.0f;
|
|
envelope.v = 0.0f;
|
|
return envelope;
|
|
}
|