[SCM] gsequencer/upstream: enhanced midi parser

jkraehemann-guest at users.alioth.debian.org jkraehemann-guest at users.alioth.debian.org
Sun Jun 14 16:07:04 UTC 2015


The following commit has been merged in the upstream branch:
commit ec1efae9f88761c487e5eaa0ec3b7ac82f811e2f
Author: Joël Krähemann <weedlight at gmail.com>
Date:   Wed Apr 29 11:54:48 2015 +0000

    enhanced midi parser

diff --git a/Makefile.midi2ags b/Makefile.midi2ags
new file mode 100644
index 0000000..aefa862
--- /dev/null
+++ b/Makefile.midi2ags
@@ -0,0 +1,14 @@
+CFLAGS = `pkg-config --cflags gtk+-2.0 libxml-2.0` -I./src
+LDFLAGS = `pkg-config --libs gtk+-2.0 libxml-2.0`
+
+midi2ags: main.o ags_midi_parser.o ags_marshal.o
+	  gcc -g -o midi2ags main.o ags_marshal.o ags_midi_parser.o $(LDFLAGS)
+
+main.o: src/midi2ags/main.c src/midi2ags/midi/ags_midi_parser.c
+	gcc -g -c -o main.o src/midi2ags/main.c $(CFLAGS)
+
+ags_marshal.o: src/midi2ags/midi/ags_marshal.c
+	gcc -g -c -o ags_marshal.o src/midi2ags/midi/ags_marshal.c $(CFLAGS)
+
+ags_midi_parser.o: src/midi2ags/midi/ags_midi_parser.c src/midi2ags/midi/ags_marshal.c
+	gcc -g -c -o ags_midi_parser.o src/midi2ags/midi/ags_midi_parser.c $(CFLAGS)
diff --git a/Makefile.midi2ags~ b/Makefile.midi2ags~
new file mode 100644
index 0000000..8d0fd77
--- /dev/null
+++ b/Makefile.midi2ags~
@@ -0,0 +1,14 @@
+CFLAGS = `pkg-config --cflags gtk+-2.0 libxml-2.0` -I./src
+LDFLAGS = `pkg-config --libs gtk+-2.0 libxml-2.0`
+
+midi2ags: main.o ags_midi_parser.o ags_marshal.o
+	  gcc -g -o midi2ags main.o ags_midi_parser.o $(LDFLAGS)
+
+main.o: src/midi2ags/main.c src/midi2ags/midi/ags_midi_parser.c
+	gcc -g -c -o main.o src/midi2ags/main.c $(CFLAGS)
+
+ags_marshal.o: src/midi2ags/midi/ags_marshal.c
+	gcc -g -c -o ags_marshal.o src/midi2ags/midi/ags_marshal.c $(CFLAGS)
+
+ags_midi_parser.o: src/midi2ags/midi/ags_midi_parser.c src/midi2ags/midi/ags_marshal.c
+	gcc -g -c -o ags_midi_parser.o src/midi2ags/midi/ags_midi_parser.c $(CFLAGS)
diff --git a/src/midi2ags/main.c b/src/midi2ags/main.c
new file mode 100644
index 0000000..a7aa306
--- /dev/null
+++ b/src/midi2ags/main.c
@@ -0,0 +1,40 @@
+#include <glib.h>
+#include <glib-object.h>
+
+#include <midi2ags/midi/ags_midi_parser.h>
+
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+  AgsMidiParser *midi_parser;
+
+  xmlDoc *doc;
+  FILE *out;
+  
+  xmlChar *buffer;
+  gchar *filename;
+  size_t length;
+  int fd;
+  
+  if(argc == 2){
+    filename = argv[1];
+  }else{
+    return;
+  }
+
+  fd = fopen(filename, "r\0");
+  fseek(fd, 0, SEEK_SET);
+  midi_parser = ags_midi_parser_new(fd);
+
+  doc = ags_midi_parser_parse_full(midi_parser);
+  
+  xmlDocDumpFormatMemoryEnc(doc, &(buffer), &length, "UTF-8", TRUE);
+
+  fwrite(buffer, length, sizeof(xmlChar), stdout);
+  fflush(stdout);
+
+  
+  return(0);
+}
diff --git a/src/midi2ags/main.c~ b/src/midi2ags/main.c~
new file mode 100644
index 0000000..a093ed7
--- /dev/null
+++ b/src/midi2ags/main.c~
@@ -0,0 +1,40 @@
+#include <glib.h>
+#include <glib-object.h>
+
+#include <midi2ags/midi/ags_midi_parser.h>
+
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+  AgsMidiParser *midi_parser;
+
+  xmlDoc *doc;
+  FILE *out;
+  
+  xmlChar *buffer;
+  gchar *filename;
+  size_t length;
+  int fd;
+  
+  if(argc == 2){
+    filename = argv[1];
+  }else{
+    return;
+  }
+
+  fd = open(filename, 0);
+  lseek(fd, 0, SEEK_SET);
+  midi_parser = ags_midi_parser_new(fd);
+
+  doc = ags_midi_parser_parse_full(midi_parser);
+  
+  xmlDocDumpFormatMemoryEnc(doc, &(buffer), &length, "UTF-8", TRUE);
+
+  fwrite(buffer, length, sizeof(xmlChar), stdout);
+  fflush(stdout);
+
+  
+  return(0);
+}
diff --git a/src/ags-client/object/ags_marshal.c b/src/midi2ags/midi/ags_marshal.c
similarity index 55%
copy from src/ags-client/object/ags_marshal.c
copy to src/midi2ags/midi/ags_marshal.c
index 260a9a5..ab8534a 100644
--- a/src/ags-client/object/ags_marshal.c
+++ b/src/midi2ags/midi/ags_marshal.c
@@ -49,21 +49,21 @@
 #endif /* !G_ENABLE_DEBUG */
 
 
-/* OBJECT:VOID (ags_marshallers.list:1) */
+/* INT:VOID (ags_marshallers.list:1) */
 void
-g_cclosure_user_marshal_OBJECT__VOID (GClosure     *closure,
-                                      GValue       *return_value G_GNUC_UNUSED,
-                                      guint         n_param_values,
-                                      const GValue *param_values,
-                                      gpointer      invocation_hint G_GNUC_UNUSED,
-                                      gpointer      marshal_data)
+g_cclosure_user_marshal_INT__VOID (GClosure     *closure,
+                                   GValue       *return_value G_GNUC_UNUSED,
+                                   guint         n_param_values,
+                                   const GValue *param_values,
+                                   gpointer      invocation_hint G_GNUC_UNUSED,
+                                   gpointer      marshal_data)
 {
-  typedef GObject* (*GMarshalFunc_OBJECT__VOID) (gpointer     data1,
-                                                 gpointer     data2);
-  register GMarshalFunc_OBJECT__VOID callback;
+  typedef gint (*GMarshalFunc_INT__VOID) (gpointer     data1,
+                                          gpointer     data2);
+  register GMarshalFunc_INT__VOID callback;
   register GCClosure *cc = (GCClosure*) closure;
   register gpointer data1, data2;
-  GObject* v_return;
+  gint v_return;
 
   g_return_if_fail (return_value != NULL);
   g_return_if_fail (n_param_values == 1);
@@ -78,30 +78,67 @@ g_cclosure_user_marshal_OBJECT__VOID (GClosure     *closure,
       data1 = g_value_peek_pointer (param_values + 0);
       data2 = closure->data;
     }
-  callback = (GMarshalFunc_OBJECT__VOID) (marshal_data ? marshal_data : cc->callback);
+  callback = (GMarshalFunc_INT__VOID) (marshal_data ? marshal_data : cc->callback);
 
   v_return = callback (data1,
                        data2);
 
-  g_value_take_object (return_value, v_return);
+  g_value_set_int (return_value, v_return);
 }
 
-/* OBJECT:POINTER (ags_marshallers.list:2) */
+/* POINTER:VOID (ags_marshallers.list:2) */
 void
-g_cclosure_user_marshal_OBJECT__POINTER (GClosure     *closure,
-                                         GValue       *return_value G_GNUC_UNUSED,
-                                         guint         n_param_values,
-                                         const GValue *param_values,
-                                         gpointer      invocation_hint G_GNUC_UNUSED,
-                                         gpointer      marshal_data)
+g_cclosure_user_marshal_POINTER__VOID (GClosure     *closure,
+                                       GValue       *return_value G_GNUC_UNUSED,
+                                       guint         n_param_values,
+                                       const GValue *param_values,
+                                       gpointer      invocation_hint G_GNUC_UNUSED,
+                                       gpointer      marshal_data)
 {
-  typedef GObject* (*GMarshalFunc_OBJECT__POINTER) (gpointer     data1,
-                                                    gpointer     arg_1,
-                                                    gpointer     data2);
-  register GMarshalFunc_OBJECT__POINTER callback;
+  typedef gpointer (*GMarshalFunc_POINTER__VOID) (gpointer     data1,
+                                                  gpointer     data2);
+  register GMarshalFunc_POINTER__VOID callback;
   register GCClosure *cc = (GCClosure*) closure;
   register gpointer data1, data2;
-  GObject* v_return;
+  gpointer v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 1);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_POINTER__VOID) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (data1,
+                       data2);
+
+  g_value_set_pointer (return_value, v_return);
+}
+
+/* POINTER:UINT (ags_marshallers.list:3) */
+void
+g_cclosure_user_marshal_POINTER__UINT (GClosure     *closure,
+                                       GValue       *return_value G_GNUC_UNUSED,
+                                       guint         n_param_values,
+                                       const GValue *param_values,
+                                       gpointer      invocation_hint G_GNUC_UNUSED,
+                                       gpointer      marshal_data)
+{
+  typedef gpointer (*GMarshalFunc_POINTER__UINT) (gpointer     data1,
+                                                  guint        arg_1,
+                                                  gpointer     data2);
+  register GMarshalFunc_POINTER__UINT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+  gpointer v_return;
 
   g_return_if_fail (return_value != NULL);
   g_return_if_fail (n_param_values == 2);
@@ -116,12 +153,12 @@ g_cclosure_user_marshal_OBJECT__POINTER (GClosure     *closure,
       data1 = g_value_peek_pointer (param_values + 0);
       data2 = closure->data;
     }
-  callback = (GMarshalFunc_OBJECT__POINTER) (marshal_data ? marshal_data : cc->callback);
+  callback = (GMarshalFunc_POINTER__UINT) (marshal_data ? marshal_data : cc->callback);
 
   v_return = callback (data1,
-                       g_marshal_value_peek_pointer (param_values + 1),
+                       g_marshal_value_peek_uint (param_values + 1),
                        data2);
 
-  g_value_take_object (return_value, v_return);
+  g_value_set_pointer (return_value, v_return);
 }
 
diff --git a/src/midi2ags/midi/ags_marshal.h b/src/midi2ags/midi/ags_marshal.h
new file mode 100644
index 0000000..0043dbc
--- /dev/null
+++ b/src/midi2ags/midi/ags_marshal.h
@@ -0,0 +1,36 @@
+
+#ifndef __g_cclosure_user_marshal_MARSHAL_H__
+#define __g_cclosure_user_marshal_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+/* INT:VOID (ags_marshallers.list:1) */
+extern void g_cclosure_user_marshal_INT__VOID (GClosure     *closure,
+                                               GValue       *return_value,
+                                               guint         n_param_values,
+                                               const GValue *param_values,
+                                               gpointer      invocation_hint,
+                                               gpointer      marshal_data);
+
+/* POINTER:VOID (ags_marshallers.list:2) */
+extern void g_cclosure_user_marshal_POINTER__VOID (GClosure     *closure,
+                                                   GValue       *return_value,
+                                                   guint         n_param_values,
+                                                   const GValue *param_values,
+                                                   gpointer      invocation_hint,
+                                                   gpointer      marshal_data);
+
+/* POINTER:UINT (ags_marshallers.list:3) */
+extern void g_cclosure_user_marshal_POINTER__UINT (GClosure     *closure,
+                                                   GValue       *return_value,
+                                                   guint         n_param_values,
+                                                   const GValue *param_values,
+                                                   gpointer      invocation_hint,
+                                                   gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* __g_cclosure_user_marshal_MARSHAL_H__ */
+
diff --git a/src/midi2ags/midi/ags_marshallers.list b/src/midi2ags/midi/ags_marshallers.list
new file mode 100644
index 0000000..79cd91d
--- /dev/null
+++ b/src/midi2ags/midi/ags_marshallers.list
@@ -0,0 +1,3 @@
+INT:VOID
+POINTER:VOID
+POINTER:UINT
diff --git a/src/midi2ags/midi/ags_marshallers.list~ b/src/midi2ags/midi/ags_marshallers.list~
new file mode 100644
index 0000000..bd89eef
--- /dev/null
+++ b/src/midi2ags/midi/ags_marshallers.list~
@@ -0,0 +1,3 @@
+INT:VOID
+POINTER:VOID
+POINTER:UINT
\ No newline at end of file
diff --git a/src/midi2ags/midi/ags_midi_parser.c b/src/midi2ags/midi/ags_midi_parser.c
index ce1ccc1..3c86568 100644
--- a/src/midi2ags/midi/ags_midi_parser.c
+++ b/src/midi2ags/midi/ags_midi_parser.c
@@ -16,16 +16,58 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <ags/audio/midi/ags_midi_parser.h>
+#include <midi2ags/midi/ags_midi_parser.h>
+#include <midi2ags/midi/ags_marshal.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
 
 void ags_midi_parser_class_init(AgsMidiParserClass *midi_parser);
 void ags_midi_parser_init(AgsMidiParser *midi_parser);
+void ags_midi_parser_set_property(GObject *gobject,
+				  guint prop_id,
+				  const GValue *value,
+				  GParamSpec *param_spec);
+void ags_midi_parser_get_property(GObject *gobject,
+				  guint prop_id,
+				  GValue *value,
+				  GParamSpec *param_spec);
 void ags_midi_parser_finalize(GObject *gobject);
 
-#define AGS_MIDI_PARSE_MSB16(x) ((x[0] << 8) | (x[1]))
-#define AGS_MIDI_PARSE_MSB24(x) ((x[0] << 16) | (x[1] << 8) | (x[2]))
-#define AGS_MIDI_PARSE_MSB32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3]))
-#define AGS_MIDI_PARSE_MSB64(x) ((x[0] << 56) | (x[1] << 48) | (x[2] << 40) | (x[3] << 32) | (x[4] << 24) | (x[5] << 16) | (x[6] << 8) | (x[7]))
+int ags_midi_parser_real_midi_getc(AgsMidiParser *midi_parser);
+void ags_midi_parser_real_on_error(AgsMidiParser *midi_parser,
+				   GError **error);
+
+xmlDoc* ags_midi_parser_real_parse_full(AgsMidiParser *midi_parser);
+xmlNode* ags_midi_parser_real_parse_header(AgsMidiParser *midi_parser);
+xmlNode* ags_midi_parser_real_parse_track(AgsMidiParser *midi_parser);
+
+xmlNode* ags_midi_parser_real_key_on(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_key_off(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_key_pressure(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_change_parameter(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_change_pitch_bend(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_change_program(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_change_channel_pressure(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_not_defined(AgsMidiParser *midi_parser, guint status);
+
+xmlNode* ags_midi_parser_real_sysex(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_system_common(AgsMidiParser *midi_parser, guint status);
+
+xmlNode* ags_midi_parser_real_meta_event(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_real_sequence_number(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_end_of_track(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_smpte(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_tempo(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_time_signature(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_key_signature(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_sequencer_meta_event(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_real_text_event(AgsMidiParser *midi_parser, guint meta_type);
+
+#define AGS_MIDI_PARSER_MAX_TEXT_LENGTH (4096)
 
 #define AGS_MIDI_EVENT "event\0"
 
@@ -39,7 +81,41 @@ void ags_midi_parser_finalize(GObject *gobject);
  * #AgsMidiParser reads your midi parsers.
  */
 
+enum{
+  PROP_0,
+  PROP_FD,
+};
+
+enum{
+  MIDI_GETC,
+  ON_ERROR,
+  PARSE_FULL,
+  PARSE_HEADER,
+  PARSE_TRACK,
+  KEY_ON,
+  KEY_OFF,
+  KEY_PRESSURE,
+  CHANGE_PARAMETER,
+  CHANGE_PITCH_BEND,
+  CHANGE_PROGRAM,
+  CHANGE_CHANNEL_PRESSURE,
+  NOT_DEFINED,
+  SYSEX,
+  SYSTEM_COMMON,
+  META_EVENT,
+  SEQUENCE_NUMBER,
+  END_OF_TRACK,
+  SMPTE,
+  TEMPO,
+  TIME_SIGNATURE,
+  KEY_SIGNATURE,
+  SEQUENCER_META_EVENT,
+  TEXT_EVENT,
+  LAST_SIGNAL,
+};
+
 static gpointer ags_midi_parser_parent_class = NULL;
+static guint midi_parser_signals[LAST_SIGNAL];
 
 GType
 ags_midi_parser_get_type(void)
@@ -71,20 +147,543 @@ void
 ags_midi_parser_class_init(AgsMidiParserClass *midi_parser)
 {
   GObjectClass *gobject;
-
+  GParamSpec *param_spec;
+  
   ags_midi_parser_parent_class = g_type_class_peek_parent(midi_parser);
 
   /* GObjectClass */
   gobject = (GObjectClass *) midi_parser;
+
+  gobject->set_property = ags_midi_parser_set_property;
+  gobject->get_property = ags_midi_parser_get_property;
   
   gobject->finalize = ags_midi_parser_finalize;
+
+  /**
+   * AgsMidiParser:dsp-channels:
+   *
+   * The dsp channel count
+   * 
+   * Since: 0.4.2
+   */
+  param_spec = g_param_spec_int("fd\0",
+				"the file descriptor fd\0",
+				"The file to parse as fd\0",
+				-1,
+				G_MAXINT,
+				-1,
+				G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FD,
+				  param_spec);
+
+  /* AgsMidiParser */
+  midi_parser->midi_getc = ags_midi_parser_real_midi_getc;
+  midi_parser->on_error = ags_midi_parser_real_on_error;
+
+  midi_parser->parse_header = ags_midi_parser_real_parse_header;
+  midi_parser->parse_track = ags_midi_parser_real_parse_track;
+
+  midi_parser->key_on = ags_midi_parser_real_key_on;
+  midi_parser->key_off = ags_midi_parser_real_key_off;
+  midi_parser->key_pressure = ags_midi_parser_real_key_pressure;
+  midi_parser->change_parameter = ags_midi_parser_real_change_parameter;
+  midi_parser->change_pitch_bend = ags_midi_parser_real_change_pitch_bend;
+  midi_parser->change_program = ags_midi_parser_real_change_program;
+  midi_parser->change_channel_pressure = ags_midi_parser_real_change_channel_pressure;
+  midi_parser->not_defined = ags_midi_parser_real_not_defined;
+
+  midi_parser->sysex = ags_midi_parser_real_sysex;
+  midi_parser->system_common = ags_midi_parser_real_system_common;
+
+  midi_parser->meta_event = ags_midi_parser_real_meta_event;
+  midi_parser->sequence_number = ags_midi_parser_real_sequence_number;
+  midi_parser->end_of_track = ags_midi_parser_real_end_of_track;
+  midi_parser->smpte = ags_midi_parser_real_smpte;
+  midi_parser->tempo = ags_midi_parser_real_tempo;
+  midi_parser->time_signature = ags_midi_parser_real_time_signature;
+  midi_parser->key_signature = ags_midi_parser_real_key_signature;
+  midi_parser->sequencer_meta_event = ags_midi_parser_real_sequencer_meta_event;
+  midi_parser->text_event = ags_midi_parser_real_text_event;
+
+  midi_parser->parse_full = ags_midi_parser_real_parse_full;
+  
+  /* signals */
+  /**
+   * AgsMidiParser::midi-getc:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::midi-getc signal is emited during parsing of event.
+   */
+  midi_parser_signals[MIDI_GETC] =
+    g_signal_new("midi-getc\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, midi_getc),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_INT__VOID,
+		 G_TYPE_INT, 0);
+
+  /**
+   * AgsMidiParser::on-error:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::on-error signal is emited during parsing of event.
+   */
+  midi_parser_signals[ON_ERROR] =
+    g_signal_new("on-error\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, on_error),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__VOID,
+		 G_TYPE_POINTER, 0);
+
+
+  /**
+   * AgsMidiParser::parse-header:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the header
+   *
+   * The ::parse-header signal is emited during parsing of header.
+   */
+  midi_parser_signals[PARSE_HEADER] =
+    g_signal_new("parse-header\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, parse_header),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__VOID,
+		 G_TYPE_POINTER, 0);
+
+  /**
+   * AgsMidiParser::parse-track:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the track
+   *
+   * The ::parse-track signal is emited during parsing of track.
+   */
+  midi_parser_signals[PARSE_TRACK] =
+    g_signal_new("parse-track\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, parse_track),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__VOID,
+		 G_TYPE_POINTER, 0);
+
+  /**
+   * AgsMidiParser::key-on:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::key-on signal is emited during parsing of event.
+   */
+  midi_parser_signals[KEY_ON] =
+    g_signal_new("key-on\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, key_on),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::key-off:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::key-off signal is emited during parsing of event.
+   */
+  midi_parser_signals[KEY_OFF] =
+    g_signal_new("key-off\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, key_off),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::key-pressure:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::key-pressure signal is emited during parsing of event.
+   */
+  midi_parser_signals[KEY_PRESSURE] =
+    g_signal_new("key-pressure\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, key_pressure),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::change-parameter:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::change-parameter signal is emited during parsing of event.
+   */
+  midi_parser_signals[CHANGE_PARAMETER] =
+    g_signal_new("change-parameter\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, change_parameter),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::change-pitch-bend:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::change-pitch-bend signal is emited during parsing of event.
+   */
+  midi_parser_signals[CHANGE_PITCH_BEND] =
+    g_signal_new("change-pitch-bend\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, change_pitch_bend),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::change-program:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::change-program signal is emited during parsing of event.
+   */
+  midi_parser_signals[CHANGE_PROGRAM] =
+    g_signal_new("change-program\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, change_program),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::change-channel-pressure:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::change-channel-pressure signal is emited during parsing of event.
+   */
+  midi_parser_signals[CHANGE_CHANNEL_PRESSURE] =
+    g_signal_new("change-channel-pressure\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, change_channel_pressure),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::not-defined:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::not-defined signal is emited during parsing of event.
+   */
+  midi_parser_signals[NOT_DEFINED] =
+    g_signal_new("not-defined\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, not_defined),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::sysex:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::sysex signal is emited during parsing of event.
+   */
+  midi_parser_signals[SYSEX] =
+    g_signal_new("sysex\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, sysex),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::system-common:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::system-common signal is emited during parsing of event.
+   */
+  midi_parser_signals[SYSTEM_COMMON] =
+    g_signal_new("system-common\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, system_common),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::meta-event:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::meta-event signal is emited during parsing of event.
+   */
+  midi_parser_signals[META_EVENT] =
+    g_signal_new("meta-event\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, meta_event),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::sequence-number:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::sequence-number signal is emited during parsing of event.
+   */
+  midi_parser_signals[SEQUENCE_NUMBER] =
+    g_signal_new("sequence-number\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, sequence_number),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::end-of-track:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::end-of-track signal is emited during parsing of event.
+   */
+  midi_parser_signals[END_OF_TRACK] =
+    g_signal_new("end-of-track\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, end_of_track),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::smpte:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::smpte signal is emited during parsing of event.
+   */
+  midi_parser_signals[SMPTE] =
+    g_signal_new("smpte\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, smpte),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::tempo:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::tempo signal is emited during parsing of event.
+   */
+  midi_parser_signals[TEMPO] =
+    g_signal_new("tempo\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, tempo),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::time-signature:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::time-signature signal is emited during parsing of event.
+   */
+  midi_parser_signals[TIME_SIGNATURE] =
+    g_signal_new("time-signature\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, time_signature),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::key-signature:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::key-signature signal is emited during parsing of event.
+   */
+  midi_parser_signals[KEY_SIGNATURE] =
+    g_signal_new("key-signature\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, key_signature),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::sequencer-meta-event:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::sequencer-meta-event signal is emited during parsing of event.
+   */
+  midi_parser_signals[SEQUENCER_META_EVENT] =
+    g_signal_new("sequencer-meta-event\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, sequencer_meta_event),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::text-event:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::text-event signal is emited during parsing of event.
+   */
+  midi_parser_signals[TEXT_EVENT] =
+    g_signal_new("text-event\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, text_event),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__UINT,
+		 G_TYPE_POINTER, 1,
+		 G_TYPE_UINT);
+
+  /**
+   * AgsMidiParser::parse-full:
+   * @midi_parser: the parser
+   *
+   * Returns: The XML node representing the event
+   *
+   * The ::parse-full signal is emited during parsing of midi file.
+   */
+  midi_parser_signals[PARSE_FULL] =
+    g_signal_new("parse-full\0",
+		 G_TYPE_FROM_CLASS(midi_parser),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsMidiParserClass, parse_full),
+		 NULL, NULL,
+		 g_cclosure_user_marshal_POINTER__VOID,
+		 G_TYPE_POINTER, 0);
 }
 
 void
 ags_midi_parser_init(AgsMidiParser *midi_parser)
 {
-  midi_parser->fd = -1;
+  midi_parser->flags = 0;
+  
+  midi_parser->file = NULL;
   midi_parser->nth_chunk = 0;
+
+  midi_parser->file_length = 0;
+  midi_parser->offset = 0;
+
+  midi_parser->current_time = 0;
+}
+
+void
+ags_midi_parser_set_property(GObject *gobject,
+			     guint prop_id,
+			     const GValue *value,
+			     GParamSpec *param_spec)
+{
+  AgsMidiParser *midi_parser;
+
+  midi_parser = AGS_MIDI_PARSER(gobject);
+  
+  switch(prop_id){
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_midi_parser_get_property(GObject *gobject,
+			     guint prop_id,
+			     GValue *value,
+			     GParamSpec *param_spec)
+{
+  AgsMidiParser *midi_parser;
+
+  midi_parser = AGS_MIDI_PARSER(gobject);
+  
+  switch(prop_id){
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
 }
 
 void
@@ -92,585 +691,1553 @@ ags_midi_parser_finalize(GObject *gobject)
 {
   G_OBJECT_CLASS(ags_midi_parser_parent_class)->finalize(gobject);
 }
+
+gint16
+ags_midi_parser_read_gint16(AgsMidiParser *midi_parser)
+{
+  char str[2];
+  gint16 value = 0;
+
+  str[0] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+  str[1] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+
+  value = (str[0] & 0xff);
+  value = (value<<8) + (str[1] & 0xff);
+  
+  return(value);
 }
 
-char*
-ags_midi_parser_read_chunk(AgsMidiParser *midi_parser,
-			   guint *message_type, guint *message_length,
-			   GError **error)
+gint32
+ags_midi_parser_read_gint24(AgsMidiParser *midi_parser)
 {
-  char chunk_type[4];
-  char chunk_length[4];
-  char *data;
+  char str[4];
+  gint32 value = 0;
+  
+  str[0] = (char) 0x00;
+  str[1] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+  str[2] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+  str[3] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+
+  value = (value<<8) + (str[1] & 0xff);
+  value = (value<<8) + (str[2] & 0xff);
+  value = (value<<8) + (str[3] & 0xff);
+  
+  return(value);
+}
 
-  guint midi_type;
-  guint data_length;
+gint32
+ags_midi_parser_read_gint32(AgsMidiParser *midi_parser)
+{
+  char str[4];
+  gint32 value;
   
-  read(midi_parser->fd, chunk_type, 4 * sizeof(char));
+  str[0] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+  str[1] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+  str[2] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+  str[3] = (char) 0xff & ags_midi_parser_midi_getc(midi_parser);
+
+  value = (str[0] & 0xff);
+  value = (value<<8) + (str[1] & 0xff);
+  value = (value<<8) + (str[2] & 0xff);
+  value = (value<<8) + (str[3] & 0xff);
+  
+  return(value);
+}
 
-  if(!g_strncmp(AGS_MIDI_PARSER_MTHD,
-		chunk_type,
-		4)){
-    midi_type = AGS_MIDI_CHUNK_HEADER;
-  }else if(!g_strncmp(AGS_MIDI_PARSER_MTCK,
-		      chunk_type,
-		      4)){
-    midi_type = AGS_MIDI_CHUNK_TRACK;
-  }else{
-    midi_type = AGS_MIDI_CHUNK_UNKNOWN;
-  }
+long
+ags_midi_parser_read_varlength(AgsMidiParser *midi_parser)
+{
+  long value;
+  guint i;
+  char c;
   
-  read(midi_parser->fd, chunk_length, 4 * sizeof(char));
-  data_length = AGS_MIDI_PARSE_MSB32(chunk_length);
+  c = ags_midi_parser_midi_getc(midi_parser);
+  value = c;
+  i = 1;
+  
+  if(c & 0x80){
+    value &= 0x7F;
+   
+    do{
+      value = (value << 7) + ((c = ags_midi_parser_midi_getc(midi_parser)) & 0x7F);
+      i++;
+    }while(c & 0x80);
+  }
+
+  return(value);
+}
 
-  data = (char *) malloc(data_length * sizeof(char));
-  read(midi_parser->fd, data, data_length * sizeof(char));
+gchar*
+ags_midi_parser_read_text(AgsMidiParser *midi_parser,
+			  gint length)
+{
+  gchar text[AGS_MIDI_PARSER_MAX_TEXT_LENGTH];
+  gchar c;
+  guint i;
 
-  midi_parser->nth_chunk += 1;
+  memset(text, 0, AGS_MIDI_PARSER_MAX_TEXT_LENGTH * sizeof(char));
+  i = 0;
   
-  if(message_type != NULL){
-    *message_type = midi_type;
+  while((c = (char) 0xff & ags_midi_parser_midi_getc(midi_parser)) != '\0' && (length <= 0 ||
+									       i < length) &&
+	c != EOF){
+    if(c == '\0' || !(g_ascii_isalnum(c) ||
+		      g_ascii_ispunct(c) ||
+		      c == ' ')){
+      break;
+    }
+
+    text[i] = c;
+    i++;
   }
 
-  if(message_length != NULL){
-    *message_length = data_length;
+  text[i] = '\0';
+    
+  return(g_strdup(text));
+}
+
+gdouble
+ags_midi_parser_ticks_to_sec(AgsMidiParser *midi_parser,
+			     guint ticks, gint division, guint tempo)
+{
+  if(division > 0){
+    return ((gdouble) (((gdouble)(ticks) * (gdouble)(tempo)) /
+		       ((gdouble)(division) * 1000000.0)));
+  }else{
+    gdouble smpte_format, smpte_resolution;
+
+    smpte_format = (gdouble) ((0xff00 & division) >> 8);
+    smpte_resolution = (gdouble) (0xff & division);
+    
+    return((gdouble) ((gdouble) ticks / (smpte_format * smpte_resolution *
+					 1000000.0)));
   }
+}
+
+int
+ags_midi_parser_midi_getc(AgsMidiParser *midi_parser)
+{
+  int c;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), '\0');
   
-  return(data);
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[MIDI_GETC], 0,
+		&c);
+  g_object_unref((GObject *) midi_parser);
+
+  return(c);
+}
+
+int
+ags_midi_parser_real_midi_getc(AgsMidiParser *midi_parser)
+{
+  int c;
+
+  c = fgetc(midi_parser->file);
+  
+  if(c == EOF){
+    g_warning("reached end of file\0");
+    midi_parser->flags |= AGS_MIDI_PARSER_EOF;
+  }
+
+  return(c);
 }
 
 void
-ags_midi_parser_write_chunk(AgsMidiParser *midi_parser,
-			    char *chunk, size_t length)
+ags_midi_parser_on_error(AgsMidiParser *midi_parser,
+			 GError **error)
 {
-  write(midi_parser->fd, chunk, length);
+  g_return_if_fail(AGS_IS_MIDI_PARSER(midi_parser));
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[ON_ERROR], 0,
+		error);
+  g_object_unref((GObject *) midi_parser);
 }
 
 void
-ags_midi_parser_seek(AgsMidiParser *midi_parser, guint n_chunks, gint whence)
+ags_midi_parser_real_on_error(AgsMidiParser *midi_parser,
+			      GError **error)
 {
-  char chunk_head[8];
-  guint start_chunk;
-  guint data_length;
+}
 
-  switch(whence){
-  case SEEK_CUR:
-    start_chunk = midi_parser->nth_chunk;
+xmlDoc*  
+ags_midi_parser_parse_full(AgsMidiParser *midi_parser)
+{
+  xmlDoc *doc;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[PARSE_FULL], 0,
+		&doc);
+  g_object_unref((GObject *) midi_parser);
 
-    while(midi_parser->nth_chunk - start_chunk < n_chunks){
-      read(midi_parser->fd, chunk_head, 8 * sizeof(char));
-      data_length = AGS_MIDI_PARSE_MSB32(&(chunk_head[4]));
-      
-      seek(midi_parser->fd, SEEK_CUR, data_length);
-      
-      midi_parser->nth_chunk += 1;
-    }
+  return(doc);
+}
 
-    break;
-  case SEEK_SET:
-    midi_parser->nth_chunk = 0;
-    seek(midi_parser->fd, SEEK_SET, 0);
+xmlDoc*
+ags_midi_parser_real_parse_full(AgsMidiParser *midi_parser)
+{
+  xmlDoc *doc;
+  xmlNode *root_node;
+  xmlNode *tracks_node;
+  xmlNode *current;
+  gchar c;
+  
+  GError *error;
+  
+  doc = xmlNewDoc("1.0\0");
+  root_node = xmlNewNode(NULL, "midi\0");
+  xmlDocSetRootElement(doc, root_node);
 
-    while(midi_parser->nth_chunk < n_chunks){
-      read(midi_parser->fd, chunk_head, 8 * sizeof(char));
-      data_length = AGS_MIDI_PARSE_MSB32(&(chunk_head[4]));
-      
-      seek(midi_parser->fd, SEEK_CUR, data_length);
+  tracks_node = xmlNewNode(NULL, "midi-tracks\0");
 
-      midi_parser->nth_chunk += 1;
-    }
+  error = NULL;
 
-    break;
-  case SEEK_END:
-    //TODO:JK: implement me
-    break;
+  current = ags_midi_parser_parse_header(midi_parser);
+  xmlAddChild(root_node,
+	      current);
+  g_message("parsed header\0");
+
+  xmlAddChild(root_node,
+	      tracks_node);
+  c = 0x0;
+  
+  while(((AGS_MIDI_PARSER_EOF & (midi_parser->flags))) == 0){
+    current = ags_midi_parser_parse_track(midi_parser);
+    
+    if(current != NULL){
+      xmlAddChild(tracks_node,
+		  current);
+      g_message("parsed track\0");
+    }else{
+      g_warning("skipped input\0");
+    }
   }
+
+
+  return(doc);
 }
 
-void
-ags_midi_parser_flush(AgsMidiParser *midi_parser)
+xmlNode*  
+ags_midi_parser_parse_header(AgsMidiParser *midi_parser)
 {
-  flush(midi_parser->fd);
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[PARSE_HEADER], 0,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
 }
 
 xmlNode*
-ags_midi_parser_parse_header(AgsMidiParser *parser,
-			     char *chunk_data,
-			     guint chunk_type,
-			     guint chunk_length)
+ags_midi_parser_real_parse_header(AgsMidiParser *midi_parser)
 {
   xmlNode *node;
 
-  char chunk_format[2];
-  char chunk_tracks[2];
-  char chunk_division[2];
+  static gchar header[] = "MThd";
+  guint format;
+  guint count;
+  guint division;
+  guint offset;
+  guint times;
+  guint beat, clicks;
+  guint n;
+  gchar c;
   
-  guint track_format;
-  guint track_count;
-  guint track_division;
+  n = 0;
   
-  node = xmlNewNode(NULL,
-		    "midi-header\0");
-
-  memcpy(chunk_format, data, 2 * sizeof(char));
-  track_format = AGS_MIDI_PARSE_MSB16(chunk_format);
-
-  switch(track_format){
-  case 0:
-    {
-      xmlNewProp(node,
-		 "track-format\0",
-		 "single\0");
-    }
-    break;
-  case 1:
-    {
-      xmlNewProp(node,
-		 "track-format\0",
-		 "simoultaneous\0");
-    }
-    break;
-  case 2
-    {
-      xmlNewProp(node,
-		 "track-format\0",
-		 "independant\0");
+  while(n < 4 &&
+	(AGS_MIDI_PARSER_EOF & (midi_parser->flags)) == 0){
+    c = ags_midi_parser_midi_getc(midi_parser);
+    
+    if(c == header[n]){
+      n++;
+    }else{
+      n = 0;
     }
-  break;
   }
   
-  memcpy(chunk_tracks, &(data[2]), 2 * sizeof(char));
-  track_count = AGS_MIDI_PARSE_MSB16(chunk_tracks);
+  node = xmlNewNode(NULL,
+		    "midi-header\0");
+
+  offset = (guint) ags_midi_parser_read_gint32(midi_parser);
+  format = (guint) ags_midi_parser_read_gint16(midi_parser);
+  count = (guint) ags_midi_parser_read_gint16(midi_parser);
+  division = (guint) ags_midi_parser_read_gint16(midi_parser);
 
   xmlNewProp(node,
-	     "track-count\0",
-	     g_strdup_printf("%d\0", track_count));
-  
-  memcpy(chunk_division, &(data[4]), 2 * sizeof(char));
-  track_division = AGS_MIDI_PARSE_MSB16(chunk_division);
+	     "format\0",
+	     g_strdup_printf("%d\0", format));
+
+  if(division & 0x8000){
+    /* SMPTE */
+    times = 0; /* Can't do beats */
 
-  if((track_division & (1 << 15)) != 0){
-    xmlNewProp(node,
-	       "smtpe\0",
-	       "false\0");
-    
     xmlNewProp(node,
-	       "delta-time\0",
-	       g_strdup_printf("%d\0",
-			       (track_division & (~(1 << 15)))));
+	       "division\0",
+	       g_strdup_printf("%d %d\0", -((-(division>>8))&0xff), division&0xff));
   }else{
     xmlNewProp(node,
-	       "smtpe\0",
-	       "true\0");
+	       "division\0",
+	       g_strdup_printf("%d\0", division));
+  }
+  
+  if(format > 2){
+    fprintf(stderr, "Can't deal with format %d files\n", format);
+    exit(-1);
+  }
+  
+  beat =
+    clicks = division;
 
-    xmlNewProp(node,
-	       "delta-time\0",
-	       g_strdup_printf("%d\0",
-			       (track_division & (~(0xff)))));
+  xmlNewProp(node,
+	     "beat\0",
+	     g_strdup_printf("%d\0", beat));
 
-    xmlNewProp(node,
-	       "smtpe-fps\0",
-	       g_strdup_printf("%d\0",
-			       (track_division & (~(0x7f00)))));
-  }
+  xmlNewProp(node,
+	     "track-count\0",
+	     g_strdup_printf("%d\0", count));
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_parse_track(AgsMidiParser *midi_parser)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
   
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[PARSE_TRACK], 0,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
   return(node);
 }
 
 xmlNode*
-ags_midi_parser_parse_track(AgsMidiParser *parser,
-			    char *chunk_data,
-			    guint chunk_type,
-			    guint chunk_length)
-{
-  xmlNode *node, *message_node;
-
-  char chunk_delta_time[8];
-  char voice_message[4];
-  guint64 delta_time;
-  guint imask;
-  guint key, control, value, program, pressure, pitch;
-  guint velocity;
-  guint offset;
-  guint i;
+ags_midi_parser_real_parse_track(AgsMidiParser *midi_parser)
+{
+  xmlNode *node, *current;
+  static gchar track[] = "MTrk";
+  gint offset, start_offset;
+  long delta_time;
+  guint status;
+  guint n;
+  gchar c;
+
+  n = 0;
   
-  node = xmlNewNode(NULL,
-		    "midi-track\0");
-
-  /* delta time */
-  for(offset = 0; offset < 8; offset++){
-    if((&(chunk_data[offset]) & (1 << 7)) != 0){
-      break;
+  while(n < 4 &&
+	(AGS_MIDI_PARSER_EOF & (midi_parser->flags)) == 0){
+    c = ags_midi_parser_midi_getc(midi_parser);
+    
+    if(c == track[n]){
+      n++;
+    }else{
+      n = 0;
     }
   }
 
-  for(i = 0; i < offset + 1; i++){
-    chunk_delta_time[i] = chunk_data[offset - i];
+  if((AGS_MIDI_PARSER_EOF & (midi_parser->flags)) != 0){
+    return(NULL);
+  }
+
+  node = xmlNewNode(NULL, "midi-track\0");
+
+  offset = ags_midi_parser_read_gint32(midi_parser);
+  g_message("n = %d\noffset = %d\0", n, offset);
+  start_offset = ftell(midi_parser->file);
+
+  if(offset < 0){
+    return(NULL);
   }
-  
-  delta_time = AGS_MIDI_PARSE_MSB64(chunk_delta_time);
-  offset++;
-  
-  xmlNewProp(node,
-	     "delta-time\0",
-	     g_strdup_printf("%d\0", delta_time));
 
-  for(; offset < chunk_length;){
-    message_node = xmlNewNode(NULL,
-			      "midi-message\0");
+  midi_parser->current_time = 0;
+  
+  for(; ftell(midi_parser->file) < start_offset + offset; ){
+    delta_time = ags_midi_parser_read_varlength(midi_parser);
+    midi_parser->current_time += delta_time;
+    
+    status = ags_midi_parser_midi_getc(midi_parser);
     
-    if((chunk_data[offset] & (0x80)) != 0 ||
-       (chunk_data[offset] & (0x90)) != 0 ||
-       (chunk_data[offset] & (0xa0)) != 0){
-      /* definitely voice message */
-      imask = 0x0f;
-
-      xmlNewProp(message_node,
-		 "type\0",
-		 "voice-message\0");
-
-      key = chunk_data[offset + 1];
-      velocity = chunk_data[offset + 2];
-
-      if((~imask) & chunk_data[offset] == 0x80){
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "note-off\0");
-      }else if((~imask) & chunk_data[offset] == 0x90){
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "note-on\0");
-      }else{
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "polyphonic\0");
+    if((0xf0 & (0xf0 & status)) != 0xf0){
+      current = ags_midi_parser_channel_message(midi_parser,
+						status);
+
+      if(current != NULL){
+	xmlNewProp(current,
+		   "delta-time\0",
+		   g_strdup_printf("%d\0", midi_parser->current_time));
+	
+	xmlAddChild(node,
+		    current);
       }
+      
+      g_message("channel message");
+    }else{
+      g_message("status message");
 
-      xmlNewProp(message_node,
-		 "key\0",
-		 g_strdup_printf("%d\0", key));
-
-      xmlNewProp(message_node,
-		 "velocity\0",
-		 g_strdup_printf("%d\0", velocity));
+      switch(status){
+      case 0xf0:
+	{
+	  /* start of system exclusive */
+	  ags_midi_parser_sysex(midi_parser,
+				status);
 
-      offset += 3;
-    }else if(chunk_data[offset] == 0xb0){
-      /* voice or channel mode message */
-      imask = 0x0f;
+	}
+      case 0xf1:
+      case 0xf2:
+      case 0xf3:
+      case 0xf4:
+      case 0xf5:
+      case 0xf6:
+	{
+	  ags_midi_parser_system_common(midi_parser,
+					status);
+	}
+	break;
+      case 0xf7:
+	{
+	  /* sysex continuation or arbitrary stuff */
+	  g_message("sysex end\0");
+	}
+	break;
+      case 0xff:
+	{
+	  /* meta event */
+	  current = ags_midi_parser_meta_event(midi_parser,
+					       status);
+
+	  if(current != NULL){
+	    xmlNewProp(current,
+		       "delta-time\0",
+		       g_strdup_printf("%d\0", midi_parser->current_time));
+	    
+	    xmlAddChild(node,
+			current);
+	  }
+	}
+	break;
+      default:
+	g_warning("bad byte\0");
+	break;
+      }
+    }
+  }
+  
+  return(node);
+}
 
-      control = chunk_data[offset + 1];
-      value = chunk_data[offset + 2];
+xmlNode*
+ags_midi_parser_channel_message(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
 
-      if(control < 120){
-	xmlNewProp(message_node,
-		   "type\0",
-		   "voice-message\0");
+  node = NULL;
+  
+  switch(status & 0xf0){
+  case 0x80:
+    {
+      node = ags_midi_parser_key_off(midi_parser, status);
+    }
+    break;
+  case 0x90:
+    {
+      node = ags_midi_parser_key_on(midi_parser, status);
+    }
+    break;
+  case 0xa0:
+    {
+      node = ags_midi_parser_key_pressure(midi_parser, status);
+    }
+    break;
+  case 0xb0:
+    {
+      node = ags_midi_parser_change_parameter(midi_parser, status);
+    }
+    break;
+  case 0xc0:
+    {
+      node = ags_midi_parser_change_program(midi_parser, status);
+    }
+    break;
+  case 0xd0:
+    {
+      node = ags_midi_parser_change_channel_pressure(midi_parser, status);
+    }
+    break;
+  case 0xe0:
+    {
+      node = ags_midi_parser_change_pitch_bend(midi_parser, status);
+    }
+    break;
+  }
 
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "control-change\0");
+  return(node);
+}
 
-	xmlNewProp(message_node,
-		   "control\0",
-		   g_strdup_printf("%d\0", control));
+xmlNode*  
+ags_midi_parser_real_key_on(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int channel, note, velocity;
 
-	xmlNewProp(message_node,
-		   "value\0",
-		   g_strdup_printf("%d\0", value));
-      }else{
-	xmlNewProp(message_node,
-		   "type\0",
-		   "mode-message\0");
-
-	switch(control){
-	case 120:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "all-sound-off\0");
-	  }
-	  break;
-	case 121:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "reset-control-all\0");
-	    
-	    xmlNewProp(message_node,
-		       "value\0",
-		       g_strdup_printf("%d\0", value));
-	  }
-	  break;
-	case 122:
-	  {
-	    if(value == 0){
-	      xmlNewProp(message_node,
-			 "mode\0",
-			 "local-control-off\0");
-	    }else{
-	      xmlNewProp(message_node,
-			 "mode\0",
-			 "local-control-on\0");
-	    }
-	  }
-	  break;
-	case 123:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "all-notes-off");
-	  }
-	  break;
-	case 124:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "omni-mode-on");
-	  }
-	  break;
-	case 125:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "omni-mode-off\0");
-	  }
-	  break;
-	case 126:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "mono-mode-on\0");
-
-	    xmlNewProp(message_node,
-		       "omni-off-channels\0",
-		       g_strdup_printf("%d\0", value));
-	  }
-	  break;
-	case 127:
-	  {
-	    xmlNewProp(message_node,
-		       "mode\0",
-		       "poly-mode-on\0");
-	  }
-	  break;
-	}  
-      }
-      
-      offset += 3;
-    }else if((chunk_data[offset] & (0xc0)) != 0 ||
-	     (chunk_data[offset] & (0xd0)) != 0 ||
-	     (chunk_data[offset] & (0xe0)) != 0){
-      imask = 0x0f;
-
-      xmlNewProp(message_node,
-		 "type\0",
-		 "voice-message\0");
-      
-      key = chunk_data[offset + 1];
-      velocity = chunk_data[offset + 2];
-
-      /* definitely voice message */
-      if((~imask) & chunk_data[offset] == 0xc0){
-	program = chunk_data[offset + 1];
-  
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "program-change\0");
-
-	xmlNewProp(message_node,
-		   "program\0",
-		   g_strdup_printf("%d\0", program));
-		
-	offset += 2;
-      }else if((~imask) & chunk_data[offset] == 0xd0){
-	pressure = chunk_data[offset + 1];
-	  	  
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "channel-pressure\0");
-
-	xmlNewProp(message_node,
-		   "pressure\0",
-		   g_strdup_printf("%d\0", pressure));
-
-	offset += 2;
-      }else{
-	pitch = AGS_MIDI_PARSE_MSB16(chunk_data[offset + 1]);
-
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "pitch-bend\0");
-
-	xmlNewProp(message_node,
-		   "pitch\0",
-		   g_strdup_printf("%d\0", pitch));	  
-
-	offset += 3;
-      }
+  channel = 0xf & status;
+  note = (0x7f) & ags_midi_parser_midi_getc(midi_parser);
+  velocity = (0x7f) & ags_midi_parser_midi_getc(midi_parser);
 
-    }else if((chunk_data[offset] & (0xf)) &&
-	     !(chunk_data[offset] & (0x08))){
-      /* system common message */
-      xmlNewProp(message_node,
-		 "type\0",
-		 "system-common\0");
-      
-      if(chunk_data[offset] == 0xf0){
-	guint manufacturer;
-	guint start_value, end_value;
-	char *reserved;
-
-	/* system exclusive */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "sysex\0");
-
-	if(chunck_length > 6){
-	  manufacturer = AGS_MIDI_PARSE_MSB24(chunk_data);
-	  offset += 3;
-	}else{
-	  manufacturer = chunk_data[0];
-	  offset++;
-	}
-	
-	xmlNewProp(message_node,
-		   "manufacturer\0"
-		   g_strdup_printf("%d\0", manufacturer));
-
-	start_value = chunk_data[offset];
-	xmlNewProp(message_node,
-		   "start-value\0"
-		   g_strdup_printf("%d\0", start_value));
-
-	end_value = chunk_data[offset + 3];
-	xmlNewProp(message_node,
-		   "end-value\0"
-		   g_strdup_printf("%d\0", end_value));
-
-	reserverd = AGS_MIDI_PARSE_MSB16(&(chunk_data[1]));
-	xmlNewProp(message_node,
-		   "reserved\0"
-		   g_strdup_printf("%x\0", reserved));
-      }else if(chunk_data[offset] == 0xf1){
-	guint frame_type;
-	guint frame_value;
-
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "quarter-frame\0");
-	
-	/* time code quarter frame */
-	frame_type = (0xf0 & (&(chunk_data[1]))) >> 4;
-	
-	xmlNewProp(message_node,
-		   "message-type\0",
-		   g_strdup_printf("%x\0", frame_type));
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
 
-	frame_type = (0x0f & (&(chunk_data[1])));
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "note-on\0");
 
-	xmlNewProp(message_node,
-		   "message-value\0",
-		   g_strdup_printf("%d\0", frame_value));
-      }else if(chunk_data[offset] == 0xf2){
-	guint beats_count;
+  xmlNewProp(node,
+	     "key\0",
+	     g_strdup_printf("%d\0", channel));
 
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "position-pointer\0");
-	
-	/* song position pointer */
-	beats_count = (((0x3f & (chunk_data[0])) << 7) | (0x7f & (chunk_data[1])));
-	
-	xmlNewProp(message_node,
-		   "beats-count\0",
-		   g_strdup_printf("%d\0", beats_count));
-      }else if(chunk_data[offset] == 0xf3){
-	guint sequence;
-
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "song-select\0");
-	
-	/* song select */
-	sequence = chunk_data[0];
-	
-	xmlNewProp(message_node,
-		   "sequence\0",
-		   g_strdup_printf("%d\0", sequence);
-      }else if(chunk_data[offset] == 0xf4){
-	g_warning("undefined system common message\0");
-      }else if(chunk_data[offset] == 0xf5){
-	g_warning("undefined system common message\0");
-      }else if(chunk_data[offset] == 0xf6){
-	/* tune request to all analog synths */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "tune-on\0");
-      }else if(chunk_data[offset] == 0xf7){
-	/* end of sysex */
-      }
-    }else{
-      /* real-time message */
-      xmlNewProp(message_node,
-		 "type\0",
-		 "system-realtime\0");
-      
-      if(chunk_data[offset] == 0xf8){
-	/* timing clock */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "clock\0");
-      }else if(chunk_data[offset] == 0xf9){
-	g_warning("undefined system realtime message\0");
-      }else if(chunk_data[offset] == 0xfa){
-	/* start */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "start\0");
-      }else if(chunk_data[offset] == 0xfb){
-	/* continue */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "continue\0");
-      }else if(chunk_data[offset] == 0xfc){
-	/* stop */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "stop\0");
-      }else if(chunk_data[offset] == 0xfd){
-	g_warning("undefined system realtime message\0");
-      }else if(chunk_data[offset] == 0xfe){
-	/* active sensinge */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "active-sense\0");
-      }else if(chunk_data[offset] == 0xff){
-	/* reset */
-	xmlNewProp(message_node,
-		   AGS_MIDI_EVENT,
-		   "reset\0");
-      }
-    }
-  }
+  xmlNewProp(node,
+	     "note\0",
+	     g_strdup_printf("%d\0", note));
 
-  xmlAddChild(node,
-	      message_node);
+  xmlNewProp(node,
+	     "velocity\0",
+	     g_strdup_printf("%d\0", velocity));
+  
+  return(node);
 }
+
+xmlNode*  
+ags_midi_parser_key_on(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
   
-  //TODO:JK: implement me
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
   
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[KEY_ON], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
   return(node);
 }
 
-AgsMidiParser*
-ags_midi_parser_new()
+xmlNode*  
+ags_midi_parser_real_key_off(AgsMidiParser *midi_parser, guint status)
 {
-  AgsMidiParser *midi_parser;
+  xmlNode *node;
+  int channel, note, velocity;
 
-  midi_parser = (AgsMidiParser *) g_object_new(AGS_TYPE_MIDI_PARSER,
-					       NULL);
+  channel = 0xf & status;
+  note = (0x7f) & ags_midi_parser_midi_getc(midi_parser);
+  velocity = (0x7f) & ags_midi_parser_midi_getc(midi_parser);
 
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+  
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "note-off\0");
+
+
+  xmlNewProp(node,
+	     "key\0",
+	     g_strdup_printf("%d\0", channel));
+
+  xmlNewProp(node,
+	     "note\0",
+	     g_strdup_printf("%d\0", note));
+
+  xmlNewProp(node,
+	     "velocity\0",
+	     g_strdup_printf("%d\0", velocity));
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_key_off(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[KEY_OFF], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_key_pressure(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int channel, note, pressure;
+
+  channel = 0xf & status;
+  note = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  pressure = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "polyphonic\0");
+	
+  xmlNewProp(node,
+	     "key\0",
+	     g_strdup_printf("%d\0", channel));
+  
+  xmlNewProp(node,
+	     "note\0",
+	     g_strdup_printf("%d\0", note));
+
+  pressure = (0x7f) & ags_midi_parser_midi_getc(midi_parser);
+
+  xmlNewProp(node,
+	     "pressure\0",
+	     g_strdup_printf("%d\0", pressure));
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_key_pressure(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[KEY_PRESSURE], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_change_parameter(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int channel, control, value;
+
+  channel = 0xf & status;
+  control = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  value = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  if(control < 120){
+    xmlNewProp(node,
+	       AGS_MIDI_EVENT,
+	       "change-parameter\0");
+
+    xmlNewProp(node,
+	       "channel\0",
+	       g_strdup_printf("%d\0", channel));
+
+    xmlNewProp(node,
+	       "control\0",
+	       g_strdup_printf("%d\0", control));
+
+    xmlNewProp(node,
+	       "value\0",
+	       g_strdup_printf("%d\0", value));
+  }else{
+    xmlNewProp(node,
+	       AGS_MIDI_EVENT,
+	       "change-mode\0");
+
+    xmlNewProp(node,
+	       "channel\0",
+	       g_strdup_printf("%d\0", channel));
+
+    switch(control){
+    case 120:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "all-sound-off\0");
+      }
+      break;
+    case 121:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "reset-control-all\0");
+	    
+	xmlNewProp(node,
+		   "value\0",
+		   g_strdup_printf("%d\0", value));
+      }
+      break;
+    case 122:
+      {
+	if(value == 0){
+	  xmlNewProp(node,
+		     "mode\0",
+		     "local-control-off\0");
+	}else{
+	  xmlNewProp(node,
+		     "mode\0",
+		     "local-control-on\0");
+	}
+      }
+      break;
+    case 123:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "all-notes-off");
+      }
+      break;
+    case 124:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "omni-mode-on");
+      }
+      break;
+    case 125:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "omni-mode-off\0");
+      }
+      break;
+    case 126:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "mono-mode-on\0");
+
+	xmlNewProp(node,
+		   "omni-off-channels\0",
+		   g_strdup_printf("%d\0", value));
+      }
+      break;
+    case 127:
+      {
+	xmlNewProp(node,
+		   "mode\0",
+		   "poly-mode-on\0");
+      }
+      break;
+    }
+  }
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_change_parameter(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[CHANGE_PARAMETER], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_change_pitch_bend(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int channel, pitch, transmitter;
+
+  channel = 0xf & status;
+  pitch = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  transmitter = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  xmlNewProp(node,
+	     "channel\0",
+	     g_strdup_printf("%d\0", channel));
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "pitch-bend\0");
+
+  xmlNewProp(node,
+	     "pitch\0",
+	     g_strdup_printf("%d\0", pitch));	  
+
+  xmlNewProp(node,
+	     "transmitter\0",
+	     g_strdup_printf("%d\0", transmitter));	  
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_change_pitch_bend(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[CHANGE_PITCH_BEND], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_change_program(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int channel, program;
+
+  channel = 0xf & status;
+  program = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "program-change\0");
+
+  xmlNewProp(node,
+	     "channel\0",
+	     g_strdup_printf("%d\0", channel));
+
+  xmlNewProp(node,
+	     "program\0",
+	     g_strdup_printf("%d\0", program));
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_change_program(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[CHANGE_PROGRAM], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_change_channel_pressure(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int channel, pressure;
+
+  channel = 0xf & status;
+  pressure = 0x7f & ags_midi_parser_midi_getc(midi_parser);
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "channel-pressure\0");
+
+  xmlNewProp(node,
+	     "channel\0",
+	     g_strdup_printf("%d\0", channel));
+
+  xmlNewProp(node,
+	     "pressure\0",
+	     g_strdup_printf("%d\0", pressure));
+  
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_change_channel_pressure(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[CHANGE_CHANNEL_PRESSURE], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_not_defined(AgsMidiParser *midi_parser, guint status)
+{
+  return(NULL);
+}
+
+xmlNode*  
+ags_midi_parser_not_defined(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[NOT_DEFINED], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*
+ags_midi_parser_real_sysex(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  gchar c;
+  
+  while((c = ags_midi_parser_midi_getc(midi_parser)) != 0xf7 &&
+	c != EOF);
+
+  g_message("discarded sysex\0");
+}
+
+xmlNode*
+ags_midi_parser_sysex(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[SYSEX], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*
+ags_midi_parser_real_system_common(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  int c;
+
+  node = NULL;
+  
+  switch(status){
+  case 0xf1:
+    {
+      guint quarter_frame;
+      
+      quarter_frame = 0xff & (ags_midi_parser_midi_getc(midi_parser));
+    }
+    break;
+  case 0xf2:
+    {
+      guint song_position;
+      
+      song_position = 0x7f & (ags_midi_parser_midi_getc(midi_parser)) << 7;
+      song_position = 0x7f & (ags_midi_parser_midi_getc(midi_parser));
+    }
+    break;
+  case 0xf3:
+    {
+      guint song_select;
+      
+      song_select = 0x7f & (ags_midi_parser_midi_getc(midi_parser));
+    }
+    break;
+  case 0xf4:
+    {
+      g_message("undefined\0");
+    }
+    break;
+  case 0xf5:
+    {
+      g_message("undefined\0");
+    }
+    break;
+  case 0xf6:
+    {
+      g_message("tune request\0");
+    }
+    break;
+  }
+
+  return(node);
+}
+
+xmlNode*
+ags_midi_parser_system_common(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[SYSTEM_COMMON], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_meta_event(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  char chunk_meta_length[4];
+  guint meta_type;
+  
+  meta_type = 0xff & (ags_midi_parser_midi_getc(midi_parser));
+  midi_parser->offset += 1;
+
+  node = NULL;
+  
+  switch(meta_type){
+  case 0x00:
+    {
+      int c;
+
+      c = ags_midi_parser_midi_getc(midi_parser);
+
+      if(c == 0x02){
+	node = ags_midi_parser_sequence_number(midi_parser, meta_type);
+      }
+    }
+    break;
+  case 0x01:      /* Text event */
+  case 0x02:      /* Copyright notice */
+  case 0x03:      /* Sequence/Track name */
+  case 0x04:      /* Instrument name */
+  case 0x05:      /* Lyric */
+  case 0x06:      /* Marker */
+  case 0x07:      /* Cue point */
+  case 0x08:
+  case 0x09:
+  case 0x0a:
+  case 0x0b:
+  case 0x0c:
+  case 0x0d:
+  case 0x0e:
+  case 0x0f:
+    {
+      /* These are all text events */
+      node = ags_midi_parser_text_event(midi_parser, meta_type);
+    }
+    break;
+  case 0x2f:
+    {
+      int c;
+
+      c = ags_midi_parser_midi_getc(midi_parser);
+
+      if(c == 0x0){
+	/* End of Track */
+	node = ags_midi_parser_end_of_track(midi_parser, meta_type);
+      }
+    }
+    break;
+  case 0x51:
+    {
+      int c;
+
+      c = ags_midi_parser_midi_getc(midi_parser);
+
+      if(c == 0x03){
+	/* Set tempo */
+	node = ags_midi_parser_tempo(midi_parser, meta_type);
+      }
+    }
+    break;
+  case 0x54:
+    {
+      int c;
+
+      c = ags_midi_parser_midi_getc(midi_parser);
+
+      if(c == 0x05){
+	node = ags_midi_parser_smpte(midi_parser, meta_type);
+      }
+    }
+    break;
+  case 0x58:
+    {
+      int c;
+
+      c = ags_midi_parser_midi_getc(midi_parser);
+      
+      if(c == 0x04){
+	node = ags_midi_parser_time_signature(midi_parser, meta_type);
+      }
+    }
+    break;
+  case 0x59:
+    {
+      int c;
+
+      c = ags_midi_parser_midi_getc(midi_parser);
+
+      if(c == 0x02){
+	node = ags_midi_parser_key_signature(midi_parser, meta_type);
+      }
+    }
+    break;
+  case 0x7f:
+    {
+      node = ags_midi_parser_sequencer_meta_event(midi_parser, meta_type);
+    }
+    break;
+  default:
+    {
+      node = xmlNewNode(NULL,
+			"midi-message\0");
+      xmlNewProp(node,
+		 AGS_MIDI_EVENT,
+		 "misc\0");
+    }
+  }
+	
+  g_message("meta type 0x%x\0", meta_type);
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_meta_event(AgsMidiParser *midi_parser, guint status)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[META_EVENT], 0,
+		status,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_sequence_number(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  guint sequence;
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  sequence = (guint) ags_midi_parser_read_gint16(midi_parser);
+  
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "sequence-number\0");
+  
+  xmlNewProp(node,
+	     "sequence\0",
+	     g_strdup_printf("%d\0", sequence));
+    
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_sequence_number(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[SEQUENCE_NUMBER], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_end_of_track(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "end-of-track\0");
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_end_of_track(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[END_OF_TRACK], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_smpte(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  int hr, mn, se, fr, ff;
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  hr = ags_midi_parser_midi_getc(midi_parser);
+  mn = ags_midi_parser_midi_getc(midi_parser);
+  se = ags_midi_parser_midi_getc(midi_parser);
+  fr = ags_midi_parser_midi_getc(midi_parser);
+  ff = ags_midi_parser_midi_getc(midi_parser);
+  
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "smpte\0");
+  
+  xmlNewProp(node,
+	     "timestamp\0",
+	     g_strdup_printf("%d %d %d %d %d\0", hr, mn, se, fr, ff));
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_smpte(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[SMPTE], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_tempo(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  gint tempo;
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  tempo = ags_midi_parser_read_gint24(midi_parser);
+  
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "tempo-number\0");
+  
+  xmlNewProp(node,
+	     "tempo\0",
+	     g_strdup_printf("%ld\0", tempo));
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_tempo(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[TEMPO], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_time_signature(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  int nn, dd, cc, bb;
+  int denom = 1;
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  nn = ags_midi_parser_midi_getc(midi_parser);
+  dd = ags_midi_parser_midi_getc(midi_parser);
+  cc = ags_midi_parser_midi_getc(midi_parser);
+  bb = ags_midi_parser_midi_getc(midi_parser);
+
+  while(dd-- > 0){
+    denom *= 2;
+  }
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "time-signature\0");
+
+  xmlNewProp(node,
+	     "timesig\0",
+	     g_strdup_printf("%d/%d %d %d\0", nn, denom, cc, bb));
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_time_signature(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[TIME_SIGNATURE], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_key_signature(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  int sf, mi;
+  
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  xmlNewProp(node,
+	     AGS_MIDI_EVENT,
+	     "key-signature\0");
+  
+  sf = ags_midi_parser_midi_getc(midi_parser);
+  mi = ags_midi_parser_midi_getc(midi_parser);
+
+  xmlNewProp(node,
+	     "keysig\0",
+	     g_strdup_printf("%d %s\0", (sf>127?sf-256:sf), (mi?"minor":"major")));
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_key_signature(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[KEY_SIGNATURE], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_sequencer_meta_event(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  guint len, id, data;
+
+  node = NULL;
+
+  len = ags_midi_parser_midi_getc(midi_parser);
+  id = ags_midi_parser_midi_getc(midi_parser);
+  data = ags_midi_parser_midi_getc(midi_parser);
+  
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_sequencer_meta_event(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[META_EVENT], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_real_text_event(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  gchar *text;
+  guint text_length;
+
+  node = xmlNewNode(NULL,
+		    "midi-message\0");
+
+  text_length = ags_midi_parser_read_varlength(midi_parser);
+  text = ags_midi_parser_read_text(midi_parser,
+				   text_length);
+  
+  switch(0x0f & meta_type){
+  case 0x01:      /* Text event */
+    break;
+  case 0x02:
+    {
+      /* Copyright notice */
+      xmlNewProp(node,
+		 "copyright\0",
+		 text);
+    }
+    break;
+  case 0x03:
+    {
+      /* Sequence/Track name */
+      xmlNewProp(node,
+		 "sequence-name\0",
+		 text);
+    }
+    break;
+  case 0x04:
+    {
+      /* Instrument name */
+      xmlNewProp(node,
+		 "instrument-name\0",
+		 text);
+    }
+    break;
+  case 0x05:      /* Lyric */
+    break;
+  case 0x06:      /* Marker */
+    break;
+  case 0x07:      /* Cue point */
+    break;
+  case 0x08:
+    break;
+  case 0x09:
+    break;
+  case 0x0a:
+    break;
+  case 0x0b:
+    break;
+  case 0x0c:
+    break;
+  case 0x0d:
+    break;
+  case 0x0e:
+    break;
+  case 0x0f:
+    break;
+  default:
+    g_warning("unknown text event\0");
+  }
+    
+  return(node);
+}
+
+xmlNode*  
+ags_midi_parser_text_event(AgsMidiParser *midi_parser, guint meta_type)
+{
+  xmlNode *node;
+  
+  g_return_val_if_fail(AGS_IS_MIDI_PARSER(midi_parser), NULL);
+  
+  g_object_ref((GObject *) midi_parser);
+  g_signal_emit(G_OBJECT(midi_parser),
+		midi_parser_signals[TEXT_EVENT], 0,
+		meta_type,
+		&node);
+  g_object_unref((GObject *) midi_parser);
+
+  return(node);
+}
+
+AgsMidiParser*
+ags_midi_parser_new(FILE *file)
+{
+  AgsMidiParser *midi_parser;
+  struct stat sb;
+  
+  midi_parser = (AgsMidiParser *) g_object_new(AGS_TYPE_MIDI_PARSER,
+					       NULL);
+
+  midi_parser->file = file;
+  
   return(midi_parser);
 }
 
diff --git a/src/midi2ags/midi/ags_midi_parser.h b/src/midi2ags/midi/ags_midi_parser.h
index f2dc896..e0f152f 100644
--- a/src/midi2ags/midi/ags_midi_parser.h
+++ b/src/midi2ags/midi/ags_midi_parser.h
@@ -22,6 +22,8 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include <libxml/tree.h>
+
 #define AGS_TYPE_MIDI_PARSER                (ags_midi_parser_get_type ())
 #define AGS_MIDI_PARSER(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_MIDI_PARSER, AgsMidiParser))
 #define AGS_MIDI_PARSER_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_MIDI_PARSER, AgsMidiParserClass))
@@ -30,12 +32,17 @@
 #define AGS_MIDI_PARSER_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_MIDI_PARSER, AgsMidiParserClass))
 
 #define AGS_MIDI_PARSER_MTHD "MThd\0"
-#define AGS_MIDI_PARSER_MTCK "MTck\0"
+#define AGS_MIDI_PARSER_MTCK "MTrk\0"
 
 typedef struct _AgsMidiParser AgsMidiParser;
 typedef struct _AgsMidiParserClass AgsMidiParserClass;
 
 typedef enum{
+  AGS_MIDI_PARSER_EOF  = 1,
+  AGS_MIDI_PARSER_EOT  = 1 << 1,
+}AgsMidiParserFlags;
+
+typedef enum{
   AGS_MIDI_CHUNK_HEADER   = 1,
   AGS_MIDI_CHUNK_TRACK    = 1 << 1,
   AGS_MIDI_CHUNK_UNKNOWN  = 1 << 2,
@@ -45,34 +52,99 @@ struct _AgsMidiParser
 {
   GObject gobject;
 
-  int fd;
+  guint flags;
+
+  FILE *file;
   guint nth_chunk;
+
+  size_t file_length;
+  size_t offset;
+
+  guint current_time;
 };
 
 struct _AgsMidiParserClass
 {
   GObjectClass gobject;
+
+  int (*midi_getc)(AgsMidiParser *midi_parser);
+  void (*on_error)(AgsMidiParser *midi_parser,
+		   GError **error);
+  
+  xmlNode* (*parse_header)(AgsMidiParser *midi_parser);
+  xmlNode* (*parse_track)(AgsMidiParser *midi_parser);
+
+  xmlNode* (*key_on)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*key_off)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*key_pressure)(AgsMidiParser *midi_parser, guint status);
+
+  xmlNode* (*change_parameter)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*change_pitch_bend)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*change_program)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*change_channel_pressure)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*not_defined)(AgsMidiParser *midi_parser, guint status);
+
+  xmlNode* (*sysex)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*system_common)(AgsMidiParser *midi_parser, guint status);
+
+  xmlNode* (*meta_event)(AgsMidiParser *midi_parser, guint status);
+  xmlNode* (*sequence_number)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*end_of_track)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*smpte)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*tempo)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*time_signature)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*key_signature)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*sequencer_meta_event)(AgsMidiParser *midi_parser, guint meta_type);
+  xmlNode* (*text_event)(AgsMidiParser *midi_parser, guint meta_type);
+  
+  xmlDoc* (*parse_full)(AgsMidiParser *midi_parser);
 };
 
 GType ags_midi_parser_get_type(void);
 
-char* ags_midi_parser_read_chunk(AgsMidiParser *midi_parser,
-				 guint *message_type, guint *message_length,
-				 GError **error);
-void ags_midi_parser_write_chunk(AgsMidiParser *midi_parser,
-				 char *chunk, size_t length);
-void ags_midi_parser_seek(AgsMidiParser *midi_parser, guint n_chunks, gint whence);
-void ags_midi_parser_flush(AgsMidiParser *midi_parser);
-
-xmlNode* ags_midi_parser_parse_header(AgsMidiParser *parser,
-				      char *chunk_data,
-				      guint chunk_type,
-				      guint chunk_length);
-xmlNode* ags_midi_parser_parse_track(AgsMidiParser *parser,
-				     char *chunk_data,
-				     guint chunk_type,
-				     guint chunk_length);
-
-AgsMidiParser* ags_midi_parser_new(int fd);
+gint16 ags_midi_parser_read_gint16(AgsMidiParser *midi_parser);
+gint32 ags_midi_parser_read_gint24(AgsMidiParser *midi_parser);
+gint32 ags_midi_parser_read_gint32(AgsMidiParser *midi_parser);
+long ags_midi_parser_read_varlength(AgsMidiParser *midi_parser);
+gchar* ags_midi_parser_read_text(AgsMidiParser *midi_parser,
+				 gint length);
+
+gdouble ags_midi_parser_ticks_to_sec(AgsMidiParser *midi_parser,
+				     guint ticks, gint division, guint tempo);
+
+int ags_midi_parser_midi_getc(AgsMidiParser *midi_parser);
+void ags_midi_parser_on_error(AgsMidiParser *midi_parser,
+			      GError **error);
+
+xmlDoc* ags_midi_parser_parse_full(AgsMidiParser *midi_parser);
+
+xmlNode* ags_midi_parser_parse_header(AgsMidiParser *midi_parser);
+xmlNode* ags_midi_parser_parse_track(AgsMidiParser *midi_parser);
+
+xmlNode* ags_midi_parser_channel_message(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_key_on(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_key_off(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_key_pressure(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_change_parameter(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_change_pitch_bend(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_change_program(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_change_channel_pressure(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_not_defined(AgsMidiParser *midi_parser, guint status);
+
+xmlNode* ags_midi_parser_sysex(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_system_common(AgsMidiParser *midi_parser, guint status);
+
+xmlNode* ags_midi_parser_meta_event(AgsMidiParser *midi_parser, guint status);
+xmlNode* ags_midi_parser_sequence_number(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_end_of_track(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_smpte(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_tempo(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_time_signature(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_key_signature(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_sequencer_meta_event(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_meta_misc(AgsMidiParser *midi_parser, guint meta_type);
+xmlNode* ags_midi_parser_text_event(AgsMidiParser *midi_parser, guint meta_type);
+
+AgsMidiParser* ags_midi_parser_new(FILE *file);
 
 #endif /*__AGS_MIDI_PARSER_H__*/

-- 
gsequencer packaging



More information about the pkg-multimedia-commits mailing list