usynth

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

commit 896187714eb29e5a8f219facc7f89205ca619026
parent a63175a99c62a0d07ccf4fa51c36e11b3bef0add
Author: zavok <an2qzavok@gmail.com>
Date:   Tue,  5 Nov 2019 09:42:03 +0300

added more midi management logic

Diffstat:
Mfm.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mfm.h | 4+++-
Mmidi.c | 39+++++++++++++++++++++++++++++++++------
Mmidi.h | 6++++++
Atune.h | 14++++++++++++++
Musynth.c | 20+++++---------------
6 files changed, 134 insertions(+), 59 deletions(-)

diff --git a/fm.c b/fm.c @@ -1,48 +1,61 @@ #include <stdio.h> #include "fm.h" -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 -}; +#include "tune.h" size_t c; int16_t vol; -struct schan{ +struct voice{ int id; + uint8_t channel; uint8_t note; uint8_t velocity; + uint8_t pressure; +}; + +struct channel{ + uint8_t program; + uint8_t pressure; + uint8_t control[128]; + int16_t pitch; + }; -struct schan fm_sounds[32]; -int16_t fm_synth(int); +struct channel fm_channels[16]; +struct voice fm_voices[32]; + +int64_t fm_synth(int); int16_t fm_mix(void); -int16_t +int64_t fm_synth(int i) { - struct schan *sc; - sc = &fm_sounds[i]; - if (sc->id < 0) return 0; - if (sc->velocity == 0) return 0; size_t dt; - int16_t out; - out = 0x7fff * sc->velocity / 0xff; - dt = 44100.0 / (tune[sc->note%12] * (1 << (sc->note/12))); + int64_t out; + struct voice *v; + struct channel *ch; + v = &fm_voices[i]; + ch = &fm_channels[v->channel]; + if (v->id < 0) return 0; + if (v->velocity == 0) return 0; + out = ch->control[7] * v->velocity; + dt = 44100.0 / (tune[v->note%12] * (1 << (v->note/12))); if (c%dt > dt/2) out = -out; 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(i); + return out; +} + int16_t fm_mix(void) { @@ -50,9 +63,7 @@ fm_mix(void) int i; c++; out = 0; - for (i=0; i<32; i++){ - out += fm_synth(i); - } + for (i=0; i<16; i++) out += fm_mix_channel(i); if (out > 0x7fff) out = 0x7fff; if (out < -0x7fff) out = -0x7fff; return out; @@ -74,13 +85,14 @@ fm_note_on(uint8_t *mm) nmin = 32; nmax = 32; for (i=0;i<32;i++){ - if (fm_sounds[i].id<fm_sounds[nmin].id) nmin = i; - if (fm_sounds[i].id>fm_sounds[nmax].id) nmax = i; - //if (fm_sounds[i].id<=0) break; + if (fm_voices[i].id<fm_voices[nmin].id) nmin = i; + if (fm_voices[i].id>fm_voices[nmax].id) nmax = i; } - fm_sounds[nmin].id = nmax+1; - fm_sounds[nmin].note = mm[2]; - fm_sounds[nmin].velocity = mm[3]; + fm_voices[nmin].id = nmax+1; + fm_voices[nmin].channel = mm[1]; + fm_voices[nmin].note = mm[2]; + fm_voices[nmin].velocity = mm[3]; + fm_voices[nmin].pressure = 0; } void @@ -88,9 +100,33 @@ fm_note_off(uint8_t *mm) { int i; for (i=0; i<32; i++){ - if (fm_sounds[i].note == mm[2]){ - fm_sounds[i].velocity = mm[3]; - fm_sounds[i].id = -1; + if (fm_voices[i].note == mm[2]){ + fm_voices[i].velocity = mm[3]; + fm_voices[i].id = -1; } } } + +void +fm_ctl_change(uint8_t *mm) +{ + fm_channels[mm[1]].control[mm[2]] = mm[3]; +} + +void +fm_prog_change(uint8_t *mm) +{ + fm_channels[mm[1]].program = mm[2]; +} + +void +fm_init(void) +{ + int i; + for (i=0; i<16; i++){ + struct channel *ch; + ch = &fm_channels[i]; + ch->control[7]=0x7f; + ch->program = i; + } +} diff --git a/fm.h b/fm.h @@ -1,4 +1,6 @@ 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_ctl_change(uint8_t*); +void fm_prog_change(uint8_t*); diff --git a/midi.c b/midi.c @@ -16,7 +16,7 @@ enum { KEY_PRESSURE = 0xa0, CTL_CHANGE = 0xb0, PROG_CHANGE = 0xc0, - CHAN_PRESSURE = 0xe0, + CHAN_PRESSURE = 0xd0, PITCH_WHEEL = 0xe0, SYS_MESSAGE = 0xf0, }; @@ -28,7 +28,7 @@ void m_status(uint8_t); void m_status(uint8_t b) { - if ((b & 0x80)==0) return; /* not a status byte */ + if (b < 0x80) return; /* not a status byte */ uint8_t t, c; t = b & 0xf0; c = b & 0x0f; @@ -40,13 +40,20 @@ m_status(uint8_t b) mi=2; switch (t){ case NOTE_OFF: + case NOTE_ON: + case KEY_PRESSURE: + case CTL_CHANGE: + PITCH_WHEEL: mlen = 4; m_update = m_data; break; - case NOTE_ON: - mlen = 4; + case PROG_CHANGE: + case CHAN_PRESSURE: + mlen = 3; m_update = m_data; break; + SYS_MESSAGE: + break; } } @@ -66,14 +73,34 @@ m_data(uint8_t b) void m_exec(void) { + void (*f)(uint8_t*); switch(mmessage[0]){ case NOTE_OFF: - m_vector.note_off(mmessage); + f = m_vector.note_off; break; case NOTE_ON: - m_vector.note_on(mmessage); + f = m_vector.note_on; + break; + case KEY_PRESSURE: + f = m_vector.key_pressure; + break; + case CTL_CHANGE: + f = m_vector.ctl_change; + break; + case PROG_CHANGE: + f = m_vector.prog_change; + break; + case CHAN_PRESSURE: + f = m_vector.chan_pressure; + break; + case PITCH_WHEEL: + f = m_vector.pitch_wheel; + break; + case SYS_MESSAGE: + f = m_vector.sys_message; break; } + if (f != NULL) f(mmessage); } void diff --git a/midi.h b/midi.h @@ -1,6 +1,12 @@ struct m_vector{ void(*note_on)(uint8_t*); void(*note_off)(uint8_t*); + void(*key_pressure)(uint8_t*); + void(*ctl_change)(uint8_t*); + void(*prog_change)(uint8_t*); + void(*chan_pressure)(uint8_t*); + void(*pitch_wheel)(uint8_t*); + void(*sys_message)(uint8_t*); }; struct m_vector m_vector; diff --git a/tune.h b/tune.h @@ -0,0 +1,14 @@ +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 +}; diff --git a/usynth.c b/usynth.c @@ -9,14 +9,7 @@ struct sio_hdl *sh; size_t bs; - -size_t rt, wt; - -void -cb(void *arg, int delta) -{ - rt += delta * 4; -} +int16_t *sbuf; void sinit(void) @@ -39,29 +32,26 @@ sinit(void) bs = par.round; printf("bufsz=%d\nappbufsz=%d\nround=%d\nbs=%lu\n", par.bufsz, par.appbufsz, par.round, bs); - sio_onmove(sh, cb, 0); + sbuf = malloc(bs * 2 * sizeof(int16_t)); sio_start(sh); } int main(int argc, char **argv) { - int16_t *sbuf; - wt = 0; - rt = 0; sinit(); m_init("rmidi/0"); + fm_init(); m_vector.note_on = fm_note_on; m_vector.note_off = fm_note_off; - sbuf = malloc(bs * 2 * sizeof(int16_t)); + m_vector.ctl_change = fm_ctl_change; + m_vector.prog_change = fm_prog_change; printf("entering main loop\n"); while (1){ size_t n; - int i; m_read(); fm_fillbuf(sbuf, bs * 2); n = sio_write(sh, sbuf, bs * 2 * sizeof(int16_t)); - wt += n; } return 0; }