Index: ext/midi/list.c
===================================================================
--- ext/midi/list.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/list.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,256 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "aubio_priv.h"
+#include "list.h"
+
+
+
+aubio_list_t*
+new_aubio_list(void)
+{
+  aubio_list_t* list;
+  list = AUBIO_NEW(aubio_list_t);
+  list->data = NULL;
+  list->next = NULL;
+  return list;
+}
+
+void
+del_aubio_list(aubio_list_t *list)
+{
+  aubio_list_t *next;
+  while (list) {
+    next = list->next;
+    AUBIO_FREE(list);
+    list = next;
+  }
+}
+
+void
+del_aubio_list1(aubio_list_t *list)
+{
+  if (list) {
+    AUBIO_FREE(list);
+  }
+}
+
+aubio_list_t*
+aubio_list_append(aubio_list_t *list, void*  data)
+{
+  aubio_list_t *new_list;
+  aubio_list_t *last;
+
+  new_list = new_aubio_list();
+  new_list->data = data;
+
+  if (list)
+    {
+      last = aubio_list_last(list);
+      /* g_assert (last != NULL); */
+      last->next = new_list;
+
+      return list;
+    }
+  else
+      return new_list;
+}
+
+aubio_list_t*
+aubio_list_prepend(aubio_list_t *list, void* data)
+{
+  aubio_list_t *new_list;
+
+  new_list = new_aubio_list();
+  new_list->data = data;
+  new_list->next = list;
+
+  return new_list;
+}
+
+aubio_list_t*
+aubio_list_nth(aubio_list_t *list, int n)
+{
+  while ((n-- > 0) && list) {
+    list = list->next;
+  }
+
+  return list;
+}
+
+aubio_list_t*
+aubio_list_remove(aubio_list_t *list, void* data)
+{
+  aubio_list_t *tmp;
+  aubio_list_t *prev;
+
+  prev = NULL;
+  tmp = list;
+
+  while (tmp) {
+    if (tmp->data == data) {
+      if (prev) {
+	prev->next = tmp->next;
+      }
+      if (list == tmp) {
+	list = list->next;
+      }
+      tmp->next = NULL;
+      del_aubio_list(tmp);
+      
+      break;
+    }
+    
+    prev = tmp;
+    tmp = tmp->next;
+  }
+
+  return list;
+}
+
+aubio_list_t*
+aubio_list_remove_link(aubio_list_t *list, aubio_list_t *link)
+{
+  aubio_list_t *tmp;
+  aubio_list_t *prev;
+
+  prev = NULL;
+  tmp = list;
+
+  while (tmp) {
+    if (tmp == link) {
+      if (prev) {
+	prev->next = tmp->next;
+      }
+      if (list == tmp) {
+	list = list->next;
+      }
+      tmp->next = NULL;
+      break;
+    }
+    
+    prev = tmp;
+    tmp = tmp->next;
+  }
+  
+  return list;
+}
+
+static aubio_list_t* 
+aubio_list_sort_merge(aubio_list_t *l1, aubio_list_t *l2, aubio_compare_func_t compare_func)
+{
+  aubio_list_t list, *l;
+
+  l = &list;
+
+  while (l1 && l2) {
+    if (compare_func(l1->data,l2->data) < 0) {
+      l = l->next = l1;
+      l1 = l1->next;
+    } else {
+      l = l->next = l2;
+      l2 = l2->next;
+    }
+  }
+  l->next= l1 ? l1 : l2;
+  
+  return list.next;
+}
+
+aubio_list_t* 
+aubio_list_sort(aubio_list_t *list, aubio_compare_func_t compare_func)
+{
+  aubio_list_t *l1, *l2;
+
+  if (!list) {
+    return NULL;
+  }
+  if (!list->next) {
+    return list;
+  }
+
+  l1 = list; 
+  l2 = list->next;
+
+  while ((l2 = l2->next) != NULL) {
+    if ((l2 = l2->next) == NULL) 
+      break;
+    l1=l1->next;
+  }
+  l2 = l1->next; 
+  l1->next = NULL;
+
+  return aubio_list_sort_merge(aubio_list_sort(list, compare_func),
+			      aubio_list_sort(l2, compare_func),
+			      compare_func);
+}
+
+
+aubio_list_t*
+aubio_list_last(aubio_list_t *list)
+{
+  if (list) {
+    while (list->next)
+      list = list->next;
+  }
+
+  return list;
+}
+
+int 
+aubio_list_size(aubio_list_t *list)
+{
+  int n = 0;
+  while (list) {
+    n++;
+    list = list->next;
+  }
+  return n;
+}
+
+aubio_list_t* aubio_list_insert_at(aubio_list_t *list, int n, void* data)
+{
+  aubio_list_t *new_list;
+  aubio_list_t *cur;
+  aubio_list_t *prev = NULL;
+
+  new_list = new_aubio_list();
+  new_list->data = data;
+
+  cur = list;
+  while ((n-- > 0) && cur) {
+    prev = cur;
+    cur = cur->next;
+  }
+
+  new_list->next = cur;
+
+  if (prev) {
+    prev->next = new_list;    
+    return list;
+  } else {
+    return new_list;
+  }
+}
Index: ext/midi/list.h
===================================================================
--- ext/midi/list.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/list.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,63 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * \file
+ * list of objects
+ *
+ * implement common list structure and its various functions
+ * 
+ * adapted for audio by Paul Brossier
+ * 
+ * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#ifndef _AUBIO_LIST_H
+#define _AUBIO_LIST_H
+
+typedef struct _aubio_list_t aubio_list_t;
+
+struct _aubio_list_t
+{
+  void* data;
+  aubio_list_t *next;
+};
+
+typedef int (*aubio_compare_func_t)(void* a, void* b);
+
+aubio_list_t* new_aubio_list(void);
+void del_aubio_list(aubio_list_t *list);
+void del_aubio_list1(aubio_list_t *list);
+aubio_list_t* aubio_list_sort(aubio_list_t *list, aubio_compare_func_t compare_func);
+aubio_list_t* aubio_list_append(aubio_list_t *list, void* data);
+aubio_list_t* aubio_list_prepend(aubio_list_t *list, void* data);
+aubio_list_t* aubio_list_remove(aubio_list_t *list, void* data);
+aubio_list_t* aubio_list_remove_link(aubio_list_t *list, aubio_list_t *llink);
+aubio_list_t* aubio_list_nth(aubio_list_t *list, int n);
+aubio_list_t* aubio_list_last(aubio_list_t *list);
+aubio_list_t* aubio_list_insert_at(aubio_list_t *list, int n, void* data);
+int aubio_list_size(aubio_list_t *list);
+
+#define aubio_list_next(slist)	((slist) ? (((aubio_list_t *)(slist))->next) : NULL)
+#define aubio_list_get(slist)	((slist) ? ((slist)->data) : NULL)
+
+#endif  /* _AUBIO_LIST_H */
Index: ext/midi/midi.c
===================================================================
--- ext/midi/midi.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,32 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+#include "aubio_priv.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_track.h"
+#include "midi_player.h"
+
+/* all outgoing user messages are stored in a global text buffer */
+#define MIDI_MESSAGE_LENGTH 1024
+char midi_message_buffer[MIDI_MESSAGE_LENGTH];
+
Index: ext/midi/midi.h
===================================================================
--- ext/midi/midi.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,190 @@
+/* 
+ *
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from fluidsynth, peter hanappe and others,
+ * adapted for aubio by paul brossier,
+ */
+
+
+/** \file 
+ * midi header
+ *
+ * contains all (?) possible known midi messages. 
+ *
+ * this file originally taken from fluidsynth, Peter Hanappe and others,
+ * adapted for aubio by Paul Brossier,
+ */
+
+#ifndef _AUBIO_MIDI_H
+#define _AUBIO_MIDI_H
+
+//typedef struct _aubio_midi_driver_t aubio_midi_driver_t;
+
+//int aubio_midi_send_event(aubio_synth_t* synth, aubio_player_t* player, aubio_midi_event_t* evt);
+
+//int aubio_midi_router_send_event(aubio_midi_router_t* router, aubio_midi_event_t* event);
+
+
+/***************************************************************
+ *
+ *                   CONSTANTS & ENUM
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum aubio_midi_event_type {
+  /* channel messages */
+  NOTE_OFF = 0x80,
+  NOTE_ON = 0x90,
+  KEY_PRESSURE = 0xa0,
+  CONTROL_CHANGE = 0xb0,
+  PROGRAM_CHANGE = 0xc0,
+  CHANNEL_PRESSURE = 0xd0,
+  PITCH_BEND = 0xe0,
+  /* system exclusive */
+  MIDI_SYSEX = 0xf0,
+  /* system common - never in midi files */
+  MIDI_TIME_CODE = 0xf1,
+  MIDI_SONG_POSITION = 0xf2,
+  MIDI_SONG_SELECT = 0xf3,
+  MIDI_TUNE_REQUEST = 0xf6,
+  MIDI_EOX = 0xf7,
+  /* system real-time - never in midi files */
+  MIDI_SYNC = 0xf8,
+  MIDI_TICK = 0xf9,
+  MIDI_START = 0xfa,
+  MIDI_CONTINUE = 0xfb,
+  MIDI_STOP = 0xfc,
+  MIDI_ACTIVE_SENSING = 0xfe,
+  MIDI_SYSTEM_RESET = 0xff,
+  /* meta event - for midi files only */
+  MIDI_META_EVENT = 0xff
+};
+
+enum aubio_midi_control_change {
+  BANK_SELECT_MSB = 0x00,
+  MODULATION_MSB = 0x01,
+  BREATH_MSB = 0x02,
+  FOOT_MSB = 0x04,
+  PORTAMENTO_TIME_MSB = 0x05,
+  DATA_ENTRY_MSB = 0x06,
+  VOLUME_MSB = 0x07,
+  BALANCE_MSB = 0x08,
+  PAN_MSB = 0x0A,
+  EXPRESSION_MSB = 0x0B,
+  EFFECTS1_MSB = 0x0C,
+  EFFECTS2_MSB = 0x0D,
+  GPC1_MSB = 0x10, /* general purpose controller */
+  GPC2_MSB = 0x11,
+  GPC3_MSB = 0x12,
+  GPC4_MSB = 0x13,
+  BANK_SELECT_LSB = 0x20,
+  MODULATION_WHEEL_LSB = 0x21,
+  BREATH_LSB = 0x22,
+  FOOT_LSB = 0x24,
+  PORTAMENTO_TIME_LSB = 0x25,
+  DATA_ENTRY_LSB = 0x26,
+  VOLUME_LSB = 0x27,
+  BALANCE_LSB = 0x28,
+  PAN_LSB = 0x2A,
+  EXPRESSION_LSB = 0x2B,
+  EFFECTS1_LSB = 0x2C,
+  EFFECTS2_LSB = 0x2D,
+  GPC1_LSB = 0x30,
+  GPC2_LSB = 0x31,
+  GPC3_LSB = 0x32,
+  GPC4_LSB = 0x33,
+  SUSTAIN_SWITCH = 0x40,
+  PORTAMENTO_SWITCH = 0x41,
+  SOSTENUTO_SWITCH = 0x42,
+  SOFT_PEDAL_SWITCH = 0x43,
+  LEGATO_SWITCH = 0x45,
+  HOLD2_SWITCH = 0x45,
+  SOUND_CTRL1 = 0x46,
+  SOUND_CTRL2 = 0x47,
+  SOUND_CTRL3 = 0x48,
+  SOUND_CTRL4 = 0x49,
+  SOUND_CTRL5 = 0x4A,
+  SOUND_CTRL6 = 0x4B,
+  SOUND_CTRL7 = 0x4C,
+  SOUND_CTRL8 = 0x4D,
+  SOUND_CTRL9 = 0x4E,
+  SOUND_CTRL10 = 0x4F,
+  GPC5 = 0x50,
+  GPC6 = 0x51,
+  GPC7 = 0x52,
+  GPC8 = 0x53,
+  PORTAMENTO_CTRL = 0x54,
+  EFFECTS_DEPTH1 = 0x5B,
+  EFFECTS_DEPTH2 = 0x5C,
+  EFFECTS_DEPTH3 = 0x5D,
+  EFFECTS_DEPTH4 = 0x5E,
+  EFFECTS_DEPTH5 = 0x5F,
+  DATA_ENTRY_INCR = 0x60,
+  DATA_ENTRY_DECR = 0x61,
+  NRPN_LSB = 0x62,
+  NRPN_MSB = 0x63,
+  RPN_LSB = 0x64,
+  RPN_MSB = 0x65,
+  ALL_SOUND_OFF = 0x78,
+  ALL_CTRL_OFF = 0x79,
+  LOCAL_CONTROL = 0x7A,
+  ALL_NOTES_OFF = 0x7B,
+  OMNI_OFF = 0x7C,
+  OMNI_ON = 0x7D,
+  POLY_OFF = 0x7E,
+  POLY_ON = 0x7F
+};
+
+enum midi_meta_event {
+  MIDI_COPYRIGHT = 0x02,
+  MIDI_TRACK_NAME = 0x03,
+  MIDI_INST_NAME = 0x04,
+  MIDI_LYRIC = 0x05,
+  MIDI_MARKER = 0x06,
+  MIDI_CUE_POINT = 0x07,
+  MIDI_EOT = 0x2f,
+  MIDI_SET_TEMPO = 0x51,
+  MIDI_SMPTE_OFFSET = 0x54,
+  MIDI_TIME_SIGNATURE = 0x58,
+  MIDI_KEY_SIGNATURE = 0x59,
+  MIDI_SEQUENCER_EVENT = 0x7f
+};
+
+enum aubio_player_status 
+{
+  AUBIO_MIDI_PLAYER_READY,
+  AUBIO_MIDI_PLAYER_PLAYING,
+  AUBIO_MIDI_PLAYER_DONE
+};
+
+enum aubio_driver_status 
+{
+  AUBIO_MIDI_READY,
+  AUBIO_MIDI_LISTENING,
+  AUBIO_MIDI_DONE
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_MIDI_H */
Index: ext/midi/midi_alsa_raw.c
===================================================================
--- ext/midi/midi_alsa_raw.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_alsa_raw.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,308 @@
+/* 
+ * Copyright 2004 Paul Brossier
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from Fluidsynth, Peter Hanappe and others. */
+ 
+/** \file
+ * Midi driver for the Advanced Linux Sound Architecture
+ */
+
+
+#include "aubio_priv.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_parser.h"
+#include "midi_driver.h"
+
+#if ALSA_SUPPORT
+
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#include <alsa/asoundlib.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/poll.h>
+/* #include <errno.h> //perror is in stdio.h */
+
+#include "config.h"
+
+#define AUBIO_ALSA_DEFAULT_MIDI_DEVICE  "default"
+
+/** \bug double define? */
+#define AUBIO_ALSA_BUFFER_LENGTH 512
+
+/* SCHED_FIFO priorities for ALSA threads (see pthread_attr_setschedparam) */
+#define ALSA_RAWMIDI_SCHED_PRIORITY 90
+#define ALSA_SEQ_SCHED_PRIORITY 90
+
+/** aubio_midi_alsa_raw_driver_t */
+typedef struct {
+  aubio_midi_driver_t driver;
+  snd_rawmidi_t *rawmidi_in;
+  snd_rawmidi_t *rawmidi_out;
+  struct pollfd *pfd;
+  int npfd;
+  pthread_t thread;
+  int status;
+  unsigned char buffer[AUBIO_ALSA_BUFFER_LENGTH];
+  aubio_midi_parser_t* parser;
+} aubio_midi_alsa_raw_driver_t;
+
+aubio_midi_driver_t* new_aubio_midi_alsa_raw_driver(//aubio_settings_t* settings, 
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+int del_aubio_midi_alsa_raw_driver(aubio_midi_driver_t* p);
+static void* aubio_midi_alsa_raw_run(void* d);
+
+
+/**************************************************************
+ *
+ *        Alsa MIDI driver
+ *
+ */
+
+//void aubio_midi_alsa_raw_driver_settings(aubio_settings_t* settings)
+//{
+//  aubio_settings_register_str(settings, "midi.alsa.device", "default", 0, NULL, NULL);
+//}
+
+/** new_aubio_midi_alsa_raw_driver */
+aubio_midi_driver_t* new_aubio_midi_alsa_raw_driver(
+    //aubio_settings_t* settings, 
+    handle_midi_event_func_t handler, 
+    void* data)
+{
+  int i, err;
+  aubio_midi_alsa_raw_driver_t* dev;
+  pthread_attr_t attr;
+  int sched = SCHED_FIFO;
+  struct sched_param priority;
+  int count;
+  struct pollfd *pfd = NULL;
+  char* device = NULL;
+
+  /* not much use doing anything */
+  if (handler == NULL) {
+    AUBIO_ERR("Invalid argument");
+    return NULL;
+  }
+
+  /* allocate the device */
+  dev = AUBIO_NEW(aubio_midi_alsa_raw_driver_t);
+  if (dev == NULL) {
+    AUBIO_ERR( "Out of memory");
+    return NULL;
+  }
+  AUBIO_MEMSET(dev, 0, sizeof(aubio_midi_alsa_raw_driver_t));
+
+  dev->driver.handler = handler;
+  dev->driver.data = data;
+
+  /* allocate one event to store the input data */
+  dev->parser = new_aubio_midi_parser();
+  if (dev->parser == NULL) {
+    AUBIO_ERR( "Out of memory");
+    goto error_recovery;
+  }
+
+  /* get the device name. if none is specified, use the default device. */
+  //aubio_settings_getstr(settings, "midi.alsa.device", &device);
+  if (device == NULL) {
+    device = "default";
+  }
+
+  /* open the hardware device. only use midi in. */
+  if ((err = snd_rawmidi_open(&dev->rawmidi_in, NULL, device, SND_RAWMIDI_NONBLOCK)) < 0) {
+  //if ((err = snd_rawmidi_open(&dev->rawmidi_in, &dev->rawmidi_out, device, SND_RAWMIDI_NONBLOCK)) < 0) {
+    AUBIO_ERR( "Error opening ALSA raw MIDI IN port");
+    goto error_recovery;
+  }
+
+  /* get # of MIDI file descriptors */
+  count = snd_rawmidi_poll_descriptors_count(dev->rawmidi_in);
+  if (count > 0) {		/* make sure there are some */
+    pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
+    dev->pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
+    /* grab file descriptor POLL info structures */
+    count = snd_rawmidi_poll_descriptors(dev->rawmidi_in, pfd, count);
+  }
+
+  /* copy the input FDs */
+  for (i = 0; i < count; i++) {		/* loop over file descriptors */
+    if (pfd[i].events & POLLIN) { /* use only the input FDs */
+      dev->pfd[dev->npfd].fd = pfd[i].fd;
+      dev->pfd[dev->npfd].events = POLLIN; 
+      dev->pfd[dev->npfd].revents = 0; 
+      dev->npfd++;
+    }
+  }
+  AUBIO_FREE(pfd);
+
+
+  
+  dev->status = AUBIO_MIDI_READY;
+
+  /* create the midi thread */
+  if (pthread_attr_init(&attr)) {
+    AUBIO_ERR( "Couldn't initialize midi thread attributes");
+    goto error_recovery;
+  }
+
+  /* Was: "use fifo scheduling. if it fails, use default scheduling." */
+  /* Now normal scheduling is used by default for the MIDI thread. The reason is,
+   * that fluidsynth works better with low latencies under heavy load, if only the 
+   * audio thread is prioritized.
+   * With MIDI at ordinary priority, that could result in individual notes being played
+   * a bit late. On the other hand, if the audio thread is delayed, an audible dropout
+   * is the result.
+   * To reproduce this: Edirol UA-1 USB-MIDI interface, four buffers
+   * with 45 samples each (roughly 4 ms latency), ravewave soundfont. -MN
+   */ 
+
+  /* Not so sure anymore. We're losing MIDI data, if we can't keep up with
+   * the speed it is generated. */
+  /* AUBIO_MSG("Note: High-priority scheduling for the MIDI thread was intentionally disabled.");
+      sched=SCHED_OTHER;*/
+
+  while (1) {
+    err = pthread_attr_setschedpolicy(&attr, sched);
+    if (err) {
+      //AUBIO_LOG(AUBIO_WARN, "Couldn't set high priority scheduling for the MIDI input");
+      AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
+      if (sched == SCHED_FIFO) {
+        sched = SCHED_OTHER;
+        continue;
+      } else {
+        AUBIO_ERR( "Couldn't set scheduling policy.");
+        goto error_recovery;
+      }
+    }
+
+    /* SCHED_FIFO will not be active without setting the priority */
+    priority.sched_priority = (sched == SCHED_FIFO) ? 
+      ALSA_RAWMIDI_SCHED_PRIORITY : 0;
+    pthread_attr_setschedparam (&attr, &priority);
+    err = pthread_create(&dev->thread, &attr, aubio_midi_alsa_raw_run, (void*) dev);
+    if (err) {
+      AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
+      if (sched == SCHED_FIFO) {
+        sched = SCHED_OTHER;
+        continue;
+      } else {
+        AUBIO_ERR( "Couldn't create the midi thread.");
+        goto error_recovery;
+      }
+    }
+    break;
+  }  
+  return (aubio_midi_driver_t*) dev;
+
+error_recovery:
+  del_aubio_midi_alsa_raw_driver((aubio_midi_driver_t*) dev);
+  return NULL;
+
+}
+
+/** del_aubio_midi_alsa_raw_driver */
+int del_aubio_midi_alsa_raw_driver(aubio_midi_driver_t* p)
+{
+  aubio_midi_alsa_raw_driver_t* dev;
+
+  dev = (aubio_midi_alsa_raw_driver_t*) p;
+  if (dev == NULL) {
+    return AUBIO_OK;
+  }
+
+  dev->status = AUBIO_MIDI_DONE;
+
+  /* cancel the thread and wait for it before cleaning up */
+  if (dev->thread) {
+    if (pthread_cancel(dev->thread)) {
+      AUBIO_ERR( "Failed to cancel the midi thread");
+      return AUBIO_FAIL;
+    }
+    if (pthread_join(dev->thread, NULL)) {
+      AUBIO_ERR( "Failed to join the midi thread");
+      return AUBIO_FAIL;
+    }
+  }
+  if (dev->rawmidi_in) {
+    snd_rawmidi_drain(dev->rawmidi_in);
+    snd_rawmidi_close(dev->rawmidi_in);
+  }
+  if (dev->rawmidi_out) {
+    snd_rawmidi_drain(dev->rawmidi_out);
+    snd_rawmidi_close(dev->rawmidi_in);
+  }
+  if (dev->parser != NULL) {
+    del_aubio_midi_parser(dev->parser);
+  }
+  AUBIO_FREE(dev);
+  return AUBIO_OK;
+}
+
+/** aubio_midi_alsa_raw_run */
+void * aubio_midi_alsa_raw_run(void* d)
+{
+  int n, i;
+  aubio_midi_event_t* evt;
+  aubio_midi_alsa_raw_driver_t* dev = (aubio_midi_alsa_raw_driver_t*) d;
+
+  /* make sure the other threads can cancel this thread any time */
+  if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
+    AUBIO_ERR( "Failed to set the cancel state of the midi thread");
+    pthread_exit(NULL);
+  }
+  if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
+    AUBIO_ERR( "Failed to set the cancel state of the midi thread");
+    pthread_exit(NULL);
+  }
+
+  /* go into a loop until someone tells us to stop */
+  dev->status = AUBIO_MIDI_LISTENING;
+  while (dev->status == AUBIO_MIDI_LISTENING) {
+
+    /* is there something to read? */
+    /* use a 100 milliseconds timeout */
+    n = poll(dev->pfd, dev->npfd, 100); 
+    if (n < 0) {
+      perror("poll");
+    } else if (n > 0) {
+
+      /* read new data */
+      n = snd_rawmidi_read(dev->rawmidi_in, dev->buffer, 
+          AUBIO_ALSA_BUFFER_LENGTH);
+      if ((n < 0) && (n != -EAGAIN)) {
+        AUBIO_ERR( "Failed to read the midi input");
+        dev->status = AUBIO_MIDI_DONE;
+      }
+
+      /* let the parser convert the data into events */
+      for (i = 0; i < n; i++) {
+        evt = aubio_midi_parser_parse(dev->parser, dev->buffer[i]);
+        if (evt != NULL) {
+          (*dev->driver.handler)(dev->driver.data, evt);
+        }
+      }
+    };
+  }
+  pthread_exit(NULL);
+}
+
+#endif /* #if ALSA_SUPPORT */
Index: ext/midi/midi_alsa_seq.c
===================================================================
--- ext/midi/midi_alsa_seq.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_alsa_seq.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,419 @@
+/* 
+ * Copyright 2004 Paul Brossier
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from Fluidsynth, Peter Hanappe and others. */
+
+/** \file
+ * Midi driver for the Advanced Linux Sound Architecture (sequencer mode)
+ */
+
+
+#include "aubio_priv.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_parser.h"
+#include "midi_driver.h"
+#include "config.h"
+
+#if ALSA_SUPPORT
+
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#include <alsa/asoundlib.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/poll.h>
+/* #include <errno.h> //perror is in stdio.h */
+
+#define AUBIO_ALSA_DEFAULT_SEQ_DEVICE   "default"
+
+#define AUBIO_ALSA_BUFFER_LENGTH 512
+
+/* SCHED_FIFO priorities for ALSA threads (see pthread_attr_setschedparam) */
+#define ALSA_RAWMIDI_SCHED_PRIORITY 90
+#define ALSA_SEQ_SCHED_PRIORITY 90
+
+
+/** aubio_alsa_seq_driver_t */
+typedef struct {
+    aubio_midi_driver_t driver;
+    snd_seq_t *seq_handle;
+    int seq_port;
+    struct pollfd *pfd;
+    int npfd;
+    pthread_t thread;
+    int status;
+} aubio_alsa_seq_driver_t;
+
+aubio_midi_driver_t* new_aubio_alsa_seq_driver(//aubio_settings_t* settings, 
+        handle_midi_event_func_t handler, 
+        void* data);
+int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p);
+static void* aubio_alsa_seq_run(void* d);
+
+//void aubio_alsa_seq_driver_settings(aubio_settings_t* settings)
+//{
+//  aubio_settings_register_str(settings, "midi.alsa_seq.device", "default", 0, NULL, NULL);
+//  aubio_settings_register_str(settings, "midi.alsa_seq.id", "pid", 0, NULL, NULL);
+//}
+
+/** new_aubio_alsa_seq_driver */
+aubio_midi_driver_t*  new_aubio_alsa_seq_driver(//aubio_settings_t* settings, 
+        handle_midi_event_func_t handler, void* data)
+{
+    int i, err;                     
+    aubio_alsa_seq_driver_t* dev;   /**< object to return */
+    pthread_attr_t attr;            /**< sequencer thread */
+    int sched = SCHED_FIFO;         /**< default scheduling policy */
+    struct sched_param priority;    /**< scheduling priority settings */
+    int count;                      /**< number of MIDI file descriptors */
+    struct pollfd *pfd = NULL;      /**< poll file descriptor array (copied in dev->pfd) */
+    char* device = NULL;            /**< the device name */
+    char* id = NULL;
+    char full_id[64];
+    char full_name[64];
+
+    /* not much use doing anything */
+    if (handler == NULL) {
+        AUBIO_ERR( "Invalid argument");
+        return NULL;
+    }
+
+    /* allocate the device */
+    dev = AUBIO_NEW(aubio_alsa_seq_driver_t);
+    if (dev == NULL) {
+        AUBIO_ERR( "Out of memory");
+        return NULL;
+    }
+    AUBIO_MEMSET(dev, 0, sizeof(aubio_alsa_seq_driver_t));
+    dev->seq_port = -1;
+    dev->driver.data = data;
+    dev->driver.handler = handler;
+
+    /* get the device name. if none is specified, use the default device. */
+    //aubio_settings_getstr(settings, "midi.alsa_seq.device", &device);
+    if (device == NULL) {
+        device = "default";
+    }
+
+    /* open the sequencer INPUT only, non-blocking */
+    //if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT,
+    if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_DUPLEX,
+                    SND_SEQ_NONBLOCK)) < 0) {
+        AUBIO_ERR( "Error opening ALSA sequencer");
+        goto error_recovery;
+    }
+
+    /* tell the ladcca server our client id */
+#ifdef LADCCA_SUPPORT
+    {
+        int enable_ladcca = 1;
+        //aubio_settings_getint (settings, "ladcca.enable", &enable_ladcca);
+        if (enable_ladcca)
+            cca_alsa_client_id (aubio_cca_client, snd_seq_client_id (dev->seq_handle));
+    }
+#endif /* LADCCA_SUPPORT */
+
+    /* get # of MIDI file descriptors */
+    count = snd_seq_poll_descriptors_count(dev->seq_handle, POLLIN);
+    if (count > 0) {        /* make sure there are some */
+        pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
+        dev->pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
+        /* grab file descriptor POLL info structures */
+        count = snd_seq_poll_descriptors(dev->seq_handle, pfd, count, POLLIN);
+    }
+
+    for (i = 0; i < count; i++) {        /* loop over file descriptors */
+        /* copy the input FDs */
+        if (pfd[i].events & POLLIN) { /* use only the input FDs */
+            dev->pfd[dev->npfd].fd = pfd[i].fd;
+            dev->pfd[dev->npfd].events = POLLIN; 
+            dev->pfd[dev->npfd].revents = 0; 
+            dev->npfd++;
+        }
+    }
+    AUBIO_FREE(pfd);
+
+    //aubio_settings_getstr(settings, "midi.alsa_seq.id", &id);
+
+    if (id != NULL) {
+        if (AUBIO_STRCMP(id, "pid") == 0) {
+            snprintf(full_id, 64, "aubio (%d)", getpid());
+            snprintf(full_name, 64, "aubio_port (%d)", getpid());
+        } else {
+            snprintf(full_id, 64, "aubio (%s)", id);
+            snprintf(full_name, 64, "aubio_port (%s)", id);
+        }
+    } else {
+        snprintf(full_id, 64, "aubio");
+        snprintf(full_name, 64, "aubio_port");
+    }
+
+    /* set the client name */
+    snd_seq_set_client_name (dev->seq_handle, full_id);
+
+    if ((dev->seq_port = snd_seq_create_simple_port (dev->seq_handle,
+                    full_name,
+                    SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE |
+                    SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | 
+                    SND_SEQ_PORT_CAP_DUPLEX,
+                    SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
+    {
+        AUBIO_ERR( "Error creating ALSA sequencer port");
+        goto error_recovery;
+    }
+
+    dev->status = AUBIO_MIDI_READY;
+
+    /* create the midi thread */
+    if (pthread_attr_init(&attr)) {
+        AUBIO_ERR( "Couldn't initialize midi thread attributes");
+        goto error_recovery;
+    }
+
+    /* use fifo scheduling. if it fails, use default scheduling. */
+    while (1) {
+        err = pthread_attr_setschedpolicy(&attr, sched);
+        if (err) {
+            AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
+            if (sched == SCHED_FIFO) {
+                sched = SCHED_OTHER;
+                continue;
+            } else {
+                AUBIO_ERR( "Couldn't set scheduling policy.");
+                goto error_recovery;
+            }
+        }
+
+        /* SCHED_FIFO will not be active without setting the priority */
+        priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_SEQ_SCHED_PRIORITY : 0;
+        pthread_attr_setschedparam (&attr, &priority);
+
+        err = pthread_create(&dev->thread, &attr, aubio_alsa_seq_run, (void*) dev);
+        if (err) {
+            AUBIO_ERR( "Couldn't set high priority scheduling for the MIDI input");
+            if (sched == SCHED_FIFO) {
+                sched = SCHED_OTHER;
+                continue;
+            } else {
+                //AUBIO_LOG(AUBIO_PANIC, "Couldn't create the midi thread.");
+                AUBIO_ERR( "Couldn't create the midi thread.");
+                goto error_recovery;
+            }
+        }
+        break;
+    }
+    return (aubio_midi_driver_t*) dev;
+
+
+error_recovery:
+    del_aubio_alsa_seq_driver((aubio_midi_driver_t*) dev);
+    return NULL;
+}
+
+/** del_aubio_alsa_seq_driver */
+int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p)
+{
+    aubio_alsa_seq_driver_t* dev;
+
+    dev = (aubio_alsa_seq_driver_t*) p;
+    if (dev == NULL) {
+        return AUBIO_OK;
+    }
+
+    dev->status = AUBIO_MIDI_DONE;
+
+    /* cancel the thread and wait for it before cleaning up */
+    if (dev->thread) {
+        if (pthread_cancel(dev->thread)) {
+            AUBIO_ERR( "Failed to cancel the midi thread");
+            return AUBIO_FAIL;
+        }
+        if (pthread_join(dev->thread, NULL)) {
+            AUBIO_ERR( "Failed to join the midi thread");
+            return AUBIO_FAIL;
+        }
+    }
+    if (dev->seq_port >= 0) {
+        snd_seq_delete_simple_port (dev->seq_handle, dev->seq_port);
+    }
+    if (dev->seq_handle) {
+        snd_seq_drain_output(dev->seq_handle);
+        snd_seq_close(dev->seq_handle);
+    }
+    AUBIO_FREE(dev);
+    return AUBIO_OK;
+}
+
+/** aubio_alsa_seq_run */
+void* aubio_alsa_seq_run(void* d)
+{
+    int n;//, i;
+    snd_seq_event_t *seq_ev;
+    aubio_midi_event_t evt;
+    aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
+
+    /* make sure the other threads can cancel this thread any time */
+    if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
+        AUBIO_ERR( "Failed to set the cancel state of the midi thread");
+        pthread_exit(NULL);
+    }
+    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
+        AUBIO_ERR( "Failed to set the cancel state of the midi thread");
+        pthread_exit(NULL);
+    }
+
+    /* go into a loop until someone tells us to stop */
+    dev->status = AUBIO_MIDI_LISTENING;
+    while (dev->status == AUBIO_MIDI_LISTENING) {
+
+        /* is there something to read? */
+        n = poll(dev->pfd, dev->npfd, 1); /* use a 1 milliseconds timeout */
+        if (n < 0) {
+            perror("poll");
+        } else if (n > 0) {
+
+            /* read new events from the midi input port */
+            while ((n = snd_seq_event_input(dev->seq_handle, &seq_ev)) >= 0)
+            {
+                switch (seq_ev->type)
+                {
+                    case SND_SEQ_EVENT_NOTEON:
+                        evt.type = NOTE_ON;
+                        evt.channel = seq_ev->data.note.channel;
+                        evt.param1 = seq_ev->data.note.note;
+                        evt.param2 = seq_ev->data.note.velocity;
+                        break;
+                    case SND_SEQ_EVENT_NOTEOFF:
+                        evt.type = NOTE_OFF;
+                        evt.channel = seq_ev->data.note.channel;
+                        evt.param1 = seq_ev->data.note.note;
+                        evt.param2 = seq_ev->data.note.velocity;
+                        break;
+                    case SND_SEQ_EVENT_KEYPRESS:
+                        evt.type = KEY_PRESSURE;
+                        evt.channel = seq_ev->data.note.channel;
+                        evt.param1 = seq_ev->data.note.note;
+                        evt.param2 = seq_ev->data.note.velocity;
+                        break;
+                    case SND_SEQ_EVENT_CONTROLLER:
+                        evt.type = CONTROL_CHANGE;
+                        evt.channel = seq_ev->data.control.channel;
+                        evt.param1 = seq_ev->data.control.param;
+                        evt.param2 = seq_ev->data.control.value;
+                        break;
+                    case SND_SEQ_EVENT_PITCHBEND:
+                        evt.type = PITCH_BEND;
+                        evt.channel = seq_ev->data.control.channel;
+                        /* ALSA pitch bend is -8192 - 8191, we adjust it here */
+                        evt.param1 = seq_ev->data.control.value + 8192;
+                        break;
+                    case SND_SEQ_EVENT_PGMCHANGE:
+                        evt.type = PROGRAM_CHANGE;
+                        evt.channel = seq_ev->data.control.channel;
+                        evt.param1 = seq_ev->data.control.value;
+                        break;
+                    case SND_SEQ_EVENT_CHANPRESS:
+                        evt.type = CHANNEL_PRESSURE;
+                        evt.channel = seq_ev->data.control.channel;
+                        evt.param1 = seq_ev->data.control.value;
+                        break;
+                    default:
+                        continue;        /* unhandled event, next loop iteration */
+                }
+
+                /* send the events to the next link in the chain */
+                (*dev->driver.handler)(dev->driver.data, &evt);
+                
+                /* dump input on output */
+                //snd_seq_ev_set_source(new_ev, dev->seq_port);
+                //snd_seq_ev_set_dest(seq_ev,dev->seq_handle,dev->seq_client);
+                //snd_seq_ev_set_subs(new_ev);
+                //snd_seq_ev_set_direct(new_ev);
+                //snd_seq_event_output(dev->seq_handle, new_ev);
+                //snd_seq_drain_output(dev->seq_handle);
+
+            }
+        }
+
+        if ((n < 0) && (n != -EAGAIN)) {
+            AUBIO_ERR( "Error occured while reading ALSA sequencer events");
+            dev->status = AUBIO_MIDI_DONE;
+        }
+
+//        /* added by piem to handle new data to output */
+//        while (/* get new data, but from where ??? (n = snd_seq_event_output(dev->seq_handle, seq_ev)) >= 0*/ )
+//        {
+//            /* dump input on output */
+//            snd_seq_ev_set_source(new_ev, dev->seq_port);
+//            //snd_seq_ev_set_dest(seq_ev,dev->seq_handle,dev->seq_client);
+//            snd_seq_ev_set_subs(new_ev);
+//            snd_seq_ev_set_direct(new_ev);
+//            snd_seq_event_output(dev->seq_handle, new_ev);
+//            snd_seq_drain_output(dev->seq_handle);
+//        }
+
+    }
+    pthread_exit(NULL);
+}
+
+
+snd_seq_event_t ev;
+
+void aubio_midi_direct_output(aubio_midi_driver_t * d, aubio_midi_event_t * event) 
+{
+    aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
+    /*
+    if (pthread_join(dev->thread, NULL)) {
+        AUBIO_ERR( "Failed to join the midi thread");
+    }
+    */
+    switch(event->type) 
+    {
+        case NOTE_ON:
+            ev.type = SND_SEQ_EVENT_NOTEON;
+            ev.data.note.channel  = event->channel;
+            ev.data.note.note     = event->param1;
+            ev.data.note.velocity = event->param2;
+            //AUBIO_ERR( "NOTE_ON %d\n", event->param1);
+            break;
+        case NOTE_OFF:
+            ev.type = SND_SEQ_EVENT_NOTEOFF;
+            ev.data.note.channel  = event->channel;
+            ev.data.note.note     = event->param1;
+            ev.data.note.velocity = event->param2;
+            //AUBIO_ERR( "NOTE_OFF %d\n", event->param1);
+            break;
+        default:
+            break;
+    }
+    if (ev.type == SND_SEQ_EVENT_NOTEOFF || ev.type == SND_SEQ_EVENT_NOTEON ) { 
+        snd_seq_ev_set_subs(&ev);
+        snd_seq_ev_set_direct(&ev);
+        snd_seq_ev_set_source(&ev, dev->seq_port);
+        snd_seq_event_output_direct(dev->seq_handle, &ev);
+    }
+    /*
+    if (pthread_detach(dev->thread)) {
+        AUBIO_ERR( "Failed to leave the midi thread");
+    }
+    */
+}
+
+#endif /* #if ALSA_SUPPORT */
Index: ext/midi/midi_driver.c
===================================================================
--- ext/midi/midi_driver.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_driver.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,195 @@
+/* 
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+/* This file originally tajke from 
+ * FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+#include "aubio_priv.h"
+#include "midi_event.h"
+#include "midi_driver.h"
+//#include "settings.h"
+
+/*
+ * aubio_mdriver_definition
+ */
+struct aubio_mdriver_definition_t {
+  char* name;
+  aubio_midi_driver_t* (*new)(
+      //aubio_settings_t* settings, 
+      handle_midi_event_func_t event_handler, 
+      void* event_handler_data);
+  int (*free)(aubio_midi_driver_t* p);
+  void (*settings)(aubio_settings_t* settings);
+};
+
+
+/* ALSA */
+#if ALSA_SUPPORT
+aubio_midi_driver_t* new_aubio_midi_alsa_raw_driver(
+    //aubio_settings_t* settings,
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+int del_aubio_midi_alsa_raw_driver(aubio_midi_driver_t* p);
+void aubio_midi_alsa_raw_driver_settings(aubio_settings_t* settings);
+
+aubio_midi_driver_t* new_aubio_alsa_seq_driver(
+    //aubio_settings_t* settings,
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p);
+void aubio_alsa_seq_driver_settings(aubio_settings_t* settings);
+#endif
+
+/* OSS */
+#if OSS_SUPPORT
+aubio_midi_driver_t* new_aubio_oss_midi_driver(aubio_settings_t* settings,
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+int del_aubio_oss_midi_driver(aubio_midi_driver_t* p);
+//void aubio_oss_midi_driver_settings(aubio_settings_t* settings);
+#endif
+
+/* Windows MIDI service */
+#if WINMIDI_SUPPORT
+aubio_midi_driver_t* new_aubio_winmidi_driver(aubio_settings_t* settings,
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+int del_aubio_winmidi_driver(aubio_midi_driver_t* p);
+#endif
+
+/* definitions for the MidiShare driver */
+#if MIDISHARE_SUPPORT
+aubio_midi_driver_t* new_aubio_midishare_midi_driver(aubio_settings_t* settings,
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+int del_aubio_midishare_midi_driver(aubio_midi_driver_t* p);
+#endif
+
+
+struct aubio_mdriver_definition_t aubio_midi_drivers[] = {
+#if OSS_SUPPORT
+  { "oss", 
+    new_aubio_oss_midi_driver, 
+    del_aubio_oss_midi_driver, 
+    aubio_oss_midi_driver_settings },
+#endif
+#if ALSA_SUPPORT
+  { "alsa_raw", 
+    new_aubio_midi_alsa_raw_driver, 
+    del_aubio_midi_alsa_raw_driver, 
+    NULL /*aubio_midi_alsa_raw_driver_settings*/ },
+  { "alsa_seq", 
+    new_aubio_alsa_seq_driver, 
+    del_aubio_alsa_seq_driver, 
+    NULL /*aubio_alsa_seq_driver_settings*/ },
+#endif
+#if WINMIDI_SUPPORT
+  { "winmidi", 
+    new_aubio_winmidi_driver, 
+    del_aubio_winmidi_driver, 
+    NULL },
+#endif
+#if MIDISHARE_SUPPORT
+  { "midishare", 
+    new_aubio_midishare_midi_driver, 
+    del_aubio_midishare_midi_driver, 
+    NULL },
+#endif
+  { NULL, NULL, NULL, NULL }
+};
+
+
+void aubio_midi_driver_settings(aubio_settings_t* settings)
+{  
+  int i;
+
+#if 0
+  /* Set the default driver */
+#if ALSA_SUPPORT
+  aubio_settings_register_str(settings, "midi.driver", "alsa_seq", 0, NULL, NULL);
+#elif OSS_SUPPORT
+  aubio_settings_register_str(settings, "midi.driver", "oss", 0, NULL, NULL);
+#elif WINMIDI_SUPPORT
+  aubio_settings_register_str(settings, "midi.driver", "winmidi", 0, NULL, NULL);
+#elif MIDISHARE_SUPPORT
+  aubio_settings_register_str(settings, "midi.driver", "midishare", 0, NULL, NULL);
+#else
+  aubio_settings_register_str(settings, "midi.driver", "", 0, NULL, NULL);
+#endif
+
+  /* Add all drivers to the list of options */
+#if ALSA_SUPPORT
+  aubio_settings_add_option(settings, "midi.driver", "alsa_seq");
+  aubio_settings_add_option(settings, "midi.driver", "alsa_raw");
+#endif
+#if OSS_SUPPORT
+  aubio_settings_add_option(settings, "midi.driver", "oss");
+#endif
+#if WINMIDI_SUPPORT
+  aubio_settings_add_option(settings, "midi.driver", "winmidi");
+#endif
+#if MIDISHARE_SUPPORT
+  aubio_settings_add_option(settings, "midi.driver", "midishare");
+#endif
+
+#endif
+
+  for (i = 0; aubio_midi_drivers[i].name != NULL; i++) {
+    if (aubio_midi_drivers[i].settings != NULL) {
+      aubio_midi_drivers[i].settings(settings);
+    }
+  }  
+}
+
+//aubio_midi_driver_t* new_aubio_midi_driver(aubio_settings_t* settings, 
+aubio_midi_driver_t* new_aubio_midi_driver(char * name, 
+    handle_midi_event_func_t handler, 
+    void* event_handler_data)
+{
+  int i;
+  aubio_midi_driver_t* driver = NULL;
+  for (i = 0; aubio_midi_drivers[i].name != NULL; i++) {
+    if (AUBIO_STRCMP(name,aubio_midi_drivers[i].name) == 0){
+      //if (aubio_settings_str_equal(settings, "midi.driver", aubio_midi_drivers[i].name)) {
+      AUBIO_DBG( "Using '%s' midi driver\n", aubio_midi_drivers[i].name);
+      //driver = aubio_midi_drivers[i].new(settings, handler, event_handler_data);
+      driver = aubio_midi_drivers[i].new(/*name,*/ handler, event_handler_data);
+      if (driver) {
+        driver->name = aubio_midi_drivers[i].name;
+      }
+      return driver;
+    }
+  }
+  AUBIO_ERR("Couldn't find the requested midi driver");
+  return NULL;
+}
+
+void del_aubio_midi_driver(aubio_midi_driver_t* driver)
+{
+  int i;
+
+  for (i = 0; aubio_midi_drivers[i].name != NULL; i++) {
+    if (aubio_midi_drivers[i].name == driver->name) {
+      aubio_midi_drivers[i].free(driver);
+      return;
+    }
+  }  
+}
+
Index: ext/midi/midi_driver.h
===================================================================
--- ext/midi/midi_driver.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_driver.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,57 @@
+/* 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file orginally taken from :
+ * FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+
+/** \file
+ * generic midi driver
+ */
+
+#ifndef _AUBIO_MDRIVER_H
+#define _AUBIO_MDRIVER_H
+
+typedef void aubio_settings_t;
+
+typedef int (*handle_midi_event_func_t)(void* data, aubio_midi_event_t* event);
+
+/** aubio_midi_driver_t */
+typedef struct _aubio_midi_driver_t aubio_midi_driver_t;
+
+struct _aubio_midi_driver_t 
+{
+  char* name;
+  handle_midi_event_func_t handler;
+  void* data;
+};
+
+//aubio_midi_driver_t* new_aubio_midi_driver(aubio_settings_t* settings, 
+aubio_midi_driver_t* new_aubio_midi_driver(char * name, 
+    handle_midi_event_func_t handler, 
+    void* event_handler_data);
+void del_aubio_midi_driver(aubio_midi_driver_t* driver);
+void aubio_midi_driver_settings(aubio_settings_t* settings);
+
+#include "config.h"
+#if JACK_SUPPORT
+void aubio_midi_direct_output(aubio_midi_driver_t * dev, aubio_midi_event_t * event); 
+#endif
+
+#endif  /* _AUBIO_AUDRIVER_H */
Index: ext/midi/midi_event.c
===================================================================
--- ext/midi/midi_event.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_event.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,222 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+#include "aubio_priv.h"
+#include "midi_event.h"
+#include "midi.h"
+
+/******************************************************
+ *
+ *     aubio_event_t
+ */
+
+/*
+ * new_aubio_midi_event
+ */
+aubio_midi_event_t* new_aubio_midi_event()
+{
+  aubio_midi_event_t* evt;
+  evt = AUBIO_NEW(aubio_midi_event_t);
+  if (evt == NULL) {
+    AUBIO_ERR( "Out of memory");
+    return NULL;
+  }
+  evt->dtime = 0;
+  evt->type = 0;
+  evt->channel = 0;
+  evt->param1 = 0;
+  evt->param2 = 0;
+  evt->next = NULL;
+  return evt;
+}
+
+/** del_aubio_midi_event */
+int del_aubio_midi_event(aubio_midi_event_t* evt)
+{
+  aubio_midi_event_t *temp;
+  while(evt)
+  {
+    temp = evt->next;
+    AUBIO_FREE(evt);
+    evt = temp;
+  }
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_type
+ */
+int aubio_midi_event_get_type(aubio_midi_event_t* evt)
+{
+  return evt->type;
+}
+
+/*
+ * aubio_midi_event_set_type
+ */
+int aubio_midi_event_set_type(aubio_midi_event_t* evt, int type)
+{
+  evt->type = type;
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_channel
+ */
+int aubio_midi_event_get_channel(aubio_midi_event_t* evt)
+{
+  return evt->channel;
+}
+
+/*
+ * aubio_midi_event_set_channel
+ */
+int aubio_midi_event_set_channel(aubio_midi_event_t* evt, int chan)
+{
+  evt->channel = chan;
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_key
+ */
+int aubio_midi_event_get_key(aubio_midi_event_t* evt)
+{
+  return evt->param1;
+}
+
+/*
+ * aubio_midi_event_set_key
+ */
+int aubio_midi_event_set_key(aubio_midi_event_t* evt, int v)
+{
+  evt->param1 = v;
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_velocity
+ */
+int aubio_midi_event_get_velocity(aubio_midi_event_t* evt)
+{
+  return evt->param2;
+}
+
+/*
+ * aubio_midi_event_set_velocity
+ */
+int aubio_midi_event_set_velocity(aubio_midi_event_t* evt, int v)
+{
+  evt->param2 = v;
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_control
+ */
+int aubio_midi_event_get_control(aubio_midi_event_t* evt)
+{
+  return evt->param1;
+}
+
+/*
+ * aubio_midi_event_set_control
+ */
+int aubio_midi_event_set_control(aubio_midi_event_t* evt, int v)
+{
+  evt->param1 = v;
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_value
+ */
+int aubio_midi_event_get_value(aubio_midi_event_t* evt)
+{
+  return evt->param2;
+}
+
+/*
+ * aubio_midi_event_set_value
+ */
+int aubio_midi_event_set_value(aubio_midi_event_t* evt, int v)
+{
+  evt->param2 = v;
+  return AUBIO_OK;
+}
+
+int aubio_midi_event_get_program(aubio_midi_event_t* evt)
+{
+  return evt->param1;
+}
+
+int aubio_midi_event_set_program(aubio_midi_event_t* evt, int val)
+{
+  evt->param1 = val;
+  return AUBIO_OK;
+}
+
+int aubio_midi_event_get_pitch(aubio_midi_event_t* evt)
+{
+  return evt->param1;
+}
+
+int aubio_midi_event_set_pitch(aubio_midi_event_t* evt, int val)
+{
+  evt->param1 = val;
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_midi_event_get_param1
+ */
+/* int aubio_midi_event_get_param1(aubio_midi_event_t* evt) */
+/* { */
+/*   return evt->param1; */
+/* } */
+
+/*
+ * aubio_midi_event_set_param1
+ */
+/* int aubio_midi_event_set_param1(aubio_midi_event_t* evt, int v) */
+/* { */
+/*   evt->param1 = v; */
+/*   return AUBIO_OK; */
+/* } */
+
+/*
+ * aubio_midi_event_get_param2
+ */
+/* int aubio_midi_event_get_param2(aubio_midi_event_t* evt) */
+/* { */
+/*   return evt->param2; */
+/* } */
+
+/*
+ * aubio_midi_event_set_param2
+ */
+/* int aubio_midi_event_set_param2(aubio_midi_event_t* evt, int v) */
+/* { */
+/*   evt->param2 = v; */
+/*   return AUBIO_OK; */
+/* } */
+
Index: ext/midi/midi_event.h
===================================================================
--- ext/midi/midi_event.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_event.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,72 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+/** \file
+ * midi event structure
+ */
+
+#ifndef _AUBIO_MIDI_EVENT_H
+#define _AUBIO_MIDI_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_midi_event_t aubio_midi_event_t;
+
+/*
+ * aubio_midi_event_t
+ */
+struct _aubio_midi_event_t {
+  aubio_midi_event_t* next; /**< Don't use it, it will dissappear. Used in midi tracks.  */
+  unsigned int dtime;       /**< Delay (ticks) between this and previous event. midi tracks. */
+  unsigned char type;       /**< MIDI event type */
+  unsigned char channel;    /**< MIDI channel */
+  unsigned int param1;      /**< First parameter */
+  unsigned int param2;      /**< Second parameter */
+};
+
+aubio_midi_event_t* new_aubio_midi_event(void);
+int del_aubio_midi_event(aubio_midi_event_t* event);
+int aubio_midi_event_set_type(aubio_midi_event_t* evt, int type);
+int aubio_midi_event_get_type(aubio_midi_event_t* evt);
+int aubio_midi_event_set_channel(aubio_midi_event_t* evt, int chan);
+int aubio_midi_event_get_channel(aubio_midi_event_t* evt);
+int aubio_midi_event_get_key(aubio_midi_event_t* evt);
+int aubio_midi_event_set_key(aubio_midi_event_t* evt, int key);
+int aubio_midi_event_get_velocity(aubio_midi_event_t* evt);
+int aubio_midi_event_set_velocity(aubio_midi_event_t* evt, int vel);
+int aubio_midi_event_get_control(aubio_midi_event_t* evt);
+int aubio_midi_event_set_control(aubio_midi_event_t* evt, int ctrl);
+int aubio_midi_event_get_value(aubio_midi_event_t* evt);
+int aubio_midi_event_set_value(aubio_midi_event_t* evt, int val);
+int aubio_midi_event_get_program(aubio_midi_event_t* evt);
+int aubio_midi_event_set_program(aubio_midi_event_t* evt, int val);
+int aubio_midi_event_get_pitch(aubio_midi_event_t* evt);
+int aubio_midi_event_set_pitch(aubio_midi_event_t* evt, int val);
+int aubio_midi_event_length(unsigned char status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*_AUBIO_MIDI_EVENT_H*/
Index: ext/midi/midi_file.c
===================================================================
--- ext/midi/midi_file.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_file.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,633 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ *
+ *  \note fixed some track names causing segfault
+ */
+
+#include "aubio_priv.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_track.h"
+#include "midi_player.h"
+#include "midi_file.h"
+
+
+/** aubio_midi_file */
+struct  _aubio_midi_file_t{
+  //aubio_file_t fp;
+  FILE *fp;
+  int running_status;
+  int c;
+  int type;
+  int ntracks;
+  int uses_smpte;
+  unsigned int smpte_fps;
+  unsigned int smpte_res;
+  unsigned int division;       /* If uses_SMPTE == 0 then division is 
+				  ticks per beat (quarter-note) */
+  double tempo;                /* Beats per second (SI rules =) */
+  int tracklen;
+  int trackpos;
+  int eot;
+  int varlen;
+};
+
+/***************************************************************
+ *
+ *                      MIDIFILE
+ */
+
+/** new_aubio_midi_file */
+aubio_midi_file_t * new_aubio_midi_file(char* filename)
+{
+  aubio_midi_file_t* mf;
+
+  mf = AUBIO_NEW(aubio_midi_file_t);
+  if (mf == NULL) {
+    AUBIO_ERR( "Out of memory");
+    return NULL;
+  }
+  AUBIO_MEMSET(mf, 0, sizeof(aubio_midi_file_t));
+
+  mf->c = -1;
+  mf->running_status = -1;
+  mf->fp = AUBIO_FOPEN(filename, "rb");
+
+  if (mf->fp == NULL) {
+    AUBIO_ERR( "Couldn't open the MIDI file !\n");
+    AUBIO_FREE(mf);
+    return NULL;    
+  }
+
+  if (aubio_midi_file_read_mthd(mf) != AUBIO_OK) {
+    AUBIO_FREE(mf);
+    return NULL;
+  }
+  return mf;
+}
+
+/** del_aubio_midi_file */
+void del_aubio_midi_file(aubio_midi_file_t* mf)
+{
+  if (mf == NULL) {
+    return;
+  }
+  if (mf->fp != NULL) {
+    AUBIO_FCLOSE(mf->fp);
+  }
+  AUBIO_FREE(mf);
+  return;
+}
+
+/** aubio_midi_file_getc */
+int aubio_midi_file_getc(aubio_midi_file_t* mf)
+{
+  unsigned char c;
+  int n;
+  if (mf->c >= 0) {
+    c = mf->c;
+    mf->c = -1;
+  } else {
+    n = AUBIO_FREAD(&c, 1, 1, mf->fp);
+    mf->trackpos++;
+  }
+  return (int) c;
+}
+
+/** aubio_midi_file_push */
+int aubio_midi_file_push(aubio_midi_file_t* mf, int c)
+{
+  mf->c = c;
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_read */
+int aubio_midi_file_read(aubio_midi_file_t* mf, void* buf, int len)
+{
+  int num = AUBIO_FREAD(buf, 1, len, mf->fp);
+  mf->trackpos += num;
+#if DEBUG
+  if (num != len) {
+    AUBIO_DBG( "Coulnd't read the requested number of bytes");
+  }
+#endif
+  return (num != len)? AUBIO_FAIL : AUBIO_OK;
+}
+
+/** aubio_midi_file_skip */
+int aubio_midi_file_skip(aubio_midi_file_t* mf, int skip)
+{
+  int err = AUBIO_FSEEK(mf->fp, skip, SEEK_CUR);
+  if (err) {
+    AUBIO_ERR( "FAIL to seek position in file");
+    return AUBIO_FAIL;    
+  }
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_read_mthd */
+int aubio_midi_file_read_mthd(aubio_midi_file_t* mf)
+{
+  char mthd[15];
+  if (aubio_midi_file_read(mf, mthd, 14) != AUBIO_OK) {
+    return AUBIO_FAIL;
+  }
+  if ((AUBIO_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6) || (mthd[9] > 2)) {
+    AUBIO_ERR( "Doesn't look like a MIDI file: invalid MThd header");
+    return AUBIO_FAIL;
+  }
+  mf->type = mthd[9];
+  mf->ntracks = (unsigned) mthd[11];
+  mf->ntracks += (unsigned int) (mthd[10]) << 16;
+  /** \bug: smpte timing not yet implemented */ 
+  if((int)(mthd[12]) < 0){
+  /*if((mthd[12]) < 0){*/
+    mf->uses_smpte = 1;
+    mf->smpte_fps = -mthd[12];
+    mf->smpte_res = (unsigned) mthd[13];
+    AUBIO_ERR( "File uses SMPTE timing -- Not implemented yet");
+    return AUBIO_FAIL;
+  } else {
+    mf->uses_smpte = 0;
+    mf->division = (mthd[12] << 8) | (mthd[13] & 0xff);
+  }
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_load_tracks */
+int aubio_midi_file_load_tracks(aubio_midi_file_t* mf, aubio_midi_player_t* player)
+{
+  int i;
+  for (i = 0; i < mf->ntracks; i++) {
+    if (aubio_midi_file_read_track(mf, player, i) != AUBIO_OK) {
+      return AUBIO_FAIL;
+    }
+  }
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_read_tracklen */
+int aubio_midi_file_read_tracklen(aubio_midi_file_t* mf)
+{
+  unsigned char length[5];
+  if (aubio_midi_file_read(mf, length, 4) != AUBIO_OK) {
+    return AUBIO_FAIL;
+  }
+  mf->tracklen = aubio_getlength(length);
+  mf->trackpos = 0;
+  mf->eot = 0;
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_eot */
+int aubio_midi_file_eot(aubio_midi_file_t* mf)
+{
+#if DEBUG
+  if (mf->trackpos > mf->tracklen) {
+    printf("track overrun: %d > %d\n", mf->trackpos, mf->tracklen);
+  }
+#endif
+  return mf->eot || (mf->trackpos >= mf->tracklen);
+}
+
+/** aubio_midi_file_read_track */
+int aubio_midi_file_read_track(aubio_midi_file_t* mf, aubio_midi_player_t* player, int num)
+{
+  aubio_track_t* track;
+  unsigned char id[5], length[5];
+  int found_track = 0;
+  int skip;
+
+  AUBIO_DBG("Loading track %d\n",num);
+  if (aubio_midi_file_read(mf, id, 4) != AUBIO_OK) {
+    AUBIO_DBG("Failed loading track %d\n",num);
+    return AUBIO_FAIL;
+  }
+  
+  id[4]='\0';
+
+  while (!found_track){
+
+    if (aubio_isasciistring((char*) id) == 0) {
+      AUBIO_ERR( "An non-ascii track header found, currupt file");
+      return AUBIO_FAIL;
+
+    } else if (strcmp((char*) id, "MTrk") == 0) {
+
+      found_track = 1;
+
+      if (aubio_midi_file_read_tracklen(mf) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }
+
+      track = new_aubio_track(num);
+      if (track == NULL) {
+        AUBIO_ERR( "Out of memory");
+        return AUBIO_FAIL;
+      }
+
+      while (!aubio_midi_file_eot(mf)) {
+        if (aubio_midi_file_read_event(mf, track) != AUBIO_OK) {
+          return AUBIO_FAIL;	  
+        }
+      }
+
+      aubio_midi_player_add_track(player, track);
+    } else {
+      found_track = 0;
+      if (aubio_midi_file_read(mf, length, 4) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }
+      skip = aubio_getlength(length);
+      /* fseek(mf->fp, skip, SEEK_CUR); */
+      if (aubio_midi_file_skip(mf, skip) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }
+    }
+  }
+
+  if (feof(mf->fp)) {
+    AUBIO_ERR( "Unexpected end of file");
+    return AUBIO_FAIL;
+  }
+  AUBIO_DBG("Loaded track %d\n",num);
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_read_varlen */
+int aubio_midi_file_read_varlen(aubio_midi_file_t* mf)
+{ 
+  int i;
+  int c;
+  mf->varlen = 0;
+  for (i = 0;;i++) {
+    if (i == 4) {
+      AUBIO_ERR( "Invalid variable length number");
+      return AUBIO_FAIL;
+    }
+    c = aubio_midi_file_getc(mf);
+    if (c < 0) {
+      AUBIO_ERR( "Unexpected end of file");
+      return AUBIO_FAIL;
+    }
+    if (c & 0x80){
+      mf->varlen |= (int) (c & 0x7F);
+      mf->varlen <<= 7;
+    } else {
+      mf->varlen += c;
+      break;
+    }    
+  }
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_read_event */
+int aubio_midi_file_read_event(aubio_midi_file_t* mf, aubio_track_t* track)
+{
+  int dtime;
+  int status;
+  int type;
+  int tempo;
+  unsigned char* metadata = NULL;
+  unsigned char* dyn_buf = NULL;
+  unsigned char static_buf[256];
+  int nominator, denominator, clocks, notes, sf, mi;
+  aubio_midi_event_t* evt;
+  int channel = 0;
+  int param1 = 0;
+  int param2 = 0;
+
+
+  /* read the delta-time of the event */
+  if (aubio_midi_file_read_varlen(mf) != AUBIO_OK) {
+    return AUBIO_FAIL;
+  }
+  dtime = mf->varlen;
+
+  /* read the status byte */
+  status = aubio_midi_file_getc(mf);
+  if (status < 0) {
+    AUBIO_ERR( "Unexpected end of file");
+    return AUBIO_FAIL;
+  }
+
+  /* not a valid status byte: use the running status instead */
+  if ((status & 0x80) == 0) {
+    if ((mf->running_status & 0x80) == 0) {
+      AUBIO_ERR( "Undefined status and invalid running status");
+      return AUBIO_FAIL;
+    }
+    aubio_midi_file_push(mf, status);
+    status = mf->running_status;
+  } 
+
+  /* check what message we have */
+  if (status & 0x80) {
+    mf->running_status = status;
+
+    if ((status == MIDI_SYSEX) || (status == MIDI_EOX)) {     /* system exclusif */
+      /** \bug Sysex messages are not handled yet */
+      /* read the length of the message */
+      if (aubio_midi_file_read_varlen(mf) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }
+
+      if (mf->varlen < 255) {
+        metadata = &static_buf[0];
+      } else {
+        AUBIO_DBG( "%s: %d: alloc metadata, len = %d", __FILE__, __LINE__, mf->varlen);
+        dyn_buf = AUBIO_MALLOC(mf->varlen + 1);
+        if (dyn_buf == NULL) {
+          //AUBIO_LOG(AUBIO_PANIC, "Out of memory");
+          AUBIO_ERR("Out of memory");
+          return AUBIO_FAIL;
+        }
+        metadata = dyn_buf;
+      }
+
+      /* read the data of the message */
+      if (mf->varlen) {
+
+        if (aubio_midi_file_read(mf, metadata, mf->varlen) != AUBIO_OK) {
+          if (dyn_buf) {
+            AUBIO_FREE(dyn_buf);
+          }
+          return AUBIO_FAIL;
+        }
+
+        if (dyn_buf) {
+          AUBIO_DBG( "%s: %d: free metadata", __FILE__, __LINE__);
+          AUBIO_FREE(dyn_buf);
+        }
+      }
+
+      return AUBIO_OK;
+
+    } else if (status == MIDI_META_EVENT) {             /* meta events */
+
+      int result = AUBIO_OK;
+
+      /* get the type of the meta message */
+      type = aubio_midi_file_getc(mf);
+      if (type < 0) {
+        AUBIO_ERR( "Unexpected end of file");
+        return AUBIO_FAIL;
+      }
+
+      /* get the length of the data part */
+      if (aubio_midi_file_read_varlen(mf) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }
+
+      if (mf->varlen) {
+
+        if (mf->varlen < 255) {
+          metadata = &static_buf[0];
+        } else {
+          AUBIO_DBG( "%s: %d: alloc metadata, len = %d", __FILE__, __LINE__, mf->varlen);
+          dyn_buf = AUBIO_MALLOC(mf->varlen + 1);
+          if (dyn_buf == NULL) {
+            AUBIO_ERR("Out of memory");
+            return AUBIO_FAIL;
+          }
+          metadata = dyn_buf;
+        }
+
+        /* read the data */
+        if (aubio_midi_file_read(mf, metadata, mf->varlen) != AUBIO_OK) {
+          if (dyn_buf) {
+            AUBIO_FREE(dyn_buf);
+          }
+          return AUBIO_FAIL;
+        }
+      }
+
+      /* handle meta data */
+      switch (type) {
+
+        case MIDI_COPYRIGHT:
+          metadata[mf->varlen] = 0;
+          break;
+
+        case MIDI_TRACK_NAME:
+          if (metadata != NULL) /* avoids crashes on empty tracks */
+            metadata[mf->varlen] = 0;
+          aubio_track_set_name(track, (char*) metadata);
+          break;
+
+        case MIDI_INST_NAME:
+          metadata[mf->varlen] = 0;
+          break;
+
+        case MIDI_LYRIC:
+          break;
+
+        case MIDI_MARKER:
+          break;
+
+        case MIDI_CUE_POINT:
+          break; /* don't care much for text events */
+
+        case MIDI_EOT:
+          if (mf->varlen != 0) {
+            AUBIO_ERR("Invalid length for EndOfTrack event");
+            result = AUBIO_FAIL;
+            break;
+          }
+          mf->eot = 1;
+          break; 
+
+        case MIDI_SET_TEMPO:
+          if (mf->varlen != 3) {
+            AUBIO_ERR("Invalid length for SetTempo meta event");
+            result = AUBIO_FAIL;
+            break;
+          }
+          tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2];
+          evt = new_aubio_midi_event();
+          if (evt == NULL) {
+            AUBIO_ERR( "Out of memory");
+            result = AUBIO_FAIL;
+            break;
+          }
+          evt->dtime = dtime;
+          evt->type = MIDI_SET_TEMPO;
+          evt->channel = 0;
+          evt->param1 = tempo;
+          evt->param2 = 0;
+          aubio_track_add_event(track, evt);
+          break; 
+
+        case MIDI_SMPTE_OFFSET:
+          if (mf->varlen != 5) {
+            AUBIO_ERR("Invalid length for SMPTE Offset meta event");
+            result = AUBIO_FAIL;
+            break;
+          }
+          break; /* we don't use smtp */	
+
+        case MIDI_TIME_SIGNATURE:
+          if (mf->varlen != 4) {
+            AUBIO_ERR("Invalid length for TimeSignature meta event");
+            result = AUBIO_FAIL;
+            break;
+          }
+          nominator = metadata[0];
+          denominator = pow(2.0, (double) metadata[1]);
+          clocks = metadata[2];
+          notes = metadata[3];
+
+          AUBIO_DBG("signature=%d/%d, metronome=%d, 32nd-notes=%d\n", 
+              nominator, denominator, clocks, notes);
+
+          break;
+
+        case MIDI_KEY_SIGNATURE:
+          if (mf->varlen != 2) {
+            AUBIO_ERR( "Invalid length for KeySignature meta event");
+            result = AUBIO_FAIL;
+            break;
+          }
+          sf = metadata[0];
+          mi = metadata[1];
+          break;
+
+        case MIDI_SEQUENCER_EVENT:
+          AUBIO_DBG("Sequencer event ignored\n");
+          break;
+
+        default:
+          break;
+      }
+
+      if (dyn_buf) {
+        AUBIO_DBG( "%s: %d: free metadata", __FILE__, __LINE__);
+        AUBIO_FREE(dyn_buf);
+      }
+
+      return result;
+
+    } else {                /* channel messages */
+
+      type = status & 0xf0;
+      channel = status & 0x0f;
+
+      /* all channel message have at least 1 byte of associated data */
+      if ((param1 = aubio_midi_file_getc(mf)) < 0) {
+        AUBIO_ERR( "Unexpected end of file");
+        return AUBIO_FAIL;
+      }
+
+      switch (type) {
+
+        case NOTE_ON:
+          if ((param2 = aubio_midi_file_getc(mf)) < 0) {
+            AUBIO_ERR( "Unexpected end of file");
+            return AUBIO_FAIL;
+          }
+          break;
+
+        case NOTE_OFF:	
+          if ((param2 = aubio_midi_file_getc(mf)) < 0) {
+            AUBIO_ERR( "Unexpected end of file");
+            return AUBIO_FAIL;
+          }
+          break;
+
+        case KEY_PRESSURE:
+          if ((param2 = aubio_midi_file_getc(mf)) < 0) {
+            AUBIO_ERR( "Unexpected end of file");
+            return AUBIO_FAIL;
+          }
+          break;
+
+        case CONTROL_CHANGE:
+          if ((param2 = aubio_midi_file_getc(mf)) < 0) {
+            AUBIO_ERR( "Unexpected end of file");
+            return AUBIO_FAIL;
+          }
+          break;
+
+        case PROGRAM_CHANGE:
+          break;
+
+        case CHANNEL_PRESSURE:
+          break;
+
+        case PITCH_BEND:
+          if ((param2 = aubio_midi_file_getc(mf)) < 0) {
+            AUBIO_ERR( "Unexpected end of file");
+            return AUBIO_FAIL;
+          }
+
+          param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f);
+          param2 = 0;
+          break;
+
+        default:
+          /* Can't possibly happen !? */
+          AUBIO_ERR( "Unrecognized MIDI event");
+          return AUBIO_FAIL;      
+      }
+      evt = new_aubio_midi_event();
+      if (evt == NULL) {
+        AUBIO_ERR( "Out of memory");
+        return AUBIO_FAIL;
+      }
+      evt->dtime = dtime;
+      evt->type = type;
+      evt->channel = channel;
+      evt->param1 = param1;
+      evt->param2 = param2;
+      aubio_track_add_event(track, evt);
+    }
+  }
+  return AUBIO_OK;
+}
+
+/** aubio_midi_file_get_division */
+int aubio_midi_file_get_division(aubio_midi_file_t* midifile)
+{
+  return midifile->division;
+}
+
+
+/** aubio_isasciistring */
+int aubio_isasciistring(char* s)
+{
+  int i;
+  int len = (int) AUBIO_STRLEN(s);
+  for (i = 0; i < len; i++) {
+    if (!aubio_isascii(s[i])) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+/** aubio_getlength */
+long aubio_getlength(unsigned char *s)
+{
+  long i = 0;
+  i = s[3] | (s[2]<<8) | (s[1]<<16) | (s[0]<<24);
+  return i;
+}
+
Index: ext/midi/midi_file.h
===================================================================
--- ext/midi/midi_file.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_file.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,62 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+/** \file
+ * midi file reader
+ */
+
+#ifndef _AUBIO_MIDI_FILE_H
+#define _AUBIO_MIDI_FILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_midi_file_t aubio_midi_file_t;
+
+
+aubio_midi_file_t* new_aubio_midi_file(char* filename);
+void del_aubio_midi_file(aubio_midi_file_t* mf);
+int aubio_midi_file_read_mthd(aubio_midi_file_t* midifile);
+int aubio_midi_file_load_tracks(aubio_midi_file_t* midifile, aubio_midi_player_t* player);
+int aubio_midi_file_read_track(aubio_midi_file_t* mf, aubio_midi_player_t* player, int num);
+int aubio_midi_file_read_event(aubio_midi_file_t* mf, aubio_track_t* track);
+int aubio_midi_file_read_varlen(aubio_midi_file_t* mf);
+int aubio_midi_file_getc(aubio_midi_file_t* mf);
+int aubio_midi_file_push(aubio_midi_file_t* mf, int c);
+int aubio_midi_file_read(aubio_midi_file_t* mf, void* buf, int len);
+int aubio_midi_file_skip(aubio_midi_file_t* mf, int len);
+int aubio_midi_file_read_tracklen(aubio_midi_file_t* mf);
+int aubio_midi_file_eot(aubio_midi_file_t* mf);
+int aubio_midi_file_get_division(aubio_midi_file_t* midifile);
+
+
+/* From ctype.h */
+#define aubio_isascii(c)    (((c) & ~0x7f) == 0)  
+int aubio_isasciistring(char* s);
+long aubio_getlength(unsigned char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_AUBIO_MIDI_FILE_H*/
Index: ext/midi/midi_parser.c
===================================================================
--- ext/midi/midi_parser.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_parser.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,221 @@
+/* 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* This file orginally taken from, Fluidsynth, Peter Hanappe */
+
+#include "aubio_priv.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_parser.h"
+
+/** aubio_midi_parser_t */
+struct _aubio_midi_parser_t {
+  unsigned char status;       /**< Identifies the type of event, that is 
+                                 currently received ('Noteon', 'Pitch Bend'
+                                 etc). */
+  unsigned char channel;      /**< The channel of the event that is received 
+                                (in case of a channel event) */
+  unsigned int nr_bytes;      /**< How many bytes have been read for the 
+                                 current event? */
+  unsigned int nr_bytes_total;/**< How many bytes does the current event 
+                                type include? */
+  unsigned short p[AUBIO_MIDI_PARSER_MAX_PAR]; /**< The parameters */
+
+  aubio_midi_event_t event;   /**< The event, that is returned to the 
+                                 MIDI driver. */
+};
+
+/** new_aubio_midi_parser */
+aubio_midi_parser_t* new_aubio_midi_parser()
+{
+  aubio_midi_parser_t* parser;
+  parser = AUBIO_NEW(aubio_midi_parser_t);
+  if (parser == NULL) {
+    AUBIO_ERR("Out of memory");
+    return NULL;
+  }
+  /* As long as the status is 0, the parser won't do anything -> no need to
+   * initialize all the fields. */
+  parser->status = 0; 
+  return parser;
+}
+
+/** del_aubio_midi_parser */
+int del_aubio_midi_parser(aubio_midi_parser_t* parser)
+{
+  AUBIO_FREE(parser);
+  return AUBIO_OK;
+}
+
+/** aubio_midi_parser_parse
+ *
+ * The MIDI byte stream is fed into the parser, one byte at a time.
+ * As soon as the parser has recognized an event, it will return it.
+ * Otherwise it returns NULL.
+ */
+aubio_midi_event_t* aubio_midi_parser_parse(aubio_midi_parser_t* parser, 
+    unsigned char c)
+{
+  /*********************************************************************/
+  /* 'Process' system real-time messages                               */
+  /*********************************************************************/
+  /* There are not too many real-time messages that are of interest here.
+   * They can occur anywhere, even in the middle of a noteon message! 
+   * Real-time range: 0xF8 .. 0xFF
+   * Note: Real-time does not affect (running) status.
+   */  
+  if (c >= 0xF8){
+    if (c == MIDI_SYSTEM_RESET){
+      parser->event.type = c;
+      parser->status = 0; /* clear the status */
+      return &parser->event;
+    };
+    return NULL;
+  };
+
+  /*********************************************************************/
+  /* 'Process' system common messages (again, just skip them)          */
+  /*********************************************************************/
+  /* There are no system common messages that are of interest here.
+   * System common range: 0xF0 .. 0xF7 
+   */
+
+  if (c > 0xF0){
+    /* MIDI specs say: To ignore a non-real-time message, just discard all data
+     * up to the next status byte.  And our parser will ignore data that is
+     * received without a valid status.  
+     * Note: system common cancels running status. */
+    parser->status = 0;
+    return NULL;
+  };
+
+  /*********************************************************************/
+  /* Process voice category messages:                                  */
+  /*********************************************************************/
+  /* Now that we have handled realtime and system common messages, only
+   * voice messages are left.
+   * Only a status byte has bit # 7 set.
+   * So no matter the status of the parser (in case we have lost sync),
+   * as soon as a byte >= 0x80 comes in, we are dealing with a status byte
+   * and start a new event.
+   */
+
+  if (c & 0x80){
+    parser->channel = c & 0x0F;
+    parser->status = c & 0xF0;
+    /* The event consumes x bytes of data... (subtract 1 for the status 
+     * byte) */
+    parser->nr_bytes_total=aubio_midi_event_length(parser->status)-1;
+    /* of which we have read 0 at this time. */
+    parser->nr_bytes = 0;
+    return NULL;
+  };
+
+  /*********************************************************************/
+  /* Process data                                                      */
+  /*********************************************************************/
+  /* If we made it this far, then the received char belongs to the data
+   * of the last event. */
+  if (parser->status == 0){
+    /* We are not interested in the event currently received.
+     * Discard the data. */
+    return NULL;
+  };
+
+  /* Store the first couple of bytes */
+  if (parser->nr_bytes < AUBIO_MIDI_PARSER_MAX_PAR){
+    parser->p[parser->nr_bytes]=c;
+  };
+  parser->nr_bytes++;
+
+  /* Do we still need more data to get this event complete? */
+  if (parser->nr_bytes < parser->nr_bytes_total){
+    return NULL;
+  };
+
+  /*********************************************************************/
+  /* Send the event                                                    */
+  /*********************************************************************/
+  /* The event is ready-to-go.  About 'running status': 
+   * 
+   * The MIDI protocol has a built-in compression mechanism. If several similar
+   * events are sent in-a-row, for example note-ons, then the event type is
+   * only sent once. For this case, the last event type (status) is remembered.
+   * We simply keep the status as it is, just reset the parameter counter. If
+   * another status byte comes in, it will overwrite the status. 
+   */
+  parser->event.type = parser->status;
+  parser->event.channel = parser->channel;
+  parser->nr_bytes = 0; /* Related to running status! */
+  switch (parser->status){
+    case NOTE_OFF:
+    case NOTE_ON:
+    case KEY_PRESSURE:
+    case CONTROL_CHANGE:
+    case PROGRAM_CHANGE:
+    case CHANNEL_PRESSURE:
+      parser->event.param1 = parser->p[0]; /* For example key number */
+      parser->event.param2 = parser->p[1]; /* For example velocity */
+      break;
+    case PITCH_BEND:
+      /* Pitch-bend is transmitted with 14-bit precision. */
+      /* Note: '|' does here the same as '+' (no common bits), 
+       * but might be faster */
+      parser->event.param1 = ((parser->p[1] << 7) | parser->p[0]); 
+      break;
+    default: 
+      /* Unlikely */
+      return NULL;
+  };
+  return &parser->event;
+};
+
+
+
+/* Taken from Nagano Daisuke's USB-MIDI driver */
+static int remains_f0f6[] = {
+  0,	/* 0xF0 */
+  2,	/* 0XF1 */
+  3,	/* 0XF2 */
+  2,	/* 0XF3 */
+  2,	/* 0XF4 (Undefined by MIDI Spec, and subject to change) */
+  2,	/* 0XF5 (Undefined by MIDI Spec, and subject to change) */
+  1	  /* 0XF6 */
+};
+
+static int remains_80e0[] = {
+  3,	/* 0x8X Note Off */
+  3,	/* 0x9X Note On */
+  3,	/* 0xAX Poly-key pressure */
+  3,	/* 0xBX Control Change */
+  2,	/* 0xCX Program Change */
+  2,	/* 0xDX Channel pressure */
+  3 	/* 0xEX PitchBend Change */
+};
+
+/** Returns the length of the MIDI message starting with c.
+ *
+ * Taken from Nagano Daisuke's USB-MIDI driver */
+int aubio_midi_event_length(unsigned char event){
+  if ( event < 0xf0 ) {
+    return remains_80e0[((event-0x80)>>4)&0x0f];
+  } else if ( event < 0xf7 ) {
+    return remains_f0f6[event-0xf0];
+  } else {
+    return 1;
+  }
+}
Index: ext/midi/midi_parser.h
===================================================================
--- ext/midi/midi_parser.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_parser.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,49 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+
+/** \file
+ * midi parser
+ */
+
+#ifndef _AUBIO_MIDI_PARSER_H
+#define _AUBIO_MIDI_PARSER_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* How many parameters may a MIDI event have? */
+#define AUBIO_MIDI_PARSER_MAX_PAR 3
+
+typedef struct _aubio_midi_parser_t aubio_midi_parser_t;
+
+aubio_midi_parser_t* new_aubio_midi_parser(void);
+int del_aubio_midi_parser(aubio_midi_parser_t* parser);
+aubio_midi_event_t* aubio_midi_parser_parse(aubio_midi_parser_t* parser, unsigned char c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_AUBIO_MIDI_PARSER_H*/
Index: ext/midi/midi_player.c
===================================================================
--- ext/midi/midi_player.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_player.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,492 @@
+/* 
+ * Copyright (C) 2003  Peter Hanappe and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * modified by Paul Brossier for aubio
+ */
+
+/**
+ *
+ * \bug timer still broken 
+ * 	(should use alsa seq anyway) (fixed?) realtime playing is slower than
+ * 	it should. moved msec_passed and deltatime to microseconds (usec)
+ * 	(rounding were causing the drift) the new offline version is not quite
+ * 	exact yet.
+ *
+ * \bug the player does not seem to understand a ``reprise'' in a file
+ */
+
+#include "aubio_priv.h"
+#include "list.h"
+#include "timer.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_track.h"
+#include "midi_player.h"
+#include "midi_file.h"
+
+
+/** aubio_midi_player */
+struct _aubio_midi_player_t {
+  aubio_track_t  *track[AUBIO_MIDI_PLAYER_MAX_TRACKS];
+  aubio_timer_t* timer;
+  sint_t         status;
+  sint_t         loop;
+  sint_t         ntracks;
+  aubio_list_t*  playlist;
+  char*          current_file;
+  char           send_program_change;/**< should we ignore the program changes? */
+  sint_t         ticks_passed;       /**< number of midi ticks that have passed */
+  sint_t         usec_passed;        /**< number of microseconds that have passed */
+  sint_t         miditempo;          /**< as indicated by midi settempo: n 24th of a
+  *                                     usec per midi-clock. bravo! */
+  lsmp_t         deltatime;          /**< microseconds per midi tick. depends on
+  *                                     set-tempo */
+  uint_t         division;           /**< the number of ticks per beat (quarter-note)
+  *                                     in the file*/
+  //aubio_synth_t*                        synth;
+};
+
+/******************************************************
+ *
+ *     aubio_midi_player
+ */
+/** new_aubio_midi_player */
+aubio_midi_player_t* new_aubio_midi_player()
+  //aubio_midi_player_t* new_aubio_midi_player(aubio_synth_t* synth)
+{
+  sint_t i;
+  aubio_midi_player_t* player;
+  player = AUBIO_NEW(aubio_midi_player_t);
+  if (player == NULL) {
+    AUBIO_ERR( "Out of memory");
+    return NULL;
+  }
+  player->status  = AUBIO_MIDI_PLAYER_READY;
+  player->loop    = 0;
+  player->ntracks = 0;
+  for (i = 0; i < AUBIO_MIDI_PLAYER_MAX_TRACKS; i++) {
+    player->track[i] = NULL;
+  }
+  //player->synth = synth;
+  player->timer               = NULL;
+  player->playlist            = NULL;
+  player->current_file        = NULL;
+  player->division            = 0;
+  player->send_program_change = 1;
+  player->ticks_passed        = 0;
+  player->usec_passed         = 0;
+  player->miditempo           = 480000;
+  player->deltatime           = 4000.0;
+  return player;
+}
+
+/** delete_aubio_midi_player */
+sint_t del_aubio_midi_player(aubio_midi_player_t* player)
+{
+  if (player == NULL) {
+    return AUBIO_OK;
+  }
+  aubio_midi_player_stop(player);
+  aubio_midi_player_reset(player);
+  AUBIO_FREE(player);
+  return AUBIO_OK;
+}
+
+/** aubio_midi_player_reset */
+sint_t aubio_midi_player_reset(aubio_midi_player_t* player)
+{
+  sint_t i;
+
+  for (i = 0; i < AUBIO_MIDI_PLAYER_MAX_TRACKS; i++) {
+    if (player->track[i] != NULL) {
+      del_aubio_track(player->track[i]);
+      player->track[i] = NULL;
+    }
+  }
+  player->current_file        = NULL;
+  player->status              = AUBIO_MIDI_PLAYER_READY;
+  player->loop                = 0;
+  player->ntracks             = 0;
+  player->division            = 0;
+  player->send_program_change = 1;
+  player->ticks_passed        = 0;
+  player->usec_passed         = 0;
+  player->miditempo           = 480000;
+  player->deltatime           = 4000.0;
+  return 0;
+}
+
+/** aubio_midi_player_add_track */
+sint_t aubio_midi_player_add_track(aubio_midi_player_t* player, aubio_track_t* track)
+{
+  if (player->ntracks < AUBIO_MIDI_PLAYER_MAX_TRACKS) {
+    player->track[player->ntracks++] = track;
+    return AUBIO_OK;
+  } else {
+    return AUBIO_FAIL;
+  }
+}
+
+/** aubio_midi_player_count_tracks */
+sint_t aubio_midi_player_count_tracks(aubio_midi_player_t* player)
+{
+  return player->ntracks;
+}
+
+/** aubio_midi_player_get_track */
+aubio_track_t* aubio_midi_player_get_track(aubio_midi_player_t* player, sint_t i)
+{
+  if ((i >= 0) && (i < AUBIO_MIDI_PLAYER_MAX_TRACKS)) {
+    return player->track[i];
+  } else {
+    return NULL;
+  }
+}
+
+/** aubio_midi_player_get_track */
+sint_t aubio_midi_player_add(aubio_midi_player_t* player, char* midifile)
+{
+  char *s = AUBIO_STRDUP(midifile);
+  player->playlist = aubio_list_append(player->playlist, s);
+  return 0;
+}
+
+/** aubio_midi_player_load */
+sint_t aubio_midi_player_load(aubio_midi_player_t* player, char *filename)
+{
+  aubio_midi_file_t* midifile;
+
+  midifile = new_aubio_midi_file(filename); 
+  if (midifile == NULL) {
+    return AUBIO_FAIL;
+  }
+  player->division = aubio_midi_file_get_division(midifile);
+
+  AUBIO_DBG("quarter note division=%d\n", player->division); 
+
+  if (aubio_midi_file_load_tracks(midifile, player) != AUBIO_OK){
+    return AUBIO_FAIL;
+  }
+
+  AUBIO_DBG("Tracks loaded\n"); 
+
+  del_aubio_midi_file(midifile);
+  return AUBIO_OK;  
+}
+
+/** aubio_midi_player_callback */
+sint_t aubio_midi_player_callback(void* data, uint_t usec)
+{
+  sint_t i;
+  uint_t ticks;
+  uint_t delta_ticks;
+  sint_t status = AUBIO_MIDI_PLAYER_DONE;
+  aubio_midi_player_t* player;
+  //aubio_synth_t* synth;
+  player  = (aubio_midi_player_t*) data;
+  //synth = player->synth;
+
+  /* Load the next file if necessary */
+  while (player->current_file == NULL) {
+
+    if (player->playlist == NULL) {
+      return 0;
+    }
+
+    aubio_midi_player_reset(player);
+
+    player->current_file = aubio_list_get(player->playlist);
+    player->playlist = aubio_list_next(player->playlist);
+
+    //AUBIO_DBG( "%s: %d: Loading midifile %s", __FILE__, __LINE__, player->current_file);
+    AUBIO_DBG("Loading midifile %s\n", player->current_file);
+
+    if (aubio_midi_player_load(player, player->current_file) == AUBIO_OK) {
+
+      player->ticks_passed = 0;
+      player->usec_passed = 0;
+
+      for (i = 0; i < player->ntracks; i++) {
+        if (player->track[i] != NULL) {
+          aubio_track_reset(player->track[i]);
+        }
+      }
+
+    } else {
+      player->current_file = NULL;
+    }
+  }
+
+  delta_ticks = (uint_t) ((lsmp_t)(usec - player->usec_passed) / player->deltatime);
+  ticks = player->ticks_passed + delta_ticks;
+
+  for (i = 0; i < player->ntracks; i++) {
+    if (!aubio_track_eot(player->track[i])) {
+      status = AUBIO_MIDI_PLAYER_PLAYING;
+      if (aubio_track_send_events(player->track[i], /*synth,*/ player, ticks) != AUBIO_OK) {
+        /* */
+      }
+    }
+  }
+
+  player->status       = status;
+  player->ticks_passed = ticks;
+  player->usec_passed  = usec;
+
+  if (player->status == AUBIO_MIDI_PLAYER_DONE) {
+    player->current_file = NULL; 
+  }
+
+  return 1;
+}
+
+/** aubio_midi_player_play */
+sint_t aubio_midi_player_play(aubio_midi_player_t* player)
+{
+  AUBIO_DBG("Starting midi player\n");
+  if (player->status == AUBIO_MIDI_PLAYER_PLAYING) {
+    AUBIO_DBG("Midi player already playing\n");
+    return AUBIO_OK;
+  }
+
+  if (player->playlist == NULL) {
+    AUBIO_DBG("No playlist\n");
+    return AUBIO_FAIL;
+  }
+
+  player->status = AUBIO_MIDI_PLAYER_PLAYING;
+
+  /** \bug timer is still in millisec, should be moved to microseconds,
+   *     and replaced in favor of the alsa sequencer api */
+  player->timer = new_aubio_timer((sint_t) player->deltatime * 1.e-3, aubio_midi_player_callback, 
+      (void*) player, 1, 0);
+  if (player->timer == NULL) {
+    AUBIO_DBG("Failed creating timer for midi player.\n");
+    return AUBIO_FAIL;
+  }
+  if (player->current_file == NULL) {
+      AUBIO_DBG("No more file.\n");
+      delete_aubio_timer(player->timer);
+      return AUBIO_FAIL;
+  }
+
+  return AUBIO_OK;
+}
+
+/** aubio_midi_player_play_offline */
+sint_t aubio_midi_player_play_offline(aubio_midi_player_t* player)
+{
+  uint_t usec = 0; /* start looking n ms in advance */
+  AUBIO_DBG("Starting midi player\n");
+  if (player->status == AUBIO_MIDI_PLAYER_PLAYING) {
+    AUBIO_DBG("Midi player already playing\n");
+    return AUBIO_OK;
+  }
+
+  if (player->playlist == NULL) {
+    AUBIO_DBG("No playlist\n");
+    return AUBIO_FAIL;
+  }
+
+  //AUBIO_DBG("Starting callback.\n");
+  player->status = AUBIO_MIDI_PLAYER_PLAYING;
+
+  /* no timer, no thread ! */
+  while(aubio_midi_player_callback((void *)player,usec))
+  { 
+    /* step at least one microsecond forward */
+    usec += 1 + player->deltatime;
+    if (player->status == AUBIO_MIDI_PLAYER_DONE)
+      break;
+  }
+  //AUBIO_DBG("End of callback.\n");
+  
+  if (player->current_file == NULL) {
+      AUBIO_DBG("No more file.\n");
+      return AUBIO_FAIL;
+  }
+  return AUBIO_OK;
+}
+/** aubio_midi_player_stop */
+sint_t aubio_midi_player_stop(aubio_midi_player_t* player)
+{
+  if (player->timer != NULL) {
+    delete_aubio_timer(player->timer);
+  }
+  player->status = AUBIO_MIDI_PLAYER_DONE;
+  player->timer = NULL;
+  return AUBIO_OK;
+}
+
+/** aubio_midi_player_set_loop */
+sint_t aubio_midi_player_set_loop(aubio_midi_player_t* player, sint_t loop)
+{
+  player->loop = loop;
+  return AUBIO_OK;
+}
+
+/**  aubio_midi_player_set_midi_tempo */
+sint_t aubio_midi_player_set_midi_tempo(aubio_midi_player_t* player, sint_t tempo)
+{
+  player->miditempo = tempo;
+  //player->deltatime = (lsmp_t) tempo / player->division * 1.e-3; /* in milliseconds */
+  player->deltatime = (lsmp_t) tempo / player->division; /* in microseconds */
+
+  AUBIO_DBG("Tempo Change: %d tempo=%f tick time=%f msec\n",
+  //    player->usec_passed, 60.*1.e6/tempo, player->deltatime);
+      player->usec_passed, 60.*1.e6/tempo, 1e-3*player->deltatime);
+  
+  return AUBIO_OK;
+}
+
+/** aubio_midi_player_set_bpm */
+sint_t aubio_midi_player_set_bpm(aubio_midi_player_t* player, sint_t bpm)
+{
+  return aubio_midi_player_set_midi_tempo(player, (sint_t)((lsmp_t) 60 * 1e6 / bpm));
+}
+
+/** aubio_midi_player_join */
+sint_t aubio_midi_player_join(aubio_midi_player_t* player)
+{
+  return player->timer? aubio_timer_join(player->timer) : AUBIO_OK;
+}
+
+/** aubio_track_send_events */
+sint_t aubio_track_send_events(aubio_track_t* track, 
+    //    aubio_synth_t* synth,
+    aubio_midi_player_t* player,
+    uint_t ticks)
+{
+  sint_t status = AUBIO_OK;
+  aubio_midi_event_t* event;
+
+  while (1) {
+
+    event = track->cur;
+    if (event == NULL) {
+      return status;
+    }
+    /* prsint_t each midi tick */
+    /*
+       AUBIO_DBG("track=%d\tticks=%u\ttrack=%u\tdtime=%u\tnext=%u\n",
+       track->num,
+       ticks,
+       track->ticks,
+       event->dtime,
+       track->ticks + event->dtime);
+       */
+
+    if (track->ticks + event->dtime > ticks) {
+      return status;
+    }
+
+    track->ticks += event->dtime;
+    status = aubio_midi_send_event(/*synth, */player, event);
+    aubio_track_next_event(track);
+
+  }
+  return status;
+}
+
+
+/**
+ * aubio_midi_send_event
+ *
+ * This is a utility function that doesn't really belong to any class or
+ * structure. It is called by aubio_midi_track and aubio_midi_device.
+ *
+ * \note This could be moved to a callback function defined in the main programs
+ */
+//sint_t aubio_midi_send_event(aubio_synth_t* synth, aubio_player_t* player, aubio_midi_event_t* event)
+sint_t aubio_midi_send_event(aubio_midi_player_t* player, aubio_midi_event_t* event)
+{
+  /* current time in seconds */
+  //smpl_t print_time = player->msec_passed * 1e-3;
+  smpl_t print_time = player->usec_passed * 1e-6;
+  switch (event->type) {
+    case NOTE_ON:
+      AUBIO_MSG("Time=%f, chan=%d, pitch=%d vol=%d \n", 
+          print_time, event->channel, event->param1, event->param2);
+      /*if (aubio_synth_noteon(synth, event->channel, event->param1, event->param2) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }*/
+      break;
+    case NOTE_OFF:
+      AUBIO_MSG("Time=%f, chan=%d, pitch=%d, vol=0\n",
+          print_time, event->channel, event->param1);
+      /*if (aubio_synth_noteoff(synth, event->channel, event->param1) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }*/
+      break;
+    case CONTROL_CHANGE:
+      AUBIO_MSG("Time=%f Parameter, chan=%d c1=%d c2=%d\n",
+          print_time, event->channel, event->param1, event->param2);
+      /*if (aubio_synth_cc(synth, event->channel, event->param1, event->param2) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }*/
+      break;
+    case MIDI_SET_TEMPO:
+      if (player != NULL) {
+        if (aubio_midi_player_set_midi_tempo(player, event->param1) != AUBIO_OK) {
+          return AUBIO_FAIL;
+        }
+      }
+      break;
+    case PROGRAM_CHANGE:
+      AUBIO_MSG("Time=%f Program, chan=%d program=%d\n",
+          print_time, event->channel, event->param1);
+      /*if (aubio_synth_program_change(synth, event->channel, event->param1) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }*/
+      break;
+    case PITCH_BEND:
+      AUBIO_MSG("Time=%f Pitchbend, chan=%d msb=%d lsb=%d \n", 
+          print_time, event->channel, event->param1, event->param2);
+      /*if (aubio_synth_pitch_bend(synth, event->channel, event->param1) != AUBIO_OK) {
+        return AUBIO_FAIL;
+      }
+      break;*/
+    default:
+      break;
+  }
+  return AUBIO_OK;
+}
+
+
+/**
+ * aubio_midi_receive_event
+ *
+ * \note This could be moved to a callback function defined in the main programs
+ */
+sint_t aubio_midi_receive_event(aubio_midi_player_t* player, aubio_midi_event_t* event)
+{
+  /* current time in seconds */
+  //smpl_t print_time = player->msec_passed * 1e-3;
+  //smpl_t print_time = player->usec_passed * 1e-6;
+  switch (event->type) {
+    case NOTE_ON:
+      break;
+    case NOTE_OFF:
+      break;
+    default:
+      break;
+  }
+  return AUBIO_OK;
+}
Index: ext/midi/midi_player.h
===================================================================
--- ext/midi/midi_player.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_player.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,69 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+/** \file
+ * midi player
+ */
+
+
+#ifndef _AUBIO_MIDI_PLAYER_H
+#define _AUBIO_MIDI_PLAYER_H
+
+#define AUBIO_MIDI_PLAYER_MAX_TRACKS 128
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _aubio_midi_player_t aubio_midi_player_t;
+
+
+aubio_midi_player_t* new_aubio_midi_player(void);
+sint_t del_aubio_midi_player(aubio_midi_player_t* player);
+sint_t aubio_midi_player_reset(aubio_midi_player_t* player);
+sint_t aubio_midi_player_add_track(aubio_midi_player_t* player, aubio_track_t* track);
+sint_t aubio_midi_player_count_tracks(aubio_midi_player_t* player);
+aubio_track_t* aubio_midi_player_get_track(aubio_midi_player_t* player, sint_t i);
+sint_t aubio_midi_player_add(aubio_midi_player_t* player, char* midifile);
+sint_t aubio_midi_player_load(aubio_midi_player_t* player, char *filename);
+sint_t aubio_midi_player_callback(void* data, uint_t msec);
+sint_t aubio_midi_player_play(aubio_midi_player_t* player);
+sint_t aubio_midi_player_play_offline(aubio_midi_player_t* player);
+sint_t aubio_midi_player_stop(aubio_midi_player_t* player);
+sint_t aubio_midi_player_set_loop(aubio_midi_player_t* player, sint_t loop);
+sint_t aubio_midi_player_set_midi_tempo(aubio_midi_player_t* player, sint_t tempo);
+sint_t aubio_midi_player_set_bpm(aubio_midi_player_t* player, sint_t bpm);
+sint_t aubio_midi_player_join(aubio_midi_player_t* player);
+
+sint_t aubio_track_send_events(aubio_track_t* track, 
+/*  aubio_synth_t* synth, */
+			   aubio_midi_player_t* player,
+			   uint_t ticks);
+
+sint_t aubio_midi_send_event(aubio_midi_player_t* player, aubio_midi_event_t* event);
+sint_t aubio_midi_receive_event(aubio_midi_player_t* player, aubio_midi_event_t* event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AUBIO_MIDI_PLAYER_H*/
Index: ext/midi/midi_track.c
===================================================================
--- ext/midi/midi_track.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_track.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,162 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+
+#include "aubio_priv.h"
+#include "midi.h"
+#include "midi_event.h"
+#include "midi_track.h"
+#include "midi_player.h"
+
+
+/** new_aubio_track */
+aubio_track_t* new_aubio_track(int num)
+{
+  aubio_track_t* track;
+  track = AUBIO_NEW(aubio_track_t);
+  if (track == NULL) {
+    return NULL;
+  }
+  track->name = NULL;
+  track->num = num;
+  track->first = NULL;
+  track->cur = NULL;
+  track->last = NULL;
+  track->ticks = 0;
+  return track;
+}
+
+/** del_aubio_track */
+int del_aubio_track(aubio_track_t* track)
+{
+  if (track->name != NULL) {
+    AUBIO_FREE(track->name);
+  }
+  if (track->first != NULL) {
+    del_aubio_midi_event(track->first);
+  }
+  AUBIO_FREE(track);
+  return AUBIO_OK;
+}
+
+/** aubio_track_set_name */
+int aubio_track_set_name(aubio_track_t* track, char* name)
+{
+  int len;
+  if (track->name != NULL) {
+    AUBIO_FREE(track->name);
+  }
+  if (name == NULL) {
+    track->name = NULL;
+    return AUBIO_OK;  
+  }
+  len = AUBIO_STRLEN(name);
+  track->name = AUBIO_MALLOC(len + 1);
+  if (track->name == NULL) {
+    AUBIO_ERR( "Out of memory");
+    return AUBIO_FAIL;
+  }
+  AUBIO_STRCPY(track->name, name);
+  return AUBIO_OK;  
+}
+
+/** aubio_track_get_name */
+char* aubio_track_get_name(aubio_track_t* track)
+{
+  return track->name;
+}
+
+/** aubio_track_get_duration */
+int aubio_track_get_duration(aubio_track_t* track)
+ {
+  int time = 0;
+  aubio_midi_event_t* evt = track->first;
+  while (evt != NULL) {
+    time += evt->dtime;
+    evt = evt->next;
+  }
+  return time;
+}
+
+/** aubio_track_count_events  */
+int aubio_track_count_events(aubio_track_t* track, int* on, int* off)
+{
+  aubio_midi_event_t* evt = track->first;
+  while (evt != NULL) {
+    if (evt->type == NOTE_ON) {
+      (*on)++;
+    } else if (evt->type == NOTE_OFF) {
+      (*off)++;
+    }
+    evt = evt->next;
+  }
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_track_add_event
+ */
+int aubio_track_add_event(aubio_track_t* track, aubio_midi_event_t* evt)
+{
+  evt->next = NULL;
+  if (track->first == NULL) {
+    track->first = evt;
+    track->cur = evt;
+    track->last = evt;
+  } else {
+    track->last->next = evt;
+    track->last = evt;
+  }
+  return AUBIO_OK;
+}
+
+/*
+ * aubio_track_first_event
+ */
+aubio_midi_event_t* aubio_track_first_event(aubio_track_t* track)
+{
+  track->cur = track->first;
+  return track->cur;
+}
+
+/*
+ * aubio_track_next_event
+ */
+aubio_midi_event_t* aubio_track_next_event(aubio_track_t* track)
+{
+  if (track->cur != NULL) {
+    track->cur = track->cur->next;
+  }
+  return track->cur;
+}
+
+/*
+ * aubio_track_reset
+ */
+  int 
+aubio_track_reset(aubio_track_t* track)
+{
+  track->ticks = 0;
+  track->cur = track->first;
+  return AUBIO_OK;
+}
+
Index: ext/midi/midi_track.h
===================================================================
--- ext/midi/midi_track.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/midi_track.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,67 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+#ifndef _AUBIO_MIDI_TRACK_H
+#define _AUBIO_MIDI_TRACK_H
+
+/** \file
+ * midi track structure
+ * 
+ * \bug need public declaration ?
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** aubio_track_t */
+struct _aubio_track_t {
+  char* name;
+  int num;
+  aubio_midi_event_t *first;
+  aubio_midi_event_t *cur;
+  aubio_midi_event_t *last;
+  unsigned int ticks;
+};
+
+typedef struct _aubio_track_t aubio_track_t;
+
+aubio_track_t* new_aubio_track(int num);
+int del_aubio_track(aubio_track_t* track);
+int aubio_track_set_name(aubio_track_t* track, char* name);
+char* aubio_track_get_name(aubio_track_t* track);
+int aubio_track_add_event(aubio_track_t* track, aubio_midi_event_t* evt);
+aubio_midi_event_t* aubio_track_first_event(aubio_track_t* track);
+aubio_midi_event_t* aubio_track_next_event(aubio_track_t* track);
+int aubio_track_get_duration(aubio_track_t* track);
+int aubio_track_reset(aubio_track_t* track);
+int aubio_track_count_events(aubio_track_t* track, int* on, int* off);
+
+
+#define aubio_track_eot(track)  ((track)->cur == NULL)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_AUBIO_MIDI_TRACK_H*/
Index: ext/midi/timer.c
===================================================================
--- ext/midi/timer.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/timer.c	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,551 @@
+/* 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+/* this file originally taken from FluidSynth - A Software Synthesizer
+ * Copyright (C) 2003  Peter Hanappe and others.
+ */
+
+#include "aubio_priv.h"
+#include "timer.h"
+
+#if defined(WIN32)
+
+/*=============================================================*/
+/*                                                             */
+/*                           Win32                             */
+/*                                                             */
+/*=============================================================*/
+
+/***************************************************************
+ *
+ *               Timer
+ *
+ */
+#include <windef.h>
+
+#if 0
+#include <winbase.h>
+
+struct _aubio_timer_t 
+{
+  long msec;
+  aubio_timer_callback_t callback;
+  void* data;
+  HANDLE thread;
+  DWORD thread_id;
+  int cont;
+  int auto_destroy;
+};
+
+static int aubio_timer_count = 0;
+DWORD WINAPI aubio_timer_run(LPVOID data);
+
+aubio_timer_t* 
+new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data, 
+           int new_thread, int auto_destroy)
+{
+  aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
+  if (timer == NULL) {
+    AUBIO_ERR( "Out of memory");     
+    return NULL;
+  }
+
+  timer->cont = 1;
+  timer->msec = msec;
+  timer->callback = callback;
+  timer->data = data;
+  timer->thread = 0;
+  timer->auto_destroy = auto_destroy;
+
+  if (new_thread) {
+    timer->thread = CreateThread(NULL, 0, aubio_timer_run, (LPVOID) timer, 0, &timer->thread_id);
+    if (timer->thread == NULL) {
+      AUBIO_ERR( "Couldn't create timer thread");     
+      AUBIO_FREE(timer);
+      return NULL;
+    }
+    SetThreadPriority(timer->thread, THREAD_PRIORITY_TIME_CRITICAL);
+  } else {
+    aubio_timer_run((LPVOID) timer); 
+  }
+  return timer;
+}
+
+DWORD WINAPI 
+aubio_timer_run(LPVOID data)
+{
+  int count = 0;
+  int cont = 1;
+  long start;
+  long delay;
+  aubio_timer_t* timer;
+  timer = (aubio_timer_t*) data;
+
+  if ((timer == NULL) || (timer->callback == NULL)) {
+    return 0;
+  }
+
+  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+
+  /* keep track of the start time for absolute positioning */
+  start = aubio_curtime();
+
+  while (cont) {
+
+    /* do whatever we have to do */
+    cont = (*timer->callback)(timer->data, aubio_curtime() - start);
+
+    count++;
+
+    /* to avoid incremental time errors, I calculate the delay between
+       two callbacks bringing in the "absolute" time (count *
+       timer->msec) */
+    delay = (count * timer->msec) - (aubio_curtime() - start);
+    if (delay > 0) {
+      Sleep(delay);
+    }
+
+    cont &= timer->cont;
+  }
+
+  AUBIO_DBG( "Timer thread finished");
+
+  if (timer->auto_destroy) {
+    AUBIO_FREE(timer);
+  }
+
+  ExitThread(0);
+  return 0;
+}
+
+int 
+delete_aubio_timer(aubio_timer_t* timer)
+{
+  timer->cont = 0;
+  aubio_timer_join(timer); 
+  AUBIO_FREE(timer);
+  return AUBIO_OK;
+}
+
+int 
+aubio_timer_join(aubio_timer_t* timer)
+{
+  DWORD wait_result;
+  if (timer->thread == 0) {
+    return AUBIO_OK;
+  }
+  wait_result = WaitForSingleObject(timer->thread, INFINITE);
+  return (wait_result == WAIT_OBJECT_0)? AUBIO_OK : AUBIO_FAIL;
+}
+/***************************************************************
+ *
+ *               Time
+ */
+
+double rdtsc(void);
+double aubio_estimate_cpu_frequency(void);
+
+static double aubio_cpu_frequency = -1.0;
+
+void aubio_time_config(void)
+{
+  if (aubio_cpu_frequency < 0.0) {
+    aubio_cpu_frequency = aubio_estimate_cpu_frequency() / 1000000.0;  
+  }
+}
+
+double aubio_utime(void)
+{
+  return (rdtsc() / aubio_cpu_frequency);
+}
+
+double rdtsc(void)
+{
+  LARGE_INTEGER t;
+  QueryPerformanceCounter(&t);
+  return (double) t.QuadPart;
+}
+
+double aubio_estimate_cpu_frequency(void)
+{
+#if 0
+  LONGLONG start, stop, ticks;
+  unsigned int before, after, delta;
+  double freq;
+
+  start = rdtsc();
+  stop = start;
+  before = aubio_curtime();
+  after = before;
+
+  while (1) {
+    if (after - before > 1000) {
+    break;
+    }
+    after = aubio_curtime();
+    stop = rdtsc();
+  }
+
+  delta = after - before;
+  ticks = stop - start;
+
+  freq = 1000 * ticks / delta;
+
+  return freq;
+
+#else
+  unsigned int before, after;
+  LARGE_INTEGER start, stop;
+
+  before = aubio_curtime();
+  QueryPerformanceCounter(&start);
+
+  Sleep(1000);
+  
+  after = aubio_curtime();
+  QueryPerformanceCounter(&stop);
+
+  return (double) 1000 * (stop.QuadPart - start.QuadPart) / (after - before);
+#endif
+}
+
+#endif
+
+
+#elif defined(MACOS9)
+/*=============================================================*/
+/*                                                             */
+/*                           MacOS 9                           */
+/*                                                             */
+/*=============================================================*/
+
+
+/***************************************************************
+ *
+ *               Timer
+ */
+
+struct _aubio_timer_t 
+{
+    TMTask myTmTask;
+  long msec;
+  unsigned int start;
+  unsigned int count;
+  int isInstalled;
+  aubio_timer_callback_t callback;
+  void* data;
+  int auto_destroy;
+};
+
+static TimerUPP myTimerUPP;
+
+void
+_timerCallback(aubio_timer_t *timer)
+{
+    int cont;
+  cont = (*timer->callback)(timer->data, aubio_curtime() - timer->start);
+  if (cont) {
+    PrimeTime((QElemPtr)timer, timer->msec);
+    } else {
+        timer->isInstalled = 0;
+    }
+  timer->count++;
+}
+
+aubio_timer_t* 
+new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data, 
+           int new_thread, int auto_destroy)
+{
+  aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
+  if (timer == NULL) {
+    AUBIO_ERR( "Out of memory");     
+    return NULL;
+  }
+
+    if (!myTimerUPP)
+        myTimerUPP = NewTimerProc(_timerCallback);
+
+  /* setup tmtask */
+    timer->myTmTask.tmAddr = myTimerUPP;
+    timer->myTmTask.qLink = NULL;
+    timer->myTmTask.qType = 0;
+    timer->myTmTask.tmCount = 0L;
+    timer->myTmTask.tmWakeUp = 0L;
+    timer->myTmTask.tmReserved = 0L;
+
+  timer->callback = callback;
+
+  timer->msec = msec;
+  timer->data = data;
+  timer->start = aubio_curtime();
+  timer->isInstalled = 1;
+  timer->count = 0;
+  timer->auto_destroy = auto_destroy;
+  
+  InsXTime((QElemPtr)timer);
+  PrimeTime((QElemPtr)timer, msec);
+
+  return timer;
+}
+
+int 
+delete_aubio_timer(aubio_timer_t* timer)
+{
+    if (timer->isInstalled) {
+        RmvTime((QElemPtr)timer);
+    }
+  AUBIO_FREE(timer);
+  return AUBIO_OK;
+}
+
+int 
+aubio_timer_join(aubio_timer_t* timer)
+{
+    if (timer->isInstalled) {
+        int count = timer->count;
+        /* wait until count has incremented */
+        while (count == timer->count) {}
+    }
+  return AUBIO_OK;
+}
+
+/***************************************************************
+ *
+ *               Time
+ */
+#define kTwoPower32 (4294967296.0)      /* 2^32 */
+
+void aubio_time_config(void)
+{
+}
+
+unsigned int aubio_curtime()
+{
+    /* could be optimized by not going though a double */
+    UnsignedWide    uS;
+    double mSf;
+    unsigned int ms;
+    
+    Microseconds(&uS);
+    
+  mSf = ((((double) uS.hi) * kTwoPower32) + uS.lo)/1000.0f;
+  
+  ms = mSf;
+  
+  return (ms);
+}
+
+
+
+#else
+
+/*=============================================================*/
+/*                                                             */
+/*                           POSIX                             */
+/*                                                             */
+/*=============================================================*/
+
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+
+/***************************************************************
+ *
+ *               Timer
+ */
+ 
+struct _aubio_timer_t 
+{
+  long msec;
+  aubio_timer_callback_t callback;
+  void* data;
+  pthread_t thread;
+  int cont;
+  int auto_destroy;
+};
+
+void* 
+aubio_timer_start(void *data)
+{
+  int count = 0;
+  int cont = 1;
+  long start;
+  long delay;
+  aubio_timer_t* timer;
+  timer = (aubio_timer_t*) data;
+
+  /* keep track of the start time for absolute positioning */
+  start = aubio_curtime();
+
+  while (cont) {
+
+    /* do whatever we have to do */
+    cont = (*timer->callback)(timer->data, aubio_curtime() - start);
+
+    count++;
+
+    /* to avoid incremental time errors, calculate the delay between
+       two callbacks bringing in the "absolute" time (count *
+       timer->msec) */
+    delay = (count * timer->msec) - (aubio_curtime() - start);
+    if (delay > 0) {
+      usleep(delay * 1000);
+    }
+
+    cont &= timer->cont;
+  }
+
+  AUBIO_DBG( "Timer thread finished");
+  if (timer->thread != 0) {
+    pthread_exit(NULL);
+  }
+
+  if (timer->auto_destroy) {
+    AUBIO_FREE(timer);
+  }
+
+  return NULL;
+}
+
+aubio_timer_t* 
+new_aubio_timer(int msec, aubio_timer_callback_t callback, void* data, 
+           int new_thread, int auto_destroy)
+{
+  aubio_timer_t* timer = AUBIO_NEW(aubio_timer_t);
+  if (timer == NULL) {
+    AUBIO_ERR( "Out of memory");     
+    return NULL;
+  }
+  timer->msec = msec;
+  timer->callback = callback;
+  timer->data = data;
+  timer->cont = 1;
+  timer->thread = 0;
+  timer->auto_destroy = auto_destroy;
+
+  if (new_thread) {
+    if (pthread_create(&timer->thread, NULL, aubio_timer_start, (void*) timer)) {
+      AUBIO_ERR( "Failed to create the timer thread");
+      AUBIO_FREE(timer);
+      return NULL;
+    }
+  } else {
+    aubio_timer_start((void*) timer);
+  }
+  return timer;
+}
+
+int 
+delete_aubio_timer(aubio_timer_t* timer)
+{
+  timer->cont = 0;
+  aubio_timer_join(timer);
+  AUBIO_DBG( "Deleted player thread\n");
+  AUBIO_FREE(timer);
+  return AUBIO_OK;
+}
+
+int 
+aubio_timer_join(aubio_timer_t* timer)
+{
+  int err = 0;
+
+  if (timer->thread != 0) {
+    err = pthread_join(timer->thread, NULL);
+  } else
+    AUBIO_DBG( "Joined player thread\n");
+  return (err == 0)? AUBIO_OK : AUBIO_FAIL;
+}
+
+
+/***************************************************************
+ *
+ *               Time
+ */
+
+static double aubio_cpu_frequency = -1.0;
+
+double rdtsc(void);
+double aubio_estimate_cpu_frequency(void);
+
+void aubio_time_config(void)
+{
+  if (aubio_cpu_frequency < 0.0) {
+    aubio_cpu_frequency = aubio_estimate_cpu_frequency() / 1000000.0;  
+  }
+}
+
+unsigned int aubio_curtime()
+{
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  return now.tv_sec * 1000 + now.tv_usec / 1000;
+}
+
+double aubio_utime(void)
+{
+  return (rdtsc() / aubio_cpu_frequency);
+}
+
+#if !defined(__i386__)
+
+double rdtsc(void)
+{
+  return 0.0;
+}
+
+double aubio_estimate_cpu_frequency(void)
+{
+  return 1.0;
+}
+
+#else
+
+double rdtsc(void)
+{
+  unsigned int a, b;
+
+  __asm__ ("rdtsc" : "=a" (a), "=d" (b));
+  return (double)b * (double)0x10000 * (double)0x10000 + a;
+}
+
+double aubio_estimate_cpu_frequency(void)
+{
+  double start, stop;
+  unsigned int a0, b0, a1, b1;
+  unsigned int before, after;
+
+  before = aubio_curtime();  
+  __asm__ ("rdtsc" : "=a" (a0), "=d" (b0));
+
+  sleep(1);
+  
+  after = aubio_curtime();
+  __asm__ ("rdtsc" : "=a" (a1), "=d" (b1));
+
+
+  start = (double)b0 * (double)0x10000 * (double)0x10000 + a0;
+  stop = (double)b1 * (double)0x10000 * (double)0x10000 + a1;
+
+  return 1000 * (stop - start) / (after - before);
+}
+
+#endif
+
+#endif
Index: ext/midi/timer.h
===================================================================
--- ext/midi/timer.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
+++ ext/midi/timer.h	(revision b60dd4ae028d987b1e9bdbd6b71e62f529465109)
@@ -0,0 +1,34 @@
+
+#if defined(WIN32)
+#define aubio_curtime()   GetTickCount()
+
+double aubio_utime(void);
+
+#elif defined(MACOS9)
+#include <OSUtils.h>
+#include <Timer.h>
+
+unsigned int aubio_curtime();
+#define aubio_utime()  0.0
+
+#else
+
+unsigned int aubio_curtime(void);
+double aubio_utime(void);
+
+#endif
+
+/* if the callback function returns 1 the timer will continue; if it
+   returns 0 it will stop */
+typedef int (*aubio_timer_callback_t)(void* data, unsigned int msec);
+
+typedef struct _aubio_timer_t aubio_timer_t;
+
+aubio_timer_t* new_aubio_timer(int msec, aubio_timer_callback_t callback, 
+                        void* data, int new_thread, int auto_destroy);
+
+int delete_aubio_timer(aubio_timer_t* timer);
+int aubio_timer_join(aubio_timer_t* timer);
+int aubio_timer_stop(aubio_timer_t* timer);
+void * aubio_timer_start(void * data);
+void aubio_time_config(void);
