Signed-off-by: Huw Davies huw@codeweavers.com --- dlls/winealsa.drv/midi.c | 207 ++++++++++++++++++++------------------- 1 file changed, 104 insertions(+), 103 deletions(-)
diff --git a/dlls/winealsa.drv/midi.c b/dlls/winealsa.drv/midi.c index ca31def8d16..77ab9720bcc 100644 --- a/dlls/winealsa.drv/midi.c +++ b/dlls/winealsa.drv/midi.c @@ -170,114 +170,115 @@ static int midiCloseSeq(void) return 0; }
+static void handle_sysex_event(struct midi_src *src, BYTE *data, UINT len) +{ + UINT pos = 0, copy_len, current_time = NtGetTickCount() - src->startTime; + MIDIHDR *hdr; + + in_buffer_lock(); + + while (len) + { + hdr = src->lpQueueHdr; + if (!hdr) break; + + copy_len = min(len, hdr->dwBufferLength - hdr->dwBytesRecorded); + memcpy(hdr->lpData + hdr->dwBytesRecorded, data + pos, copy_len); + hdr->dwBytesRecorded += copy_len; + len -= copy_len; + pos += copy_len; + + if ((hdr->dwBytesRecorded == hdr->dwBufferLength) || + (*(BYTE*)(hdr->lpData + hdr->dwBytesRecorded - 1) == 0xF7)) + { /* buffer full or end of sysex message */ + src->lpQueueHdr = hdr->lpNext; + hdr->dwFlags &= ~MHDR_INQUEUE; + hdr->dwFlags |= MHDR_DONE; + MIDI_NotifyClient(src - MidiInDev, MIM_LONGDATA, (DWORD_PTR)hdr, current_time); + } + } + + in_buffer_unlock(); +} + +static void handle_regular_event(struct midi_src *src, snd_seq_event_t *ev) +{ + UINT data = 0, value, current_time = NtGetTickCount() - src->startTime; + + switch (ev->type) + { + case SND_SEQ_EVENT_NOTEOFF: + data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel; + break; + case SND_SEQ_EVENT_NOTEON: + data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel; + break; + case SND_SEQ_EVENT_KEYPRESS: + data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel; + break; + case SND_SEQ_EVENT_CONTROLLER: + data = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel; + break; + case SND_SEQ_EVENT_PITCHBEND: + value = ev->data.control.value + 0x2000; + data = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel; + break; + case SND_SEQ_EVENT_PGMCHANGE: + data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel; + break; + case SND_SEQ_EVENT_CHANPRESS: + data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel; + break; + case SND_SEQ_EVENT_CLOCK: + data = 0xF8; + break; + case SND_SEQ_EVENT_START: + data = 0xFA; + break; + case SND_SEQ_EVENT_CONTINUE: + data = 0xFB; + break; + case SND_SEQ_EVENT_STOP: + data = 0xFC; + break; + case SND_SEQ_EVENT_SONGPOS: + data = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS; + break; + case SND_SEQ_EVENT_SONGSEL: + data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT; + break; + case SND_SEQ_EVENT_RESET: + data = 0xFF; + break; + case SND_SEQ_EVENT_QFRAME: + data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER; + break; + case SND_SEQ_EVENT_SENSING: + /* Noting to do */ + break; + } + + if (data != 0) + { + MIDI_NotifyClient(src - MidiInDev, MIM_DATA, data, current_time); + } +} + static void handle_midi_event(snd_seq_event_t *ev) { - WORD wDevID; + struct midi_src *src;
/* 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) || (MidiInDev[wDevID].state != 1)) - FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port); - else { - DWORD dwTime, toSend = 0; - int value = 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; - 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; + for (src = MidiInDev; src < MidiInDev + MIDM_NumDevs; src++) + if ((ev->source.client == src->addr.client) && (ev->source.port == src->addr.port)) 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: - value = ev->data.control.value + 0x2000; - toSend = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel; - break; - case SND_SEQ_EVENT_PGMCHANGE: - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel; - break; - case SND_SEQ_EVENT_CHANPRESS: - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel; - break; - case SND_SEQ_EVENT_CLOCK: - toSend = 0xF8; - break; - case SND_SEQ_EVENT_START: - toSend = 0xFA; - break; - case SND_SEQ_EVENT_CONTINUE: - toSend = 0xFB; - break; - case SND_SEQ_EVENT_STOP: - toSend = 0xFC; - break; - case SND_SEQ_EVENT_SONGPOS: - toSend = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS; - break; - case SND_SEQ_EVENT_SONGSEL: - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT; - break; - case SND_SEQ_EVENT_RESET: - toSend = 0xFF; - break; - case SND_SEQ_EVENT_QFRAME: - toSend = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER; - break; - case SND_SEQ_EVENT_SYSEX: - { - int pos = 0; - int len = ev->data.ext.len; - LPBYTE ptr = ev->data.ext.ptr; - LPMIDIHDR lpMidiHdr; - - in_buffer_lock(); - while (len) { - if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) { - int copylen = min(len, lpMidiHdr->dwBufferLength - lpMidiHdr->dwBytesRecorded); - memcpy(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded, ptr + pos, copylen); - lpMidiHdr->dwBytesRecorded += copylen; - len -= copylen; - pos += copylen; - /* We check if we reach the end of buffer or the end of sysex before notifying - * to handle the case where ALSA split the sysex into several events */ - if ((lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) || - (*(BYTE*)(lpMidiHdr->lpData + lpMidiHdr->dwBytesRecorded - 1) == 0xF7)) { - MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext; - lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; - lpMidiHdr->dwFlags |= MHDR_DONE; - MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime); - } - } else { - FIXME("Sysex data received but no buffer to store it!\n"); - break; - } - } - in_buffer_unlock(); - } - 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("Received event %08x from %d:%d\n", toSend, ev->source.client, ev->source.port); - MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime); - } - } + if ((src == MidiInDev + MIDM_NumDevs) || (src->state != 1)) + return; + + if (ev->type == SND_SEQ_EVENT_SYSEX) + handle_sysex_event(src, ev->data.ext.ptr, ev->data.ext.len); + else + handle_regular_event(src, ev); }
static DWORD WINAPI midRecThread(void *arg)