winealsa.drv: Don't crash when getting NULL event from midi.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46170 Signed-off-by: Fabian Maurer <dark.shadow4@web.de> Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
57110d5bc2
commit
20e5920135
|
@ -292,6 +292,116 @@ static int midiCloseSeq(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void handle_midi_event(snd_seq_event_t *ev)
|
||||
{
|
||||
WORD wDevID;
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
|
||||
EnterCriticalSection(&crit_sect);
|
||||
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;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&crit_sect);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD WINAPI midRecThread(LPVOID arg)
|
||||
{
|
||||
int npfd;
|
||||
|
@ -323,116 +433,16 @@ static DWORD WINAPI midRecThread(LPVOID arg)
|
|||
}*/
|
||||
|
||||
do {
|
||||
WORD wDevID;
|
||||
snd_seq_event_t* ev;
|
||||
EnterCriticalSection(&midiSeqLock);
|
||||
snd_seq_event_input(midiSeq, &ev);
|
||||
LeaveCriticalSection(&midiSeqLock);
|
||||
/* 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;
|
||||
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;
|
||||
snd_seq_event_t *ev;
|
||||
|
||||
EnterCriticalSection(&crit_sect);
|
||||
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;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&crit_sect);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
snd_seq_free_event(ev);
|
||||
EnterCriticalSection(&midiSeqLock);
|
||||
snd_seq_event_input(midiSeq, &ev);
|
||||
LeaveCriticalSection(&midiSeqLock);
|
||||
|
||||
if (ev) {
|
||||
handle_midi_event(ev);
|
||||
snd_seq_free_event(ev);
|
||||
}
|
||||
|
||||
EnterCriticalSection(&midiSeqLock);
|
||||
ret = snd_seq_event_input_pending(midiSeq, 0);
|
||||
|
|
Loading…
Reference in New Issue