int OPLMIDIDevice::PlayTick() { DWORD delay = 0; while (delay == 0 && Events != NULL) { DWORD *event = (DWORD *)(Events->lpData + Position); if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) { SetTempo(MEVT_EVENTPARM(event[2])); } else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) { // Should I handle master volume changes? } else if (MEVT_EVENTTYPE(event[2]) == 0) { // Short MIDI event int status = event[2] & 0xff; int parm1 = (event[2] >> 8) & 0x7f; int parm2 = (event[2] >> 16) & 0x7f; HandleEvent(status, parm1, parm2); } // Advance to next event. if (event[2] < 0x80000000) { // Short message Position += 12; } else { // Long message Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); } // Did we use up this buffer? if (Position >= Events->dwBytesRecorded) { Events = Events->lpNext; Position = 0; if (Callback != NULL) { Callback(MOM_DONE, CallbackData, 0, 0); } } if (Events == NULL) { // No more events. Just return something to keep the song playing // while we wait for more to be submitted. return int(Division); } delay = *(DWORD *)(Events->lpData + Position); }
/************************************************************************** * MMSYSTEM_MidiStream_Player [internal] */ static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) { WINE_MIDIStream* lpMidiStrm = pmt; WINE_MIDI* lpwm; MSG msg; DWORD dwToGo; DWORD dwCurrTC; LPMIDIHDR lpMidiHdr; DWORD dwOffset; TRACE("(%p)!\n", lpMidiStrm); if (!lpMidiStrm || (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) goto the_end; /* force thread's queue creation */ PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE); lpMidiStrm->dwStartTicks = 0; lpMidiStrm->dwPulses = 0; lpMidiStrm->lpMidiHdr = 0; /* midiStreamOpen is waiting for ack */ SetEvent(lpMidiStrm->hEvent); start_header: lpMidiHdr = lpMidiStrm->lpMidiHdr; if (!lpMidiHdr) { /* for first message, block until one arrives, then process all that are available */ GetMessageA(&msg, 0, 0, 0); do { if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) goto the_end; } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); goto start_header; } dwOffset = 0; while (dwOffset + offsetof(MIDIEVENT,dwParms) <= lpMidiHdr->dwBytesRecorded) { LPMIDIEVENT me = (LPMIDIEVENT)(lpMidiHdr->lpData+dwOffset); /* do we have to wait ? */ if (me->dwDeltaTime) { lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); lpMidiStrm->dwPulses += me->dwDeltaTime; dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; TRACE("%d/%d/%d\n", dwToGo, GetTickCount(), me->dwDeltaTime); while ((dwCurrTC = GetTickCount()) < dwToGo) { if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { /* got a message, handle it */ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) goto the_end; /* is lpMidiHdr still current? */ if (lpMidiHdr != lpMidiStrm->lpMidiHdr) { goto start_header; } } } else { /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ break; } } } switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { case MEVT_COMMENT: FIXME("NIY: MEVT_COMMENT\n"); /* do nothing, skip bytes */ break; case MEVT_LONGMSG: midiOutLongMsg(lpMidiStrm->hDevice, lpMidiStrm->lpMidiHdr, MEVT_EVENTPARM(me->dwEvent)); break; case MEVT_NOP: break; case MEVT_SHORTMSG: midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); break; case MEVT_TEMPO: lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); break; case MEVT_VERSION: break; default: FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); break; } if (me->dwEvent & MEVT_F_CALLBACK) { /* native fills dwOffset regardless of the cbMidiHdr size argument to midiStreamOut */ lpMidiHdr->dwOffset = dwOffset; DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); } dwOffset += offsetof(MIDIEVENT,dwParms); if (me->dwEvent & MEVT_F_LONG) dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; } /* done with this header */ lpMidiStrm->lpMidiHdr = lpMidiHdr->lpNext; lpMidiHdr->dwFlags |= MHDR_DONE; lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); goto start_header; the_end: TRACE("End of thread\n"); return 0; }
int SoftSynthMIDIDevice::PlayTick() { DWORD delay = 0; while (delay == 0 && Events != NULL) { DWORD *event = (DWORD *)(Events->lpData + Position); if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO) { SetTempo(MEVT_EVENTPARM(event[2])); } else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG) { HandleLongEvent((BYTE *)&event[3], MEVT_EVENTPARM(event[2])); } else if (MEVT_EVENTTYPE(event[2]) == 0) { // Short MIDI event int status = event[2] & 0xff; int parm1 = (event[2] >> 8) & 0x7f; int parm2 = (event[2] >> 16) & 0x7f; HandleEvent(status, parm1, parm2); if (synth_watch) { static const char *const commands[8] = { "Note off", "Note on", "Poly press", "Ctrl change", "Prgm change", "Chan press", "Pitch bend", "SysEx" }; char buffer[128]; mysnprintf(buffer, countof(buffer), "C%02d: %11s %3d %3d\n", (status & 15) + 1, commands[(status >> 4) & 7], parm1, parm2); #ifdef _WIN32 OutputDebugString(buffer); #else fputs(buffer, stderr); #endif } } // Advance to next event. if (event[2] < 0x80000000) { // Short message Position += 12; } else { // Long message Position += 12 + ((MEVT_EVENTPARM(event[2]) + 3) & ~3); } // Did we use up this buffer? if (Position >= Events->dwBytesRecorded) { Events = Events->lpNext; Position = 0; if (Callback != NULL) { Callback(MOM_DONE, CallbackData, 0, 0); } } if (Events == NULL) { // No more events. Just return something to keep the song playing // while we wait for more to be submitted. return int(Division); } delay = *(DWORD *)(Events->lpData + Position); }