📄 midi.c
字号:
if (!KillTimer(0, midiInTimerID)) { WARN("Couldn't stop timer for midi-in\n"); } midiInTimerID = 0; } 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;}/************************************************************************** * 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){ TRACE("(%04X);\n", wDevID); if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE; MidiInDev[wDevID].state = 1; MidiInDev[wDevID].startTime = GetTickCount(); return MMSYSERR_NOERROR;}/************************************************************************** * midStop [internal] */static DWORD midStop(WORD wDevID){ TRACE("(%04X);\n", wDevID); if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID; if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE; MidiInDev[wDevID].state = 0; return MMSYSERR_NOERROR;}/************************************************************************** * modGetDevCaps [internal] */static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSA lpCaps, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize); if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID; if (lpCaps == NULL) return MMSYSERR_INVALPARAM; memcpy(lpCaps, &MidiOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps))); 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;}/************************************************************************** * 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: 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; } if (MidiOutDev[wDevID].lpExtra != 0) { 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;}/************************************************************************** * modData [internal] */static DWORD modData(WORD wDevID, DWORD dwParam){ BYTE evt = LOBYTE(LOWORD(dwParam)); BYTE d1 = HIBYTE(LOWORD(dwParam)); BYTE d2 = LOBYTE(HIWORD(dwParam)); TRACE("(%04X, %08lX);\n", wDevID, dwParam); 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; } switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_SYNTH: case MOD_MIDIPORT: { int handled = 1; /* Assume event is handled */ snd_seq_event_t event; snd_seq_ev_clear(&event); switch (evt & 0xF0) { case MIDI_CMD_NOTE_OFF: snd_seq_ev_set_noteoff(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_NOTE_ON: snd_seq_ev_set_noteon(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_NOTE_PRESSURE: snd_seq_ev_set_keypress(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_CONTROL: snd_seq_ev_set_controller(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_BENDER: snd_seq_ev_set_pitchbend(&event, evt&0x0F, ((WORD)d1 << 7) | (WORD)d2); break; case MIDI_CMD_PGM_CHANGE: snd_seq_ev_set_pgmchange(&event, evt&0x0F, d1); break; case MIDI_CMD_CHANNEL_PRESSURE: snd_seq_ev_set_chanpress(&event, evt&0x0F, d1); break; case MIDI_CMD_COMMON_SYSEX: switch (evt & 0x0F) { case 0x00: /* System Exclusive, don't do it on modData, * should require modLongData*/ case 0x01: /* Undefined */ case 0x04: /* Undefined. */ case 0x05: /* Undefined. */ case 0x07: /* End of Exclusive. */ case 0x09: /* Undefined. */ case 0x0D: /* Undefined. */ handled = 0; break; case 0x06: /* Tune Request */ case 0x08: /* Timing Clock. */ case 0x0A: /* Start. */ case 0x0B: /* Continue */ case 0x0C: /* Stop */ case 0x0E: /* Active Sensing. */ /* FIXME: Is this function suitable for these purposes (and also Song Select and Song Position Pointer) */ snd_seq_ev_set_sysex(&event, 1, &evt); break; case 0x0F: /* Reset */ /* snd_seq_ev_set_sysex(&event, 1, &evt); this other way may be better */ { BYTE reset_sysex_seq[] = {MIDI_CMD_COMMON_SYSEX, 0x7e, 0x7f, 0x09, 0x01, 0xf7}; snd_seq_ev_set_sysex(&event, sizeof(reset_sysex_seq), reset_sysex_seq); } break; case 0x03: /* Song Select. */ { BYTE buf[2]; buf[0] = evt; buf[1] = d1; snd_seq_ev_set_sysex(&event, sizeof(buf), buf); } case 0x02: /* Song Position Pointer. */ { BYTE buf[3]; buf[0] = evt; buf[1] = d1; buf[2] = d2; snd_seq_ev_set_sysex(&event, sizeof(buf), buf); } } break; } if (handled) snd_seq_event_output_direct(midiSeq, &event); } break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -