usynth

simple midi synth for sndio
git clone git://nsmpr.xyz/usynth.git
Log | Files | Refs

commit 2cb921c89ee168d42e552f1cd438ddc3eb2d3741
parent 428fdf59a82f5b9315caaaaca136292dfc0f00d1
Author: zavok <an2qzavok@gmail.com>
Date:   Mon, 30 Dec 2019 00:25:19 +0300

working on programmability

Diffstat:
MMakefile | 2+-
Mfm.c | 127++++++++++++++++++++++++++++++++-----------------------------------------------
Mfm.h | 26++++++++++++++++++++++++++
Mmachine.c | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmachine.h | 31+++++++++++++++++++++++++++++++
Moperator.c | 2+-
Moperator.h | 2+-
Mtune.h | 24++++++++++++------------
Musynth.c | 1+
9 files changed, 280 insertions(+), 90 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,7 +5,7 @@ MANDIR = $(PREFIX)/share/man/man1 BIN = usynth MAN = $(BIN).1 -OBJ = $(BIN:=.o) audio.o fm.o midi.o \ +OBJ = $(BIN:=.o) audio.o fm.o midi.o\ machine.o operator.o wavetable.o LDFLAGS=-lsndio diff --git a/fm.c b/fm.c @@ -1,90 +1,18 @@ #include <stdio.h> #include <stdlib.h> -#include "fm.h" #include "operator.h" +#include "fm.h" #include "wavetable.h" #include "tune.h" size_t c; int16_t vol; -struct voice{ - int id; - uint8_t channel; - uint8_t note; - uint8_t velocity; - uint8_t pressure; - struct op_state op[2]; -}; - -struct channel{ - uint8_t program; - uint8_t pressure; - uint8_t control[128]; - int16_t pitch; - -}; - -struct channel fm_channels[16]; -struct voice fm_voices[32]; - -int64_t fm_synth(struct voice*); -int16_t fm_mix(void); - -int64_t -fm_synth(struct voice *v) -{ - struct channel *ch; - size_t dt; - int64_t out; - if (v->id < 0) return 0; - if (v->velocity == 0) return 0; - ch = &fm_channels[v->channel]; - dt = (double)(0xff00)*(tune[v->note%12] * (1 << (v->note/12)))/44100.0; - out = op_fetch(&v->op[1], dt*2, 0); - out = op_fetch(&v->op[0], dt*3, out) * v->velocity / 0x7f; - return out; -} - -int64_t -fm_mix_channel(int n) -{ - struct voice *vs; - int64_t out; - int i; - out = 0; - vs = fm_voices; - for (i = 0; i < 32; i++) if (vs[i].channel == n) out += fm_synth(&vs[i]); - out = out * fm_channels[n].control[7] / 0x7f; - return out; -} - -int16_t -fm_mix(void) -{ - int64_t out; - int i; - c++; - out = 0; - for (i=0; i<16; i++) out += fm_mix_channel(i); - if (out > 0x7fff) out = 0x7fff; - if (out < -0x7fff) out = -0x7fff; - return out; -} - -void -fm_fillbuf(int16_t *buf, size_t nsamples) -{ - size_t i; - for (i=0; i < nsamples; i+=2){ - buf[i] = buf[i+1] = fm_mix(); - } -} void fm_note_on(uint8_t *mm) { int i, nmin, nmax; - struct voice *v; + Voice *v; nmin = 0; nmax = 0; for (i=0;i<32;i++){ @@ -137,10 +65,59 @@ fm_init(void) int i; wt_init(); for (i=0; i<16; i++){ - struct channel *ch; + Channel *ch; ch = &fm_channels[i]; ch->control[7]=0x7f; ch->program = i; } } +int64_t +fm_synth(Voice *v) +{ + Channel *ch; + size_t dt; + int64_t out; + if (v->id < 0) return 0; + if (v->velocity == 0) return 0; + ch = &fm_channels[v->channel]; + dt = (double)(0xff00)*(tune[v->note%12] * (1 << (v->note/12)))/44100.0; + out = op_fetch(&v->op[1], dt*2, 0); + out = op_fetch(&v->op[0], dt*3, out) * v->velocity / 0x7f; + return out; +} + +int64_t +fm_mix_channel(int n) +{ + Voice *vs; + int64_t out; + int i; + out = 0; + vs = fm_voices; + for (i = 0; i < 32; i++) if (vs[i].channel == n) out += fm_synth(&vs[i]); + out = out * fm_channels[n].control[7] / 0x7f; + return out; +} + +int16_t +fm_mix(void) +{ + int64_t out; + int i; + c++; + out = 0; + for (i=0; i<16; i++) out += fm_mix_channel(i); + if (out > 0x7fff) out = 0x7fff; + if (out < -0x7fff) out = -0x7fff; + return out; +} + +void +fm_fillbuf(int16_t *buf, size_t nsamples) +{ + size_t i; + for (i=0; i < nsamples; i+=2){ + buf[i] = buf[i+1] = fm_mix(); + } +} diff --git a/fm.h b/fm.h @@ -1,3 +1,29 @@ +typedef struct Voice Voice; +struct Voice { + int id; + uint8_t channel; + uint8_t note; + uint8_t velocity; + uint8_t pressure; + struct op_state op[2]; +}; + +typedef struct Channel Channel; +struct Channel { + uint8_t program; + uint8_t pressure; + uint8_t control[128]; + int16_t pitch; +}; + +Channel fm_channels[16]; +Voice fm_voices[32]; + +int64_t fm_synth(Voice*); +int16_t fm_mix(void); + + + void fm_fillbuf(int16_t*, size_t); void fm_init(void); void fm_note_on(uint8_t*); diff --git a/machine.c b/machine.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <stdint.h> + +#include "operator.h" +#include "fm.h" +#include "tune.h" + +#include "machine.h" + + +typedef void (*instruction)(VM*); + + +void +i_halt(VM *vm) +{ + vm->halted = 1; +} + + +void +i_lit(VM *vm) +{ + vm->stack[vm->sp] = vm->prog[vm->pc]; + vm->sp++; + vm->pc++; +} + + +void +i_fetch(VM *vm) +{ + vm->stack[vm->sp-1] = vm->prog[vm->stack[vm->sp-1]]; +} + + +void +i_chan(VM *vm) +{ + switch (vm->stack[vm->sp-1]) { + case 0x80: + vm->stack[vm->sp-1] = vm->channel->pressure; + case 0x81: + vm->stack[vm->sp-1] = vm->channel->pitch; + default: + vm->stack[vm->sp-1] = vm->channel->control[vm->stack[vm->sp-1]]; + } +} + + +void +i_voic(VM *vm) +{ + switch (vm->stack[vm->sp-1]) { + case 0x00: + vm->stack[vm->sp-1] = vm->voice->note; + break; + case 0x01: + vm->stack[vm->sp-1] = vm->voice->velocity; + break; + case 0x02: + vm->stack[vm->sp-1] = vm->voice->pressure; + break; + } +} + + +void +i_op(VM *vm) +{ + int16_t opn, dp, mod; + opn = vm->stack[vm->sp-1]; + dp = vm->stack[vm->sp-2]; + mod = vm->stack[vm->sp-3]; + vm->stack[vm->sp-3] = op_fetch(&vm->voice->op[opn], dp, mod); + vm->sp -= 2; +} + + +void +i_dup(VM *vm) +{ + vm->stack[vm->sp] = vm->stack[vm->sp-1]; + vm->sp++; +} + + +void +i_drop(VM *vm) +{ + vm->sp--; +} + + +void +i_swap(VM *vm) +{ + int16_t b; + b = vm->stack[vm->sp-1]; + vm->stack[vm->sp-1] = vm->stack[vm->sp-2]; + vm->stack[vm->sp-2] = b; +} + + +void +i_add(VM *vm) +{ + vm->stack[vm->sp-2] += vm->stack[vm->sp-2]; + vm->sp--; +} + + +instruction instructions[128] = { + i_halt, + i_lit, + i_fetch, + i_chan, + i_voic, + i_op, + i_dup, + i_drop, + i_swap, + i_add, +}; + +void +vm_set(VM *vm, Channel *channel, Voice *voice) +{ + int16_t *sprog = { + I_LIT, 0x00, + I_LIT, 0x00, I_VOIC, + I_LIT, 0x00, + I_OP, + I_HALT + }; + vm->voice = voice; + vm->channel = channel; + vm->prog = sprog; +} + +int16_t +vm_run(VM *vm) +{ + instruction *inst; + vm->halted = 0; + vm->pc = 0; + vm->sp = 0; + while (vm->halted == 0) { + inst = vm->prog[vm->pc]; + vm->pc++; + inst(vm); + } + return vm->stack[vm->sp-1]; +} +\ No newline at end of file diff --git a/machine.h b/machine.h @@ -0,0 +1,30 @@ +enum { + I_HALT = 0, + /* * * * * */ + I_LIT, + I_FETCH, + I_CHAN, + I_VOIC, + I_OP, + /* * * * * */ + I_DUP, + I_DROP, + I_SWAP, + /* * * * * */ + I_ADD, +}; + +#define SDEPTH 256 + +typedef struct VM VM; +struct VM { + int halted; + int16_t stack[SDEPTH]; + int16_t sp; + int16_t *prog; + int16_t pc; + Voice *voice; + Channel *channel; +}; + +void vm_set(VM*, Channel*, Voice*); +\ No newline at end of file diff --git a/operator.c b/operator.c @@ -2,7 +2,7 @@ #include <stdint.h> #include "operator.h" -int64_t +int16_t op_fetch(struct op_state *op, size_t dp, int16_t mod) { uint8_t pos; diff --git a/operator.h b/operator.h @@ -9,5 +9,5 @@ struct op_state { size_t p; }; -int64_t op_fetch(struct op_state*, size_t, int16_t); +int16_t op_fetch(struct op_state*, size_t, int16_t); diff --git a/tune.h b/tune.h @@ -1,15 +1,15 @@ double tune[]={ -16.35, //C 36 -17.32, //C# 37 -18.35, //D 38 -19.45, //D# 39 -20.60, //E 40 -21.83, //F 41 -23.12, //F# 42 -24.50, //G 43 -25.96, //G# 44 -27.50, //A 45 - 440 - 100 -29.14, //A# 46 -30.87, //B 47 +16.35, // C 36 +17.32, // C# 37 +18.35, // D 38 +19.45, // D# 39 +20.60, // E 40 +21.83, // F 41 +23.12, // F# 42 +24.50, // G 43 +25.96, // G# 44 +27.50, // A 45 - 440 - 100 +29.14, // A# 46 +30.87, // B 47 }; diff --git a/usynth.c b/usynth.c @@ -5,6 +5,7 @@ #include <sndio.h> #include "midi.h" #include "audio.h" +#include "operator.h" #include "fm.h" struct sio_hdl *sh;