Changelog : Added Midi IN support to the ALSA driver.
Christian Costa titan.costa@xxxxxxxxxx
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); } /**************************************************************************