usynth

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

commit 3c2f6c0e4068f93d6d1efe833633fee7705490c8
parent 9129563bedd9b5a7833d910e682ebea66a119e45
Author: zavok <an2qzavok@gmail.com>
Date:   Wed,  1 Jan 2020 21:54:40 +0300

programmability is almost done

Diffstat:
Mfm.c | 97++++++++++++++++++++++++++++---------------------------------------------------
Mfm.h | 9+++++----
Mmachine.c | 205+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mmachine.h | 18++++++++++++++----
Mmidi.h | 1+
Musynth.c | 5+++--
Mwavetable.c | 4++--
7 files changed, 180 insertions(+), 159 deletions(-)

diff --git a/fm.c b/fm.c @@ -1,48 +1,51 @@ #include <stdio.h> #include <stdlib.h> #include "operator.h" -#include "fm.h" #include "wavetable.h" -#include "tune.h" +#include "fm.h" +#include "machine.h" -size_t c; int16_t vol; +int16_t +clip(int64_t in) +{ + if (in > 0x7fff) return 0x7fff; + if (in < -0x7fff) return -0x7fff; + return in; +} + void -fm_note_on(uint8_t *mm) +fm_key_on(uint8_t *mm) { - int i, nmin, nmax; + int i; + int nmin, nmax; Voice *v; - nmin = 0; - nmax = 0; - for (i=0;i<32;i++){ + nmin = nmax = 0; + for (i = 0; i < 32; i++) { if (fm_voices[i].id<fm_voices[nmin].id) nmin = i; if (fm_voices[i].id>fm_voices[nmax].id) nmax = i; } v = &fm_voices[nmin]; - v->op[0].p = 0; - v->op[0].conf.waveform = wavetable[1]; - v->op[0].conf.gain = 0xff; - v->op[0].conf.freq_multiplier = 1; - v->op[1].p = 0; - v->op[1].conf.waveform = wavetable[1]; - v->op[1].conf.gain = 0xff; - v->op[1].conf.freq_multiplier = 1; - v->id = nmax+1; - v->channel = mm[1]; - v->note = mm[2]; - v->velocity = mm[3]; - v->pressure = 0; + v->id = fm_voices[nmax].id+1; + //v->channel = mm[1]; + //v->key = mm[2]; + //v->velocity = mm[3]; + vms[nmin].status = 1; + vms[nmin].key = mm[2]; + //v->pressure = 0; + vm_set(&vms[nmin], 0, 0); } void -fm_note_off(uint8_t *mm) +fm_key_off(uint8_t *mm) { int i; for (i=0; i<32; i++){ - if (fm_voices[i].note == mm[2]){ - fm_voices[i].velocity = mm[3]; - fm_voices[i].id = -1; + if (vms[i].key == mm[2]){ + //fm_voices[i].velocity = mm[3]; + vms[i].status = 0; + fm_voices[i].id = 0; } } } @@ -62,55 +65,22 @@ fm_prog_change(uint8_t *mm) void fm_init(void) { - int i; + Channel *ch; wt_init(); - for (i=0; i<16; i++){ - Channel *ch; - ch = &fm_channels[i]; + for (ch=fm_channels; ch<fm_channels+16; ch++){ ch->control[7]=0x7f; - ch->program = i; + ch->program = ch - fm_channels; } } -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; + for (i=0; i<32; i++) out += vm_run(&vms[i]); + return clip(out); } void @@ -121,3 +91,4 @@ fm_fillbuf(int16_t *buf, size_t nsamples) buf[i] = buf[i+1] = fm_mix(); } } + diff --git a/fm.h b/fm.h @@ -1,6 +1,8 @@ typedef struct Voice Voice; struct Voice { int id; + int status; + uint8_t key; uint8_t channel; uint8_t note; uint8_t velocity; @@ -22,11 +24,10 @@ 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*); -void fm_note_off(uint8_t*); +void fm_key_on(uint8_t*); +void fm_key_off(uint8_t*); void fm_ctl_change(uint8_t*); void fm_prog_change(uint8_t*); + diff --git a/machine.c b/machine.c @@ -1,98 +1,170 @@ +#include <stdlib.h> #include <stdio.h> #include <stdint.h> - #include "operator.h" #include "fm.h" +#include "wavetable.h" #include "machine.h" +#include "tune.h" + +typedef void (*instruction)(VM*, uint8_t); + +void vm_fatal(VM*, char*); +void vm_adsr(VM*); + +void i_halt(VM*, uint8_t); +void i_lit(VM*, uint8_t); +void i_fetch(VM*, uint8_t); +void i_op(VM*, uint8_t); +void i_adsr(VM*, uint8_t); +void i_wave(VM*, uint8_t); +void i_note(VM*, uint8_t); +void i_2dt(VM*, uint8_t); +void i_dup(VM*, uint8_t); +void i_drop(VM*, uint8_t); +void i_swap(VM*, uint8_t); +void i_add(VM*, uint8_t); +void i_comb(VM*, uint8_t); +instruction instructions[128] = { + [I_HALT] = i_halt, + [I_LIT] = i_lit, + [I_FETCH] = i_fetch, + [I_OP] = i_op, + [I_ADSR] = i_adsr, + [I_WAVE] = i_wave, + [I_NOTE] = i_note, + [I_2DT] = i_2dt, + [I_DUP] = i_dup, + [I_DROP] = i_drop, + [I_SWAP] = i_swap, + [I_ADD] = i_add, + [I_COMB] = i_comb, +}; + +int16_t sprog[] = { + I_NOTE, + I_2DT, + I_OP|0x0000, + I_WAVE|0x0000, + I_ADSR|0x0000, + I_COMB, + I_HALT +}; + +void +vm_set(VM *vm, Channel *channel, Voice *voice) +{ + vm->prog = sprog; +} + +int16_t +vm_run(VM *vm) +{ + instruction inst; + if (vm->prog == 0) return 0; + vm->halted = 0; + vm->pc = 0; + vm->sp = 0; + vm_adsr(vm); + while (vm->halted == 0) { + inst = instructions[0xff & vm->prog[vm->pc]]; + if (inst == 0) + vm_fatal(vm, "illegal instruction"); + vm->pc++; + inst(vm, vm->prog[vm->pc]>>8); + } + return vm->stack[vm->sp-1]; +} -typedef void (*instruction)(VM*); +void +vm_adsr(VM *vm) +{ + int i; + for (i=0; i<16; i++) { + vm->adsr[i] = vm->status * 0x7fff; + } +} +void +vm_fatal(VM* vm, char *errstr) +{ + dprintf(2, "VM FATAL: %s\n", errstr); + dprintf(2, "pc = \n", vm->pc); + exit(-1); +} void -i_halt(VM *vm) +i_halt(VM *vm, uint8_t arg) { vm->halted = 1; } - void -i_lit(VM *vm) +i_lit(VM *vm, uint8_t arg) { vm->stack[vm->sp] = vm->prog[vm->pc]; vm->sp++; vm->pc++; } - void -i_fetch(VM *vm) +i_fetch(VM *vm, uint8_t arg) { vm->stack[vm->sp-1] = vm->prog[vm->stack[vm->sp-1]]; } - void -i_chan(VM *vm) +i_op(VM *vm, uint8_t arg) { - 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]]; - } + vm->op[arg] += vm->stack[vm->sp-1]; + vm->stack[vm->sp-1] = vm->op[arg]; } - void -i_voic(VM *vm) +i_adsr(VM *vm, uint8_t arg) { - 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; - } + vm->stack[vm->sp] = vm->adsr[arg]; + vm->sp++; } +void +i_wave(VM *vm, uint8_t arg) +{ + vm->stack[vm->sp-1] = + wavetable[0][vm->stack[vm->sp-1]>>8]; +} void -i_op(VM *vm) +i_note(VM *vm, uint8_t arg) { - 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; + vm->stack[vm->sp] = vm->key; + vm->sp++; } +void +i_2dt(VM *vm, uint8_t arg) +{ + uint8_t note = vm->stack[vm->sp-1]; + int16_t dt = tune[note%12] * (1 << (note/12)); + vm->stack[vm->sp-1] = dt; +} void -i_dup(VM *vm) +i_dup(VM *vm, uint8_t arg) { vm->stack[vm->sp] = vm->stack[vm->sp-1]; vm->sp++; } - void -i_drop(VM *vm) +i_drop(VM *vm, uint8_t arg) { vm->sp--; } - void -i_swap(VM *vm) +i_swap(VM *vm, uint8_t arg) { int16_t b; b = vm->stack[vm->sp-1]; @@ -100,54 +172,19 @@ i_swap(VM *vm) vm->stack[vm->sp-2] = b; } - void -i_add(VM *vm) +i_add(VM *vm, uint8_t arg) { 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) +i_comb(VM *vm, uint8_t arg) { - 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; + vm->stack[vm->sp-2] = + vm->stack[vm->sp-1] * vm->stack[vm->sp-2] + / 0x7fff; + vm->sp--; } -int16_t -vm_run(VM *vm) -{ - instruction inst; - vm->halted = 0; - vm->pc = 0; - vm->sp = 0; - while (vm->halted == 0) { - inst = instructions[vm->prog[vm->pc]]; - vm->pc++; - inst(vm); - } - return vm->stack[vm->sp-1]; -} diff --git a/machine.h b/machine.h @@ -3,15 +3,18 @@ enum { /* * * * * */ I_LIT, I_FETCH, - I_CHAN, - I_VOIC, I_OP, + I_ADSR, + I_WAVE, + I_NOTE, + I_2DT, /* * * * * */ I_DUP, I_DROP, I_SWAP, /* * * * * */ I_ADD, + I_COMB, }; #define SDEPTH 256 @@ -19,7 +22,11 @@ enum { typedef struct VM VM; struct VM { int halted; + int status; + uint8_t key; int16_t stack[SDEPTH]; + int16_t op[16]; + int16_t adsr[16]; int16_t sp; int16_t *prog; int16_t pc; @@ -27,4 +34,8 @@ struct VM { Channel *channel; }; -void vm_set(VM*, Channel*, Voice*); -\ No newline at end of file +VM vms[32]; + +void vm_set(VM*, Channel*, Voice*); +int16_t vm_run(VM*); + diff --git a/midi.h b/midi.h @@ -14,3 +14,4 @@ Mvector m_vector; void m_init(char *mdev); void m_read(void); + diff --git a/usynth.c b/usynth.c @@ -6,6 +6,7 @@ #include "midi.h" #include "operator.h" #include "fm.h" +#include "machine.h" struct sio_hdl *sh; size_t bs; @@ -40,8 +41,8 @@ main(int argc, char **argv) s_init(); m_init("rmidi/0"); fm_init(); - m_vector.note_on = fm_note_on; - m_vector.note_off = fm_note_off; + m_vector.note_on = fm_key_on; + m_vector.note_off = fm_key_off; m_vector.ctl_change = fm_ctl_change; m_vector.prog_change = fm_prog_change; while (1){ diff --git a/wavetable.c b/wavetable.c @@ -15,8 +15,8 @@ wt_init(void) wavetable = malloc(sizeof(int16_t*) * WT_SIZE); for (i=0;i<8;i++) wavetable[i] = malloc(sizeof(int16_t) * WT_LENGTH); //wt_sin(wavetable[0]); - wt_triangle(wavetable[1]); - wt_pulse(wavetable[2]); + wt_triangle(wavetable[0]); + wt_pulse(wavetable[1]); } void