added LFO, made Envelope generator actually do things.

master
Rachel Fae Fox (foxiepaws) 2019-10-31 01:50:01 -04:00
parent 16f7e0664f
commit 680053eb88
8 changed files with 232 additions and 15 deletions

View File

@ -17,4 +17,5 @@ typedef struct EngineState {
uint32_t t;
int sample_rate;
} EngineState;
typedef enum Waveform {_waveform_sine, _waveform_saw, _waveform_square} Waveform;
#endif

View File

@ -15,28 +15,29 @@
#include "../utils/envelope.h"
#include <stdlib.h>
#include <math.h>
typedef enum Waveform {_waveform_sine, _waveform_saw, _waveform_square} Waveform;
typedef struct Basic {
float freq;
Waveform shape;
int gate;
Envelope Env;
Envelope env;
float pwm;
float amp;
float(*process)(struct Basic *, EngineState*);
} Basic;
float basic_process(Basic *self, EngineState *t) {
float out;
self->env.gate = self->gate;
switch (self->shape) {
case _waveform_saw:
out = fmod((self->freq+1) * t->t / 44100,1.0);
out = (self->amp * self->env.process(&(self->env),t)) * fmod((self->freq+1) * t->t / 44100,1.0);
break;
case _waveform_sine:
out = sin(2 * M_PI * t->t * self->freq / 44100);
out = (self->amp * self->env.process(&(self->env),t)) * sin(2 * M_PI * t->t * self->freq / 44100);
break;
case _waveform_square:
out = fmod((self->freq+1) * t->t / 44100,1.0) > self->pwm;
out = (self->amp * self->env.process(&(self->env),t)) * fmod((self->freq+1) * t->t / 44100,1.0) > self->pwm;
break;
default:
out = 0.0F;
@ -47,8 +48,10 @@ float basic_process(Basic *self, EngineState *t) {
}
Basic* basic_new(Waveform w, Envelope e) {
Basic *b = malloc(sizeof(Envelope));
Basic *b = malloc(sizeof(Basic));
b->shape = w;
b->env = e;
b->amp = 0;
b->process = basic_process;
return b;
}

View File

@ -16,13 +16,13 @@
#ifndef _H_BASIC
#define _H_BASIC
typedef enum Waveform {_waveform_sine, _waveform_saw, _waveform_square} Waveform;
typedef struct Basic {
float freq;
Waveform shape;
int gate;
Envelope Env;
float pwm;
float amp;
float(*process)(struct Basic *, EngineState*);
} Basic;

View File

@ -23,6 +23,7 @@
#include "synths/basic.h"
#include "filters/svf.h"
#include "utils/envelope.h"
#include "utils/lfo.h"
@ -32,6 +33,7 @@
Basic saw;
SVF filt;
LFO lfo;
static EngineState data;
int mycallback( const void *input,
@ -84,9 +86,15 @@ int main(int argc, char**argv) {
}
Envelope b = *envelope_new();
saw = *basic_new(_waveform_square, b);
b.attack = 44100*2;
b.release = 44100/2;
b.ar = true;
b.sustain = true;
saw = *basic_new(_waveform_sine, b);
saw.amp = 1.0f;
saw.pwm = 0.5;
saw.freq = 440;
saw.gate = false;
filt = *svf_new(7000.0f, 0.5f);
//data.sample_rate=SAMPLE_RATE;
PaStream *stream;
@ -105,11 +113,9 @@ int main(int argc, char**argv) {
if( err != paNoError ) goto error;
/* start anything intersting */
saw.gate = true;
for (int freq = 7000; freq >= 60; freq = freq - 0.0001) {
filt.freq = freq;
usleep(500);
}
sleep(1);
sleep(5);
saw.gate = false;
sleep(5);
/* more crap */
error:

View File

@ -16,6 +16,8 @@
#include <stdbool.h>
#include <stdlib.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;
@ -24,18 +26,137 @@ typedef struct Envelope {
float sustain_level;
float max_level;
float min_level;
float level;
bool gate;
unsigned 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) {
return self->gate ? self->max_level : self-> min_level;
switch (self->envstate) {
case _e_off:
if (self->gate) {
self->t = 0;
self->envstate = _e_attack;
return envelope_process(self, t);
}
break;
case _e_attack:
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:
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:
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:
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;
}

View File

@ -16,6 +16,7 @@
#include <stdbool.h>
#include "../common.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;
@ -24,8 +25,13 @@ typedef struct Envelope {
float sustain_level;
float max_level;
float min_level;
float level;
bool gate;
float(*process)(struct Envelope *, EngineState *);
unsigned int t;
EnvState envstate;
bool ar;
bool sustain;
float(*process)(struct Envelope *,EngineState *);
} Envelope;

51
src/utils/lfo.c Normal file
View File

@ -0,0 +1,51 @@
/*
* Filename: lfo.c
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:08:31 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include "../common.h"
#include <stdlib.h>
#include <math.h>
typedef struct LFO {
float freq;
Waveform shape;
float pwm;
float(*process)(struct LFO *, EngineState*);
} LFO;
float lfo_process(LFO *self, EngineState *t) {
float out;
switch (self->shape) {
case _waveform_saw:
out = fmod((self->freq+1) * t->t / 44100,1.0);
break;
case _waveform_sine:
out = sin(2 * M_PI * t->t * self->freq / 44100);
break;
case _waveform_square:
out = fmod((self->freq+1) * t->t / 44100,1.0) > self->pwm;
break;
default:
out = 0.0F;
break;
}
return out;
}
LFO* lfo_new(Waveform w) {
LFO *b = malloc(sizeof(LFO));
b->shape = w;
b->process = lfo_process;
return b;
}

29
src/utils/lfo.h Normal file
View File

@ -0,0 +1,29 @@
/*
* Filename: lfo.h
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:08:31 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#ifndef _H_LFO
#define _H_LFO
#include "../common.h"
#include <stdlib.h>
#include <math.h>
typedef struct LFO {
float freq;
Waveform shape;
float pwm;
float(*process)(struct LFO *, EngineState*);
} LFO;
float lfo_process(LFO *self, EngineState *t);
LFO* lfo_new(Waveform w);
#endif