#include "midi.h"
#include "notes.h"
#include "control.h"
#include <string.h>
void midi_decode(uint32_t msg, synth_t * synth) {
// printf("MIDI message: 0x%X\n", msg);
uint8_t status = msg;
uint8_t data1 = (msg >> 8) & 0xFF;
uint8_t data2 = (msg >> 16) & 0xFF;
uint8_t channel = (status & 0x0F) + 1; // convert to human
uint8_t message = status >> 4;
int flag = 1;
switch (message) {
case 0x08:
printf("Note Off: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
synth->midi_note[data1].noteOff = Pa_GetStreamTime(synth->stream);
synth->midi_note[data1].noteOffSample = synth->midi_note[data1].elapsed;
break;
case 0x09:
printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
//synth->midi_note[i].n = -1;
synth->midi_note[data1].freq = notes[data1 % 12][(data1 / 12) % 8];
synth->midi_note[data1].channel = channel;
synth->midi_note[data1].noteOn = Pa_GetStreamTime(synth->stream);
synth->midi_note[data1].noteOff = 0;
synth->midi_note[data1].velocity = (float)data2 / 127.0;
synth->midi_note[data1].elapsed = 0;
synth->midi_note[data1].active = 1;
for (int i = 0; i < synth->midi_active_n; i++) {
if (synth->midi_active[i] == &synth->midi_note[data1]) {
flag = 0;
}
}
if (flag) {
synth->midi_active[synth->midi_active_n++] = &synth->midi_note[data1];
}
synth->active = 1;
break;
case 0x0A:
printf("Aftertouch: channel=%d, note=%d, pressure=%d\n", channel, data1, data2);
break;
case 0x0B:
printf("Control Change: channel=%d, controller=%d, value=%d\n", channel, data1, data2);
int x = data2 < 64 ? 1 : -1;
switch (data1) {
case 0:
cc_step(&synth->cc_adsr_a, x);
//synth->adsr.a = synth->adsr.a + (x * 0.01);
//synth->freq_offset = synth->freq_offset + (x*5);
//cc_step(&synth->cc_cutoff, x);
break;
case 1:
cc_step(&synth->cc_adsr_d, x);
//synth->adsr.d = synth->adsr.d + (x * 0.01);
break;
case 2:
cc_step(&synth->cc_adsr_s, x);
//synth->adsr.s = synth->adsr.s + (x * 0.01);
break;
case 3:
cc_step(&synth->cc_adsr_r, x);
//synth->adsr.r = synth->adsr.r + (x * 0.01);
break;
case 4:
cc_step(&synth->cc_cutoff, x);
//synth->cutoff = synth->cutoff + (x * (10 * log10(synth->cutoff)));
break;
case 5:
cc_step(&synth->cc_resonance, x);
break;
case 6:
//cc_step(&synth->cc_pitch, x);
cc_step(&synth->cc_lfo_freq, x);
//synth->lfo.freq = synth->lfo.freq + (x * 0.1);
break;
case 7:
//cc_reset(&synth->cc_pitch);
cc_step(&synth->cc_lfo_amp, x);
//synth->lfo.amp = synth->lfo.amp + (x * 0.002);
break;
case 8:
//cc_reset(&synth->cc_pitch);
synth->wvt_pos = data2;
//synth->lfo.amp = synth->lfo.amp + (x * 0.002);
break;
case 28:
if (synth->geni > 0) synth->geni--;
break;
case 29:
if (synth->geni < 6) synth->geni++;
break;
default:
}
break;
case 0x0C:
printf("Program Change: channel=%d, program=%d\n", channel, data1);
break;
case 0x0D:
printf("Channel Pressure: channel=%d, pressure=%d\n", channel, data1);
break;
case 0x0E:
int val = ((data2 << 7) | data1) - 8192;
printf("Pitch Bend: channel=%d, value=%d\n", channel, val);
float pitch;
float semitones = 2;
if (val == 0) {
pitch = 1;
} else if (val > 0) {
pitch = 1 + ((float)val / 8191) * semitones * pow(2.0, 1.0 / 12.0) / 12;
} else {
pitch = 1 + ((float)val / 8192) * semitones * pow(2.0, 1.0 / 12.0) / 12;
}
synth->cc_pitch.target = pitch;
/* cc_step(synth->cc_pitch, 1); */
break;
default:
printf("Unknown MIDI message\n");
break;
}
}
void
midiCallback(PtTimestamp timestamp, void *userData) {
midi_t * m = (midi_t *)userData;
if (!m->stream) return;
// if (!Pm_Poll(m->stream)) return;
PmEvent buf;
int e = Pm_Read(m->stream, &buf, 1);
if (e == 0) return; // nothing to do
if (e < 0) {
printf("Pm_Read error %d\n", e);
return;
}
//printf("%d\n", buf.message);
midi_decode(buf.message, m->synth);
}
void
init_midi(midi_t *m, synth_t *synth)
{
m->stream = NULL;
m->synth = synth;
Pm_Initialize();
printf("midi devs: %d\n", Pm_CountDevices());
const PmDeviceInfo *info;
int i;
for (i = 0; i < Pm_CountDevices(); i++) {
info = Pm_GetDeviceInfo(i);
printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s) -- %d\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf, Pm_GetDefaultInputDeviceID());
//if (!strcmp("MPK225 MIDI", info->name) && !info->input) break;
if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break;
//if (!strcmp("CH345 MIDI 1", info->name) && info->input == 1) break;
//if (!strcmp("Midi Through Port-0", info->name) && info->input == 1) break;
//if (!strcmp("DigitalKBD MIDI 1", info->name) && info->input == 1) break;
}
Pt_Start(1, midiCallback, m);
Pm_OpenInput(&(m->stream),
i, //Pm_GetDefaultInputDeviceID(),
NULL,
128,
NULL,
NULL);
}
void
terminate_midi(midi_t *m)
{
Pt_Stop();
Pm_Close(m->stream);
Pm_Terminate();
}