Initial commit

master
Rachel Fae Fox (foxiepaws) 2019-10-30 20:09:28 -04:00
commit de368d0ee3
10 changed files with 474 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
bin/
*.o
*.gch

50
Makefile Normal file
View File

@ -0,0 +1,50 @@
CC ?= gcc
SRCDIR ?= src
INCDIR += -I${SRCDIR}
OBJDIR ?= src
BINDIR ?= bin
INSTALLDIR ?= /usr/local/bin
TARGET ?= synththing
CFLAGS += -std=c99
CFLAGS += `pkg-config --cflags portaudio-2.0`
LDFLAGS += `pkg-config --libs portaudio-2.0`
UNAME=$(shell uname -s)
ifeq (${UNAME},FreeBSD)
INCDIR += -I/sys/
endif
SHELL=/bin/sh
SRC = $(wildcard ${SRCDIR}/*.c ${SRCDIR}/*/*.c)
OBJ = ${SRC:${SRCDIR}/%.c=${OBJDIR}/%.o}
all: synththing
${OBJ}: $(OBJDIR)/%.o : $(SRCDIR)/%.c
@echo CC $<
${CC} -o $@ ${INCDIR} -c ${CFLAGS} ${DEFINES} $<
synththing: ${OBJ}
@echo CC -o ${BINDIR}/${TARGET}
@mkdir -p ${BINDIR}
${CC} -I${INCDIR} -o ${BINDIR}/${TARGET} ${OBJ} ${LDFLAGS} ${CFLAGS} ${DEFINES}
clean:
@echo cleaning
@rm -f syswriter ${OBJ}
remove: clean
@echo deleting binary
@rm -f ${BINDIR}/${TARGET}
@rm -r ${BINDIR}
install: synththing
mkdir -p ${INSTALLDIR}
cp ${BINDIR}/${TARGET} ${INSTALLDIR}/${TARGET}
chmod 4555 ${INSTALLDIR}/${TARGET}

20
src/common.h Normal file
View File

@ -0,0 +1,20 @@
/*
* Filename: common.h
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:12:37 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#ifndef _H_COMMON
#define _H_COMMON
#include <stdint.h>
typedef struct EngineState {
uint32_t t;
int sample_rate;
} EngineState;
#endif

83
src/filters/svf.c Normal file
View File

@ -0,0 +1,83 @@
/*
* Filename: svf.c
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 00:00:40 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#define M_PI 3.14159265358979323846
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a<b?a:b)
typedef enum DBO { _6dbo, _12dbo, _18dbo, _24dbo, _36dbo = 6, _48dbo } DBO;
typedef struct SVF {
float notch;
float low;
float high;
float band;
float drive;
float freq;
float q;
DBO dbo;
float out;
float(*damp)(struct SVF*);
float(*process)(struct SVF*,float in);
void(*reset)(struct SVF*);
} SVF;
float svf_damp(SVF *self) {
float freq = 2.0*sin(M_PI * MIN(0.25, self->freq/(44100*2)));
return MIN(2.0 * (1.0 - powf(self->q,0.25)), MIN(2.0, 2.0/freq - freq * 0.5));
// return MIN(2.0 * (1.0 - pow(self->q,0.25)), MIN(2.0, (2.0/freq - freq * 0.5)));
}
float svf_process(SVF *self,float in) {
float a = in;
float freq = 2.0*sin(M_PI * MIN(0.25, self->freq/(44100*2)));
float damp = self->damp(self);
//printf("prefilt status: freq: %f, drive: %f, damp: %f, in: %f, low: %f, notch: %f, high: %f, band: %f\n",self->freq,self->drive, damp,in, self->low, self->notch, self->high, self->band);
for (unsigned int i = 0; i <= self->dbo; i++) {
self->notch = a - damp * self->band;
self->low = self->low + freq * self->band;
self->high = self->notch - self->low;
self->band = freq * self->high + self->band - self->drive * self->band * self->band * self->band;
a = self->low;
}
self->out = a;
//printf("postfilt status: freq: %f, drive: %f, damp: %f, in: %f, low: %f, notch: %f, high: %f, band: %f\n",self->freq,self->drive, damp,in, self->low, self->notch, self->high, self->band);
return self->out;
}
void svf_reset(SVF* self){
self->notch = 0;
self->low = 0;
self->band = 0;
self->high = 0;
self->out = 0;
}
SVF* svf_new(float freq,float q,float drive) {
SVF *self = malloc(sizeof(SVF));
self->freq = freq;
self->q = q;
self->drive = drive;
self->dbo = _12dbo;
// functions.
self->damp = svf_damp;
self->process = svf_process;
self->reset = svf_reset;
self->reset(self);
return self;
}

42
src/filters/svf.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Filename: svf.c
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 00:00:40 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#ifndef _H_FILTERS_SVF
#define _H_FILTERS_SVF
#include <math.h>
#include <stdlib.h>
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
typedef enum DBO { _6dbo, _12dbo, _18dbo, _24dbo, _36dbo = 6, _48dbo } DBO;
typedef struct SVF {
float notch;
float low;
float high;
float band;
float drive;
float freq;
float q;
DBO dbo;
float out;
float(*damp)(struct SVF*);
float(*process)(struct SVF*,float in);
void(*reset)(struct SVF*);
} SVF;
float svf_damp(SVF *self);
float svf_process(SVF *self,float in);
void svf_reset(SVF* self);
SVF* svf_new(float freq,float q,float drive);
#endif

48
src/synths/basic.c Normal file
View File

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

30
src/synths/basic.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Filename: basic.h
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:37:08 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include "../common.h"
#include "../utils/envelope.h"
#ifndef _H_BASIC
#define _H_BASIC
typedef enum Waveform {_waveform_sine, _waveform_saw} Waveform;
typedef struct Basic {
float freq;
Waveform shape;
int gate;
Envelope Env;
float(*process)(struct Basic *, EngineState*);
} Basic;
float basic_process(Basic *self, EngineState *t);
Basic* basic_new(Waveform w, Envelope e);
#endif

120
src/synththing.c Normal file
View File

@ -0,0 +1,120 @@
/*
* Filename: synththing.c
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:52:12 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include <math.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <stdbool.h>
#include <unistd.h>
#include "common.h"
#include "synths/basic.h"
#include "filters/svf.h"
#include "utils/envelope.h"
#define SAMPLE_RATE (44100)
Basic saw;
SVF filt;
static EngineState data;
int mycallback( const void *input,
void *output,
unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData ) {
EngineState *data = (EngineState*)userData;
float *out = (float*) output;
unsigned int i;
for( i=0; i<frameCount; i++ )
{
//filt.process(&filt, (saw.process(&saw,data)));
//float a = filt.low;
float a = 0.5 * saw.process(&saw,data);
filt.process(&filt,a);
a = filt.low;
*out++ = a;
*out++ = a;
data->t++;
}
return 0;
}
int main(int argc, char**argv) {
/* portaudio boilerplate crap */
PaError err;
err = Pa_Initialize();
const PaDeviceInfo *deviceInfo;
int numDevices;
numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
{
printf( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
for(int i=0; i<numDevices; i++ )
{
deviceInfo = Pa_GetDeviceInfo( i );
printf("name: %s\n"
"max channels\tin: %d\tout: %d\n"
"samplerate: %f",deviceInfo->name,deviceInfo->maxInputChannels,deviceInfo->maxOutputChannels,deviceInfo->defaultSampleRate);
}
Envelope b = *envelope_new();
saw = *basic_new(_waveform_saw, b);
saw.freq = 440;
filt = *svf_new(7000.0f, 0.99f, 0.000001f);
//data.sample_rate=SAMPLE_RATE;
PaStream *stream;
/* Open an audio I/O stream. */
err = Pa_OpenDefaultStream( &stream,
0,
2,
paFloat32,
SAMPLE_RATE,
256,
mycallback,
&data );
if( err != paNoError ) goto error;
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
/* start anything intersting */
saw.gate = true;
for (int freq = 7000; freq >= 60; freq--) {
filt.freq = freq;
usleep(500);
}
sleep(1);
/* more crap */
error:
printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
err = Pa_Terminate();
if( err != paNoError )
printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) );
}

43
src/utils/envelope.c Normal file
View File

@ -0,0 +1,43 @@
/*
* Filename: envelope.h
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:15:02 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#include "../common.h"
#ifndef _H_ENVELOPE
#define _H_ENVELOPE
#include <stdbool.h>
#include <stdlib.h>
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;
bool gate;
float(*process)(struct Envelope *,EngineState *);
} Envelope;
float envelope_process(Envelope *self, EngineState *t) {
return self->gate ? self->max_level : self-> min_level;
}
Envelope* envelope_new() {
Envelope *e = malloc(sizeof(Envelope));
e->process = envelope_process;
e->max_level = 1.0f;
e->min_level = 0.0f;
return e;
}
#endif

35
src/utils/envelope.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Filename: envelope.h
*
* Description:
*
*
* Version:
* Created: Wed Oct 30 17:15:02 2019
* Revision: None
* Author: Rachel Fae Fox (foxiepaws),fox@foxiepa.ws
*
*/
#ifndef _H_ENVELOPE
#define _H_ENVELOPE
#include <stdbool.h>
#include "../common.h"
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;
bool gate;
float(*process)(struct Envelope *, EngineState *);
} Envelope;
float envelope_process(Envelope *self, EngineState *t);
Envelope* envelope_new();
#endif