Commit 87bef514 authored by Christian Costa's avatar Christian Costa Committed by Alexandre Julliard

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.
parent ca890164
...@@ -93,12 +93,23 @@ static int MIDM_NumDevs = 0; ...@@ -93,12 +93,23 @@ static int MIDM_NumDevs = 0;
static snd_seq_t* midiSeq = NULL; static snd_seq_t* midiSeq = NULL;
static int numOpenMidiSeq = 0; static int numOpenMidiSeq = 0;
static UINT midiInTimerID = 0;
static int numStartedMidiIn = 0; static int numStartedMidiIn = 0;
static int port_in; static int port_in;
static int port_out; static int port_out;
static CRITICAL_SECTION crit_sect; /* protects all MidiIn buffer queues */
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &crit_sect,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { 0, (DWORD)(__FILE__ ": crit_sect") }
};
static CRITICAL_SECTION crit_sect = { &critsect_debug, -1, 0, 0, 0, 0 };
static int end_thread;
static HANDLE hThread;
/*======================================================================* /*======================================================================*
* Low level MIDI implementation * * Low level MIDI implementation *
*======================================================================*/ *======================================================================*/
...@@ -270,46 +281,50 @@ static int midiCloseSeq(void) ...@@ -270,46 +281,50 @@ static int midiCloseSeq(void)
return 0; return 0;
} }
static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime) static DWORD WINAPI midRecThread(LPVOID arg)
{ {
int npfd; int npfd;
struct pollfd *pfd; 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); while(!end_thread) {
pfd = (struct pollfd *)HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd)); TRACE("Thread loop\n");
snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN); npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
pfd = (struct pollfd *)HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd));
/* Check if a event is present */ snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN);
if (poll(pfd, npfd, 0) <= 0) {
HeapFree(GetProcessHeap(), 0, pfd); /* Check if a event is present */
return; 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; /* Note: This definitely does not work.
snd_seq_event_input(midiSeq, &ev); * while(snd_seq_event_input_pending(midiSeq, 0) > 0) {
.................... snd_seq_event_t* ev;
snd_seq_free_event(ev); snd_seq_event_input(midiSeq, &ev);
}*/ ....................
snd_seq_free_event(ev);
do { }*/
WORD wDevID;
snd_seq_event_t* ev; do {
snd_seq_event_input(midiSeq, &ev); WORD wDevID;
/* Find the target device */ snd_seq_event_t* ev;
for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++) snd_seq_event_input(midiSeq, &ev);
if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) ) /* Find the target device */
break; for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
if (wDevID == MIDM_NumDevs) if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port); break;
else { if ((wDevID == MIDM_NumDevs) || (MidiInDev[wDevID].state != 1))
DWORD toSend = 0; FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID); else {
switch(ev->type) 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: case SND_SEQ_EVENT_NOTEOFF:
toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel; toSend = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel;
break; break;
...@@ -335,24 +350,24 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime) ...@@ -335,24 +350,24 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
{ {
int len = ev->data.ext.len; int len = ev->data.ext.len;
LPBYTE ptr = (BYTE*) ev->data.ext.ptr; LPBYTE ptr = (BYTE*) ev->data.ext.ptr;
LPMIDIHDR lpMidiHdr = MidiInDev[wDevID].lpQueueHdr; LPMIDIHDR lpMidiHdr;
/* FIXME: Should handle sysex greater that a single buffer */ /* FIXME: Should handle sysex greater that a single buffer */
if (lpMidiHdr) { EnterCriticalSection(&crit_sect);
if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) {
if (len <= lpMidiHdr->dwBufferLength) { if (len <= lpMidiHdr->dwBufferLength) {
lpMidiHdr->dwBytesRecorded = len; lpMidiHdr->dwBytesRecorded = len;
memcpy(lpMidiHdr->lpData, ptr, len); memcpy(lpMidiHdr->lpData, ptr, len);
lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
lpMidiHdr->dwFlags |= MHDR_DONE; lpMidiHdr->dwFlags |= MHDR_DONE;
MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)lpMidiHdr->lpNext; MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)lpMidiHdr, dwTime) != MMSYSERR_NOERROR) { if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)lpMidiHdr, dwTime) != MMSYSERR_NOERROR)
WARN("Couldn't notify client\n"); WARN("Couldn't notify client\n");
}
} else } else
FIXME("No enough space in the buffer to store sysex!\n"); FIXME("No enough space in the buffer to store sysex!\n");
} else } else
FIXME("Sysex received but no buffer to store it!\n"); FIXME("Sysex received but no buffer to store it!\n");
LeaveCriticalSection(&crit_sect);
} }
break; break;
case SND_SEQ_EVENT_SENSING: case SND_SEQ_EVENT_SENSING:
...@@ -361,19 +376,20 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime) ...@@ -361,19 +376,20 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
default: default:
FIXME("Unhandled event received, type = %x\n", ev->type); FIXME("Unhandled event received, type = %x\n", ev->type);
break; break;
} }
if (toSend != 0) { if (toSend != 0) {
TRACE("Sending event %08lx (from %d %d)\n", toSend, ev->source.client, ev->source.port); 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) != MMSYSERR_NOERROR) {
if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime-MidiInDev[wDevID].startTime) != MMSYSERR_NOERROR) { WARN("Couldn't notify client\n");
WARN("Couldn't notify client\n"); }
} }
} }
} snd_seq_free_event(ev);
snd_seq_free_event(ev); } while(snd_seq_event_input_pending(midiSeq, 0) > 0);
} while(snd_seq_event_input_pending(midiSeq, 0) > 0);
HeapFree(GetProcessHeap(), 0, pfd); HeapFree(GetProcessHeap(), 0, pfd);
}
return 0;
} }
/************************************************************************** /**************************************************************************
...@@ -438,15 +454,16 @@ static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) ...@@ -438,15 +454,16 @@ static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
TRACE("input port connected %d %d %d\n",port_in,MidiInDev[wDevID].addr.client,MidiInDev[wDevID].addr.port); TRACE("input port connected %d %d %d\n",port_in,MidiInDev[wDevID].addr.client,MidiInDev[wDevID].addr.port);
if (numStartedMidiIn++ == 0) { if (numStartedMidiIn++ == 0) {
midiInTimerID = SetTimer(0, 0, 250, midTimeCallback); end_thread = 0;
if (!midiInTimerID) { hThread = CreateThread(NULL, 0, midRecThread, NULL, 0, NULL);
if (!hThread) {
numStartedMidiIn = 0; numStartedMidiIn = 0;
WARN("Couldn't start timer for midi-in\n"); WARN("Couldn't create thread for midi-in\n");
midiCloseSeq(); midiCloseSeq();
return MMSYSERR_ERROR; 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); MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
...@@ -492,11 +509,13 @@ static DWORD midClose(WORD wDevID) ...@@ -492,11 +509,13 @@ static DWORD midClose(WORD wDevID)
return MMSYSERR_ERROR; return MMSYSERR_ERROR;
} }
if (--numStartedMidiIn == 0) { if (--numStartedMidiIn == 0) {
TRACE("Stopping timer for midi-in\n"); TRACE("Stopping thread for midi-in\n");
if (!KillTimer(0, midiInTimerID)) { end_thread = 1;
WARN("Couldn't stop timer for midi-in\n"); 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); snd_seq_disconnect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port);
...@@ -529,6 +548,7 @@ static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) ...@@ -529,6 +548,7 @@ static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
EnterCriticalSection(&crit_sect);
if (MidiInDev[wDevID].lpQueueHdr == 0) { if (MidiInDev[wDevID].lpQueueHdr == 0) {
MidiInDev[wDevID].lpQueueHdr = lpMidiHdr; MidiInDev[wDevID].lpQueueHdr = lpMidiHdr;
} else { } else {
...@@ -539,6 +559,8 @@ static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) ...@@ -539,6 +559,8 @@ static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
ptr = (LPMIDIHDR)ptr->lpNext); ptr = (LPMIDIHDR)ptr->lpNext);
ptr->lpNext = (struct midihdr_tag*)lpMidiHdr; ptr->lpNext = (struct midihdr_tag*)lpMidiHdr;
} }
LeaveCriticalSection(&crit_sect);
return MMSYSERR_NOERROR; return MMSYSERR_NOERROR;
} }
...@@ -595,6 +617,7 @@ static DWORD midReset(WORD wDevID) ...@@ -595,6 +617,7 @@ static DWORD midReset(WORD wDevID)
if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE; if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;
EnterCriticalSection(&crit_sect);
while (MidiInDev[wDevID].lpQueueHdr) { while (MidiInDev[wDevID].lpQueueHdr) {
MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE; MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE;
MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE; MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE;
...@@ -605,6 +628,7 @@ static DWORD midReset(WORD wDevID) ...@@ -605,6 +628,7 @@ static DWORD midReset(WORD wDevID)
} }
MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext; MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext;
} }
LeaveCriticalSection(&crit_sect);
return MMSYSERR_NOERROR; return MMSYSERR_NOERROR;
} }
...@@ -1240,6 +1264,7 @@ DWORD WINAPI ALSA_midMessage(UINT wDevID, UINT wMsg, DWORD dwUser, ...@@ -1240,6 +1264,7 @@ DWORD WINAPI ALSA_midMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
switch (wMsg) { switch (wMsg) {
#if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1) #if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1)
case DRVM_INIT: case DRVM_INIT:
case DRVM_EXIT:
case DRVM_ENABLE: case DRVM_ENABLE:
case DRVM_DISABLE: case DRVM_DISABLE:
/* FIXME: Pretend this is supported */ /* FIXME: Pretend this is supported */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment