📄 midi.c
字号:
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; } 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"); lpNewData = HeapAlloc(GetProcessHeap, 0, lpMidiHdr->dwBufferLength + 2); } 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 start of System Exclusive */ len_add = 1; lpData[0] = 0xF0; memcpy(lpNewData, lpData, lpMidiHdr->dwBufferLength); WARN("Adding missing 0xF0 marker at the beginning of " "system exclusive byte stream\n"); } if (lpData[lpMidiHdr->dwBufferLength-1] != 0xF7) { /* Send end of System Exclusive */ memcpy(lpData + len_add, lpData, lpMidiHdr->dwBufferLength); lpNewData[lpMidiHdr->dwBufferLength + len_add - 1] = 0xF0; len_add++; WARN("Adding missing 0xF7 marker at the end of " "system exclusive byte stream\n"); } snd_seq_ev_clear(&event); snd_seq_ev_set_direct(&event); snd_seq_ev_set_source(&event, port_out); snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); TRACE("client = %d port = %d\n", MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength + len_add, lpNewData ? lpNewData : lpData); snd_seq_event_output_direct(midiSeq, &event); if (lpNewData) HeapFree(GetProcessHeap(), 0, lpData); 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 (midiSeq == NULL) { 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 (midiSeq == NULL) { 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_CMD_CONTROL | chn); /* remove sustain on all channels */ modData(wDevID, (MIDI_CTL_SUSTAIN << 8) | MIDI_CMD_CONTROL | chn); } /* FIXME: the LongData buffers must also be returned to the app */ return MMSYSERR_NOERROR;}#endif /* defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1) *//*======================================================================* * MIDI entry points * *======================================================================*//************************************************************************** * ALSA_MidiInit [internal] * * Initializes the MIDI devices information variables */LONG ALSA_MidiInit(void){#if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1) static BOOL bInitDone = FALSE; snd_seq_client_info_t *cinfo; snd_seq_port_info_t *pinfo; int count; if (bInitDone) return TRUE; TRACE("Initializing the MIDI variables.\n"); bInitDone = TRUE; /* try to open device */ if (midiOpenSeq(0) == -1) { return TRUE; }#if 0 /* Debug purpose */ snd_lib_error_set_handler(error_handler);#endif snd_seq_client_info_alloca(&cinfo); snd_seq_port_info_alloca(&pinfo); snd_seq_client_info_set_client(cinfo, -1); while(snd_seq_query_next_client(midiSeq, cinfo) >= 0) { snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); snd_seq_port_info_set_port(pinfo, -1); count = 0; while (snd_seq_query_next_port(midiSeq, pinfo) >= 0) { int cap = snd_seq_port_info_get_capability(pinfo); int type = snd_seq_port_info_get_type(pinfo); if (cap & SND_SEQ_PORT_CAP_WRITE) { TRACE("OUT (%d:%s:%s:%d:%s:%x)\n",snd_seq_client_info_get_client(cinfo), snd_seq_client_info_get_name(cinfo), snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ? "user" : "kernel", snd_seq_port_info_get_port(pinfo), snd_seq_port_info_get_name(pinfo), type); if (MODM_NumDevs >= MAX_MIDIOUTDRV) continue; if (!type) continue; memcpy(&MidiOutDev[MODM_NumDevs].addr, snd_seq_port_info_get_addr(pinfo), sizeof(snd_seq_addr_t)); /* Manufac ID. We do not have access to this with soundcard.h * Does not seem to be a problem, because in mmsystem.h only * Microsoft's ID is listed. */ MidiOutDev[MODM_NumDevs].caps.wMid = 0x00FF; MidiOutDev[MODM_NumDevs].caps.wPid = 0x0001; /* FIXME Product ID */ /* Product Version. We simply say "1" */ MidiOutDev[MODM_NumDevs].caps.vDriverVersion = 0x001; MidiOutDev[MODM_NumDevs].caps.wChannelMask = 0xFFFF; /* FIXME Do we have this information? * Assuming the soundcards can handle * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but * not MIDICAPS_CACHE. */ MidiOutDev[MODM_NumDevs].caps.dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; strcpy(MidiOutDev[MODM_NumDevs].caps.szPname, snd_seq_client_info_get_name(cinfo)); MidiOutDev[MODM_NumDevs].caps.wTechnology = MIDI_AlsaToWindowsDeviceType(type); MidiOutDev[MODM_NumDevs].caps.wVoices = 16; /* FIXME Is it possible to know the maximum * number of simultaneous notes of a soundcard ? * I believe we don't have this information, but * it's probably equal or more than wVoices */ MidiOutDev[MODM_NumDevs].caps.wNotes = 16; MidiOutDev[MODM_NumDevs].bEnabled = TRUE; TRACE("MidiOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%ld\n" "\tALSA info: midi dev-type=%lx, capa=%lx\n", MODM_NumDevs, MidiOutDev[MODM_NumDevs].caps.szPname, MidiOutDev[MODM_NumDevs].caps.wTechnology, MidiOutDev[MODM_NumDevs].caps.wVoices, MidiOutDev[MODM_NumDevs].caps.wNotes, MidiOutDev[MODM_NumDevs].caps.wChannelMask, MidiOutDev[MODM_NumDevs].caps.dwSupport, (long)type, (long)0); MODM_NumDevs++; } if (cap & SND_SEQ_PORT_CAP_READ) { TRACE("IN (%d:%s:%s:%d:%s:%x)\n",snd_seq_client_info_get_client(cinfo), snd_seq_client_info_get_name(cinfo), snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ? "user" : "kernel", snd_seq_port_info_get_port(pinfo), snd_seq_port_info_get_name(pinfo), type); if (MIDM_NumDevs >= MAX_MIDIINDRV) continue; if (!type) continue; memcpy(&MidiInDev[MIDM_NumDevs].addr, snd_seq_port_info_get_addr(pinfo), sizeof(snd_seq_addr_t)); /* Manufac ID. We do not have access to this with soundcard.h * Does not seem to be a problem, because in mmsystem.h only * Microsoft's ID is listed. */ MidiInDev[MIDM_NumDevs].caps.wMid = 0x00FF; MidiInDev[MIDM_NumDevs].caps.wPid = 0x0001; /* FIXME Product ID */ /* Product Version. We simply say "1" */ MidiInDev[MIDM_NumDevs].caps.vDriverVersion = 0x001; /* FIXME Do we have this information? * Assuming the soundcards can handle * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but * not MIDICAPS_CACHE. */ MidiInDev[MIDM_NumDevs].caps.dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; strcpy(MidiInDev[MIDM_NumDevs].caps.szPname, snd_seq_client_info_get_name(cinfo)); MidiInDev[MIDM_NumDevs].state = 0; TRACE("MidiIn [%d]\tname='%s' support=%ld\n" "\tALSA info: midi dev-type=%lx, capa=%lx\n", MIDM_NumDevs, MidiInDev[MIDM_NumDevs].caps.szPname, MidiInDev[MIDM_NumDevs].caps.dwSupport, (long)type, (long)0); MIDM_NumDevs++; } } } /* close file and exit */ midiCloseSeq(); TRACE("End\n");#endif return TRUE;}/************************************************************************** * midMessage (WINEOSS.4) */DWORD WINAPI ALSA_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) {#if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1) 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 ALSA_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) {#if defined(HAVE_ALSA) && ((SND_LIB_MAJOR == 0 && SND_LIB_MINOR >= 9) || SND_LIB_MAJOR >= 1) 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 + -