void MidiInputDeviceMme::MidiInputPortMme::ConnectToMmeMidiSource(const char* MidiSource) { // close the old MIDI Input port if it was already opened CloseMmeMidiPort(); MIDIINCAPS midiincaps; int NumDevs = midiInGetNumDevs(); int FoundMidiInDeviceId = -1; for(int i=0;i<NumDevs;i++) { int res = midiInGetDevCaps(i, &midiincaps, sizeof(MIDIINCAPS)); if(res == MMSYSERR_NOERROR) { if(!strcmp(midiincaps.szPname, MidiSource)) { FoundMidiInDeviceId = i; break; } } } if(FoundMidiInDeviceId == -1) throw MidiInputException("MIDI port connect failed"); int res; res = midiInOpen(&MidiInHandle, FoundMidiInDeviceId, (DWORD_PTR)win32_midiin_callback, (DWORD_PTR)this, CALLBACK_FUNCTION); if(res != MMSYSERR_NOERROR) { throw MidiInputException("MIDI port connect failed. midiInOpen error"); } MidiInOpened = true; /* Store pointer to our input buffer for System Exclusive messages in MIDIHDR */ midiHdr.lpData = &TmpSysExBuf[0]; /* Store its size in the MIDIHDR */ midiHdr.dwBufferLength = MME_MAX_SYSEX_BUF_SIZE; /* Flags must be set to 0 */ midiHdr.dwFlags = 0; /* Prepare the buffer and MIDIHDR */ res = midiInPrepareHeader(MidiInHandle, &midiHdr, sizeof(MIDIHDR)); if(res != MMSYSERR_NOERROR) { CloseMmeMidiPort(); throw MidiInputException("MIDI port connect failed. midiInPrepareHeader error"); } /* Queue MIDI input buffer */ res = midiInAddBuffer(MidiInHandle, &midiHdr, sizeof(MIDIHDR)); if(res != MMSYSERR_NOERROR) { CloseMmeMidiPort(); throw MidiInputException("MIDI port connect failed. midiInAddBuffer error"); } res = midiInStart(MidiInHandle); if(res != MMSYSERR_NOERROR) { CloseMmeMidiPort(); throw MidiInputException("MIDI port connect failed, midiInStart failed."); } }
Parameter::Parameter(void) { /* Initialize values */ for (int i = 0; i < NUM_PARAMETERS; i++) { value[i] = 0.0f; changed[i] = false; } /* Open Midi device */ numDevices = midiInGetNumDevs(); if (numDevices > MAX_NUM_DEVICES) numDevices = MAX_NUM_DEVICES; for (unsigned int devID = 0; devID < numDevices; devID++) { MMRESULT rc; rc = midiInOpen(&(midiInDevice[devID]), devID, (DWORD_PTR)MidiInProc, NULL, CALLBACK_FUNCTION); /* Create input buffers */ midiInHeader[devID].lpData = (LPSTR)midiData[devID]; midiInHeader[devID].dwBufferLength = MIDI_DATA_SIZE; midiInHeader[devID].dwFlags = 0; rc = midiInPrepareHeader(midiInDevice[devID], &midiInHeader[devID], sizeof(midiInHeader[devID])); rc = midiInAddBuffer(midiInDevice[devID], &midiInHeader[devID], sizeof(midiInHeader[devID])); rc = midiInStart(midiInDevice[devID]); } }
boolean JMIDIInObj::auxNotify(JEvent& e, void* pdata) { #if defined(WIN32) cs.lock(); MMRESULT rc; MIDIHDR *mhdr; if (!connected) goto CSEND; mhdr = (MIDIHDR*)(char*)data; if ((void*)mhdr != pdata) goto CSEND; if (!(mhdr->dwFlags & MHDR_DONE)) goto CSEND; if (mhdr->dwBytesRecorded > 0) {} rc = midiInUnprepareHeader((HMIDIIN)handle, mhdr, sizeof(MIDIHDR)); if (rc == MMSYSERR_NOERROR) rc = midiInPrepareHeader((HMIDIIN)handle, mhdr, sizeof(MIDIHDR)); if (rc == MMSYSERR_NOERROR) rc = midiInAddBuffer((HMIDIIN)handle, mhdr, sizeof(MIDIHDR)); if (rc != MMSYSERR_NOERROR) close(); #endif cs.unlock(); return true; CSEND: cs.unlock(); return false; }
void CALLBACK Win32MidiIn::midiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { Q_UNUSED(dwParam2); MidiSession *midiSession = (MidiSession *)dwInstance; LPMIDIHDR pMIDIhdr = (LPMIDIHDR)dwParam1; if (wMsg == MIM_LONGDATA) { if (pMIDIhdr->dwBytesRecorded == 0) { // 0 length means returning the buffer to the application when closing return; } // Use QMidiStreamParser to extract well-formed SysEx messages from buffer QMidiStreamParser &qMidiStreamParser = *midiSession->getQMidiStreamParser(); qMidiStreamParser.setTimestamp(MasterClock::getClockNanos()); qMidiStreamParser.parseStream((BYTE *)pMIDIhdr->lpData, pMIDIhdr->dwBytesRecorded); // Add SysEx Buffer for reuse if (midiInAddBuffer(hMidiIn, pMIDIhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR) { QMessageBox::critical(NULL, "Win32MidiIn Error", "Failed to add SysEx Buffer for reuse"); return; } return; } if (wMsg == MIM_DATA) { // No need to use QMidiStreamParser for short messages: they are guaranteed to have explicit status byte // if ((dwParam1 & 0xF8) == 0xF8) // No support for System Realtime yet midiSession->getSynthRoute()->pushMIDIShortMessage(dwParam1, MasterClock::getClockNanos()); } }
bool Win32MidiIn::open(MidiSession *midiSession, unsigned int midiDevID) { int wResult; // Init midiIn port wResult = midiInOpen(&hMidiIn, midiDevID, (DWORD_PTR)midiInProc, (DWORD_PTR)midiSession, CALLBACK_FUNCTION); if (wResult != MMSYSERR_NOERROR) { QMessageBox::critical(NULL, "Win32MidiIn Error", "Failed to open MIDI input port"); return false; } // Prepare SysEx midiIn buffer MidiInHdr.lpData = (LPSTR)sysexbuf; MidiInHdr.dwBufferLength = 4096; MidiInHdr.dwFlags = 0L; wResult = midiInPrepareHeader(hMidiIn, &MidiInHdr, sizeof(MIDIHDR)); if (wResult != MMSYSERR_NOERROR) { QMessageBox::critical(NULL, "Win32MidiIn Error", "Failed to prepare MIDI buffer header"); return false; } // Add SysEx Buffer wResult = midiInAddBuffer(hMidiIn, &MidiInHdr, sizeof(MIDIHDR)); if (wResult != MMSYSERR_NOERROR) { QMessageBox::critical(NULL, "Win32MidiIn Error", "Failed to add SysEx buffer"); return false; } return midiInStart(hMidiIn) == MMSYSERR_NOERROR; }
/* * Procedure definitions */ MMRESULT Midi_BufferDone(MIDI *midi, MIDIHDR *midiHdr) { MMRESULT error; midiHdr->dwBytesRecorded = 0; error = midiInAddBuffer(midi->midiIn, midiHdr, sizeof(MIDIHDR)); return error; }
int rtsyn_synth_start(){ int i; UINT port; #ifdef __W32__ DWORD processPriority; processPriority = GetPriorityClass(GetCurrentProcess()); #endif port=0; sleep(2); for(port=0;port<rtsyn_portnumber;port++){ for (i=0;i<MAX_EXBUF;i++){ IMidiHdr[port][i] = (MIDIHDR *)sIMidiHdr[port][i]; memset(IMidiHdr[port][i],0,sizeof(MIDIHDR)); IMidiHdr[port][i]->lpData = sImidiHdr_data[port][i]; memset((IMidiHdr[port][i]->lpData),0,BUFF_SIZE); IMidiHdr[port][i]->dwBufferLength = BUFF_SIZE; } } evbwpoint=0; evbrpoint=0; mvbuse=0; for(port=0;port<rtsyn_portnumber;port++){ midiInOpen(&hMidiIn[port],portID[port],(DWORD)MidiInProc,(DWORD)port,CALLBACK_FUNCTION); for (i=0;i<MAX_EXBUF;i++){ midiInUnprepareHeader(hMidiIn[port],IMidiHdr[port][i],sizeof(MIDIHDR)); midiInPrepareHeader(hMidiIn[port],IMidiHdr[port][i],sizeof(MIDIHDR)); midiInAddBuffer(hMidiIn[port],IMidiHdr[port][i],sizeof(MIDIHDR)); } } #ifdef __W32__ // HACK:midiInOpen()でリセットされてしまうため、再設定 SetPriorityClass(GetCurrentProcess(), processPriority); #endif for(port=0;port<rtsyn_portnumber;port++){ if(MMSYSERR_NOERROR !=midiInStart(hMidiIn[port])){ int i; for(i=0;i<port;i++){ midiInStop(hMidiIn[i]); midiInReset(hMidiIn[i]); midiInClose(hMidiIn[i]); } goto winmmerror; } } mim_start_time = get_current_calender_time(); InitializeCriticalSection(&mim_section); return ~0; winmmerror: ctl->cmsg( CMSG_ERROR, VERB_NORMAL, "midiInStarterror\n" ); return 0; }
int rtsyn_play_some_data(void){ UINT wMsg; DWORD dwInstance; DWORD dwParam1; DWORD dwParam2; DWORD timestamp; MidiEvent ev; MidiEvent evm[260]; int port; UINT evbpoint; MIDIHDR *IIMidiHdr; int exlen; char *sysexbuffer; int ne,i,j,chk,played; played=0; if( !rtsyn_buf_check() ){ played=~0; return played; } do{ EnterCriticalSection(&mim_section); evbpoint=evbrpoint; if (++evbrpoint >= EVBUFF_SIZE) evbrpoint -= EVBUFF_SIZE; wMsg=evbuf[evbpoint].wMsg; dwInstance=evbuf[evbpoint].dwInstance; dwParam1=evbuf[evbpoint].dwParam1; dwParam2=evbuf[evbpoint].dwParam2; LeaveCriticalSection(&mim_section); port=(UINT)dwInstance; switch (wMsg) { case MIM_DATA: rtsyn_play_one_data (port, dwParam1, mim_start_time+(double)dwParam2/1000.0); break; case MIM_LONGDATA: IIMidiHdr = (MIDIHDR *) dwParam1; exlen=(int)IIMidiHdr->dwBytesRecorded; sysexbuffer=IIMidiHdr->lpData; rtsyn_play_one_sysex (sysexbuffer,exlen, mim_start_time+(double)dwParam2/1000.0); if (MMSYSERR_NOERROR != midiInUnprepareHeader( hMidiIn[port], IIMidiHdr, sizeof(MIDIHDR))) ctl->cmsg( CMSG_ERROR, VERB_NORMAL,"error1\n"); if (MMSYSERR_NOERROR != midiInPrepareHeader( hMidiIn[port], IIMidiHdr, sizeof(MIDIHDR))) ctl->cmsg( CMSG_ERROR, VERB_NORMAL,"error5\n"); if (MMSYSERR_NOERROR != midiInAddBuffer( hMidiIn[port], IIMidiHdr, sizeof(MIDIHDR))) ctl->cmsg( CMSG_ERROR, VERB_NORMAL,"error6\n"); break; } }while(rtsyn_buf_check()); return played; }
MMRESULT Midi_InOpen(MIDI *midi) { MMRESULT error; int i; if (midi->inPort == -1) { return MMSYSERR_NOERROR; } /* * Open the port. */ m_closing = FALSE; error = midiInOpen(&midi->midiIn, midi->inPort , (DWORD) m_MidiInProc, (DWORD) midi, CALLBACK_FUNCTION); if (error != MMSYSERR_NOERROR) { return error; } /* * Initialize the midi header array. */ for (i = 0; i < midi->bufCnt; i++) { error = midiInPrepareHeader(midi->midiIn, &midi->midiHdrs[i] , sizeof(MIDIHDR)); if (error != MMSYSERR_NOERROR) { for (i--; i >= 0; i--) { midiInUnprepareHeader(midi->midiIn, &midi->midiHdrs[i] , sizeof(MIDIHDR)); } midiInClose(midi->midiIn); return error; } error = midiInAddBuffer(midi->midiIn, &midi->midiHdrs[i] , sizeof(MIDIHDR)); if (error != MMSYSERR_NOERROR) { midiInReset(midi->midiIn); for ( ; i >= 0; i--) { midiInUnprepareHeader(midi->midiIn, &midi->midiHdrs[i] , sizeof(MIDIHDR)); } midiInClose(midi->midiIn); return error; } } /* * Initiate MIDI input. */ error = midiInStart(midi->midiIn); if (error != MMSYSERR_NOERROR) { midiInReset(midi->midiIn); midiInClose(midi->midiIn); return error; } return error; }
void CALLBACK midiCallback(HMIDIIN handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { debugPrintf(1, "callback called %d, handle %p\n", uMsg, handle); switch (uMsg) { case MIM_DATA: midiReceive(SHORT_MSG_STATUS(dwParam1)); midiReceive(SHORT_MSG_BYTE1(dwParam1)); midiReceive(SHORT_MSG_BYTE2(dwParam1)); break; case MIM_LONGDATA: { MIDIHDR *midiHdr = (MIDIHDR *)dwParam1; if (midiHdr->dwBytesRecorded == 0) { return; } unsigned int len = 0; sleepCount = 0; for (len = 0; len < midiHdr->dwBufferLength; len++) { midiReceive(midiHdr->lpData[len]); if (((unsigned char)midiHdr->lpData[len]) == 0xF7) break; } midiInUnprepareHeader(handle, midiHdr, sizeof(*midiHdr)); midiInPrepareHeader(handle, midiHdr, sizeof(*midiHdr)); midiInAddBuffer(handle, midiHdr, sizeof(*midiHdr)); } break; case MIM_MOREDATA: // XXX set IO_STATUS flag to midiInOpen() debugPrintf(1, "midi driver is throwing away received data: %x %x %x\n", SHORT_MSG_STATUS(dwParam1), SHORT_MSG_BYTE1(dwParam1), SHORT_MSG_BYTE2(dwParam1)); break; case MIM_ERROR: logPrintf(LOG_ERROR, "error\n"); break; case MIM_LONGERROR: { logPrintf(LOG_ERROR, "long error\n"); } break; default: debugPrintf(1, "received event %x\n", uMsg); /* ignore */ return; } }
static PmError allocate_input_buffer(HMIDIIN h, long buffer_len) { LPMIDIHDR hdr = allocate_buffer(buffer_len); if (!hdr) return pmInsufficientMemory; pm_hosterror = midiInPrepareHeader(h, hdr, sizeof(MIDIHDR)); if (pm_hosterror) { pm_free(hdr); return pm_hosterror; } pm_hosterror = midiInAddBuffer(h, hdr, sizeof(MIDIHDR)); return pm_hosterror; }
void cmmidi_recvexcv(HMIDIIN hdr, MIDIHDR *data) { CMMIDI midi; midi = midiinhdlget(hdr); if (midi) { midiinrecv(midi, (UINT8 *)data->lpData, data->dwBytesRecorded); midiInUnprepareHeader(midi->hmidiin, &midi->hmidiinhdr, sizeof(MIDIHDR)); midiInPrepareHeader(midi->hmidiin, &midi->hmidiinhdr, sizeof(MIDIHDR)); midiInAddBuffer(midi->hmidiin, &midi->hmidiinhdr, sizeof(MIDIHDR)); } }
void midiInitialize(char *inputDeviceStr, char *outputDeviceStr) { int inputDevice = atoi(inputDeviceStr); int outputDevice = atoi(outputDeviceStr); char name[256]; getOutDeviceName(outputDevice, name, sizeof(name)); unsigned long result = midiOutOpen(&outHandle, outputDevice, 0, 0, CALLBACK_NULL); if (result) { logPrintf(LOG_ERROR, "Error opening output device %s with ID %d, aborting\n", name, outputDevice); exit(-1); } else { debugPrintf(1, "Opened output device %s.\n", name); } getInDeviceName(inputDevice, name, sizeof(name)); result = midiInOpen(&inHandle, inputDevice, (DWORD)midiCallback, 0, CALLBACK_FUNCTION); if (result) { logPrintf(LOG_ERROR, "Error opening input device %s with ID %d, aborting\n", name, inputDevice); exit(-1); } else { debugPrintf(1, "Opened input device %s.\n", name); } sleepCount = 0; midiHdr.lpData = inputBuffer; midiHdr.dwBufferLength = sizeof(inputBuffer); midiHdr.dwFlags = 0; result = midiInPrepareHeader(inHandle, &midiHdr, sizeof(MIDIHDR)); if (result) { logPrintf(LOG_ERROR, "Could not prepare input buffer\n"); exit(-1); } result = midiInAddBuffer(inHandle, &midiHdr, sizeof(MIDIHDR)); if (result) { logPrintf(LOG_ERROR, "could not add input buffer\n"); exit(-1); } result = midiInStart(inHandle); if (result) { logPrintf(LOG_ERROR, "Could not start recording on input\n"); exit(-1); } }
void MidiInputDeviceMme::MidiInputPortMme::MmeCallbackDispatcher(HMIDIIN handle, UINT uMsg, DWORD dwParam1, DWORD dwParam2) { unsigned char *DataPtr; // pointer to SysEx data unsigned char *data; // pointer to standard MIDI messages which are not sysex data(max 3 bytes long) data = (unsigned char *)&dwParam1; switch(uMsg) { case MIM_DATA: DispatchRaw(data); break; case MIM_LONGDATA: if(!ExitFlag) { LPMIDIHDR lpMIDIHeader = (LPMIDIHDR)dwParam1; DataPtr = (unsigned char *)(lpMIDIHeader->lpData); if(lpMIDIHeader->dwBytesRecorded == 0) break; if(FirstSysExBlock) { SysExOffset = 0; FirstSysExBlock = false; } if( DataPtr[lpMIDIHeader->dwBytesRecorded - 1] == 0xF7) { SysExMsgComplete = true; FirstSysExBlock = true; } else { SysExMsgComplete = false; } if(SysExOffset + lpMIDIHeader->dwBytesRecorded <= MME_MAX_SYSEX_BUF_SIZE) { memcpy(&SysExBuf[SysExOffset], DataPtr, lpMIDIHeader->dwBytesRecorded); SysExOffset += lpMIDIHeader->dwBytesRecorded; } if(SysExMsgComplete) DispatchSysex(SysExBuf, SysExOffset); /* Queue the MIDIHDR for more input, only if ExitFlag was not set otherwise we risk an infinite loop because when we call midiInReset() below, Windows will send a final MIM_LONGDATA message to that callback. */ midiInAddBuffer(MidiInHandle, lpMIDIHeader, sizeof(MIDIHDR)); } break; } }
void CALLBACK Win32MidiIn::midiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { Q_UNUSED(dwParam2); SynthRoute *synthRoute = (SynthRoute *)dwInstance; LPMIDIHDR pMIDIhdr = (LPMIDIHDR)dwParam1; if (wMsg == MIM_LONGDATA) { if (pMIDIhdr->dwBytesRecorded == 0) { // 0 length means returning the buffer to the application when closing return; } synthRoute->pushMIDISysex((BYTE *)pMIDIhdr->lpData, pMIDIhdr->dwBytesRecorded, MasterClock::getClockNanos()); // Add SysEx Buffer for reuse if (midiInAddBuffer(hMidiIn, pMIDIhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR) { QMessageBox::critical(NULL, "Win32MidiIn Error", "Failed to add SysEx Buffer for reuse"); return; } return; } if (wMsg == MIM_DATA) synthRoute->pushMIDIShortMessage(dwParam1, MasterClock::getClockNanos()); }
void MidiUartWinClass::init(int _inputDevice, int _outputDevice) { MidiUartHostParent::init(_inputDevice, _outputDevice); unsigned long result; char name[256]; getOutputDeviceName(outputDevice, name, sizeof(name)); result = midiOutOpen(&outHandle, outputDevice, 0, 0, CALLBACK_NULL); if (result) { throw "Error opening utput device"; } else { printf("Opened output device %s\n", name); } getInputDeviceName(inputDevice, name, sizeof(name)); result = midiInOpen(&inHandle, inputDevice, (DWORD)midiCallback, (DWORD)this, CALLBACK_FUNCTION); if (result) { throw "Error opening input devic"; } else { printf("Opening input device %s\n", name); } midiHdr.lpData = inputBuffer; midiHdr.dwBufferLength = sizeof(inputBuffer); midiHdr.dwFlags = 0; result = midiInPrepareHeader(inHandle, &midiHdr, sizeof(MIDIHDR)); if (result) { throw "Could not prepare input buffer"; } result = midiInAddBuffer(inHandle, &midiHdr, sizeof(MIDIHDR)); if (result) { throw "Could not add input buffer"; } result = midiInStart(inHandle); if (result) { throw "Could not start recording on input"; } }
MMRESULT Open(unsigned int deviceId) { // open midi input MMRESULT mmResult; mmResult = midiInOpen(&handle, deviceId, DWORD_PTR(Proc), NULL, CALLBACK_FUNCTION); if (mmResult) { char buf[256]; GetLastErrorMessage(buf, 256); DebugPrint("Error opening MIDI input: %s", buf); return mmResult; } // prepare input buffer header.lpData = sysexbuffer; header.dwBufferLength = sizeof(sysexbuffer); header.dwFlags = 0; mmResult = midiInPrepareHeader(handle, &header, sizeof(MIDIHDR)); if (mmResult) { char buf[256]; GetLastErrorMessage(buf, 256); DebugPrint("Error preparing MIDI header: %s", buf); return mmResult; } // queue input buffer mmResult = midiInAddBuffer(handle, &header, sizeof(MIDIHDR)); if (mmResult) { char buf[256]; GetLastErrorMessage(buf, 256); DebugPrint("Error adding MIDI input buffer: %s", buf); return mmResult; } return mmResult; }
static PmError winmm_in_open(PmInternal *midi, void *driverInfo) { DWORD dwDevice; int i = midi->device_id; midiwinmm_type m; LPMIDIHDR hdr; dwDevice = (DWORD) descriptors[i].descriptor; /* create system dependent device data */ m = (midiwinmm_type) pm_alloc(sizeof(midiwinmm_node)); /* create */ midi->descriptor = m; if (!m) goto no_memory; m->handle.in = NULL; m->buffers = NULL; m->num_buffers = 0; m->next_buffer = 0; m->last_time = 0; m->first_message = TRUE; /* not used for input */ m->sysex_mode = FALSE; m->sysex_word = 0; m->sysex_byte_count = 0; m->sync_time = 0; m->delta = 0; m->error = MMSYSERR_NOERROR; m->callback_error = MMSYSERR_NOERROR; /* open device */ pm_hosterror = midiInOpen(&(m->handle.in), /* input device handle */ dwDevice, /* device ID */ (DWORD) winmm_in_callback, /* callback address */ (DWORD) midi, /* callback instance data */ CALLBACK_FUNCTION); /* callback is a procedure */ if (pm_hosterror) goto free_descriptor; /* allocate first buffer for sysex data */ hdr = allocate_buffer(PM_DEFAULT_SYSEX_BUFFER_SIZE); if (!hdr) goto close_device; pm_hosterror = midiInPrepareHeader(m->handle.in, hdr, sizeof(MIDIHDR)); if (pm_hosterror) { pm_free(hdr); goto close_device; } pm_hosterror = midiInAddBuffer(m->handle.in, hdr, sizeof(MIDIHDR)); if (pm_hosterror) goto close_device; /* allocate second buffer */ hdr = allocate_buffer(PM_DEFAULT_SYSEX_BUFFER_SIZE); if (!hdr) goto close_device; pm_hosterror = midiInPrepareHeader(m->handle.in, hdr, sizeof(MIDIHDR)); if (pm_hosterror) { pm_free(hdr); goto reset_device; /* because first buffer was added */ } pm_hosterror = midiInAddBuffer(m->handle.in, hdr, sizeof(MIDIHDR)); if (pm_hosterror) goto reset_device; /* start device */ pm_hosterror = midiInStart(m->handle.in); if (pm_hosterror) goto reset_device; return pmNoError; /* undo steps leading up to the detected error */ reset_device: /* ignore return code (we already have an error to report) */ midiInReset(m->handle.in); close_device: midiInClose(m->handle.in); /* ignore return code */ free_descriptor: midi->descriptor = NULL; pm_free(m); no_memory: if (pm_hosterror) { int err = midiInGetErrorText(pm_hosterror, (char *) pm_hosterror_text, PM_HOST_ERROR_MSG_LEN); assert(err == MMSYSERR_NOERROR); return pmHostError; } /* if !pm_hosterror, then the error must be pmInsufficientMemory */ return pmInsufficientMemory; /* note: if we return an error code, the device will be closed and memory will be freed. It's up to the caller to free the parameter midi */ }
/* Callback function executed via midiInput SW interrupt (via midiInOpen). */ static void FAR PASCAL winmm_in_callback( HMIDIIN hMidiIn, /* midiInput device Handle */ WORD wMsg, /* midi msg */ DWORD dwInstance, /* application data */ DWORD dwParam1, /* MIDI data */ DWORD dwParam2) /* device timestamp (wrt most recent midiInStart) */ { static int entry = 0; PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; if (++entry > 1) { assert(FALSE); } /* for simplicity, this logic perhaps overly conservative */ /* note also that this might leak memory if buffers are being returned as a result of midiInReset */ if (m->callback_error) { entry--; return; } switch (wMsg) { case MIM_DATA: { /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of message LOB; dwParam2 is time message received by input device driver, specified in [ms] from when midiInStart called. each message is expanded to include the status byte */ long new_driver_time = dwParam2; if ((dwParam1 & 0x80) == 0) { /* not a status byte -- ignore it. This happens running the sysex.c test under Win2K with MidiMan USB 1x1 interface. Is it a driver bug or a Win32 bug? If not, there's a bug here somewhere. -RBD */ } else { /* data to process */ PmEvent event; if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); event.timestamp = dwParam2; event.message = dwParam1; pm_read_short(midi, &event); } break; } case MIM_LONGDATA: { MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1; unsigned char *data = lpMidiHdr->lpData; unsigned int i = 0; long size = sizeof(MIDIHDR) + lpMidiHdr->dwBufferLength; /* ignore sysex data, but free returned buffers */ if (lpMidiHdr->dwBytesRecorded > 0 && midi->filters & PM_FILT_SYSEX) { m->callback_error = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); break; } if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); while (i < lpMidiHdr->dwBytesRecorded) { /* collect bytes from *data into a word */ pm_read_byte(midi, *data, dwParam2); data++; i++; } /* when a device is closed, the pending MIM_LONGDATA buffers are returned to this callback with dwBytesRecorded == 0. In this case, we do not want to send them back to the interface (if we do, the interface will not close, and Windows OS may hang). */ if (lpMidiHdr->dwBytesRecorded > 0) { m->callback_error = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); } else { pm_free(lpMidiHdr); } break; } case MIM_OPEN: /* fall thru */ case MIM_CLOSE: case MIM_ERROR: case MIM_LONGERROR: default: break; } entry--; }
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; } } }
void CALLBACK midiCallback(HMIDIIN handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { MidiUartWinClass *uart = (MidiUartWinClass *)dwInstance; if (uart == NULL) return; // printf("dwParam1: %lx, dwParam2: %lx\n", dwParam1, dwParam2); switch (uMsg) { case MIM_DATA: { uint8_t status = SHORT_MSG_STATUS(dwParam1); if (MIDI_IS_REALTIME_STATUS_BYTE(status)) { if (status >= 0xF8) { uart->rxRb.put(status); } else { switch (status) { case MIDI_MTC_QUARTER_FRAME: case MIDI_SONG_SELECT: uart->rxRb.put(SHORT_MSG_STATUS(dwParam1)); uart->rxRb.put(SHORT_MSG_BYTE1(dwParam1)); break; case MIDI_SONG_POSITION_PTR: uart->rxRb.put(SHORT_MSG_STATUS(dwParam1)); uart->rxRb.put(SHORT_MSG_BYTE1(dwParam1)); uart->rxRb.put(SHORT_MSG_BYTE2(dwParam1)); break; default: printf("unknown status: %x\n", status); break; } } } else { switch (status & 0xF0) { case MIDI_NOTE_OFF: case MIDI_NOTE_ON: case MIDI_AFTER_TOUCH: case MIDI_CONTROL_CHANGE: case MIDI_PITCH_WHEEL: uart->rxRb.put(SHORT_MSG_STATUS(dwParam1)); uart->rxRb.put(SHORT_MSG_BYTE1(dwParam1)); uart->rxRb.put(SHORT_MSG_BYTE2(dwParam1)); break; case MIDI_PROGRAM_CHANGE: case MIDI_CHANNEL_PRESSURE: uart->rxRb.put(SHORT_MSG_STATUS(dwParam1)); uart->rxRb.put(SHORT_MSG_BYTE1(dwParam1)); break; default: printf("unknown midi status: %x\n", status); break; } } } break; case MIM_LONGDATA: { MIDIHDR *midiHdr = (MIDIHDR *)dwParam1; if (midiHdr->dwBytesRecorded == 0) { return; } int len = 0; for (len = 0; len < midiHdr->dwBufferLength; len++) { uart->rxRb.put(midiHdr->lpData[len]); if (((unsigned char)midiHdr->lpData[len]) == 0xF7) break; } midiInUnprepareHeader(handle, midiHdr, sizeof(*midiHdr)); midiInPrepareHeader(handle, midiHdr, sizeof(*midiHdr)); midiInAddBuffer(handle, midiHdr, sizeof(*midiHdr)); } break; case MIM_MOREDATA: printf("midi driver is throwing away received data: %x %x %x\n", SHORT_MSG_STATUS(dwParam1), SHORT_MSG_BYTE1(dwParam1), SHORT_MSG_BYTE2(dwParam1)); break; case MIM_ERROR: printf("callback error\n"); break; case MIM_LONGERROR: printf("callback long error"); break; default: printf("received unknown event %x\n", uMsg); return; } }
static void test_midiIn_device(UINT udev, HWND hwnd) { HMIDIIN hm; MMRESULT rc; MIDIINCAPSA capsA; MIDIHDR mhdr; rc = midiInGetDevCapsA(udev, &capsA, sizeof(capsA)); ok((MIDIMAPPER==udev) ? (rc==MMSYSERR_BADDEVICEID || broken(rc==MMSYSERR_NODRIVER /*nt,w2k*/)) : rc==0, "midiInGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (!rc) { /* MIDI IN capsA.dwSupport may contain garbage, absent in old MS-Windows */ trace("* %s: manufacturer=%d, product=%d, support=%X\n", capsA.szPname, capsA.wMid, capsA.wPid, capsA.dwSupport); } if (hwnd) rc = midiInOpen(&hm, udev, (DWORD_PTR)hwnd, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); else rc = midiInOpen(&hm, udev, (DWORD_PTR)callback_func, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); ok((MIDIMAPPER!=udev) ? rc==0 : (rc==MMSYSERR_BADDEVICEID || broken(rc==MMSYSERR_NODRIVER /*nt,w2k*/)), "midiInOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return; test_notification(hwnd, "midiInOpen", MIM_OPEN, 0); memset(&mhdr, 0, sizeof(mhdr)); mhdr.dwFlags = MHDR_DONE; mhdr.dwUser = 0x56FA552C; mhdr.dwBufferLength = 70000; /* > 64KB! */ mhdr.dwBytesRecorded = 5; mhdr.lpData = HeapAlloc(GetProcessHeap(), 0 , mhdr.dwBufferLength); ok(mhdr.lpData!=NULL, "No %d bytes of memory!\n", mhdr.dwBufferLength); if (mhdr.lpData) { rc = midiInPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)-1); ok(rc==MMSYSERR_INVALPARAM, "midiInPrepare tiny rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == MHDR_DONE, "dwFlags=%x\n", mhdr.dwFlags); mhdr.dwFlags |= MHDR_INQUEUE; rc = midiInPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiInPrepare old size rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_INQUEUE|MHDR_DONE)/*w9x*/ || mhdr.dwFlags == MHDR_PREPARED, "dwFlags=%x\n", mhdr.dwFlags); trace("MIDIHDR flags=%x when unsent\n", mhdr.dwFlags); mhdr.dwFlags |= MHDR_INQUEUE|MHDR_DONE; rc = midiInPrepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiInPrepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_INQUEUE|MHDR_DONE), "dwFlags=%x\n", mhdr.dwFlags); mhdr.dwFlags &= ~MHDR_INQUEUE; rc = midiInUnprepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiInUnprepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == MHDR_DONE, "dwFlags=%x\n", mhdr.dwFlags); mhdr.dwFlags &= ~MHDR_DONE; rc = midiInUnprepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiInUnprepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == 0, "dwFlags=%x\n", mhdr.dwFlags); rc = midiInPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiInPrepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == MHDR_PREPARED, "dwFlags=%x\n", mhdr.dwFlags); mhdr.dwFlags |= MHDR_DONE; rc = midiInPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiInPrepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwBytesRecorded == 5, "BytesRec=%u\n", mhdr.dwBytesRecorded); mhdr.dwFlags |= MHDR_DONE; rc = midiInAddBuffer(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiAddBuffer rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_INQUEUE), "dwFlags=%x\n", mhdr.dwFlags); /* w95 does not set dwBytesRecorded=0 within midiInAddBuffer. Wine does. */ if (mhdr.dwBytesRecorded != 0) trace("dwBytesRecorded %u\n", mhdr.dwBytesRecorded); rc = midiInAddBuffer(hm, &mhdr, sizeof(mhdr)); ok(rc==MIDIERR_STILLPLAYING, "midiAddBuffer rc=%s\n", mmsys_error(rc)); rc = midiInPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiInPrepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_INQUEUE), "dwFlags=%x\n", mhdr.dwFlags); } rc = midiInReset(hm); /* Return any pending buffer */ ok(!rc, "midiInReset rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiInReset", MIM_LONGDATA, (DWORD_PTR)&mhdr); ok(mhdr.dwFlags == (MHDR_PREPARED|MHDR_DONE), "dwFlags=%x\n", mhdr.dwFlags); rc = midiInUnprepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiInUnprepare rc=%s\n", mmsys_error(rc)); ok(mhdr.dwBytesRecorded == 0, "Did some MIDI HW send %u bytes?\n", mhdr.dwBytesRecorded); rc = midiInClose(hm); ok(!rc, "midiInClose rc=%s\n", mmsys_error(rc)); ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser); HeapFree(GetProcessHeap(), 0, mhdr.lpData); test_notification(hwnd, "midiInClose", MIM_CLOSE, 0); test_notification(hwnd, "midiIn over", 0, WHATEVER); }
//$$fb dwParam1 holds a pointer for long messages. How can that be a DWORD then ??? void CALLBACK MIDI_IN_PutMessage( HMIDIIN hMidiIn, UINT wMsg, UINT_PTR dwInstance, UINT_PTR dwParam1, UINT_PTR dwParam2 ) { MidiDeviceHandle* handle = (MidiDeviceHandle*) dwInstance; TRACE3("> MIDI_IN_PutMessage, hMidiIn: %x, wMsg: %x, dwInstance: %x\n", hMidiIn, wMsg, dwInstance); TRACE2(" dwParam1: %x, dwParam2: %x\n", dwParam1, dwParam2); switch(wMsg) { case MIM_OPEN: TRACE0("< MIDI_IN_PutMessage: MIM_OPEN\n"); break; case MIM_CLOSE: TRACE0("< MIDI_IN_PutMessage: MIM_CLOSE\n"); break; case MIM_MOREDATA: case MIM_DATA: TRACE3(" MIDI_IN_PutMessage: MIM_MOREDATA or MIM_DATA. status=%x data1=%x data2=%x\n", dwParam1 & 0xFF, (dwParam1 & 0xFF00)>>8, (dwParam1 & 0xFF0000)>>16); if (handle!=NULL && handle->queue!=NULL && handle->platformData) { MIDI_QueueAddShort(handle->queue, // queue stores packedMsg in big endian //(dwParam1 << 24) | ((dwParam1 << 8) & 0xFF0000) | ((dwParam1 >> 8) & 0xFF00), (UINT32) dwParam1, // queue uses microseconds ((INT64) dwParam2)*1000, // overwrite if queue is full TRUE); SetEvent((HANDLE) handle->platformData); } TRACE0("< MIDI_IN_PutMessage\n"); break; case MIM_LONGDATA: TRACE1(" MIDI_IN_PutMessage: MIM_LONGDATA (%d bytes recorded)\n", (int) (((MIDIHDR*) dwParam1)->dwBytesRecorded)); if (handle!=NULL && handle->queue!=NULL && handle->platformData) { MIDIHDR* hdr = (MIDIHDR*) dwParam1; TRACE2(" MIDI_IN_PutMessage: Adding to queue: index %d, %d bytes\n", (INT32) hdr->dwUser, hdr->dwBytesRecorded); MIDI_QueueAddLong(handle->queue, (UBYTE*) hdr->lpData, (UINT32) hdr->dwBytesRecorded, // sysex buffer index (INT32) hdr->dwUser, // queue uses microseconds ((INT64) dwParam2)*1000, // overwrite if queue is full TRUE); SetEvent((HANDLE) handle->platformData); } TRACE0("< MIDI_IN_PutMessage\n"); break; case MIM_ERROR: ERROR0("< MIDI_IN_PutMessage: MIM_ERROR!\n"); break; case MIM_LONGERROR: if (dwParam1 != 0) { MIDIHDR* hdr = (MIDIHDR*) dwParam1; #ifdef USE_TRACE if (hdr->dwBytesRecorded > 0) { TRACE2(" MIDI_IN_PutMessage: MIM_LONGERROR! recorded: %d bytes with status 0x%2x\n", hdr->dwBytesRecorded, (int) (*((UBYTE*) hdr->lpData))); } #endif // re-add hdr to device query hdr->dwBytesRecorded = 0; midiInAddBuffer((HMIDIIN)handle->deviceHandle, hdr, sizeof(MIDIHDR)); } ERROR0("< MIDI_IN_PutMessage: MIM_LONGERROR!\n"); break; default: ERROR1("< MIDI_IN_PutMessage: ERROR unknown message %d!\n", wMsg); break; } // switch (wMsg) }
/* Callback function executed via midiInput SW interrupt (via midiInOpen). */ static void FAR PASCAL winmm_in_callback( HMIDIIN hMidiIn, /* midiInput device Handle */ UINT wMsg, /* midi msg */ DWORD_PTR dwInstance, /* application data */ DWORD_PTR dwParam1, /* MIDI data */ DWORD_PTR dwParam2) /* device timestamp (wrt most recent midiInStart) */ { static int entry = 0; PmInternal *midi = (PmInternal *) dwInstance; midiwinmm_type m = (midiwinmm_type) midi->descriptor; /* NOTE: we do not just EnterCriticalSection() here because an * MIM_CLOSE message arrives when the port is closed, but then * the m->lock has been destroyed. */ switch (wMsg) { case MIM_DATA: { /* if this callback is reentered with data, we're in trouble. * It's hard to imagine that Microsoft would allow callbacks * to be reentrant -- isn't the model that this is like a * hardware interrupt? -- but I've seen reentrant behavior * using a debugger, so it happens. */ EnterCriticalSection(&m->lock); /* dwParam1 is MIDI data received, packed into DWORD w/ 1st byte of message LOB; dwParam2 is time message received by input device driver, specified in [ms] from when midiInStart called. each message is expanded to include the status byte */ if ((dwParam1 & 0x80) == 0) { /* not a status byte -- ignore it. This happened running the sysex.c test under Win2K with MidiMan USB 1x1 interface, but I can't reproduce it. -RBD */ /* printf("non-status byte found\n"); */ } else { /* data to process */ PmEvent event; if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); event.timestamp = (PmTimestamp)dwParam2; event.message = (PmMessage)dwParam1; pm_read_short(midi, &event); } LeaveCriticalSection(&m->lock); break; } case MIM_LONGDATA: { MIDIHDR *lpMidiHdr = (MIDIHDR *) dwParam1; unsigned char *data = (unsigned char *) lpMidiHdr->lpData; unsigned int processed = 0; int remaining = lpMidiHdr->dwBytesRecorded; EnterCriticalSection(&m->lock); /* printf("midi_in_callback -- lpMidiHdr %x, %d bytes, %2x...\n", lpMidiHdr, lpMidiHdr->dwBytesRecorded, *data); */ if (midi->time_proc) dwParam2 = (*midi->time_proc)(midi->time_info); /* can there be more than one message in one buffer? */ /* assume yes and iterate through them */ while (remaining > 0) { unsigned int amt = pm_read_bytes(midi, data + processed, remaining, (PmTimestamp)dwParam2); remaining -= amt; processed += amt; } /* when a device is closed, the pending MIM_LONGDATA buffers are returned to this callback with dwBytesRecorded == 0. In this case, we do not want to send them back to the interface (if we do, the interface will not close, and Windows OS may hang). */ if (lpMidiHdr->dwBytesRecorded > 0) { MMRESULT rslt; lpMidiHdr->dwBytesRecorded = 0; lpMidiHdr->dwFlags = 0; /* note: no error checking -- can this actually fail? */ rslt = midiInPrepareHeader(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); assert(rslt == MMSYSERR_NOERROR); /* note: I don't think this can fail except possibly for * MMSYSERR_NOMEM, but the pain of reporting this * unlikely but probably catastrophic error does not seem * worth it. */ rslt = midiInAddBuffer(hMidiIn, lpMidiHdr, sizeof(MIDIHDR)); assert(rslt == MMSYSERR_NOERROR); LeaveCriticalSection(&m->lock); } else { midiInUnprepareHeader(hMidiIn,lpMidiHdr,sizeof(MIDIHDR)); LeaveCriticalSection(&m->lock); pm_free(lpMidiHdr); } break; } case MIM_OPEN: break; case MIM_CLOSE: break; case MIM_ERROR: /* printf("MIM_ERROR\n"); */ break; case MIM_LONGERROR: /* printf("MIM_LONGERROR\n"); */ break; default: break; } }
COMMNG cmmidi_create(const OEMCHAR *midiout, const OEMCHAR *midiin, const OEMCHAR *module) { UINT opened; UINT id; void (*shortout)(CMMIDI self, UINT32 msg); void (*longout)(CMMIDI self, const UINT8 *msg, UINT leng); HMIDIFNOUT out; HMIDIIN hmidiin = NULL; COMMNG ret; CMMIDI midi; opened = 0; ZeroMemory(&out, sizeof(out)); shortout = midi_ncshort; longout = midi_nclong; if (getmidioutid(midiout, &id) == SUCCESS) { if (midiOutOpen(&out.win32.hmidiout, id, 0, 0, CALLBACK_NULL) == MMSYSERR_NOERROR) { midiOutReset(out.win32.hmidiout); shortout = midi_win32short; longout = midi_win32long; opened |= CMMIDI_MIDIOUT; } } if (getmidiinid(midiin, &id) == SUCCESS) { if (midiInOpen(&hmidiin, id, (DWORD)g_hWndMain, 0, CALLBACK_WINDOW) == MMSYSERR_NOERROR) { midiInReset(hmidiin); opened |= CMMIDI_MIDIIN; } } #if defined(VERMOUTH_LIB) else if (!milstr_cmp(midiout, cmmidi_vermouth)) { out.vermouth = midiout_create(vermouth_module, 512); if (out.vermouth != NULL) { shortout = midi_vermouthshort; longout = midi_vermouthlong; opened |= CMMIDI_VERMOUTH; } } #endif #if defined(MT32SOUND_DLL) else if (!milstr_cmp(midiout, cmmidi_mt32sound)) { if (mt32sound_open() == SUCCESS) { shortout = midi_mt32short; longout = midi_mt32long; opened |= CMMIDI_MT32SOUND; } } #endif if (!opened) { goto cmcre_err1; } ret = (COMMNG)_MALLOC(sizeof(_COMMNG) + sizeof(_CMMIDI), "MIDI"); if (ret == NULL) { goto cmcre_err2; } ret->connect = COMCONNECT_MIDI; ret->read = midiread; ret->write = midiwrite; ret->getstat = midigetstat; ret->msg = midimsg; ret->release = midirelease; midi = (CMMIDI)(ret + 1); ZeroMemory(midi, sizeof(_CMMIDI)); midi->opened = opened; midi->shortout = shortout; midi->longout = longout; midi->out = out; midi->midictrl = MIDICTRL_READY; #if 1 midi->hmidiin = hmidiin; if (opened & CMMIDI_MIDIIN) { if (midiinhdlreg(midi, hmidiin) == SUCCESS) { midi->opened |= CMMIDI_MIDIINSTART; midi->hmidiinhdr.lpData = (char *)midi->midiinbuf; midi->hmidiinhdr.dwBufferLength = MIDI_BUFFER; midiInPrepareHeader(hmidiin, &midi->hmidiinhdr, sizeof(MIDIHDR)); midiInAddBuffer(hmidiin, &midi->hmidiinhdr, sizeof(MIDIHDR)); midiInStart(hmidiin); } } #endif #if defined(VERMOUTH_LIB) if (opened & CMMIDI_VERMOUTH) { sound_streamregist((void *)out.vermouth, (SOUNDCB)vermouth_getpcm); } #endif #if defined(MT32SOUND_DLL) if (opened & CMMIDI_MT32SOUND) { sound_streamregist(NULL, (SOUNDCB)mt32_getpcm); } #endif // midi->midisyscnt = 0; // midi->mpos = 0; midi->midilast = 0x80; // midi->midiexcvwait = 0; midi->midimodule = (UINT8)module2number(module); FillMemory(midi->mch, sizeof(midi->mch), 0xff); return(ret); cmcre_err2: if (opened & CMMIDI_MIDIOUT) { midiOutReset(out.win32.hmidiout); midiOutClose(out.win32.hmidiout); } #if defined(VERMOUTH_LIB) if (opened & CMMIDI_VERMOUTH) { midiout_destroy(out.vermouth); } #endif #if defined(MT32SOUND_DLL) if (opened & CMMIDI_MT32SOUND) { mt32sound_close(); } #endif cmcre_err1: return(NULL); }
void write (HMIDIIN deviceHandle) { hdr.dwBytesRecorded = 0; MMRESULT res = midiInPrepareHeader (deviceHandle, &hdr, sizeof (hdr)); res = midiInAddBuffer (deviceHandle, &hdr, sizeof (hdr)); }
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus, DWORD instancePtr, DWORD midiMessage, DWORD timestamp ) { if ( inputStatus != MIM_DATA && inputStatus != MIM_LONGDATA && inputStatus != MIM_LONGERROR ) return; //RtMidiIn::RtMidiInData *data = static_cast<RtMidiIn::RtMidiInData *> (instancePtr); RtMidiIn::RtMidiInData *data = (RtMidiIn::RtMidiInData *)instancePtr; WinMidiData *apiData = static_cast<WinMidiData *> (data->apiData); // Calculate time stamp. apiData->message.timeStamp = 0.0; if ( data->firstMessage == true ) data->firstMessage = false; else apiData->message.timeStamp = (double) ( timestamp - apiData->lastTime ) * 0.001; apiData->lastTime = timestamp; if ( inputStatus == MIM_DATA ) { // Channel or system message // Make sure the first byte is a status byte. unsigned char status = (unsigned char) (midiMessage & 0x000000FF); if ( !(status & 0x80) ) return; // Determine the number of bytes in the MIDI message. unsigned short nBytes = 1; if ( status < 0xC0 ) nBytes = 3; else if ( status < 0xE0 ) nBytes = 2; else if ( status < 0xF0 ) nBytes = 3; else if ( status < 0xF3 ) { // A MIDI time code message and we're ignoring it. if ( status == 0xF1 && (data->ignoreFlags & 0x02) ) return; nBytes = 3; } else if ( status == 0xF3 ) nBytes = 2; else if ( status == 0xF8 && (data->ignoreFlags & 0x02) ) { // A MIDI timing tick message and we're ignoring it. return; } else if ( status == 0xFE && (data->ignoreFlags & 0x04) ) { // A MIDI active sensing message and we're ignoring it. return; } // Copy bytes to our MIDI message. unsigned char *ptr = (unsigned char *) &midiMessage; for ( int i=0; i<nBytes; ++i ) apiData->message.bytes.push_back( *ptr++ ); } else { // Sysex message ( MIM_LONGDATA or MIM_LONGERROR ) MIDIHDR *sysex = ( MIDIHDR *) midiMessage; if ( !( data->ignoreFlags & 0x01 ) && inputStatus != MIM_LONGERROR ) { // Sysex message and we're not ignoring it for ( int i=0; i<(int)sysex->dwBytesRecorded; ++i ) apiData->message.bytes.push_back( sysex->lpData[i] ); } // The WinMM API requires that the sysex buffer be requeued after // input of each sysex message. Even if we are ignoring sysex // messages, we still need to requeue the buffer in case the user // decides to not ignore sysex messages in the future. However, // it seems that WinMM calls this function with an empty sysex // buffer when an application closes and in this case, we should // avoid requeueing it, else the computer suddenly reboots after // one or two minutes. if ( apiData->sysexBuffer[sysex->dwUser]->dwBytesRecorded > 0 ) { //if ( sysex->dwBytesRecorded > 0 ) { MMRESULT result = midiInAddBuffer( apiData->inHandle, apiData->sysexBuffer[sysex->dwUser], sizeof(MIDIHDR) ); if ( result != MMSYSERR_NOERROR ) std::cerr << "\nRtMidiIn::midiInputCallback: error sending sysex to Midi device!!\n\n"; if ( data->ignoreFlags & 0x01 ) return; } else return; } if ( data->usingCallback ) { RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback; callback( apiData->message.timeStamp, &apiData->message.bytes, data->userData ); } else { // As long as we haven't reached our queue size limit, push the message. if ( data->queueLimit > data->queue.size() ) data->queue.push( apiData->message ); else std::cerr << "\nRtMidiIn: message queue limit reached!!\n\n"; } // Clear the vector for the next input message. apiData->message.bytes.clear(); }
MOboolean moMidiDevice::Init( moText devicetext ) { SetName(devicetext); #ifdef WIN32 /* BOOL result; GUID hidGUID; HDEVINFO hardwareDeviceInfoSet; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; DWORD Index = 0; DWORD requiredSize; //Get the HID GUID value - used as mask to get list of devices HidD_GetHidGuid ( &hidGUID ); //Get a list of devices matching the criteria (hid interface, present) hardwareDeviceInfoSet = SetupDiGetClassDevs (&hidGUID, NULL, // Define no enumerator (global) NULL, // Define no (DIGCF_PRESENT | DIGCF_ALLCLASSES |DIGCF_DEVICEINTERFACE)); deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //Go through the list and get the interface data for(int i = 0; i < 10; i++) { result = SetupDiEnumDeviceInterfaces (hardwareDeviceInfoSet, NULL, //infoData, &hidGUID, //interfaceClassGuid, Index, &deviceInterfaceData); if (result == FALSE) { Index++; } } // Failed to get a device - possibly the index is larger than the number of devices if (result == FALSE) { SetupDiDestroyDeviceInfoList (hardwareDeviceInfoSet); return;// INVALID_HANDLE_VALUE; } //Get the details with null values to get the required size of the buffer SetupDiGetDeviceInterfaceDetail (hardwareDeviceInfoSet, &deviceInterfaceData, NULL, //interfaceDetail, 0, //interfaceDetailSize, &requiredSize, 0); //infoData)) */ MIDIINCAPS moc; unsigned long iNumDevs, i; /* Get the number of MIDI Out devices in this computer */ iNumDevs = midiInGetNumDevs(); if (iNumDevs==0) { MODebug2->Message( moText("ERROR! NO MIDI DEVICES FOUND")); } /* Go through all of those devices, displaying their names */ for (i = 0; i < iNumDevs; i++) { /* Get info about the next device */ if (!midiInGetDevCaps(i, &moc, sizeof(MIDIINCAPS))) { /* Display its Device ID and name */ MODebug2->Message( moText("Device ID #") + IntToStr(i) + moText(":") + moText(moc.szPname)); if ( !stricmp(moc.szPname, devicetext) ) { m_DeviceId = i; break; } } } /* unsigned long result; HMIDIOUT outHandle; // Open the MIDI Mapper result = midiOutOpen(&outHandle, i, 0, 0, CALLBACK_WINDOW); if (!result) { // Output the C note (ie, sound the note) midiOutShortMsg(outHandle, 0x00403C90); // Output the E note midiOutShortMsg(outHandle, 0x00404090); // Output the G note midiOutShortMsg(outHandle, 0x00404390); // Here you should insert a delay so that you can hear the notes sounding Sleep(1000); // Now let's turn off those 3 notes midiOutShortMsg(outHandle, 0x00003C90); midiOutShortMsg(outHandle, 0x00004090); midiOutShortMsg(outHandle, 0x00004390); // Close the MIDI device midiOutClose(outHandle); } else { printf("There was an error opening MIDI Mapper!\r\n"); } */ HMIDIIN handle; MIDIHDR midiHdr; unsigned long err; if (m_DeviceId!=-1) { /* Open default MIDI In device */ if (!(err = midiInOpen(&handle, m_DeviceId, (DWORD)midiCallback, (DWORD)this, CALLBACK_FUNCTION))) { // Store pointer to our input buffer for System Exclusive messages in MIDIHDR midiHdr.lpData = (LPSTR)&SysXBuffer[0]; // Store its size in the MIDIHDR midiHdr.dwBufferLength = sizeof(SysXBuffer); // Flags must be set to 0 midiHdr.dwFlags = 0; // Prepare the buffer and MIDIHDR err = midiInPrepareHeader(handle, &midiHdr, sizeof(MIDIHDR)); if (!err) { // Queue MIDI input buffer err = midiInAddBuffer(handle, &midiHdr, sizeof(MIDIHDR)); if (!err) { // Start recording Midi err = midiInStart(handle); m_bInit = true; return true; /* if (!err) { // Wait for user to abort recording printf("Press any key to stop recording...\r\n\n"); _getch(); // We need to set a flag to tell our callback midiCallback() // not to do any more midiInAddBuffer(), because when we // call midiInReset() below, Windows will send a final // MIM_LONGDATA message to that callback. If we were to // allow midiCallback() to midiInAddBuffer() again, we'd // never get the driver to finish with our midiHdr SysXFlag |= 0x80; printf("\r\nRecording stopped!\n"); }*/ /* Stop recording */ //midiInReset(handle); } } /* // If there was an error above, then print a message if (err) PrintMidiInErrorMsg(err); // Close the MIDI In device while ((err = midiInClose(handle)) == MIDIERR_STILLPLAYING) Sleep(0); if (err) PrintMidiInErrorMsg(err); // Unprepare the buffer and MIDIHDR. Unpreparing a buffer that has not been prepared is ok midiInUnprepareHeader(handle, &midiHdr, sizeof(MIDIHDR)); */ } else { printf("Error opening the default MIDI In Device!\r\n"); PrintMidiInErrorMsg(err); return false; } } #else #endif return false; }
void RtMidiIn :: openPort( unsigned int portNumber, const std::string /*portName*/ ) { if ( connected_ ) { errorString_ = "RtMidiIn::openPort: a valid connection already exists!"; error( RtError::WARNING ); return; } unsigned int nDevices = midiInGetNumDevs(); if (nDevices == 0) { errorString_ = "RtMidiIn::openPort: no MIDI input sources found!"; error( RtError::NO_DEVICES_FOUND ); } std::ostringstream ost; if ( portNumber >= nDevices ) { ost << "RtMidiIn::openPort: the 'portNumber' argument (" << portNumber << ") is invalid."; errorString_ = ost.str(); error( RtError::INVALID_PARAMETER ); } WinMidiData *data = static_cast<WinMidiData *> (apiData_); MMRESULT result = midiInOpen( &data->inHandle, portNumber, (DWORD)&midiInputCallback, (DWORD)&inputData_, CALLBACK_FUNCTION ); if ( result != MMSYSERR_NOERROR ) { errorString_ = "RtMidiIn::openPort: error creating Windows MM MIDI input port."; error( RtError::DRIVER_ERROR ); } // Allocate and init the sysex buffers. for ( int i=0; i<RT_SYSEX_BUFFER_COUNT; ++i ) { data->sysexBuffer[i] = (MIDIHDR*) new char[ sizeof(MIDIHDR) ]; data->sysexBuffer[i]->lpData = new char[ RT_SYSEX_BUFFER_SIZE ]; data->sysexBuffer[i]->dwBufferLength = RT_SYSEX_BUFFER_SIZE; data->sysexBuffer[i]->dwUser = i; // We use the dwUser parameter as buffer indicator data->sysexBuffer[i]->dwFlags = 0; result = midiInPrepareHeader( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) ); if ( result != MMSYSERR_NOERROR ) { midiInClose( data->inHandle ); errorString_ = "RtMidiIn::openPort: error starting Windows MM MIDI input port (PrepareHeader)."; error( RtError::DRIVER_ERROR ); } // Register the buffer. result = midiInAddBuffer( data->inHandle, data->sysexBuffer[i], sizeof(MIDIHDR) ); if ( result != MMSYSERR_NOERROR ) { midiInClose( data->inHandle ); errorString_ = "RtMidiIn::openPort: error starting Windows MM MIDI input port (AddBuffer)."; error( RtError::DRIVER_ERROR ); } } result = midiInStart( data->inHandle ); if ( result != MMSYSERR_NOERROR ) { midiInClose( data->inHandle ); errorString_ = "RtMidiIn::openPort: error starting Windows MM MIDI input port."; error( RtError::DRIVER_ERROR ); } connected_ = true; }
void moMidiDevice::midiCallback(HMIDIIN handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { LPMIDIHDR lpMIDIHeader; unsigned char * ptr; TCHAR buffer[80]; unsigned char bytes; moMidiDevice* pMidiDevice = NULL; pMidiDevice = (moMidiDevice*)dwInstance; /* Determine why Windows called me */ switch (uMsg) { /* Received some regular MIDI message */ case MIM_DATA: { /* Display the time stamp, and the bytes. (Note: I always display 3 bytes even for Midi messages that have less) */ sprintf(&buffer[0], "0x%08X 0x%02X 0x%02X 0x%02X\0", dwParam2, dwParam1 & 0x000000FF, (dwParam1>>8) & 0x000000FF, (dwParam1>>16) & 0x000000FF); _cputs(&buffer[0]); moMidiData mididata; mididata.m_Type = MOMIDI_ROTARY;//???? mididata.m_Channel = (dwParam1 & 0x000000FF) - 175;//channel 1 = 0xB0 mididata.m_CC = (dwParam1>>8) & 0x000000FF; mididata.m_Val = (dwParam1>>16) & 0x000000FF; if (pMidiDevice) pMidiDevice->NewData( mididata ); break; } /* Received all or part of some System Exclusive message */ case MIM_LONGDATA: { /* If this application is ready to close down, then don't midiInAddBuffer() again */ if (!(pMidiDevice->SysXFlag & 0x80)) { /* Assign address of MIDIHDR to a LPMIDIHDR variable. Makes it easier to access the field that contains the pointer to our block of MIDI events */ lpMIDIHeader = (LPMIDIHDR)dwParam1; /* Get address of the MIDI event that caused this call */ ptr = (unsigned char *)(lpMIDIHeader->lpData); /* Is this the first block of System Exclusive bytes? */ if (!pMidiDevice->SysXFlag) { /* Print out a noticeable heading as well as the timestamp of the first block. (But note that other, subsequent blocks will have their own time stamps). */ printf("*************** System Exclusive **************\r\n0x%08X ", dwParam2); /* Indicate we've begun handling a particular System Exclusive message */ pMidiDevice->SysXFlag |= 0x01; } /* Is this the last block (ie, the end of System Exclusive byte is here in the buffer)? */ if (*(ptr + (lpMIDIHeader->dwBytesRecorded - 1)) == 0xF7) { /* Indicate we're done handling this particular System Exclusive message */ pMidiDevice->SysXFlag &= (~0x01); } /* Display the bytes -- 16 per line */ bytes = 16; while((lpMIDIHeader->dwBytesRecorded--)) { if (!(--bytes)) { sprintf(&buffer[0], "0x%02X\r\n", *(ptr)++); bytes = 16; } else sprintf(&buffer[0], "0x%02X ", *(ptr)++); _cputs(&buffer[0]); } /* Was this the last block of System Exclusive bytes? */ if (!pMidiDevice->SysXFlag) { /* Print out a noticeable ending */ _cputs("\r\n******************************************\r\n"); } /* Queue the MIDIHDR for more input */ midiInAddBuffer(handle, lpMIDIHeader, sizeof(MIDIHDR)); } break; } /* Process these messages if you desire */ /* case MIM_OPEN: case MIM_CLOSE: case MIM_ERROR: case MIM_LONGERROR: case MIM_MOREDATA: break; */ } }