summaryrefslogblamecommitdiffstats
path: root/src/midi.c
blob: 0bd44a8adad4deab52b8be9fe4f090ad058c1f72 (plain) (tree)
1
2
3
4
5
6
                 
                  


                   
                                                 









                                                                                    


                                                           


                                                                        


                                                                                   






                                                          










                                                                         
 





                                                                                             


































                                                                          








                                                                                           
                                                      













                                                     
                                      

              





                                      

                                
                                     






                                    

                   




























                                                                                                                                                                                                             
#include "midi.h"
#include "notes.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;

  switch (message) {
    case 0x08:
      printf("Note Off: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
      if (synth->n.key == data1) {
        synth->n.noteOff = Pa_GetStreamTime(synth->stream);
      }

      synth->midi_note[data1].noteOff = Pa_GetStreamTime(synth->stream);

      break;
    case 0x09:
      printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
      synth->n.key = data1;
      synth->n.freq = notes[data1 % 12][(data1 / 12) % 8];
      synth->n.noteOn = Pa_GetStreamTime(synth->stream);
      synth->n.noteOff = 0;
      synth->n.elapsed = 0;
      synth->adsr.elapsed = 0;
      synth->active = 1;
      //synth->gain = data2 / 127.0;

      
      //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;

      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:
        synth->adsr.a = synth->adsr.a + (x * 0.01);
        break;
      case 1:
        synth->adsr.d = synth->adsr.d + (x * 0.01);
        break;
      case 2:
        synth->adsr.s = synth->adsr.s + (x * 0.01);
        break;
      case 3:
        synth->adsr.r = synth->adsr.r + (x * 0.01);
        break;
      case 4:
        synth->cutoff = synth->cutoff + (x * (10 * log10(synth->cutoff)));
        break;
      case 5:
        synth->resonance = synth->resonance + (x * 0.02);
        break;
      case 6:
        synth->lfo.freq = synth->lfo.freq + (x * 0.1);
        break;
      case 7:
        synth->lfo.amp = synth->lfo.amp + (x * 0.002);
        break;
        break;
      case 28:
        synth->filter = x - 1;
        break;
      case 29:
        synth->multi = x - 1;
        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:
      printf("Pitch Bend: channel=%d, value=%d\n", channel, ((data2 << 7) | data1) - 8192);
      synth->n.freq = (((data2 << 7) | data1) - 8192);
      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;
  }

  Pt_Start(1, midiCallback, m);

  Pm_OpenInput(&(m->stream),
               i, //Pm_GetDefaultInputDeviceID(),
               NULL,
               128,
               NULL,
               NULL);
}

void
terminate_midi(midi_t *m)
{
  Pm_Close(m->stream);
  Pt_Stop();
  Pm_Terminate();
}