[WINEALSA] Replaced the timer and its callback by a thread for receiving midi in events.

Christian Costa titan.costa at wanadoo.fr
Wed Feb 11 18:10:35 CST 2004


Hi,

SetTimer requires the caller to process its message loop in order to 
have timer callbacks be executed.
To be independant of what apps do, let's use a thread for receiving midi 
in events.

This patch fixed midi communication in Midi Quest 9.
This app works fine with my Korg X5D.

Bye.

Changelog :
Replaced the timer and its callback by a thread for receiving midi in 
events.
Fixed time of MIM_LONGDATA notification.
Handled DRVM_EXIT in ALSA_midMessage.

Christian Costa   titan.costa at wanadoo.fr

-------------- next part --------------
Index: midi.c
===================================================================
RCS file: /home/wine/wine/dlls/winmm/winealsa/midi.c,v
retrieving revision 1.7
diff -u -r1.7 midi.c
--- midi.c	5 Feb 2004 01:24:28 -0000	1.7
+++ midi.c	11 Feb 2004 22:46:13 -0000
@@ -93,12 +93,14 @@
 
 static	snd_seq_t*      midiSeq = NULL;
 static	int		numOpenMidiSeq = 0;
-static	UINT		midiInTimerID = 0;
 static	int		numStartedMidiIn = 0;
 
 static int port_in;
 static int port_out;
 
+static int end_thread;
+static HANDLE hThread;
+
 /*======================================================================*
  *                  Low level MIDI implementation			*
  *======================================================================*/
@@ -270,46 +272,50 @@
     return 0;
 }
 
-static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
+static DWORD WINAPI midRecThread(LPVOID arg)
 {
     int npfd;
     struct pollfd *pfd;
 
-    TRACE("(%p, %d, %d, %lu)\n", hwnd, msg, id, dwTime);
+    TRACE("Thread startup\n");
 
-    npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
-    pfd = (struct pollfd *)HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd));
-    snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN);
-    
-    /* Check if a event is present */
-    if (poll(pfd, npfd, 0) <= 0) {
-	HeapFree(GetProcessHeap(), 0, pfd);
-	return;
-    }  
+    while(!end_thread) {
+	TRACE("Thread loop\n");
+	npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
+	pfd = (struct pollfd *)HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd));
+	snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN);
+
+	/* Check if a event is present */
+	if (poll(pfd, npfd, 250) < 0) {
+	    HeapFree(GetProcessHeap(), 0, pfd);
+	    continue;
+	}
 
-    /* Note: This definitely does not work.  
-     * while(snd_seq_event_input_pending(midiSeq, 0) > 0) {
-	snd_seq_event_t* ev;
-	snd_seq_event_input(midiSeq, &ev);
-	....................
-	snd_seq_free_event(ev);
-    }*/
-
-    do {
-	WORD wDevID;
-	snd_seq_event_t* ev;
-	snd_seq_event_input(midiSeq, &ev);
-	/* Find the target device */
-	for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
-	    if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
-		break;
-	if (wDevID == MIDM_NumDevs)
-	    FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
-	else {
-	    DWORD toSend = 0;
-	    TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID);
-	    switch(ev->type)
-	    {
+	/* Note: This definitely does not work.  
+	 * while(snd_seq_event_input_pending(midiSeq, 0) > 0) {
+	       snd_seq_event_t* ev;
+	       snd_seq_event_input(midiSeq, &ev);
+	       ....................
+	       snd_seq_free_event(ev);
+	   }*/
+
+	do {
+	    WORD wDevID;
+	    snd_seq_event_t* ev;
+	    snd_seq_event_input(midiSeq, &ev);
+	    /* Find the target device */
+	    for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
+		if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
+		    break;
+	    if (wDevID == MIDM_NumDevs)
+		FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
+	    else {
+		DWORD dwTime, toSend = 0;
+		/* FIXME: Should use ev->time instead for better accuracy */
+		dwTime = GetTickCount() - MidiInDev[wDevID].startTime;
+		TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID);
+		switch(ev->type)
+		{
 		case SND_SEQ_EVENT_NOTEOFF:
 		    toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
 		    break;
@@ -361,19 +367,20 @@
 		default:
 		    FIXME("Unhandled event received, type = %x\n", ev->type);
 		    break;
-	    }
-	    if (toSend != 0) {
-		TRACE("Sending event %08lx (from %d %d)\n", toSend, ev->source.client, ev->source.port);
-		/* FIXME: Should use ev->time instead for better accuracy */
-		if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime-MidiInDev[wDevID].startTime) != MMSYSERR_NOERROR) {
-		    WARN("Couldn't notify client\n");
+		}
+		if (toSend != 0) {
+		    TRACE("Sending event %08lx (from %d %d)\n", toSend, ev->source.client, ev->source.port);
+		    if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) {
+			WARN("Couldn't notify client\n");
+		    }
 		}
 	    }
-	}
-	snd_seq_free_event(ev);
-    } while(snd_seq_event_input_pending(midiSeq, 0) > 0);
+	    snd_seq_free_event(ev);
+	} while(snd_seq_event_input_pending(midiSeq, 0) > 0);
 	
-    HeapFree(GetProcessHeap(), 0, pfd);
+	HeapFree(GetProcessHeap(), 0, pfd);
+    }
+    return 0;
 }
 
 /**************************************************************************
@@ -439,14 +446,15 @@
     TRACE("input port connected %d %d %d\n",port_in,MidiInDev[wDevID].addr.client,MidiInDev[wDevID].addr.port);
 
    if (numStartedMidiIn++ == 0) {
-	midiInTimerID = SetTimer(0, 0, 250, midTimeCallback);
-	if (!midiInTimerID) {
+	end_thread = 0;
+	hThread = CreateThread(NULL, 0, midRecThread, NULL, 0, NULL);
+	if (!hThread) {
 	    numStartedMidiIn = 0;
-	    WARN("Couldn't start timer for midi-in\n");
+	    WARN("Couldn't create thread for midi-in\n");
 	    midiCloseSeq();
 	    return MMSYSERR_ERROR;
 	}
-	TRACE("Starting timer (%u) for midi-in\n", midiInTimerID);
+	TRACE("Created thread for midi-in\n");
     }
 
     MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
@@ -492,11 +500,13 @@
 	return MMSYSERR_ERROR;
     }
     if (--numStartedMidiIn == 0) {
-	TRACE("Stopping timer for midi-in\n");
-	if (!KillTimer(0, midiInTimerID)) {
-	    WARN("Couldn't stop timer for midi-in\n");
+	TRACE("Stopping thread for midi-in\n");
+	end_thread = 1;
+	if (WaitForSingleObject(hThread, 5000) != WAIT_OBJECT_0) {
+	    WARN("Thread end not signaled, force termination\n");
+	    TerminateThread(hThread, 0);
 	}
-	midiInTimerID = 0;
+    	TRACE("Stopped thread for midi-in\n");
     }
 
     snd_seq_disconnect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port);
@@ -1240,6 +1250,7 @@
     switch (wMsg) {
 #if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1)
     case DRVM_INIT:
+    case DRVM_EXIT:
     case DRVM_ENABLE:
     case DRVM_DISABLE:
 	/* FIXME: Pretend this is supported */


More information about the wine-patches mailing list