added LFO, made Envelope generator actually do things.
parent
16f7e0664f
commit
680053eb88
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
Loading…
Reference in New Issue