167 lines
4.0 KiB
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;
|
|
}
|