diff --git a/src/main.c b/src/main.c
index 5c73143..0aeeba7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,13 +12,14 @@
 #include "midi_interface.h"
 #include "midi_parser.h"
 
-uint32_t time_per_quarter;
-uint32_t ticks_per_quarter;
 MidiInterface* interface;
 
 static int _Atomic playing = ATOMIC_VAR_INIT(0);
+static uint32_t _Atomic time_per_quarter = ATOMIC_VAR_INIT(1);
+static uint32_t _Atomic current_tick = ATOMIC_VAR_INIT(0);
 
 void* play_track(void* data);
+void* advance_counter(void* data);
 
 int main(int argc, char** argv)
 {
@@ -28,8 +29,7 @@ int main(int argc, char** argv)
         exit(-1);
     }
 
-
-
+    printf("Loading MIDI file...\n");
     MidiParser* parser;
     parser = parseMidi(argv[1], false, true);
     if(!parser)
@@ -37,14 +37,17 @@ int main(int argc, char** argv)
         fprintf(stderr, "Failed to read MIDI file\n");
         exit(-1);
     }
-
-    time_per_quarter = ((uint32_t*)(parser->tracks[0].events[2].infos))[0];
-    ticks_per_quarter = parser->ticks;
+    printf("Done. Press enter to continue.\n");
+    getchar();  
 
     int result = open_midi_device(&interface, NULL);
     if(result < 0)
         exit(result);
 
+    pthread_t counter_thread;
+    pthread_create(&counter_thread, NULL, advance_counter, &(parser->ticks));
+    pthread_detach(counter_thread);
+
     pthread_t* threads = (pthread_t*)malloc(parser->nbOfTracks * sizeof(pthread_t));
     for(int i = 0; i < parser->nbOfTracks; i++)
     {
@@ -60,39 +63,61 @@ int main(int argc, char** argv)
     free(threads);
     close_midi_device(interface);
     
-
     return 0;
 }
 
+void* advance_counter(void* data)
+{
+    uint16_t ticks_per_quarter = *((uint32_t*)data);
+    while(!playing);
+
+    for(;;)
+    {
+        usleep((uint64_t)time_per_quarter / ticks_per_quarter);
+        current_tick++;
+    }
+}
+
 void* play_track(void* data)
 {
     Track* track = (Track*)data;
     Message* message;
     create_message(&message);
-    message->channel = 0;
     message->length = 2;
 
+    uint64_t tick_of_last_event = 0;
     int current_event = 0;
-    struct timeval begin, end;
 
     while(!playing);
-    gettimeofday(&begin, NULL);
 
     while(current_event < track->nbOfEvents)
     {
         Event event = track->events[current_event];
+        while(tick_of_last_event + event.timeToAppear > current_tick);
 
-        gettimeofday(&end, NULL);
-        uint64_t deltatime = ((end.tv_sec - begin.tv_sec) * 1000000) + (end.tv_usec - begin.tv_usec);
-        if(event.timeToAppear > 0)
-            usleep(event.timeToAppear * time_per_quarter / ticks_per_quarter - deltatime);
-        gettimeofday(&begin, NULL);
-
-        if(event.type == MidiNotePressed || event.type == MidiNoteReleased)
+        if(event.type == MidiTempoChanged)
         {
-            message->type = (event.type == MidiNotePressed) ? NOTE_ON : NOTE_OFF;
+            time_per_quarter = ((uint32_t*)(event.infos))[0];
+        }
+        else if(event.type == MidiNotePressed || event.type == MidiNoteReleased || event.type == MidiControllerValueChanged)
+        {
+            message->channel = (((uint8_t*)(event.infos))[0] & 0xF);
             message->data = event.infos + 1;
 
+            switch(event.type)
+            {
+                case MidiNotePressed:
+                    message->type = NOTE_ON;
+                    break;
+
+                case MidiNoteReleased:
+                    message->type = NOTE_OFF;
+                    break;
+
+                case MidiControllerValueChanged:
+                    message->type = CONTROLLER_CHANGE;
+                    break;
+            }
             // printf("Sending %d %d\n", message->data[0], message->data[1]);
             int result = write_midi_device(interface, message);
             if(result < 0)
@@ -100,5 +125,6 @@ void* play_track(void* data)
         }
 
         current_event++;
+        tick_of_last_event += event.timeToAppear;
     }
 }
\ No newline at end of file
diff --git a/src/message.c b/src/message.c
index 9996c3b..4398e4b 100644
--- a/src/message.c
+++ b/src/message.c
@@ -22,6 +22,7 @@ int data_length(MessageType type)
     {
     case NOTE_ON:   return 2;
     case NOTE_OFF:  return 2;
+    case CONTROLLER_CHANGE: return 2;
 
     case SYSTEM_EXCLUSIVE: return 0;
     }
@@ -43,6 +44,10 @@ int decode_status_byte(Message* message, uint8_t status)
         message->type = NOTE_OFF;
         break;
 
+    case 0xB0:
+        message->type = CONTROLLER_CHANGE;
+        break;
+
     case 0xF0:
         message->type = SYSTEM_EXCLUSIVE;
         break;
@@ -69,6 +74,10 @@ int encode_status_byte(const Message* message, uint8_t* status)
         *status |= 0x80;
         break;
 
+    case CONTROLLER_CHANGE:
+        *status |= 0xB0;
+        break;
+
     case SYSTEM_EXCLUSIVE:
         *status |= 0xF0;
         break;
diff --git a/src/message.h b/src/message.h
index 9fac323..da9112e 100644
--- a/src/message.h
+++ b/src/message.h
@@ -5,7 +5,7 @@
 
 typedef enum MessageType
 {
-    NOTE_OFF, NOTE_ON,
+    NOTE_OFF, NOTE_ON, CONTROLLER_CHANGE,
     SYSTEM_EXCLUSIVE
 } MessageType;
 
diff --git a/src/midi_interface.c b/src/midi_interface.c
index d679e7f..905d28d 100644
--- a/src/midi_interface.c
+++ b/src/midi_interface.c
@@ -39,12 +39,15 @@ int open_midi_device(MidiInterface** interface, const char* device)
 
     (*interface)->fd = fd;
     (*interface)->out_buf = (uint8_t*)malloc(8);
+    pthread_mutex_init(&((*interface)->write_mutex), NULL);
+
     return fd;
 }
 
 int close_midi_device(MidiInterface* interface)
 {
     close(interface->fd);
+    pthread_mutex_destroy(&(interface->write_mutex));
 
     free(interface->out_buf);
     free(interface);
@@ -86,12 +89,17 @@ int write_midi_device(MidiInterface* interface, const Message* buffer)
     if(result < 0)
         return result;
 
+    pthread_mutex_lock(&(interface->write_mutex));
     interface->out_buf[0] = status;
+    
     memcpy(interface->out_buf + 1, buffer->data, buffer->length);
 
     result = write(interface->fd, interface->out_buf, 1 + buffer->length);
+    pthread_mutex_unlock(&(interface->write_mutex));
     if(result < 0)
         return MIDI_WRITE_ERROR;
+
+    return 0;
 }
 
 int write_midi_device_raw(MidiInterface* interface, const char* buffer)
@@ -101,7 +109,7 @@ int write_midi_device_raw(MidiInterface* interface, const char* buffer)
 
 int try_open_device(const char* device)
 {
-    int fd = open(device, O_RDWR, 0);
+    int fd = open(device, O_RDWR | O_ASYNC, 0);
 
     return fd;
 }
\ No newline at end of file
diff --git a/src/midi_interface.h b/src/midi_interface.h
index dd1ef46..5fe9398 100644
--- a/src/midi_interface.h
+++ b/src/midi_interface.h
@@ -2,6 +2,7 @@
 #define _MIDI_INTERFACE_H_
 
 #include <stdint.h>
+#include <pthread.h>
 
 #include "message.h"
 #include "midi_error.h"
@@ -10,6 +11,7 @@ typedef struct MidiInterface
 {
     int fd;
     uint8_t* out_buf;
+    pthread_mutex_t write_mutex;
 } MidiInterface;
 
 int open_midi_device(MidiInterface** interface, const char* device);