[WINEALSA] Add Midi IN support (w/o alloca)

Christian Costa titan.costa at wanadoo.fr
Sun Jan 11 14:03:52 CST 2004


Changelog :
Added Midi IN support to the ALSA driver.

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.5
diff -u -r1.5 midi.c
--- midi.c	8 Dec 2003 21:46:50 -0000	1.5
+++ midi.c	11 Jan 2004 18:42:47 -0000
@@ -96,8 +96,12 @@
 static	UINT		midiInTimerID = 0;
 static	int		numStartedMidiIn = 0;
 
-int port_in;
-int port_out;
+static int port_in;
+static int port_out;
+
+static int npfd;
+static int pfd_array_size = 0;
+static struct pollfd *pfd = NULL;
 
 /*======================================================================*
  *                  Low level MIDI implementation			*
@@ -270,13 +274,106 @@
 {
     TRACE("(%p, %d, %d, %lu)\n", hwnd, msg, id, dwTime);
 
-    while(snd_seq_event_input_pending(midiSeq, 0) > 0) {
+    npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
+    if (npfd > pfd_array_size)
+    {
+	if (pfd)
+	    HeapFree(GetProcessHeap(), 0, pfd);
+	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) {
+	return;
+    }  
+
+    /* Note: This definitely does not work.  
+     * while(snd_seq_event_input_pending(midiSeq, 0) > 0) {
 	snd_seq_event_t* ev;
-	TRACE("An event is pending\n");
 	snd_seq_event_input(midiSeq, &ev);
-	TRACE("Event received, type = %d\n", ev->type);
+	....................
 	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.client == MidiInDev[wDevID].addr.client) )
+		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)
+	    {
+		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;
+		case SND_SEQ_EVENT_NOTEON:
+		    toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel;
+		    break;
+		case SND_SEQ_EVENT_KEYPRESS:
+		    toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel;
+		    break;
+		case SND_SEQ_EVENT_CONTROLLER: 
+		    toSend = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel;
+		    break;
+		case SND_SEQ_EVENT_PITCHBEND:
+		    toSend = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_BENDER | ev->data.control.channel;
+		    break;
+		case SND_SEQ_EVENT_PGMCHANGE:
+		    toSend = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel;
+		    break;
+		case SND_SEQ_EVENT_CHANPRESS:
+		    toSend = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel;
+		    break;
+		case SND_SEQ_EVENT_SYSEX:
+		    {
+			int len = ev->data.ext.len;
+			LPBYTE ptr = (BYTE*) ev->data.ext.ptr;
+			LPMIDIHDR lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
+
+			/* FIXME: Should handle sysex greater that a single buffer */
+			if (lpMidiHdr) {
+			    if (len <= lpMidiHdr->dwBufferLength) {
+				lpMidiHdr->dwBytesRecorded = len;
+				memcpy(lpMidiHdr->lpData, ptr, len);
+				lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
+				lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
+				lpMidiHdr->dwFlags |= MHDR_DONE;
+				MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
+				if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)lpMidiHdr, dwTime) != MMSYSERR_NOERROR) {
+				    WARN("Couldn't notify client\n");
+				}
+			    } else
+				FIXME("No enough space in the buffer to store sysex!\n");
+			} else
+			    FIXME("Sysex received but no buffer to store it!\n");
+		    }
+		    break;
+		case SND_SEQ_EVENT_SENSING:
+		    /* Noting to do */
+		    break;
+		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 */
+		dwTime -= MidiInDev[wDevID].startTime;
+		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);
 }
 
 /**************************************************************************


More information about the wine-patches mailing list