usynth

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

commit 6b918683b79ecfedb68a649f8a450910f4537475
Author: zavok <an2qzavok@gmail.com>
Date:   Mon,  4 Nov 2019 11:31:26 +0300

time for version control

Diffstat:
AMakefile | 34++++++++++++++++++++++++++++++++++
Aaudio.c | 2++
Aaudio.h | 0
Afm.c | 2++
Afm.h | 0
Amidi.c | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amidi.h | 11+++++++++++
Ausynth.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 270 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,34 @@ +.POSIX: + +PREFIX = /usr/local +MANDIR = $(PREFIX)/share/man/man1 + +BIN = usynth +MAN = $(BIN).1 +OBJ = $(BIN:=.o) audio.o fm.o midi.o + +LDFLAGS=-lsndio + +all: $(BIN) + +$(BIN): $(OBJ) + $(CC) $(OBJ) $(LDFLAGS) $(LIBS) -o $@ + +$(OBJ): audio.c fm.c midi.c usynth.c + +install: $(BIN) + mkdir -p $(DESTDIR)$(PREFIX)/bin/ + cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/ + chmod 555 $(DESTDIR)$(PREFIX)/bin/$(BIN) + mkdir -p $(DESTDIR)$(MANDIR) + cp -f $(MAN) $(DESTDIR)$(MANDIR) + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN) + rm -f $(DESTDIR)$(MANDIR)/$(MAN) + +clean: + rm -f $(BIN) $(OBJ) + +.c.o: + $(CC) $(CFLAGS) -c $< diff --git a/audio.c b/audio.c @@ -0,0 +1,2 @@ +#include <stdio.h> +#include <sndio.h> diff --git a/audio.h b/audio.h diff --git a/fm.c b/fm.c @@ -0,0 +1,2 @@ +#include <stdio.h> +#include "fm.h" diff --git a/fm.h b/fm.h diff --git a/midi.c b/midi.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdint.h> +#include <sndio.h> +#include "midi.h" + +uint8_t mmessage[8]; +uint8_t mlen; +uint8_t mi; +enum { + NOTE_OFF 0x80, + NOTE_ON 0x90, + KEY_PRESSURE 0xa0, + CTL_CHANGE 0xb0, + PROG_CHANGE 0xc0, + CHAN_PRESSURE 0xe0, + PITCH_WHEEL 0xe0, + SYS_MESSAGE 0xf0, +}; + +void +m_status(uint8_t b) +{ + if ((b && 0x80)==0) return; /* not a status byte */ + uint8_t t, ch; + t = b & 0xf0; + c = b & 0x0f; + if (t == SYS_MESSAGE){ + return; + } + mmesage[0] = t; + mmesage[1] = c; + mi=2; + switch (t){ + case NOTE_OFF: + mlen = 4; + m_update = m_data; + break; + case NOTE_ON: + mlen = 4; + m_update = m_data; + break; + } +} + +m_data(uint_t b) +{ + mmessage[mi] = b; + mi++; + if (mi = mlen){ + mi = 0; + mlen = 0; + m_exec(); + m_update = m_status; + } +} + +void +m_exec(void) +{ + switch(mmesage[0]){ + case NOTE_OFF: + break; + case NOTE_ON: + break; + } +} + +void +m_init(void) +{ +// char *mdev; +// mdev = "rmidi/0"; +// mh = mio_open(mdev, MIO_IN, 1); +// if (mh == 0){ +// fprintf(stderr, "error: couldn't open midi device %s\n" mdev); +// exit(-1); +// } + m_update = m_status; + mlen = 0; + mi = 0; +} + diff --git a/midi.h b/midi.h @@ -0,0 +1,11 @@ +struct m_vector{ + void(*note_on)(uint8_t*); + void(*note_off)(uint8_t*); +}; + +struct m_vector m_vector; + +void (*m_update)(uint8_t); + +void m_init(void); + diff --git a/usynth.c b/usynth.c @@ -0,0 +1,139 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <sndio.h> +#include "midi.h" +#include "audio.h" +#include "fm.h" + +enum{ + STATUS, + DATA, +}; + +struct mpstate{ + int s; + uint8_t m[8]; + int dc; +}; + +struct mpstate mparser; + + +struct sio_hdl *sh; +struct mio_hdl *mh; +size_t bs; +int16_t vol, dt; + +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 +}; + +size_t rt, wt; + +void +cb(void *arg, int delta) +{ + rt += delta * 4; +} + +void +sinit(void) +{ + char *sdev = "rsnd/0";//SIO_DEVANY; + struct sio_par par; + sh = sio_open(sdev, SIO_PLAY, 0); + sio_initpar(&par); + par.pchan = 2; + par.sig = 1; + par.bits = 16; + par.le = 0; + par.rate = 44100; + par.xrun = SIO_SYNC; + par.appbufsz = 1024; + sio_setpar(sh, &par); + sio_getpar(sh, &par); + //bs = 256 + par.round; + //bs -= bs % par.round; + 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); + sio_start(sh); +} + +void +mparse(uint8_t b){ + switch (mparser.s){ + case STATUS: + if (b&0x80){ + mparser.m[0] = b; + mparser.dc = 1; + mparser.s = DATA; + } + return; + case DATA: + mparser.m[1] = b; + mparser.dc--; + mparser.s = STATUS; + break; + } + if (mparser.dc == 0){ + uint8_t ctl = mparser.m[0]>>4; + if (ctl == 9) { + vol = 250; + uint8_t note = mparser.m[1]; + dt = 44100.0 / (tune[note%12] * (double)(0x1<<(note/12))); + } + if (ctl == 8) vol = 0; + } +} + +int +main(int argc, char **argv) +{ + char *mdev; + int64_t c; + int16_t *sbuf; + uint8_t *mbuf; + vol = 0; + wt = 0; + rt = 0; + mdev = "rmidi/0"; + mh = mio_open(mdev, MIO_IN, 1); + sinit(); + sbuf = malloc(bs * 2 * sizeof(int16_t)); + mbuf = malloc(32); + c = 0; + dt = 100; + while (1){ + size_t n; + int i; + n = mio_read(mh, mbuf, 32); + for (i=0; i < n; i++){ + mparse(mbuf[i]); + } + for (i=0; i<bs * 2; i+=2){ + c++; + sbuf[i] = (c%dt > (dt/2))? vol : -vol; + sbuf[i+1] = sbuf[i]; + } + n = 0; + n = sio_write(sh, sbuf, bs * 2 * sizeof(int16_t)); + wt += n; + } + return 0; +} +