#if defined(STFU_MAIN) && !defined(STFU_ENVELOPE) #define STFU_ENVELOPE #include #include #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) { float d = stfu_get_envelope_duration(envelope); if (envelope.p >= d) /* Needs retriggering after that point */ return envelope; envelope.p += 1.0f / STFU_AUDIO_FRAME_RATE; 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; } #endif