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; uint32_t t;
int sample_rate; int sample_rate;
} EngineState; } EngineState;
typedef enum Waveform {_waveform_sine, _waveform_saw, _waveform_square} Waveform;
#endif #endif

View File

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

View File

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

View File

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

View File

@ -16,6 +16,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.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 { typedef struct Envelope {
// these values are in samples. // these values are in samples.
unsigned int attack; unsigned int attack;
@ -24,18 +26,137 @@ typedef struct Envelope {
float sustain_level; float sustain_level;
float max_level; float max_level;
float min_level; float min_level;
float level;
bool gate; bool gate;
unsigned int t;
EnvState envstate;
bool ar;
bool sustain;
float(*process)(struct Envelope *,EngineState *); float(*process)(struct Envelope *,EngineState *);
} Envelope; } 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) { 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* envelope_new() {
Envelope *e = malloc(sizeof(Envelope)); Envelope *e = malloc(sizeof(Envelope));
e->process = envelope_process; e->process = envelope_process;
e->envstate = _e_off;
e->t = 0;
e->max_level = 1.0f; e->max_level = 1.0f;
e->sustain_level = 1.0f;
e->min_level = 0.0f; e->min_level = 0.0f;
return e; return e;
} }

View File

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