commit 896187714eb29e5a8f219facc7f89205ca619026
parent a63175a99c62a0d07ccf4fa51c36e11b3bef0add
Author: zavok <an2qzavok@gmail.com>
Date: Tue, 5 Nov 2019 09:42:03 +0300
added more midi management logic
Diffstat:
M | fm.c | | | 110 | ++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------- |
M | fm.h | | | 4 | +++- |
M | midi.c | | | 39 | +++++++++++++++++++++++++++++++++------ |
M | midi.h | | | 6 | ++++++ |
A | tune.h | | | 14 | ++++++++++++++ |
M | usynth.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;
}