📄 mcimidi.c
字号:
return MCIERR_DEVICE_OPEN; } wmm->nUseCount++; wmm->hFile = 0; wmm->hMidi = 0; dwDeviceID = lpParms->wDeviceID; TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID); /* lpParms->wDeviceID = wDevID;*/ if (dwFlags & MCI_OPEN_ELEMENT) { TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpParms->lpstrElementName); if (lpParms->lpstrElementName && strlen(lpParms->lpstrElementName) > 0) { wmm->hFile = mmioOpenA(lpParms->lpstrElementName, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); if (wmm->hFile == 0) { WARN("Can't find file '%s' !\n", lpParms->lpstrElementName); wmm->nUseCount--; return MCIERR_FILE_NOT_FOUND; } } else { wmm->hFile = 0; } } TRACE("hFile=%p\n", wmm->hFile); /* FIXME: should I get a strdup() of it instead? */ wmm->lpstrElementName = HeapAlloc( GetProcessHeap(), 0, strlen(lpParms->lpstrElementName)+1 ); strcpy( wmm->lpstrElementName, lpParms->lpstrElementName ); wmm->lpstrCopyright = NULL; wmm->lpstrName = NULL; wmm->wNotifyDeviceID = dwDeviceID; wmm->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */ /* spec says it should be the default format from the MIDI file... */ wmm->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS; if (wmm->hFile != 0) { MMCKINFO ckMainRIFF; MMCKINFO mmckInfo; DWORD dwOffset = 0; if (mmioDescend(wmm->hFile, &ckMainRIFF, NULL, 0) != 0) { dwRet = MCIERR_INVALID_FILE; } else { TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize); if (ckMainRIFF.ckid == FOURCC_RIFF && ckMainRIFF.fccType == mmioFOURCC('R', 'M', 'I', 'D')) { mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); mmioSeek(wmm->hFile, ckMainRIFF.dwDataOffset + ((ckMainRIFF.cksize + 1) & ~1), SEEK_SET); if (mmioDescend(wmm->hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) { TRACE("... is a 'RMID' file \n"); dwOffset = mmckInfo.dwDataOffset; } else { dwRet = MCIERR_INVALID_FILE; } } if (dwRet == 0 && MIDI_mciReadMThd(wmm, dwOffset) != 0) { WARN("Can't read 'MThd' header \n"); dwRet = MCIERR_INVALID_FILE; } } } else { TRACE("hFile==0, setting #tracks to 0; is this correct ?\n"); wmm->nTracks = 0; wmm->wFormat = 0; wmm->nDivision = 1; } if (dwRet != 0) { wmm->nUseCount--; if (wmm->hFile != 0) mmioClose(wmm->hFile, 0); wmm->hFile = 0; } else { wmm->dwPositionMS = 0; wmm->dwStatus = MCI_MODE_STOP; } return dwRet;}/************************************************************************** * MIDI_mciStop [internal] */static DWORD MIDI_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms){ WINE_MCIMIDI* wmm = MIDI_mciGetOpenDev(wDevID); DWORD dwRet = 0; TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (wmm == NULL) return MCIERR_INVALID_DEVICE_ID; if (wmm->dwStatus != MCI_MODE_STOP) { int oldstat = wmm->dwStatus; wmm->dwStatus = MCI_MODE_NOT_READY; if (oldstat == MCI_MODE_PAUSE) dwRet = midiOutReset((HMIDIOUT)wmm->hMidi); while (wmm->dwStatus != MCI_MODE_STOP) Sleep(10); } /* sanitiy reset */ wmm->dwStatus = MCI_MODE_STOP; TRACE("wmm->dwStatus=%d\n", wmm->dwStatus); if (lpParms && (dwFlags & MCI_NOTIFY)) { TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wmm->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); } return 0;}/************************************************************************** * MIDI_mciClose [internal] */static DWORD MIDI_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms){ WINE_MCIMIDI* wmm = MIDI_mciGetOpenDev(wDevID); TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (wmm == NULL) return MCIERR_INVALID_DEVICE_ID; if (wmm->dwStatus != MCI_MODE_STOP) { MIDI_mciStop(wDevID, MCI_WAIT, lpParms); } wmm->nUseCount--; if (wmm->nUseCount == 0) { if (wmm->hFile != 0) { mmioClose(wmm->hFile, 0); wmm->hFile = 0; TRACE("hFile closed !\n"); } HeapFree(GetProcessHeap(), 0, wmm->tracks); HeapFree(GetProcessHeap(), 0, (LPSTR)wmm->lpstrElementName); HeapFree(GetProcessHeap(), 0, (LPSTR)wmm->lpstrCopyright); HeapFree(GetProcessHeap(), 0, (LPSTR)wmm->lpstrName); } else { TRACE("Shouldn't happen... nUseCount=%d\n", wmm->nUseCount); return MCIERR_INTERNAL; } if (lpParms && (dwFlags & MCI_NOTIFY)) { TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback); mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)), wmm->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL); } return 0;}/************************************************************************** * MIDI_mciFindNextEvent [internal] */static MCI_MIDITRACK* MIDI_mciFindNextEvent(WINE_MCIMIDI* wmm, LPDWORD hiPulse){ WORD cnt, nt; MCI_MIDITRACK* mmt; *hiPulse = 0xFFFFFFFFul; cnt = 0xFFFFu; for (nt = 0; nt < wmm->nTracks; nt++) { mmt = &wmm->tracks[nt]; if (mmt->wStatus == 0) continue; if (mmt->dwEventPulse < *hiPulse) { *hiPulse = mmt->dwEventPulse; cnt = nt; } } return (cnt == 0xFFFFu) ? 0 /* no more event on all tracks */ : &wmm->tracks[cnt];}/************************************************************************** * MIDI_mciPlay [internal] */static DWORD MIDI_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms){ DWORD dwStartMS, dwEndMS; DWORD dwRet = 0; WORD doPlay, nt; MCI_MIDITRACK* mmt; DWORD hiPulse; WINE_MCIMIDI* wmm = MIDI_mciGetOpenDev(wDevID); TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms); if (wmm == NULL) return MCIERR_INVALID_DEVICE_ID; if (wmm->hFile == 0) { WARN("Can't play: no file '%s' !\n", wmm->lpstrElementName); return MCIERR_FILE_NOT_FOUND; } if (wmm->dwStatus != MCI_MODE_STOP) { if (wmm->dwStatus == MCI_MODE_PAUSE) { /* FIXME: parameters (start/end) in lpParams may not be used */ return MIDI_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms); } WARN("Can't play: device is not stopped !\n"); return MCIERR_INTERNAL; } if (!(dwFlags & MCI_WAIT)) { /** FIXME: I'm not 100% sure that wNotifyDeviceID is the right value in all cases ??? */ return MCI_SendCommandAsync(wmm->wNotifyDeviceID, MCI_PLAY, dwFlags, (DWORD)lpParms, sizeof(LPMCI_PLAY_PARMS)); } if (lpParms && (dwFlags & MCI_FROM)) { dwStartMS = MIDI_ConvertTimeFormatToMS(wmm, lpParms->dwFrom); } else { dwStartMS = wmm->dwPositionMS; } if (lpParms && (dwFlags & MCI_TO)) { dwEndMS = MIDI_ConvertTimeFormatToMS(wmm, lpParms->dwTo); } else { dwEndMS = 0xFFFFFFFFul; } TRACE("Playing from %lu to %lu\n", dwStartMS, dwEndMS); /* init tracks */ for (nt = 0; nt < wmm->nTracks; nt++) { mmt = &wmm->tracks[nt]; mmt->wStatus = 1; /* ok, playing */ mmt->dwIndex = mmt->dwFirst; if (wmm->wFormat == 2 && nt > 0) { mmt->dwEventPulse = wmm->tracks[nt - 1].dwLength; } else { mmt->dwEventPulse = 0; } MIDI_mciReadNextEvent(wmm, mmt); /* FIXME == 0 */ } dwRet = midiOutOpen((LPHMIDIOUT)&wmm->hMidi, MIDIMAPPER, 0L, 0L, CALLBACK_NULL); /* dwRet = midiInOpen(&wmm->hMidi, MIDIMAPPER, 0L, 0L, CALLBACK_NULL);*/ if (dwRet != MMSYSERR_NOERROR) { return dwRet; } wmm->dwPulse = 0; wmm->dwTempo = 500000; wmm->dwStatus = MCI_MODE_PLAY; wmm->dwPositionMS = 0; wmm->wStartedPlaying = FALSE; while (wmm->dwStatus != MCI_MODE_STOP && wmm->dwStatus != MCI_MODE_NOT_READY) { /* it seems that in case of multi-threading, gcc is optimizing just a little bit * too much. Tell gcc not to optimize status value using volatile. */ while (((volatile WINE_MCIMIDI*)wmm)->dwStatus == MCI_MODE_PAUSE); doPlay = (wmm->dwPositionMS >= dwStartMS && wmm->dwPositionMS <= dwEndMS); TRACE("wmm->dwStatus=%d, doPlay=%c\n", wmm->dwStatus, doPlay ? 'T' : 'F'); if ((mmt = MIDI_mciFindNextEvent(wmm, &hiPulse)) == NULL) break; /* no more event on tracks */ /* if starting playing, then set StartTicks to the value it would have had * if play had started at position 0 */ if (doPlay && !wmm->wStartedPlaying) { wmm->dwStartTicks = GetTickCount() - MIDI_ConvertPulseToMS(wmm, wmm->dwPulse); wmm->wStartedPlaying = TRUE; TRACE("Setting dwStartTicks to %lu\n", wmm->dwStartTicks); } if (hiPulse > wmm->dwPulse) { wmm->dwPositionMS += MIDI_ConvertPulseToMS(wmm, hiPulse - wmm->dwPulse); if (doPlay) { DWORD togo = wmm->dwStartTicks + wmm->dwPositionMS; DWORD tc = GetTickCount(); TRACE("Pulses hi=0x%08lx <> cur=0x%08lx\n", hiPulse, wmm->dwPulse); TRACE("Wait until %lu => %lu ms\n", tc - wmm->dwStartTicks, togo - wmm->dwStartTicks); if (tc < togo) Sleep(togo - tc); } wmm->dwPulse = hiPulse; } switch (LOBYTE(LOWORD(mmt->dwEventData))) { case 0xF0: case 0xF7: /* sysex events */ { FIXME("Not handling SysEx events (yet)\n"); } break; case 0xFF: /* position after meta data header */ mmioSeek(wmm->hFile, mmt->dwIndex + HIWORD(mmt->dwEventData), SEEK_SET); switch (HIBYTE(LOWORD(mmt->dwEventData))) { case 0x00: /* 16-bit sequence number */ if (TRACE_ON(mcimidi)) { WORD twd; MIDI_mciReadWord(wmm, &twd); /* == 0 */ TRACE("Got sequence number %u\n", twd); } break; case 0x01: /* any text */ case 0x02: /* Copyright Message text */ case 0x03: /* Sequence/Track Name text */ case 0x04: /* Instrument Name text */ case 0x05: /* Lyric text */ case 0x06: /* Marker text */ case 0x07: /* Cue-point text */ if (TRACE_ON(mcimidi)) { char buf[1024]; WORD len = mmt->wEventLength - HIWORD(mmt->dwEventData); static const char* info[8] = {"", "Text", "Copyright", "Seq/Trk name", "Instrument", "Lyric", "Marker", "Cue-point"}; WORD idx = HIBYTE(LOWORD(mmt->dwEventData)); if (len >= sizeof(buf)) { WARN("Buffer for text is too small (%d bytes, when %u are needed)\n", sizeof(buf) - 1, len); len = sizeof(buf) - 1; } if (mmioRead(wmm->hFile, (HPSTR)buf, len) == len) { buf[len] = 0; /* end string in case */ TRACE("%s => \"%s\"\n", (idx < 8 ) ? info[idx] : "", buf); } else { WARN("Couldn't read data for %s\n", (idx < 8) ? info[idx] : ""); } } break; case 0x20: /* MIDI channel (cc) */ if (FIXME_ON(mcimidi)) { BYTE bt; MIDI_mciReadByte(wmm, &bt); /* == 0 */ FIXME("NIY: MIDI channel=%u, track=%u\n", bt, mmt->wTrackNr); } break; case 0x21: /* MIDI port (pp) */ if (FIXME_ON(mcimidi)) { BYTE bt; MIDI_mciReadByte(wmm, &bt); /* == 0 */ FIXME("NIY: MIDI port=%u, track=%u\n", bt, mmt->wTrackNr); } break; case 0x2F: /* end of track */ mmt->wStatus = 0; break; case 0x51:/* set tempo */ /* Tempo is expressed in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -