#include <stdio.h>
#include <io.h>
#include <system.h>

#define DATAREG (volatile char*) 0x00101008
#define STATUSREG (volatile char*) 0x00101009
#define NUMVOICES 5

int main() {
  unsigned char byte = 0;
  unsigned char data[2] = {0, 0};
  
  unsigned char status = 0;
  unsigned char note = 0;
  unsigned char vel = 0;
  
  unsigned char onVoices[5] = {0};
  
                            // freq[0] is MIDI note 21
  unsigned int freq[128] = {28, 29, 31, 33, 35, 37, 39, 41,
                            44, 46, 49, 52, 55, 58, 61, 65,
                            69, 73, 78, 82, 87, 92, 98, 104,
                            110, 117, 123, 131, 139, 147, 156,
                            165, 175, 185, 196, 208, 220, 233,
                            247, 262, 277, 294, 311, 330, 349,
                            370, 392, 415, 440, 466, 494, 523,
                            554, 587, 622, 659, 698, 740, 784,
                            831, 880, 932, 988, 1047, 1109, 1319,
                            1397, 1480, 1568, 1661, 1760, 1865, 2093,
                            2218, 2349, 2489, 2637, 2793, 2960, 3136,
                            3322, 3520, 3729, 3951, 4186};
  
  int numbytes = 0;
  
  while (1) {
    if(*STATUSREG == 0x01) {
        byte = *DATAREG;
        if (byte >> 7) { //status signal
            status = byte >> 4; // use only the top nibble (the bottom nibble holds the channel)
            data[0] = 0;
            data[1] = 0;
            numbytes = 0;
        }
        else { // note-on or note-off byte
            data[numbytes] = byte;
            numbytes++;
        }
    }
    
    if (numbytes == 2) {
        note = data[0];
        vel = data[1];
        
        if (status == 0x9) { // note-on event
            if (vel != 0) { // true note-on event
                /* 1. find an available voice (we need to define a number)
                 * 2. set that voice to busy
                 * 3. send a signal to FM synthesis hardware to start synthesis
                 */
                int x = 0;
                while (x < 5) {
                    if (onVoices[x] == 0) {
                        onVoices[x] = note;
                        // turn note on
                        printf("Playing MIDI note: %s, Frequency: %d", &note, freq[note - 21]);
                        break;
                    }
                    x++;
                }
            }
            else { // note-on with velocity of 0 is the same as note-off event
                /* 1. search for this voice
                 * 2. set that voice to not busy
                 * 3. send a reset to the FM synthesis hardware to stop synthesis
                 */
                int x = 0;
                while (x < 5) {
                    if (onVoices[x] == note) {
                        onVoices[x] = 0;
                        // turn note off
                        printf("Stopping MIDI note: %s, Frequency: %d", &note, freq[note - 21]);
                        break;
                    }
                    x++;
                }
            }
        }
        else if (status == 0x8) { // explicit note-off event
            // see comments above for the note-on with velocity 0 event
            int x = 0;
            while (x < 5) {
                if (onVoices[x] == note) {
                    onVoices[x] = 0;
                    // turn note off
                    printf("Playing MIDI note: %s, Frequency: %d", &note, freq[note - 21]);
                    break;
                }
            }
        }
        numbytes = 0;
    }
  }
  return 0;
}