#include "midi.h" #include "notes.h" #include "control.h" #include 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; } } int enable = 0; void midiCallback(PtTimestamp timestamp, void *userData) { midi_t * m = (midi_t *)userData; if (!m->stream) return; if (!enable) 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); enable = 1; } void terminate_midi(midi_t *m) { Pt_Stop(); Pm_Close(m->stream); Pm_Terminate(); }