---
 dlls/winealsa.drv/midi.c |  103 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 91 insertions(+), 12 deletions(-)

Index: src/dlls/winealsa.drv/midi.c
===================================================================
--- src.orig/dlls/winealsa.drv/midi.c	2010-09-11 20:05:04.000000000 +0100
+++ src/dlls/winealsa.drv/midi.c	2010-09-14 20:50:35.000000000 +0100
@@ -101,6 +101,9 @@ static	int		numStartedMidiIn = 0;
 static int port_in;
 static int port_out;
 
+static snd_midi_event_t *alsa_encoder;
+
+
 static CRITICAL_SECTION crit_sect;   /* protects all MidiIn buffer queues */
 static CRITICAL_SECTION_DEBUG critsect_debug =
 {
@@ -247,7 +250,8 @@ static int midiOpenSeq(int create_client
             else
 	       TRACE("Outport port created successfully (%d)\n", port_out);
 #else
-            port_out = snd_seq_create_simple_port(midiSeq, "WINE ALSA Output", SND_SEQ_PORT_CAP_READ,
+            port_out = snd_seq_create_simple_port(midiSeq, "WINE ALSA Output", SND_SEQ_PORT_CAP_READ
+						  | SND_SEQ_PORT_CAP_SUBS_READ,
 	                 	                                                 SND_SEQ_PORT_TYPE_APPLICATION);
 	    if (port_out < 0)
 		TRACE("Unable to create output port\n");
@@ -835,8 +839,12 @@ static DWORD modData(WORD wDevID, DWORD 
             snd_seq_ev_clear(&event);
             snd_seq_ev_set_direct(&event);
             snd_seq_ev_set_source(&event, port_out);
+#if 0
             snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
-	    
+#else
+	    snd_seq_ev_set_subs (&event);
+#endif
+
 	    switch (evt & 0xF0) {
 	    case MIDI_CMD_NOTE_OFF:
 		snd_seq_ev_set_noteoff(&event, evt&0x0F, d1, d2);
@@ -927,9 +935,10 @@ static DWORD modData(WORD wDevID, DWORD 
  */
 static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-    int		len_add = 0;
-    LPBYTE	lpData, lpNewData = NULL;
+    LPBYTE	lpData;
+#if 0
     snd_seq_event_t event;
+#endif
 
     TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
 
@@ -964,19 +973,33 @@ static DWORD modLongData(WORD wDevID, LP
      */
     if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) {
 	WARN("Alleged system exclusive buffer is not correct\n\tPlease report with MIDI file\n");
-	lpNewData = HeapAlloc(GetProcessHeap(), 0, lpMidiHdr->dwBufferLength + 2);
     }
 
     TRACE("dwBufferLength=%u !\n", lpMidiHdr->dwBufferLength);
-    TRACE("                 %02X %02X %02X ... %02X %02X %02X\n",
-	  lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3],
-	  lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]);
+    {
+	char *buf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+				100 + lpMidiHdr->dwBufferLength * 3);
+	char *p = buf;
+	int i;
+
+	for (i = 0; i < lpMidiHdr->dwBufferLength; i++)
+	{
+		sprintf(p, " %02X", lpData[i]);
+		p += 3;
+	}
+	*p = '\0';
+
+	TRACE("                 %s\n", buf);
+
+	HeapFree(GetProcessHeap(), 0, buf);
+    }
 
     switch (MidiOutDev[wDevID].caps.wTechnology) {
     case MOD_FMSYNTH:
 	/* FIXME: I don't think there is much to do here */
 	break;
     case MOD_MIDIPORT:
+#if 0
 	if (lpData[0] != 0xF0) {
 	    /* Send start of System Exclusive */
 	    len_add = 1;
@@ -993,20 +1016,76 @@ static DWORD modLongData(WORD wDevID, LP
 	    WARN("Adding missing 0xF7 marker at the end of "
 		 "system exclusive byte stream\n");
 	}
+#endif
+#if 0
 	snd_seq_ev_clear(&event);
 	snd_seq_ev_set_direct(&event);
 	snd_seq_ev_set_source(&event, port_out);
 	snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
 	TRACE("client = %d port = %d\n", MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port);
-	snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength + len_add, lpNewData ? lpNewData : lpData);
+	// snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength, lpData);
+	event.type = SND_SEQ_EVENT_SYSEX;
+	snd_seq_ev_set_variable(&event, lpMidiHdr->dwBufferLength, lpData);
+
 	snd_seq_event_output_direct(midiSeq, &event);
-	if (lpNewData)
-		HeapFree(GetProcessHeap(), 0, lpData);
+#else
+	{
+		size_t event_size = lpMidiHdr->dwBufferLength;
+		char *event_buffer = (char *) lpData;
+		/* Note that this object maintains state across calls to
+		   snd_midi_event_encode/output_event */
+		static snd_seq_event_t alsa_event;
+		size_t sent = 0;
+
+		if (alsa_encoder == NULL)
+		{
+			snd_midi_event_new(1024, &alsa_encoder);
+			snd_seq_ev_clear(&alsa_event);
+		}
+
+		while (sent < event_size) {
+			long s;
+			size_t tosend = event_size - sent;
+
+			s = snd_midi_event_encode(alsa_encoder, (unsigned char*)event_buffer + sent, 
+						  (long)tosend, &alsa_event);
+
+			if (s > 0) {
+				if (alsa_event.type != SND_SEQ_EVENT_NONE) {
+					snd_seq_ev_set_direct(&alsa_event);
+					snd_seq_ev_set_source(&alsa_event, port_out);
+#if 0
+					snd_seq_ev_set_dest(&alsa_event,
+							    MidiOutDev[wDevID].addr.client,
+							    MidiOutDev[wDevID].addr.port);
+#else
+					snd_seq_ev_set_subs (&alsa_event);
+#endif
+
+					snd_seq_event_output_direct(midiSeq, &alsa_event);
+				} else {
+					/* We don't have enough data to finish encoding an event
+					   yet */
+					TRACE("We don't have enough data to finish encoding an event yet\n");
+				}
+
+				TRACE("processed %ld\n", s);
+
+				sent += s;
+			} else if (s < 0) {
+				TRACE("encoding sequencer event failed: %s (%ld)\n",
+				      strerror (-s), -s);
+				break;
+			}
+		}
+	}
+#endif
+
+	
 	break;
     default:
 	WARN("Technology not supported (yet) %d !\n",
 	     MidiOutDev[wDevID].caps.wTechnology);
-	HeapFree(GetProcessHeap(), 0, lpNewData);
 	return MMSYSERR_NOTENABLED;
     }
 
