📄 midi.c
字号:
if (voice[i].channel == chn) { SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange); } } } break; case 0x7F7F: channel[chn].benderRange = 2; for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) { if (voice[i].channel == chn) { SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange); } } break; default: TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n", channel[chn].regPmtMSB, channel[chn].regPmtLSB, channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB, d2); break; } break; case 0x78: /* all sounds off */ /* FIXME: I don't know if I have to take care of the channel * for this control ? */ for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) { if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) { voice[i].status = sVS_UNUSED; SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64); } } break; case 0x7B: /* all notes off */ /* FIXME: I don't know if I have to take care of the channel * for this control ? */ for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) { if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) { voice[i].status = sVS_UNUSED; SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64); } } break; default: TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n", d1, d2, chn); break; } break; case MIDI_PGM_CHANGE: channel[chn].program = d1; break; case MIDI_CHN_PRESSURE: for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) { if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) { SEQ_KEY_PRESSURE(wDevID, i, voice[i].note, d1); } } break; case MIDI_PITCH_BEND: channel[chn].bender = (d2 << 7) + d1; for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) { if (voice[i].channel == chn) { SEQ_BENDER(wDevID, i, channel[chn].bender); } } break; case MIDI_SYSTEM_PREFIX: switch (evt & 0x0F) { case 0x0F: /* Reset */ modFMReset(wDevID); break; default: WARN("Unsupported (yet) system event %02x\n", evt & 0x0F); } break; default: WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0); return MMSYSERR_NOTENABLED; } } break; case MOD_MIDIPORT: { int dev = wDevID - MODM_NumFMSynthDevs; if (dev < 0) { WARN("Internal error on devID (%u) !\n", wDevID); return MIDIERR_NODEVICE; } switch (evt & 0xF0) { case MIDI_NOTEOFF: case MIDI_NOTEON: case MIDI_KEY_PRESSURE: case MIDI_CTL_CHANGE: case MIDI_PITCH_BEND: SEQ_MIDIOUT(dev, evt); SEQ_MIDIOUT(dev, d1); SEQ_MIDIOUT(dev, d2); break; case MIDI_PGM_CHANGE: case MIDI_CHN_PRESSURE: SEQ_MIDIOUT(dev, evt); SEQ_MIDIOUT(dev, d1); break; case MIDI_SYSTEM_PREFIX: 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. */ break; case 0x06: /* Tune Request */ case 0x08: /* Timing Clock. */ case 0x0A: /* Start. */ case 0x0B: /* Continue */ case 0x0C: /* Stop */ case 0x0E: /* Active Sensing. */ SEQ_MIDIOUT(dev, evt); break; case 0x0F: /* Reset */ /* SEQ_MIDIOUT(dev, evt); this other way may be better */ SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX); SEQ_MIDIOUT(dev, 0x7e); SEQ_MIDIOUT(dev, 0x7f); SEQ_MIDIOUT(dev, 0x09); SEQ_MIDIOUT(dev, 0x01); SEQ_MIDIOUT(dev, 0xf7); break; case 0x03: /* Song Select. */ SEQ_MIDIOUT(dev, evt); SEQ_MIDIOUT(dev, d1); case 0x02: /* Song Position Pointer. */ SEQ_MIDIOUT(dev, evt); SEQ_MIDIOUT(dev, d1); SEQ_MIDIOUT(dev, d2); } break; } } break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } SEQ_DUMPBUF(); return MMSYSERR_NOERROR;}/************************************************************************** * modLongData [internal] */static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize){ int count; LPBYTE lpData; 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 (midiSeqFD == -1) { WARN("can't play !\n"); return MIDIERR_NODEVICE; } lpData = 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=%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 end of System Exclusive */ SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, 0xF0); WARN("Adding missing 0xF0 marker at the beginning of " "system exclusive byte stream\n"); } for (count = 0; count < lpMidiHdr->dwBufferLength; count++) { SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, lpData[count]); } if (lpData[count - 1] != 0xF7) { /* Send end of System Exclusive */ SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, 0xF7); WARN("Adding missing 0xF7 marker at the end of " "system exclusive byte stream\n"); } SEQ_DUMPBUF(); 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;}/************************************************************************** * modPrepare [internal] */static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); if (midiSeqFD == -1) { WARN("can't prepare !\n"); return MMSYSERR_NOTENABLED; } /* MS doc says that dwFlags must be set to zero, but (kinda funny) MS mciseq drivers * asks to prepare MIDIHDR which dwFlags != 0. * So at least check for the inqueue flag */ if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0 || (lpMidiHdr->dwFlags & MHDR_INQUEUE) != 0 || lpMidiHdr->dwBufferLength >= 0x10000ul) { WARN("%p %p %08lx %d/%ld\n", lpMidiHdr, lpMidiHdr->lpData, lpMidiHdr->dwFlags, sizeof(MIDIHDR), dwSize); return MMSYSERR_INVALPARAM; } lpMidiHdr->lpNext = 0; lpMidiHdr->dwFlags |= MHDR_PREPARED; lpMidiHdr->dwFlags &= ~MHDR_DONE; return MMSYSERR_NOERROR;}/************************************************************************** * modUnprepare [internal] */static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize){ TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); if (midiSeqFD == -1) { WARN("can't unprepare !\n"); return MMSYSERR_NOTENABLED; } if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0) return MMSYSERR_INVALPARAM; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; lpMidiHdr->dwFlags &= ~MHDR_PREPARED; return MMSYSERR_NOERROR;}/************************************************************************** * modReset [internal] */static DWORD modReset(WORD wDevID){ unsigned chn; TRACE("(%04X);\n", wDevID); if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID; if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE; /* stop all notes */ /* FIXME: check if 0x78B0 is channel dependent or not. I coded it so that * it's channel dependent... */ for (chn = 0; chn < 16; chn++) { /* turn off every note */ modData(wDevID, 0x7800 | MIDI_CTL_CHANGE | chn); /* remove sustain on all channels */ modData(wDevID, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn); } /* FIXME: the LongData buffers must also be returned to the app */ return MMSYSERR_NOERROR;}#endif /* HAVE_OSS_MIDI *//*======================================================================* * MIDI entry points * *======================================================================*//************************************************************************** * midMessage (WINEOSS.4) */DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); switch (wMsg) {#ifdef HAVE_OSS_MIDI case DRVM_INIT: case DRVM_ENABLE: case DRVM_DISABLE: /* FIXME: Pretend this is supported */ return 0; case MIDM_OPEN: return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2); case MIDM_CLOSE: return midClose(wDevID); case MIDM_ADDBUFFER: return midAddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2); case MIDM_PREPARE: return midPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); case MIDM_UNPREPARE: return midUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); case MIDM_GETDEVCAPS: return midGetDevCaps(wDevID, (LPMIDIINCAPSA)dwParam1,dwParam2); case MIDM_GETNUMDEVS: return MIDM_NumDevs; case MIDM_RESET: return midReset(wDevID); case MIDM_START: return midStart(wDevID); case MIDM_STOP: return midStop(wDevID);#endif default: TRACE("Unsupported message\n"); } return MMSYSERR_NOTSUPPORTED;}/************************************************************************** * modMessage (WINEOSS.5) */DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); switch (wMsg) {#ifdef HAVE_OSS_MIDI case DRVM_INIT: case DRVM_EXIT: case DRVM_ENABLE: case DRVM_DISABLE: /* FIXME: Pretend this is supported */ return 0; case MODM_OPEN: return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2); case MODM_CLOSE: return modClose(wDevID); case MODM_DATA: return modData(wDevID, dwParam1); case MODM_LONGDATA: return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2); case MODM_PREPARE: return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); case MODM_UNPREPARE: return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); case MODM_GETDEVCAPS: return modGetDevCaps(wDevID, (LPMIDIOUTCAPSA)dwParam1, dwParam2); case MODM_GETNUMDEVS: return MODM_NumDevs; case MODM_GETVOLUME: return 0; case MODM_SETVOLUME: return 0; case MODM_RESET: return modReset(wDevID);#endif default: TRACE("Unsupported message\n"); } return MMSYSERR_NOTSUPPORTED;}/*-----------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -