Initial commit
commit
de368d0ee3
|
@ -0,0 +1,3 @@
|
|||
bin/
|
||||
*.o
|
||||
*.gch
|
|
@ -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}
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 ) );
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue