synththing/src/utils/envelope.c

167 lines
4.0 KiB
C

/*
* Filename: envelope.c
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:15:02 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include "../common.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
typedef enum EnvState {_e_off,_e_attack, _e_attackrelease, _e_decay, _e_sustain,_e_release, _e_finished} EnvState;
typedef struct Envelope {
// these values are in samples.
unsigned int attack;
unsigned int decay;
unsigned int release;
float sustain_level;
float max_level;
float min_level;
float level;
bool gate;
unsigned long int t;
EnvState envstate;
bool ar;
bool sustain;
float(*process)(struct Envelope *,EngineState *);
} Envelope;
/*
if (self->ar) {
float diff = (self->max_level - self->min_level) / (float) self->attack;
if (self->t <= self->attack && self->gate) {
self->level = self->state * diff;
self->state++;
} else if (self->sustain && self->gate) {
self->level = self->max_level;
} else if (self->state < self->attack && self->state > 0){
self->level = self->level - diff;
self->state--;
} else if ((self->state - self->attack) <= self->release) {
self->level = self->max_level - ((self->state - self->attack) * diff);
self->state++;
}
}
return self->level;
return self->gate ? self->max_level : self-> min_level;
*/
float envelope_process(Envelope *self, EngineState *t) {
switch (self->envstate) {
case _e_off:
//printf("_off\n");
if (self->gate) {
self->t = 0;
self->envstate = _e_attack;
return envelope_process(self, t);
}
break;
case _e_attack:
//printf("_attack: %i\n", self->t);
if (self->gate) {
if ( self->t < self->attack ) {
float stepsize = (self->max_level - self->min_level) / self->attack;
self->t++;
return self->t * stepsize;
} else {
if (self->ar) {
self->t = 0;
self->envstate = _e_sustain;
return self->max_level;
} else {
self->t = 0;
self->envstate = _e_decay;
return self->max_level;
}
}
} else {
self->envstate = _e_attackrelease;
return envelope_process(self, t);
}
break;
case _e_decay:
// printf("_decay: %i\n", self->t);
if (self->gate) {
if (self->t < self->decay) {
float stepsize = (self->max_level - self->sustain_level) / self->decay;
self->t++;
return (self->max_level - (self->t * stepsize));
} else {
self->envstate = _e_sustain;
return self->sustain_level;
}
} else {
self->envstate = _e_attackrelease;
return envelope_process(self, t);
}
break;
case _e_sustain:
//printf("_sustain\n", self->t);
if (!self->sustain) {
self->envstate = _e_release;
self->t = 0;
return envelope_process(self, t);
}
if (!self->gate) {
self->t = 0;
self->envstate = _e_release;
if (self->ar)
return self->max_level;
return self->sustain_level;
}
if (self->ar)
return self->max_level;
return self->sustain_level;
break;
case _e_release:
// printf("_release: %i\n", self->t);
if (self->gate && self->sustain) {
// reset envelope.
self->envstate=_e_off;
return envelope_process(self,t);
}
if (self->t < self->release) {
float stepsize = ((self->ar ? self->max_level : self->sustain_level) - self->min_level) / self->release;
self->t++;
return (self->ar ? self->max_level : self->sustain_level) - (stepsize * self->t);
} else {
self->envstate = _e_off;
return self->min_level;
}
break;
case _e_attackrelease:
if (self->gate) {
//reset envelope
self->envstate=_e_off;
return envelope_process(self,t);
}
return 0.0f;
break;
}
return 0.0f; // if this is reached, something went wrong or an unhandled function was used.
}
Envelope* envelope_new() {
Envelope *e = malloc(sizeof(Envelope));
e->process = envelope_process;
e->envstate = _e_off;
e->t = 0;
e->max_level = 1.0f;
e->sustain_level = 1.0f;
e->min_level = 0.0f;
return e;
}