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.
This commit is contained in:
parent
ca8901640e
commit
87bef514db
@ -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,21 +281,23 @@ 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");
|
||||||
|
|
||||||
|
while(!end_thread) {
|
||||||
|
TRACE("Thread loop\n");
|
||||||
npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
|
npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN);
|
||||||
pfd = (struct pollfd *)HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd));
|
pfd = (struct pollfd *)HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd));
|
||||||
snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN);
|
snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN);
|
||||||
|
|
||||||
/* Check if a event is present */
|
/* Check if a event is present */
|
||||||
if (poll(pfd, npfd, 0) <= 0) {
|
if (poll(pfd, npfd, 250) < 0) {
|
||||||
HeapFree(GetProcessHeap(), 0, pfd);
|
HeapFree(GetProcessHeap(), 0, pfd);
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: This definitely does not work.
|
/* Note: This definitely does not work.
|
||||||
@ -303,10 +316,12 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
|
|||||||
for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
|
for (wDevID = 0; wDevID < MIDM_NumDevs; wDevID++)
|
||||||
if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
|
if ( (ev->source.client == MidiInDev[wDevID].addr.client) && (ev->source.port == MidiInDev[wDevID].addr.port) )
|
||||||
break;
|
break;
|
||||||
if (wDevID == MIDM_NumDevs)
|
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);
|
FIXME("Unexpected event received, type = %x from %d:%d\n", ev->type, ev->source.client, ev->source.port);
|
||||||
else {
|
else {
|
||||||
DWORD toSend = 0;
|
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);
|
TRACE("Event received, type = %x, device = %d\n", ev->type, wDevID);
|
||||||
switch(ev->type)
|
switch(ev->type)
|
||||||
{
|
{
|
||||||
@ -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:
|
||||||
@ -364,8 +379,7 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
|
|||||||
}
|
}
|
||||||
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,6 +389,8 @@ static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
|
|||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, pfd);
|
HeapFree(GetProcessHeap(), 0, pfd);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* midGetDevCaps [internal]
|
* midGetDevCaps [internal]
|
||||||
@ -439,14 +455,15 @@ 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user