Index: Makefile
===================================================================
--- Makefile	(revision 8270a1b555559b631c448852f8177a4dfa1142eb)
+++ Makefile	(revision 5326a5eefb1eb6da6195dd8a616fbcca4e0fe2bc)
@@ -3,5 +3,7 @@
 ifndef WIN
 GCC :=			gcc
+GPP :=			g++
 SDL2 :=			/opt/sdl2
+RTMIDI :=		/opt/rtmidi
 EXT :=
 else
@@ -14,4 +16,7 @@
 SDL2_LIB :=		$(SDL2)/lib
 
+RTMIDI_INC :=	$(RTMIDI)/include
+RTMIDI_LIB :=	$(RTMIDI)/lib
+
 FLAGS :=		-std=c99 -O2 -gdwarf-4
 
@@ -23,5 +28,5 @@
 				-Wpedantic -Wconversion -Wsign-conversion -Wshadow \
 				-Wstrict-prototypes -Wmissing-declarations -Wredundant-decls \
-				-I cpu -I emu -I build -I $(SDL2_INC)
+				-I cpu -I emu -I build -I $(SDL2_INC) -I $(RTMIDI_INC)
 
 FLAGS_AUX :=	$(FLAGS) -Wall -Wextra \
@@ -37,4 +42,5 @@
 				$(SDL2_LIB)/libSDL2_ttf.a \
 				$(SDL2_LIB)/libfreetype.a \
+				$(RTMIDI_LIB)/librtmidi.a \
 				-ldl -lm
 endif
@@ -47,7 +53,9 @@
 				$(SDL2_LIB)/libSDL2_ttf.a \
 				$(SDL2_LIB)/libfreetype.a \
+				$(RTMIDI_LIB)/librtmidi.a \
 				-framework AppKit \
 				-framework AudioToolbox \
 				-framework Carbon \
+				-framework CoreMIDI \
 				-framework CoreAudio \
 				-framework CoreFoundation \
@@ -116,5 +124,5 @@
 
 buchla$(EXT):	$(CPU_OP) $(GEN_OP)	$(EMU_OP)
-				$(GCC) $(FLAGS_LNK) -o buchla$(EXT) \
+				$(GPP) $(FLAGS_LNK) -o buchla$(EXT) \
 				$(CPU_OP) $(GEN_OP) $(EMU_OP) \
 				$(LIBS)
Index: emu/cpu.c
===================================================================
--- emu/cpu.c	(revision 8270a1b555559b631c448852f8177a4dfa1142eb)
+++ emu/cpu.c	(revision 5326a5eefb1eb6da6195dd8a616fbcca4e0fe2bc)
@@ -91,5 +91,5 @@
 	{ 0x3a4001, 0x3a8001, 0, lcd_init, lcd_quit, lcd_exec, lcd_read, lcd_write },
 	{ 0x3a8001, 0x3ac001, 5, ser_init, ser_quit, ser_exec, ser_read, ser_write },
-	{ 0x3ac001, 0x3b0001, 0, mid_init, mid_quit, mid_exec, mid_read, mid_write },
+	{ 0x3ac001, 0x3b0001, 5, mid_init, mid_quit, mid_exec, mid_read, mid_write },
 	{ 0x3b0001, 0x3b4001, 0, fdd_init, fdd_quit, fdd_exec, fdd_read, fdd_write },
 	{ 0x3b4001, 0x3b8001, 0, snd_init, snd_quit, snd_exec, snd_read, snd_write },
Index: emu/mid.c
===================================================================
--- emu/mid.c	(revision 8270a1b555559b631c448852f8177a4dfa1142eb)
+++ emu/mid.c	(revision 5326a5eefb1eb6da6195dd8a616fbcca4e0fe2bc)
@@ -17,10 +17,9 @@
 
 #include <all.h>
+#include <rtmidi/rtmidi_c.h>
 
 #define ver(...) _ver(mid_verbose, 0, __VA_ARGS__)
 #define ver2(...) _ver(mid_verbose, 1, __VA_ARGS__)
 #define ver3(...) _ver(mid_verbose, 2, __VA_ARGS__)
-
-int32_t mid_verbose = 0;
 
 #define REG_IER_ISR 0
@@ -29,11 +28,128 @@
 #define REG_TDR_RDR 3
 
+#define BUF_SZ 128
+
+typedef struct {
+	int32_t buf_hd;
+	int32_t buf_tl;
+	uint8_t buf[BUF_SZ];
+	bool irq_r;
+	bool irq_t;
+	bool rdr_ok;
+	uint8_t rdr;
+} state_t;
+
+static state_t state[] = {
+	{ .buf_hd = 0, .buf_tl = 0, .irq_r = false, .irq_t = false, .rdr_ok = false, .rdr = 0x00 },
+	{ .buf_hd = 0, .buf_tl = 0, .irq_r = false, .irq_t = false, .rdr_ok = false, .rdr = 0x00 }
+};
+
+int32_t mid_verbose = 0;
+
+struct RtMidiWrapper* midiin;
+
+static void xmit(int32_t un)
+{
+	int32_t i = state[un].buf_tl;
+	ver2("mid xmit %d %d", i, state[un].buf_hd);
+
+	if (i >= state[un].buf_hd) {
+		return;
+	}
+
+	uint8_t byte = state[un].buf[i % BUF_SZ];
+	ver2("mid xmit 0x%02x", byte);
+
+	state[un].rdr = byte;
+	state[un].rdr_ok = true;
+	state[un].irq_r = true;
+
+	state[un].buf_tl = i + 1;
+
+	if (state[un].buf_tl >= BUF_SZ) {
+		state[un].buf_hd -= BUF_SZ;
+		state[un].buf_tl -= BUF_SZ;
+		ver2("mid adj %d %d", state[un].buf_tl, state[un].buf_hd);
+	}
+}
+
+static void out_lk(int32_t un, uint8_t c)
+{
+	int32_t i = state[un].buf_hd;
+	ver2("mid out %d %d 0x%02x", state[un].buf_tl, i, c);
+
+	if (i >= state[un].buf_tl + BUF_SZ) {
+		err("midi port %d losing data", un);
+		return;
+	}
+
+	state[un].buf[i % BUF_SZ] = c;
+	state[un].buf_hd = i + 1;
+
+	if (!state[un].irq_r && !state[un].rdr_ok) {
+		xmit(un);
+	}
+}
+
+static void out(int32_t un, uint8_t c)
+{
+	if (SDL_LockMutex(cpu_mutex) < 0) {
+		fail("SDL_LockMutex() failed: %s", SDL_GetError());
+	}
+
+	out_lk(un, c);
+
+	if (SDL_UnlockMutex(cpu_mutex) < 0) {
+		fail("SDL_UnlockMutex() failed: %s", SDL_GetError());
+	}
+}
+
+static void midi_callback(double timeStamp, const unsigned char* message, void *userData) {
+	ver2("Timestamp %f\n", timeStamp);
+
+	for (uint8_t i = 0; i < sizeof(message); i++) {
+		ver2("Message %i %u", i, (uint8_t) message[i]);
+		out(0, message[i]);
+	}
+}
+
 void mid_init(void)
 {
 	ver("mid init");
+
+	midiin = rtmidi_in_create_default();
+	ver2("%p", midiin->ptr);
+	// check if null
+	uint32_t portcount = rtmidi_get_port_count(midiin);
+	ver2("%d", midiin->ok);
+
+	if (portcount == 0) {
+		midiin = NULL;
+		ver2("no midi ports\n");
+		return;
+	}
+
+	for (uint32_t i = 0; i < portcount; i++) {
+		ver2("Port %d: %s", i, rtmidi_get_port_name(midiin, i));
+	}
+
+	rtmidi_open_port(midiin, 0, rtmidi_get_port_name(midiin, 0));
+	if(!midiin->ok) {
+		fail("Failed to open Midi port");
+	}
+
+	rtmidi_in_set_callback(midiin, midi_callback, midiin->data);
+	if(!midiin->ok) {
+		fail("Failed to set Midi Callback");
+	}
 }
 
 void mid_quit(void)
 {
+	if(midiin) {
+		rtmidi_close_port(midiin);
+		rtmidi_in_free(midiin);
+	}
+
 	ver("mid quit");
 }
@@ -42,5 +158,5 @@
 {
 	ver3("mid exec");
-	return false;
+	return state[0].irq_r || state[0].irq_t || state[1].irq_r || state[1].irq_t;
 }
 
@@ -48,5 +164,38 @@
 {
 	ver2("mid rd %u:%d", off, sz * 8);
-	return 0;
+
+	if (sz != 1 || off > 7) {
+		fail("invalid mid rd %u:%d", off, sz * 8);
+	}
+
+	int32_t rg = (int32_t)(off % 4);
+	int32_t un = (int32_t)(off / 4);
+
+	uint32_t rv;
+
+	switch (rg) {
+	case REG_IER_ISR:
+		rv = (uint32_t)(0xc0 | (state[un].rdr_ok ? 0x01 : 0x00));
+		state[un].irq_r = false;
+		state[un].irq_t = false;
+		ver2("ISR[%d] 0x%02x", un, rv);
+		break;
+
+	case REG_TDR_RDR:
+		rv = state[un].rdr;
+		state[un].rdr_ok = false;
+		ver2("RDR[%d] 0x%02x", un, rv);
+		break;
+
+	default:
+		rv = 0x00;
+		break;
+	}
+
+	if (!state[un].irq_r && !state[un].rdr_ok) {
+		xmit(un);
+	}
+
+	return rv;
 }
 
Index: readme.txt
===================================================================
--- readme.txt	(revision 8270a1b555559b631c448852f8177a4dfa1142eb)
+++ readme.txt	(revision 5326a5eefb1eb6da6195dd8a616fbcca4e0fe2bc)
@@ -91,4 +91,16 @@
   ../configure --prefix=/opt/sdl2 --with-sdl-prefix=/opt/sdl2
 
+  make
+  make install
+  
+  # Build and install rtmidi
+  
+  tar zxvf rtmidi-3.0.0.tar.gz
+  cd rtmidi-3.0.0
+  mkdir build
+  cd build
+  
+  ../configure --prefix=/opt/rtmidi
+  
   make
   make install
