static DWORD MIDIIn_Open(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) { TRACE("wDevID=%d lpDesc=%p dwFlags=%08x\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= MIDIIn_NumDevs) { WARN("bad device ID : %d\n", wDevID); return MMSYSERR_BADDEVICEID; } if (sources[wDevID].midiDesc.hMidi != 0) { WARN("device already open !\n"); return MMSYSERR_ALLOCATED; } if ((dwFlags & MIDI_IO_STATUS) != 0) { WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n"); dwFlags &= ~MIDI_IO_STATUS; } if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { FIXME("Bad dwFlags\n"); return MMSYSERR_INVALFLAG; } sources[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); sources[wDevID].lpQueueHdr = NULL; sources[wDevID].midiDesc = *lpDesc; sources[wDevID].startTime = 0; sources[wDevID].state = 0; MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L); return MMSYSERR_NOERROR; }
static DWORD MIDIOut_Open(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) { MIDIDestination *dest; TRACE("wDevID=%d lpDesc=%p dwFlags=%08x\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= MIDIOut_NumDevs) { WARN("bad device ID : %d\n", wDevID); return MMSYSERR_BADDEVICEID; } if (destinations[wDevID].midiDesc.hMidi != 0) { WARN("device already open !\n"); return MMSYSERR_ALLOCATED; } if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { WARN("bad dwFlags\n"); return MMSYSERR_INVALFLAG; } dest = &destinations[wDevID]; if (dest->caps.wTechnology == MOD_SYNTH) { if (!SynthUnit_CreateDefaultSynthUnit(&dest->graph, &dest->synth)) { ERR("SynthUnit_CreateDefaultSynthUnit dest=%p failed\n", dest); return MMSYSERR_ERROR; } if (!SynthUnit_Initialize(dest->synth, dest->graph)) { ERR("SynthUnit_Initialise dest=%p failed\n", dest); return MMSYSERR_ERROR; } } dest->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); dest->midiDesc = *lpDesc; MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L); return MMSYSERR_NOERROR; }
/************************************************************************** * midClose [internal] */ static DWORD midClose(WORD wDevID) { int ret = MMSYSERR_NOERROR; TRACE("(%04X);\n", wDevID); if (wDevID >= MIDM_NumDevs) { WARN("wDevID too big (%u) !\n", wDevID); return MMSYSERR_BADDEVICEID; } if (MidiInDev[wDevID].midiDesc.hMidi == 0) { WARN("device not opened !\n"); return MMSYSERR_ERROR; } if (MidiInDev[wDevID].lpQueueHdr != 0) { return MIDIERR_STILLPLAYING; } if (midiSeq == NULL) { WARN("ooops !\n"); return MMSYSERR_ERROR; } if (--numStartedMidiIn == 0) { TRACE("Stopping thread for midi-in\n"); end_thread = 1; if (WaitForSingleObject(hThread, 5000) != WAIT_OBJECT_0) { WARN("Thread end not signaled, force termination\n"); TerminateThread(hThread, 0); } TRACE("Stopped thread for midi-in\n"); } snd_seq_disconnect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port); midiCloseSeq(); MidiInDev[wDevID].bufsize = 0; if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { WARN("can't notify client !\n"); ret = MMSYSERR_INVALPARAM; } MidiInDev[wDevID].midiDesc.hMidi = 0; return ret; }
/************************************************************************** * modClose [internal] */ static DWORD modClose(WORD wDevID) { int ret = MMSYSERR_NOERROR; TRACE("(%04X);\n", wDevID); if (MidiOutDev[wDevID].midiDesc.hMidi == 0) { WARN("device not opened !\n"); return MMSYSERR_ERROR; } /* FIXME: should test that no pending buffer is still in the queue for * playing */ if (midiSeq == NULL) { WARN("can't close !\n"); return MMSYSERR_ERROR; } switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_FMSYNTH: case MOD_MIDIPORT: case MOD_SYNTH: snd_seq_disconnect_to(midiSeq, port_out, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); midiCloseSeq(); break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra); MidiOutDev[wDevID].lpExtra = 0; MidiOutDev[wDevID].bufsize = 0; if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { WARN("can't notify client !\n"); ret = MMSYSERR_INVALPARAM; } MidiOutDev[wDevID].midiDesc.hMidi = 0; return ret; }
static DWORD MIDIOut_Close(WORD wDevID) { DWORD ret = MMSYSERR_NOERROR; TRACE("wDevID=%d\n", wDevID); if (wDevID >= MIDIOut_NumDevs) { WARN("bad device ID : %d\n", wDevID); return MMSYSERR_BADDEVICEID; } if (destinations[wDevID].caps.wTechnology == MOD_SYNTH) SynthUnit_Close(destinations[wDevID].graph); destinations[wDevID].graph = 0; destinations[wDevID].synth = 0; MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L); destinations[wDevID].midiDesc.hMidi = 0; return ret; }
static DWORD MIDIIn_Reset(WORD wDevID) { DWORD dwTime = GetTickCount(); TRACE("%d\n", wDevID); if (wDevID >= MIDIIn_NumDevs) { WARN("bad device ID : %d\n", wDevID); return MMSYSERR_BADDEVICEID; } EnterCriticalSection(&midiInLock); while (sources[wDevID].lpQueueHdr) { LPMIDIHDR lpMidiHdr = sources[wDevID].lpQueueHdr; sources[wDevID].lpQueueHdr = lpMidiHdr->lpNext; lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; lpMidiHdr->dwFlags |= MHDR_DONE; /* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */ MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime); } LeaveCriticalSection(&midiInLock); return MMSYSERR_NOERROR; }
static DWORD MIDIIn_Close(WORD wDevID) { DWORD ret = MMSYSERR_NOERROR; TRACE("wDevID=%d\n", wDevID); if (wDevID >= MIDIIn_NumDevs) { WARN("bad device ID : %d\n", wDevID); return MMSYSERR_BADDEVICEID; } if (sources[wDevID].midiDesc.hMidi == 0) { WARN("device not opened !\n"); return MMSYSERR_ERROR; } if (sources[wDevID].lpQueueHdr != 0) { return MIDIERR_STILLPLAYING; } MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L); sources[wDevID].midiDesc.hMidi = 0; return ret; }
/************************************************************************** * midReset [internal] */ static DWORD midReset(WORD wDevID) { DWORD dwTime = GetTickCount(); TRACE("(%04X);\n", wDevID); if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE; EnterCriticalSection(&crit_sect); while (MidiInDev[wDevID].lpQueueHdr) { MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE; MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE; /* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */ if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) { WARN("Couldn't notify client\n"); } MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext; } LeaveCriticalSection(&crit_sect); return MMSYSERR_NOERROR; }
static CFDataRef MIDIIn_MessageHandler(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info) { MIDIMessage *msg = NULL; int i = 0; MIDISource *src = NULL; DWORD sendData = 0; int pos = 0; DWORD currentTime; switch (msgid) { case 0: msg = (MIDIMessage *) CFDataGetBytePtr(data); TRACE("devID=%d\n", msg->devID); for (i = 0; i < msg->length; ++i) { TRACE("%02X ", msg->data[i]); } TRACE("\n"); src = &sources[msg->devID]; if (src->state < 1) { TRACE("input not started, thrown away\n"); goto done; } /* FIXME skipping SysEx */ if (msg->data[0] == 0xF0) { FIXME("Starting System Exclusive\n"); src->state |= 2; } if (src->state & 2) { for (i = 0; i < msg->length; ++i) { if (msg->data[i] == 0xF7) { FIXME("Ending System Exclusive\n"); src->state &= ~2; } } goto done; } EnterCriticalSection(&midiInLock); currentTime = GetTickCount() - src->startTime; while (pos < msg->length) { sendData = 0; switch (msg->data[pos] & 0xF0) { case 0xF0: sendData = (msg->data[pos] << 0); pos++; break; case 0xC0: case 0xD0: sendData = (msg->data[pos + 1] << 8) | (msg->data[pos] << 0); pos += 2; break; default: sendData = (msg->data[pos + 2] << 16) | (msg->data[pos + 1] << 8) | (msg->data[pos] << 0); pos += 3; break; } MIDI_NotifyClient(msg->devID, MIM_DATA, sendData, currentTime); } LeaveCriticalSection(&midiInLock); break; default: CFRunLoopStop(CFRunLoopGetCurrent()); break; } done: return NULL; }
static DWORD MIDIOut_LongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) { LPBYTE lpData; OSStatus err = noErr; TRACE("wDevID=%d lpMidiHdr=%p dwSize=%d\n", wDevID, lpMidiHdr, dwSize); /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure * but it seems to be used only for midi input. * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption. */ if (wDevID >= MIDIOut_NumDevs) { WARN("bad device ID : %d\n", wDevID); return MMSYSERR_BADDEVICEID; } if (lpMidiHdr == NULL) { WARN("Invalid Parameter\n"); return MMSYSERR_INVALPARAM; } lpData = (LPBYTE) lpMidiHdr->lpData; if (lpData == NULL) return MIDIERR_UNPREPARED; if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; lpMidiHdr->dwFlags &= ~MHDR_DONE; lpMidiHdr->dwFlags |= MHDR_INQUEUE; /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive * data, or can it also contain raw MIDI data, to be split up and sent to * modShortData() ? * If the latest is true, then the following WARNing will fire up */ if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) { WARN("Alledged system exclusive buffer is not correct\n\tPlease report with MIDI file\n"); } TRACE("dwBufferLength=%u !\n", lpMidiHdr->dwBufferLength); TRACE(" %02X %02X %02X ... %02X %02X %02X\n", lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3], lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]); if (lpData[0] != 0xF0) { /* System Exclusive */ ERR("Add missing 0xF0 marker at the beginning of system exclusive byte stream\n"); } if (lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) { /* Send end of System Exclusive */ ERR("Add missing 0xF7 marker at the end of system exclusive byte stream\n"); } if (destinations[wDevID].caps.wTechnology == MOD_SYNTH) /* FIXME */ { err = MusicDeviceSysEx(destinations[wDevID].synth, (const UInt8 *) lpData, lpMidiHdr->dwBufferLength); if (err != noErr) { ERR("MusicDeviceSysEx(%p, %p, %d) return %s\n", destinations[wDevID].synth, lpData, lpMidiHdr->dwBufferLength, wine_dbgstr_fourcc(err)); return MMSYSERR_ERROR; } } else { FIXME("MOD_MIDIPORT\n"); } lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; lpMidiHdr->dwFlags |= MHDR_DONE; MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD_PTR)lpMidiHdr, 0L); return MMSYSERR_NOERROR; }
/************************************************************************** * modLongData [internal] */ static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) { int len_add = 0; LPBYTE lpData, lpNewData = NULL; snd_seq_event_t event; TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure * but it seems to be used only for midi input. * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption. */ if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID; if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE; if (midiSeq == NULL) { WARN("can't play !\n"); return MIDIERR_NODEVICE; } lpData = (LPBYTE) lpMidiHdr->lpData; if (lpData == NULL) return MIDIERR_UNPREPARED; if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; lpMidiHdr->dwFlags &= ~MHDR_DONE; lpMidiHdr->dwFlags |= MHDR_INQUEUE; /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive * data, or can it also contain raw MIDI data, to be split up and sent to * modShortData() ? * If the latest is true, then the following WARNing will fire up */ if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) { WARN("Alleged system exclusive buffer is not correct\n\tPlease report with MIDI file\n"); lpNewData = HeapAlloc(GetProcessHeap(), 0, lpMidiHdr->dwBufferLength + 2); } TRACE("dwBufferLength=%lu !\n", lpMidiHdr->dwBufferLength); TRACE(" %02X %02X %02X ... %02X %02X %02X\n", lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3], lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]); switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_FMSYNTH: /* FIXME: I don't think there is much to do here */ break; case MOD_MIDIPORT: if (lpData[0] != 0xF0) { /* Send start of System Exclusive */ len_add = 1; lpData[0] = 0xF0; memcpy(lpNewData, lpData, lpMidiHdr->dwBufferLength); WARN("Adding missing 0xF0 marker at the beginning of " "system exclusive byte stream\n"); } if (lpData[lpMidiHdr->dwBufferLength-1] != 0xF7) { /* Send end of System Exclusive */ memcpy(lpData + len_add, lpData, lpMidiHdr->dwBufferLength); lpNewData[lpMidiHdr->dwBufferLength + len_add - 1] = 0xF0; len_add++; WARN("Adding missing 0xF7 marker at the end of " "system exclusive byte stream\n"); } snd_seq_ev_clear(&event); snd_seq_ev_set_direct(&event); snd_seq_ev_set_source(&event, port_out); snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); TRACE("client = %d port = %d\n", MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength + len_add, lpNewData ? lpNewData : lpData); snd_seq_event_output_direct(midiSeq, &event); if (lpNewData) HeapFree(GetProcessHeap(), 0, lpData); break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; lpMidiHdr->dwFlags |= MHDR_DONE; if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) { WARN("can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; }
/************************************************************************** * modOpen [internal] */ static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) { TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= MODM_NumDevs) { TRACE("MAX_MIDIOUTDRV reached !\n"); return MMSYSERR_BADDEVICEID; } if (MidiOutDev[wDevID].midiDesc.hMidi != 0) { WARN("device already open !\n"); return MMSYSERR_ALLOCATED; } if (!MidiOutDev[wDevID].bEnabled) { WARN("device disabled !\n"); return MIDIERR_NODEVICE; } if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { WARN("bad dwFlags\n"); return MMSYSERR_INVALFLAG; } if (!MidiOutDev[wDevID].bEnabled) { TRACE("disabled wDevID\n"); return MMSYSERR_NOTENABLED; } MidiOutDev[wDevID].lpExtra = 0; switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_FMSYNTH: case MOD_MIDIPORT: case MOD_SYNTH: if (midiOpenSeq(1) < 0) { return MMSYSERR_ALLOCATED; } break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); MidiOutDev[wDevID].lpQueueHdr = NULL; MidiOutDev[wDevID].dwTotalPlayed = 0; MidiOutDev[wDevID].bufsize = 0x3FFF; MidiOutDev[wDevID].midiDesc = *lpDesc; /* Connect our app port to the device port */ if (snd_seq_connect_to(midiSeq, port_out, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port) < 0) return MMSYSERR_NOTENABLED; if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { WARN("can't notify client !\n"); return MMSYSERR_INVALPARAM; } TRACE("Successful !\n"); return MMSYSERR_NOERROR; }
/************************************************************************** * midOpen [internal] */ static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) { TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } /* FIXME : * how to check that content of lpDesc is correct ? */ if (wDevID >= MIDM_NumDevs) { WARN("wDevID too large (%u) !\n", wDevID); return MMSYSERR_BADDEVICEID; } if (MidiInDev[wDevID].state == -1) { WARN("device disabled\n"); return MIDIERR_NODEVICE; } if (MidiInDev[wDevID].midiDesc.hMidi != 0) { WARN("device already open !\n"); return MMSYSERR_ALLOCATED; } if ((dwFlags & MIDI_IO_STATUS) != 0) { WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n"); dwFlags &= ~MIDI_IO_STATUS; } if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { FIXME("Bad dwFlags\n"); return MMSYSERR_INVALFLAG; } if (midiOpenSeq(1) < 0) { return MMSYSERR_ERROR; } /* Connect our app port to the device port */ if (snd_seq_connect_from(midiSeq, port_in, MidiInDev[wDevID].addr.client, MidiInDev[wDevID].addr.port) < 0) return MMSYSERR_NOTENABLED; TRACE("input port connected %d %d %d\n",port_in,MidiInDev[wDevID].addr.client,MidiInDev[wDevID].addr.port); if (numStartedMidiIn++ == 0) { end_thread = 0; hThread = CreateThread(NULL, 0, midRecThread, NULL, 0, NULL); if (!hThread) { numStartedMidiIn = 0; WARN("Couldn't create thread for midi-in\n"); midiCloseSeq(); return MMSYSERR_ERROR; } SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); TRACE("Created thread for midi-in\n"); } MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); MidiInDev[wDevID].lpQueueHdr = NULL; MidiInDev[wDevID].dwTotalPlayed = 0; MidiInDev[wDevID].bufsize = 0x3FFF; MidiInDev[wDevID].midiDesc = *lpDesc; MidiInDev[wDevID].state = 0; MidiInDev[wDevID].incLen = 0; MidiInDev[wDevID].startTime = 0; if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { WARN("can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; }
static DWORD WINAPI midRecThread(LPVOID arg) { int npfd; struct pollfd *pfd; TRACE("Thread startup\n"); while(!end_thread) { TRACE("Thread loop\n"); npfd = snd_seq_poll_descriptors_count(midiSeq, POLLIN); pfd = HeapAlloc(GetProcessHeap(), 0, npfd * sizeof(struct pollfd)); snd_seq_poll_descriptors(midiSeq, pfd, npfd, POLLIN); /* Check if an event is present */ 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; snd_seq_event_input(midiSeq, &ev); .................... 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.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; /* 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: 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; /* FIXME: Should handle sysex greater that a single buffer */ EnterCriticalSection(&crit_sect); if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) { if (len <= lpMidiHdr->dwBufferLength) { lpMidiHdr->dwBytesRecorded = len; memcpy(lpMidiHdr->lpData, ptr, len); 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"); 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("Sending event %08lx (from %d %d)\n", toSend, ev->source.client, ev->source.port); 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); HeapFree(GetProcessHeap(), 0, pfd); } return 0; }