MF_API void MFMidi_SendPacket(MFDevice *pDevice, const uint8 *pBytes, size_t len) { MFMidiPC_MidiOutputDevice *pMidi = (MFMidiPC_MidiOutputDevice*)pDevice->pInternal; // TODO: get hdr from pool... MIDIHDR hdr; MFZeroMemory(&hdr, sizeof(hdr)); hdr.lpData = (LPSTR)pBytes; hdr.dwBufferLength = (DWORD)len; hdr.dwBytesRecorded = (DWORD)len; hdr.dwUser = (DWORD_PTR)pDevice; MMRESULT r = midiOutPrepareHeader(pMidi->hMidiOut, &hdr, sizeof(hdr)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to send MIDI message: %s", MFString_WCharAsUTF8(errorBuffer))); return; } r = midiOutLongMsg(pMidi->hMidiOut, &hdr, sizeof(hdr)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to send MIDI message: %s", MFString_WCharAsUTF8(errorBuffer))); } }
MF_API bool MFMidi_Start(MFDevice *pDevice) { MFMidiPC_MidiInputDevice *pMidi = (MFMidiPC_MidiInputDevice*)pDevice->pInternal; if (pDevice->state == MFDevState_Active) { MFDebug_Warn(1, "Midi input device already started!"); return false; } if (pDevice->state != MFDevState_Ready) { MFDebug_Warn(1, "Midi input device not ready!"); return false; } pMidi->numEvents = pMidi->numEventsRead = 0; MMRESULT r = midiInStart(pMidi->hMidiIn); if (r != MMSYSERR_NOERROR) { pDevice->state = MFDevState_Unknown; wchar_t errorBuffer[256]; midiInGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Couldn't start MIDI device: %s", MFString_WCharAsUTF8(errorBuffer))); return false; } pDevice->state = MFDevState_Active; return true; }
static void CALLBACK MidiOutProc(HMIDIOUT hMidiOut, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { MFDevice *pDevice = (MFDevice*)dwInstance; MFMidiPC_MidiOutputDevice *pMidi = (MFMidiPC_MidiOutputDevice*)pDevice->pInternal; switch (wMsg) { case MOM_OPEN: MFDebug_Log(0, MFStr("Opened MIDI output device: %s", pDevice->strings[MFDS_ID])); break; case MOM_CLOSE: MFDebug_Log(0, MFStr("Opened MIDI output device: %s", pDevice->strings[MFDS_ID])); break; case MOM_DONE: { MIDIHDR *pHdr = (MIDIHDR*)dwParam1; MMRESULT r = midiOutUnprepareHeader(pMidi->hMidiOut, pHdr, sizeof(*pHdr)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to cleanup MIDI message: %s", MFString_WCharAsUTF8(errorBuffer))); } // TODO: return to pool... break; } case MOM_POSITIONCB: MFDebug_Log(0, "MIDI output device: Position CB"); break; } }
MF_API bool MFMidi_OpenOutput(MFDevice *pDevice) { MFDebug_Assert(pDevice->type == MFDT_MidiOutput, "Not a MIDI device!"); if (pDevice->state == MFDevState_Ready) { MFDebug_Warn(1, "Midi output device already opened!"); return false; } if (pDevice->state != MFDevState_Available) { MFDebug_Warn(1, "Unable to open midi output device!"); return false; } MFMidiPC_MidiOutputDevice *pMidi = (MFMidiPC_MidiOutputDevice*)pDevice->pInternal; // find and open the device // TODO: FIXME! this won't work if there are 2 instances of the same device attached to the PC!!! UINT numOutputDevices = midiOutGetNumDevs(); UINT i = 0; for (; i < numOutputDevices; ++i) { MIDIOUTCAPS caps; MMRESULT r = midiOutGetDevCaps(i, &caps, sizeof(caps)); if (r != MMSYSERR_NOERROR) continue; if (caps.wMid == pMidi->mid && caps.wPid == pMidi->pid) break; } if (i == numOutputDevices) { MFDebug_Log(0, MFStr("Midi output device '%s' not found!", pDevice->strings[MFDS_ID])); pDevice->state = MFDevState_Unknown; // set this flag? return false; } MMRESULT r = midiOutOpen(&pMidi->hMidiOut, i, (DWORD_PTR)MidiOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION); if (r != MMSYSERR_NOERROR) { pMidi->hMidiOut = NULL; pDevice->state = MFDevState_Unknown; wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to open MIDI output device: %s", MFString_WCharAsUTF8(errorBuffer))); return false; } pDevice->state = MFDevState_Ready; return true; }
MF_API void MFMidi_SendShortMessage(MFDevice *pDevice, uint32 message) { MFMidiPC_MidiOutputDevice *pMidi = (MFMidiPC_MidiOutputDevice*)pDevice->pInternal; MMRESULT r = midiOutShortMsg(pMidi->hMidiOut, (DWORD)message); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to send MIDI message: %s", MFString_WCharAsUTF8(errorBuffer))); } }
static void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { MFDevice *pDevice = (MFDevice*)dwInstance; MFMidiPC_MidiInputDevice *pMidi = (MFMidiPC_MidiInputDevice*)pDevice->pInternal; switch(wMsg) { case MIM_OPEN: MFDebug_Log(0, MFStr("Opened MIDI input device: %s", pDevice->strings[MFDS_ID])); break; case MIM_CLOSE: MFDebug_Log(0, MFStr("Closed MIDI input device: %s", pDevice->strings[MFDS_ID])); break; case MIM_MOREDATA: MFDebug_Log(0, "MIDI message: MIM_MOREDATA"); break; case MIM_DATA: { MFMidiEvent ev; MFMidi_DecodeShortMessage((uint32)dwParam1, &ev, (uint32)dwParam2); switch(ev.ev) { case MFMET_NoteOff: pMidi->channels[ev.channel].notes[ev.noteOff.note] = 0; break; case MFMET_NoteOn: case MFMET_NoteAftertouch: pMidi->channels[ev.channel].notes[ev.noteOn.note] = ev.noteOn.velocity; break; case MFMET_ControlChange: pMidi->channels[ev.channel].control[ev.controlChange.control] = ev.controlChange.value; break; case MFMET_ProgramChange: pMidi->channels[ev.channel].program = ev.programChange.program; break; case MFMET_ChannelAftertouch: // TODO: ... what is this? break; case MFMET_PitchBend: pMidi->channels[ev.channel].pitch = ev.pitchBend.value; break; default: MFDebug_Assert(false, "Why are we getting sys events?"); break; } if (pMidi->bBuffered || pMidi->pEventCallback) { if (pMidi->bBuffered) { if (pMidi->numEvents >= pMidi->numAllocated) { pMidi->numAllocated *= 2; pMidi->pEvents = (MFMidiEvent*)MFHeap_Realloc(pMidi->pEvents, sizeof(MFMidiEvent)*pMidi->numAllocated); } pMidi->pEvents[pMidi->numEvents++] = ev; } if (pMidi->pEventCallback) { pMidi->pEventCallback(pDevice, &ev); } } break; } case MIM_LONGDATA: { MIDIHDR *pHdr = (MIDIHDR*)dwParam1; MFMidiEvent ev; MFMidi_DecodePacket((const uint8*)pHdr->lpData, pHdr->dwBytesRecorded, &ev, (uint32)dwParam2); if (pMidi->bBuffered || pMidi->pEventCallback) { if (pMidi->bBuffered) { if (pMidi->numEvents >= pMidi->numAllocated) { pMidi->numAllocated *= 2; pMidi->pEvents = (MFMidiEvent*)MFHeap_Realloc(pMidi->pEvents, sizeof(MFMidiEvent)*pMidi->numAllocated); } pMidi->pEvents[pMidi->numEvents++] = ev; } if (pMidi->pEventCallback) { pMidi->pEventCallback(pDevice, &ev); } } MMRESULT r = midiInAddBuffer(pMidi->hMidiIn, pHdr, sizeof(*pHdr)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiInGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to open MIDI input device: %s", MFString_WCharAsUTF8(errorBuffer))); } break; } case MIM_ERROR: case MIM_LONGERROR: { MFDebug_Log(0, MFStr("MIDI input error: %d, 0x%08X : 0x%08X", wMsg, dwParam1, dwParam2)); break; } } }
MF_API bool MFMidi_OpenInput(MFDevice *pDevice, bool bBuffered, MFMidiEventCallback *pEventCallback) { MFDebug_Assert(pDevice->type == MFDT_MidiInput, "Not a MIDI device!"); if (pDevice->state == MFDevState_Ready || pDevice->state == MFDevState_Active) { MFDebug_Warn(1, "Midi input device already opened!"); return false; } if (pDevice->state != MFDevState_Available) { MFDebug_Warn(1, "Unable to open midi input device!"); return false; } MFMidiPC_MidiInputDevice *pMidi = (MFMidiPC_MidiInputDevice*)pDevice->pInternal; // find and open the device // TODO: FIXME! this won't work if there are 2 instances of the same device attached to the PC!!! UINT numInputDevices = midiInGetNumDevs(); UINT i = 0; for (; i < numInputDevices; ++i) { MIDIINCAPS caps; MMRESULT r = midiInGetDevCaps(i, &caps, sizeof(caps)); if (r != MMSYSERR_NOERROR) continue; if (caps.wMid == pMidi->mid && caps.wPid == pMidi->pid) break; } if (i == numInputDevices) { MFDebug_Warn(1, MFStr("Midi output device '%s' not found!", pDevice->strings[MFDS_ID])); pDevice->state = MFDevState_Unknown; // set this flag? return false; } MMRESULT r = midiInOpen(&pMidi->hMidiIn, i, (DWORD_PTR)MidiInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION | MIDI_IO_STATUS); if (r != MMSYSERR_NOERROR) { pMidi->hMidiIn = NULL; pDevice->state = MFDevState_Unknown; wchar_t errorBuffer[256]; midiInGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to open MIDI input device: %s", MFString_WCharAsUTF8(errorBuffer))); return false; } MFZeroMemory(&pMidi->sysexRecv, sizeof(pMidi->sysexRecv)); pMidi->sysexRecv.lpData = (LPSTR)pMidi->sysexRecvBuffer; pMidi->sysexRecv.dwBufferLength = sizeof(pMidi->sysexRecvBuffer); r = midiInPrepareHeader(pMidi->hMidiIn, &pMidi->sysexRecv, sizeof(pMidi->sysexRecv)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiInGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to open MIDI input device: %s", MFString_WCharAsUTF8(errorBuffer))); } r = midiInAddBuffer(pMidi->hMidiIn, &pMidi->sysexRecv, sizeof(pMidi->sysexRecv)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiInGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to open MIDI input device: %s", MFString_WCharAsUTF8(errorBuffer))); } pMidi->bBuffered = bBuffered; pMidi->pEventCallback = pEventCallback; pMidi->numAllocated = 256; pMidi->pEvents = (MFMidiEvent*)MFHeap_Alloc(sizeof(MFMidiEvent) * pMidi->numAllocated); pDevice->state = MFDevState_Ready; if (!bBuffered && !pEventCallback) MFMidi_Start(pDevice); return true; }
void MFMidi_InitModulePlatformSpecific() { UINT numInputDevices = midiInGetNumDevs(); for (UINT i = 0; i < numInputDevices; ++i) { MIDIINCAPS caps; MMRESULT r = midiInGetDevCaps(i, &caps, sizeof(caps)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to query midi input device: %s", MFString_WCharAsUTF8(errorBuffer))); continue; } MFDevice *pDevice = MFDevice_AllocDevice(MFDT_MidiInput, &DestroyInputDevice); pDevice->pInternal = MFHeap_AllocAndZero(sizeof(MFMidiPC_MidiInputDevice)); pDevice->state = MFDevState_Available; MFMidiPC_MidiOutputDevice *pDev = (MFMidiPC_MidiOutputDevice*)pDevice->pInternal; pDev->mid = caps.wMid; pDev->pid = caps.wPid; MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_ID], caps.szPname); MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_DeviceName], caps.szPname); MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_Description], caps.szPname); MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_InterfaceName], caps.szPname); // MFDS_Manufacturer MFDebug_Log(0, MFStr("Found midi input device: %s (%04X:%04X) - state: %d", pDevice->strings[MFDS_ID], caps.wMid, caps.wPid, pDevice->state)); } UINT numOutputDevices = midiOutGetNumDevs(); for (UINT i = 0; i < numOutputDevices; ++i) { MIDIOUTCAPS caps; MMRESULT r = midiOutGetDevCaps(i, &caps, sizeof(caps)); if (r != MMSYSERR_NOERROR) { wchar_t errorBuffer[256]; midiOutGetErrorText(r, errorBuffer, sizeof(errorBuffer)); MFDebug_Warn(1, MFStr("Failed to query midi output device: %s", MFString_WCharAsUTF8(errorBuffer))); continue; } MFDevice *pDevice = MFDevice_AllocDevice(MFDT_MidiOutput, &DestroyOutputDevice); pDevice->pInternal = MFHeap_AllocAndZero(sizeof(MFMidiPC_MidiOutputDevice)); pDevice->state = MFDevState_Available; MFMidiPC_MidiOutputDevice *pDev = (MFMidiPC_MidiOutputDevice*)pDevice->pInternal; pDev->mid = caps.wMid; pDev->pid = caps.wPid; MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_ID], caps.szPname); MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_DeviceName], caps.szPname); MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_Description], caps.szPname); MFString_CopyUTF16ToUTF8(pDevice->strings[MFDS_InterfaceName], caps.szPname); // MFDS_Manufacturer MFDebug_Log(0, MFStr("Found midi output device: %s (%04X:%04X) - state: %d", pDevice->strings[MFDS_ID], caps.wMid, caps.wPid, pDevice->state)); } }
const char* MFFileNative_MakeAbsolute(const char *pFilename) { wchar_t path[256]; GetFullPathName(MFString_UFT8AsWChar(pFilename), sizeof(path)/sizeof(path[0]), path, NULL); return MFString_WCharAsUTF8(path); }