📄 midi.c
字号:
* midiCloseSeq [internal] */static int midiCloseSeq(void){ if (--numOpenMidiSeq == 0) { close(midiSeqFD); midiSeqFD = -1; } return 0;}/* FIXME: this is a bad idea, it's even not static... */SEQ_DEFINEBUF(1024);/* FIXME: this is not reentrant, not static - because of global variable * _seqbuf and al. *//************************************************************************** * seqbuf_dump [internal] * * Used by SEQ_DUMPBUF to flush the buffer. * */void seqbuf_dump(void){ if (_seqbufptr) { if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) { WARN("Can't write data to sequencer %d, errno %d (%s)!\n", midiSeqFD, errno, strerror(errno)); } /* FIXME: * in any case buffer is lost so that if many errors occur the buffer * will not overrun */ _seqbufptr = 0; }}/************************************************************************** * midReceiveChar [internal] */static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime){ DWORD toSend = 0; TRACE("Adding %02xh to %d[%d]\n", value, wDevID, MidiInDev[wDevID].incLen); if (wDevID >= MIDM_NumDevs) { WARN("bad devID\n"); return; } if (MidiInDev[wDevID].state <= 0) { TRACE("disabled or input not started, thrown away\n"); return; } if (MidiInDev[wDevID].state & 2) { /* system exclusive */ LPMIDIHDR lpMidiHdr = MidiInDev[wDevID].lpQueueHdr; WORD sbfb = FALSE; if (lpMidiHdr) { LPBYTE lpData = lpMidiHdr->lpData; lpData[lpMidiHdr->dwBytesRecorded++] = value; if (lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) { sbfb = TRUE; } } if (value == 0xF7) { /* then end */ MidiInDev[wDevID].state &= ~2; sbfb = TRUE; } if (sbfb && lpMidiHdr != NULL) { lpMidiHdr = MidiInDev[wDevID].lpQueueHdr; 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"); } } return; }#define IS_CMD(_x) (((_x) & 0x80) == 0x80)#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0) if (!IS_CMD(value) && MidiInDev[wDevID].incLen == 0) { /* try to reuse old cmd */ if (IS_CMD(MidiInDev[wDevID].incPrev) && !IS_SYS_CMD(MidiInDev[wDevID].incPrev)) { MidiInDev[wDevID].incoming[0] = MidiInDev[wDevID].incPrev; MidiInDev[wDevID].incLen = 1; TRACE("Reusing old command %02xh\n", MidiInDev[wDevID].incPrev); } else { FIXME("error for midi-in, should generate MIM_ERROR notification:" " prev=%02Xh, incLen=%02Xh\n", MidiInDev[wDevID].incPrev, MidiInDev[wDevID].incLen); return; } } MidiInDev[wDevID].incoming[(int)(MidiInDev[wDevID].incLen++)] = value; if (MidiInDev[wDevID].incLen == 1 && !IS_SYS_CMD(MidiInDev[wDevID].incoming[0])) { /* store new cmd, just in case */ MidiInDev[wDevID].incPrev = MidiInDev[wDevID].incoming[0]; }#undef IS_CMD#undef IS_SYS_CMD switch (MidiInDev[wDevID].incoming[0] & 0xF0) { case MIDI_NOTEOFF: case MIDI_NOTEON: case MIDI_KEY_PRESSURE: case MIDI_CTL_CHANGE: case MIDI_PITCH_BEND: if (MidiInDev[wDevID].incLen == 3) { toSend = (MidiInDev[wDevID].incoming[2] << 16) | (MidiInDev[wDevID].incoming[1] << 8) | (MidiInDev[wDevID].incoming[0] << 0); } break; case MIDI_PGM_CHANGE: case MIDI_CHN_PRESSURE: if (MidiInDev[wDevID].incLen == 2) { toSend = (MidiInDev[wDevID].incoming[1] << 8) | (MidiInDev[wDevID].incoming[0] << 0); } break; case MIDI_SYSTEM_PREFIX: if (MidiInDev[wDevID].incoming[0] == 0xF0) { MidiInDev[wDevID].state |= 2; MidiInDev[wDevID].incLen = 0; } else { if (MidiInDev[wDevID].incLen == 1) { toSend = (MidiInDev[wDevID].incoming[0] << 0); } } break; default: WARN("This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]); } if (toSend != 0) { TRACE("Sending event %08lx\n", toSend); MidiInDev[wDevID].incLen = 0; dwTime -= MidiInDev[wDevID].startTime; if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) { WARN("Couldn't notify client\n"); } }}static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime){ unsigned char buffer[256]; int len, idx; TRACE("(%p, %d, %d, %lu)\n", hwnd, msg, id, dwTime); len = read(midiSeqFD, buffer, sizeof(buffer)); if (len < 0) return; if ((len % 4) != 0) { WARN("Bad length %d, errno %d (%s)\n", len, errno, strerror(errno)); return; } for (idx = 0; idx < len; ) { if (buffer[idx] & 0x80) { TRACE( "Reading<8> %02x %02x %02x %02x %02x %02x %02x %02x\n", buffer[idx + 0], buffer[idx + 1], buffer[idx + 2], buffer[idx + 3], buffer[idx + 4], buffer[idx + 5], buffer[idx + 6], buffer[idx + 7]); idx += 8; } else { switch (buffer[idx + 0]) { case SEQ_WAIT: case SEQ_ECHO: break; case SEQ_MIDIPUTC: midReceiveChar(buffer[idx + 2], buffer[idx + 1], dwTime); break; default: TRACE("Unsupported event %d\n", buffer[idx + 0]); break; } idx += 4; } }}/************************************************************************** * midGetDevCaps [internal] */static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSA lpCaps, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize); if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (lpCaps == NULL) return MMSYSERR_INVALPARAM; memcpy(lpCaps, &MidiInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps))); 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() < 0) { return MMSYSERR_ERROR; } if (numStartedMidiIn++ == 0) { midiInTimerID = SetTimer(0, 0, 250, midTimeCallback); if (!midiInTimerID) { numStartedMidiIn = 0; WARN("Couldn't start timer for midi-in\n"); midiCloseSeq(); return MMSYSERR_ERROR; } TRACE("Starting timer (%u) for midi-in\n", midiInTimerID); } 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;}/************************************************************************** * 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 (midiSeqFD == -1) { WARN("ooops !\n"); return MMSYSERR_ERROR; } if (--numStartedMidiIn == 0) { TRACE("Stopping timer for midi-in\n"); if (!KillTimer(0, midiInTimerID)) { WARN("Couldn't stop timer for midi-in\n"); } midiInTimerID = 0; } 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;}/************************************************************************** * midAddBuffer [internal] */static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE; if (lpMidiHdr == NULL) return MMSYSERR_INVALPARAM; if (sizeof(MIDIHDR) > dwSize) return MMSYSERR_INVALPARAM; if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; if (MidiInDev[wDevID].lpQueueHdr == 0) { MidiInDev[wDevID].lpQueueHdr = lpMidiHdr; } else { LPMIDIHDR ptr; for (ptr = MidiInDev[wDevID].lpQueueHdr; ptr->lpNext != 0; ptr = (LPMIDIHDR)ptr->lpNext); ptr->lpNext = (struct midihdr_tag*)lpMidiHdr; } return MMSYSERR_NOERROR;}/************************************************************************** * midPrepare [internal] */static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 || lpMidiHdr->dwBufferLength >= 0x10000ul) return MMSYSERR_INVALPARAM; lpMidiHdr->lpNext = 0; lpMidiHdr->dwFlags |= MHDR_PREPARED; lpMidiHdr->dwBytesRecorded = 0; return MMSYSERR_NOERROR;}/************************************************************************** * midUnprepare [internal] */static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE; if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0 || lpMidiHdr->dwBufferLength >= 0x10000ul) return MMSYSERR_INVALPARAM; if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; lpMidiHdr->dwFlags &= ~MHDR_PREPARED; return MMSYSERR_NOERROR;}/************************************************************************** * 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; 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; } return MMSYSERR_NOERROR;}/************************************************************************** * midStart [internal] */static DWORD midStart(WORD wDevID){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -