static PmError winmm_write_flush(PmInternal *midi, PmTimestamp timestamp) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; assert(m); if (m->hdr) { m->error = midiOutPrepareHeader(m->handle.out, m->hdr, sizeof(MIDIHDR)); if (m->error) { /* do not send message */ } else if (midi->latency == 0) { /* As pointed out by Nigel Brown, 20Sep06, dwBytesRecorded * should be zero. This is set in get_free_sysex_buffer(). * The msg length goes in dwBufferLength in spite of what * Microsoft documentation says (or doesn't say). */ m->hdr->dwBufferLength = m->hdr->dwBytesRecorded; m->hdr->dwBytesRecorded = 0; m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR)); } else { m->error = midiStreamOut(m->handle.stream, m->hdr, sizeof(MIDIHDR)); } midi->fill_base = NULL; m->hdr = NULL; if (m->error) { m->hdr->dwFlags = 0; /* release the buffer */ return pmHostError; } } return pmNoError; }
int flushMidiDevice (MidiDevice *midi) { int ok = 1; if (midi->count > 0) { MMRESULT error; MIDIHDR header; header.lpData = midi->buffer; header.dwBufferLength = midi->count; header.dwFlags = 0; if ((error = midiOutPrepareHeader(midi->handle, &header, sizeof(header))) == MMSYSERR_NOERROR) { if ((error = midiOutLongMsg(midi->handle, &header, sizeof(header))) == MMSYSERR_NOERROR) { midi->count = 0; } else { logMidiOutError(error, LOG_ERR, "midiOutLongMsg"); ok = 0; } while ((error = midiOutUnprepareHeader(midi->handle, &header, sizeof(header))) == MIDIERR_STILLPLAYING) { approximateDelay(1); } if (error != MMSYSERR_NOERROR) { logMidiOutError(error, LOG_ERR, "midiOutUnprepareHeader"); } } else { logMidiOutError(error, LOG_ERR, "midiOutPrepareHeader"); ok = 0; } } return ok; }
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))); } }
MMRESULT Midi_SendLong(MIDI *midi, BYTE *buffer, size_t bufSize) { HMIDIOUT midiOut = midi->midiOut; MIDIHDR outMsgHdr = { buffer, /* sysex message */ bufSize, /* sysex message length */ bufSize }; MMRESULT error = MMSYSERR_NOERROR; if (midi->outPort == -1) { return MMSYSERR_NOERROR; } error = midiOutPrepareHeader(midiOut, &outMsgHdr, sizeof outMsgHdr); if (error) return error; error = midiOutLongMsg(midiOut, &outMsgHdr, sizeof outMsgHdr); if (error) goto UnprepareHeader; if (WaitForSingleObject(midi->outEvent, 500) == WAIT_TIMEOUT) { // ? goto UnprepareHeader; } ResetEvent(midi->outEvent); UnprepareHeader: error = midiOutUnprepareHeader(midiOut, &outMsgHdr, sizeof outMsgHdr); if (error == MIDIERR_STILLPLAYING) { SleepEx(20, FALSE); goto UnprepareHeader; } return error; }
// ----------------------------------------------------------------------- // えくすくるーしぶ ごー // ----------------------------------------------------------------------- void MIDI_Sendexclusive(BYTE *excv, int length) { // エクスクルーシヴを送ります CopyMemory(MIDI_EXCVBUF, excv, length); hHdr.lpData = MIDI_EXCVBUF; hHdr.dwFlags = 0; hHdr.dwBufferLength = length; midiOutPrepareHeader(hOut, &hHdr, sizeof(MIDIHDR)); midiOutLongMsg(hOut, &hHdr, sizeof(MIDIHDR)); MIDI_EXCVWAIT = 1; }
//--------------------------------------------------------------------------- static void TVPMIDIOut(tjs_uint8 *data,int len) { if(!TVPMIDIOutHandle) return; TVPCheckMIDIDelay(); MIDIHDR hdr; hdr.lpData = (char*)data; hdr.dwFlags = 0; hdr.dwBufferLength = len; midiOutPrepareHeader(TVPMIDIOutHandle, &hdr, sizeof(MIDIHDR)); midiOutLongMsg(TVPMIDIOutHandle, &hdr, sizeof(MIDIHDR)); midiOutUnprepareHeader(TVPMIDIOutHandle, &hdr, sizeof(MIDIHDR)); }
static void midi_win32long(CMMIDI midi, const UINT8 *msg, UINT leng) { waitlastexclusiveout(midi); CopyMemory(midi->excvbuf, msg, leng); midi->out.win32.midihdr.lpData = (char *)midi->excvbuf; midi->out.win32.midihdr.dwFlags = 0; midi->out.win32.midihdr.dwBufferLength = leng; midiOutPrepareHeader(midi->out.win32.hmidiout, &midi->out.win32.midihdr, sizeof(midi->out.win32.midihdr)); midiOutLongMsg(midi->out.win32.hmidiout, &midi->out.win32.midihdr, sizeof(midi->out.win32.midihdr)); midi->midiexcvwait = 1; }
/*--------------------------------------------------------------------- Function: MPU_SendMidiImmediate Sends a MIDI message immediately to the the music device. ---------------------------------------------------------------------*/ void MPU_SendMidiImmediate( char *data, int count ) { MIDIHDR mhdr; static int masks[3] = { 0x00ffffffl, 0x0000ffffl, 0x000000ffl }; if (!count) return; if (count<=3) midiOutShortMsg((HMIDIOUT)hmido, (*((long*)data)) & masks[count-1]); else { ZeroMemory(&mhdr, sizeof(mhdr)); mhdr.lpData = data; mhdr.dwBufferLength = count; midiOutPrepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR)); midiOutLongMsg((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR)); while (!(mhdr.dwFlags & MHDR_DONE)) ; midiOutUnprepareHeader((HMIDIOUT)hmido, &mhdr, sizeof(MIDIHDR)); } }
BOOL CMidiDevice::SendLongMsg(LPBYTE pSys, DWORD dwMsgLen) { UINT err; MIDIHDR hdr; if(m_StateOut == OPENEDOUT) { // lock buffer and store pointer in MIDIHDR hdr.lpData = (LPSTR)pSys; if(hdr.lpData) { // store its size in the MIDIHDR hdr.dwBufferLength = dwMsgLen; // flags must be set to 0 hdr.dwFlags = 0; // prepare the buffer and MIDIHDR err = midiOutPrepareHeader(m_hMidiOut, &hdr, sizeof(MIDIHDR)); if(!err) { // send the buffer to midi out device err = midiOutLongMsg(m_hMidiOut, &hdr, sizeof(MIDIHDR)); if(err) { return FALSE; } // unprepare the buffer and MIDIHDR while(MIDIERR_STILLPLAYING == midiOutUnprepareHeader(m_hMidiOut, &hdr, sizeof(MIDIHDR))) { // should put a delay in here rather than a busy-wait Sleep(5); } return TRUE; } } } return FALSE; }
void MidiOutput::sendMessageNow (const MidiMessage& message) { const MidiOutHandle* const handle = static_cast <const MidiOutHandle*> (internal); if (message.getRawDataSize() > 3 || message.isSysEx()) { MIDIHDR h = { 0 }; h.lpData = (char*) message.getRawData(); h.dwBufferLength = message.getRawDataSize(); h.dwBytesRecorded = message.getRawDataSize(); if (midiOutPrepareHeader (handle->handle, &h, sizeof (MIDIHDR)) == MMSYSERR_NOERROR) { MMRESULT res = midiOutLongMsg (handle->handle, &h, sizeof (MIDIHDR)); if (res == MMSYSERR_NOERROR) { while ((h.dwFlags & MHDR_DONE) == 0) Sleep (1); int count = 500; // 1 sec timeout while (--count >= 0) { res = midiOutUnprepareHeader (handle->handle, &h, sizeof (MIDIHDR)); if (res == MIDIERR_STILLPLAYING) Sleep (2); else break; } } } } else { midiOutShortMsg (handle->handle, *(unsigned int*) message.getRawData()); } }
void MIDIDeviceOutJack::longMsgOut(const char* data, int size) { m_hdr.dwBufferLength = size; m_hdr.dwBytesRecorded = size; m_hdr.lpData = (char*)data; MMRESULT result; result = midiOutPrepareHeader((HMIDIOUT)m_handle, &m_hdr, sizeof(m_hdr)); if (result != MMSYSERR_NOERROR) error("MIDIDeviceOutJack::longMsgOut (prepare)", result); result = midiOutLongMsg((HMIDIOUT)m_handle, &m_hdr, sizeof(m_hdr)); if (result != MMSYSERR_NOERROR) error("MIDIDeviceOutJack::longMsgOut", result); result = midiOutUnprepareHeader((HMIDIOUT)m_handle, &m_hdr, sizeof(m_hdr)); if (result != MMSYSERR_NOERROR) error("MIDIDeviceOutJack::longMsgOut (unprepare)", result); }
int MidiOutPort_visual::rawsend(uchar* array, int size) { // Note: this function will work in Windows 95 and Windows NT. // This function will not work in Windows 3.x because a // different memory model is necessary. if (size > 64000 || size < 1) { cerr << "Warning: cannot write a MIDI stream larger than 64kB" << endl; return 0; } MIDIHDR midiheader; // structure for sending an array of MIDI bytes midiheader.lpData = (char *)array; midiheader.dwBufferLength = size; // midiheader.dwBytesRecorded = size; // example program doesn't set midiheader.dwFlags = 0; // flags must be set to 0 if (getPort() == -1) { return -1; } int status = midiOutPrepareHeader(device[getPort()], &midiheader, sizeof(MIDIHDR)); if (status != MMSYSERR_NOERROR) { return 0; } status = midiOutLongMsg(device[getPort()], &midiheader, sizeof(MIDIHDR)); if (status != MMSYSERR_NOERROR) { return 0; } while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(device[getPort()], &midiheader, sizeof(MIDIHDR))) { Sleep(1); // sleep for 1 millisecond } return 1; }
static int midi_init(void){ MIDIHDR mhMidi; /* GMリセット用データ */ BYTE abyGMReset[] = {0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7}; /* MIDIデバイスオープン */ if (midiOutOpen(&g_hMidi, MIDIMAPPER, 0, 0, 0) != MMSYSERR_NOERROR) { return 0; } ZeroMemory(&mhMidi, sizeof(mhMidi)); /* GMリセット送信用バッファ設定 */ mhMidi.lpData = (LPSTR)abyGMReset; mhMidi.dwBufferLength = 6; mhMidi.dwBytesRecorded = 6; midiOutPrepareHeader(g_hMidi, &mhMidi, sizeof(mhMidi)); /* GMリセットメッセージ送信 */ if (midiOutLongMsg(g_hMidi, &mhMidi, sizeof(mhMidi)) != MMSYSERR_NOERROR) { midiOutUnprepareHeader(g_hMidi, &mhMidi, sizeof(mhMidi)); std::cout<<"MIDI音源の初期化に失敗しました。"<<std::endl; midiOutClose(g_hMidi); return 0; } /* GMリセット完了待機 */ while ((mhMidi.dwFlags & MHDR_DONE) == 0); midiOutUnprepareHeader(g_hMidi, &mhMidi, sizeof(mhMidi)); return 0; }
void midiSendLong(unsigned char *buf, unsigned long len) { MIDIHDR midiHdr; HANDLE hBuffer; hBuffer = GlobalAlloc(GHND, len); if (!hBuffer) { logPrintf(LOG_ERROR, "error allocating buffer for sysex\n"); return; } midiHdr.lpData = (LPBYTE)GlobalLock(hBuffer); if (midiHdr.lpData) { midiHdr.dwBufferLength = len; midiHdr.dwFlags = 0; debugPrintf(2, "midiSendLong: \n"); debugHexdump(2, buf, len); UINT err = midiOutPrepareHeader(outHandle, &midiHdr, sizeof(MIDIHDR)); if (!err) { memcpy(midiHdr.lpData, buf, len); err = midiOutLongMsg(outHandle, &midiHdr, sizeof(MIDIHDR)); if (err) { char errBuf[256]; midiOutGetErrorText(err, errBuf, sizeof(errBuf)); logPrintf(LOG_ERROR, "error sending long message: %s\n", errBuf); } while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(outHandle, &midiHdr, sizeof(MIDIHDR))) { ; } debugPrintf(2, "midiSendLong finished\n"); } } GlobalUnlock(hBuffer); GlobalFree(hBuffer); }
void Win32MidiOutputDevice::writeSysEx(QByteArray message) { if(message.isEmpty()) return; if (isOpen() == false) return; MIDIHDR midiHdr; /* Store pointer in MIDIHDR */ midiHdr.lpData = (LPSTR)message.data(); /* Store its size in the MIDIHDR */ midiHdr.dwBufferLength = message.count(); /* Flags must be set to 0 */ midiHdr.dwFlags = 0; UINT err; /* Prepare the buffer and MIDIHDR */ err = midiOutPrepareHeader(m_handle, &midiHdr, sizeof(MIDIHDR)); if (!err) { /* Output the SysEx message */ err = midiOutLongMsg(m_handle, &midiHdr, sizeof(MIDIHDR)); if (err) qDebug() << "Error while sending SysEx message"; /* Unprepare the buffer and MIDIHDR */ while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(m_handle, &midiHdr, sizeof(MIDIHDR))) { /* Should put a delay in here rather than a busy-wait */ } } /* Close the MIDI device */ midiOutClose(m_handle); }
void MidiDriver_WIN::sysEx(const byte *msg, uint16 length) { if (!_isOpen) return; if (WaitForSingleObject (_streamEvent, 2000) == WAIT_TIMEOUT) { warning ("Could not send SysEx - MMSYSTEM is still trying to send data"); return; } assert(length+2 <= 266); midiOutUnprepareHeader(_mo, &_streamHeader, sizeof(_streamHeader)); // Add SysEx frame _streamBuffer[0] = 0xF0; memcpy(&_streamBuffer[1], msg, length); _streamBuffer[length+1] = 0xF7; _streamHeader.lpData = (char *)_streamBuffer; _streamHeader.dwBufferLength = length + 2; _streamHeader.dwBytesRecorded = length + 2; _streamHeader.dwUser = 0; _streamHeader.dwFlags = 0; MMRESULT result = midiOutPrepareHeader(_mo, &_streamHeader, sizeof(_streamHeader)); if (result != MMSYSERR_NOERROR) { check_error (result); return; } ResetEvent(_streamEvent); result = midiOutLongMsg(_mo, &_streamHeader, sizeof(_streamHeader)); if (result != MMSYSERR_NOERROR) { check_error(result); SetEvent(_streamEvent); return; } }
static DWORD modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) { WORD chn; DWORD ret = MMSYSERR_NOERROR; MIDIHDR mh; if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; mh = *lpMidiHdr; for (chn = 0; chn < 16; chn++) { if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) { mh.dwFlags = 0; midiOutPrepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); ret = midiOutLongMsg(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); midiOutUnprepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); if (ret != MMSYSERR_NOERROR) break; } } return ret; }
void RtMidiOut :: sendMessage( std::vector<unsigned char> *message ) { unsigned int nBytes = message->size(); if ( nBytes == 0 ) { errorString_ = "RtMidiOut::sendMessage: message argument is empty!"; error( RtError::WARNING ); return; } MMRESULT result; WinMidiData *data = static_cast<WinMidiData *> (apiData_); if ( message->at(0) == 0xF0 ) { // Sysex message // Allocate buffer for sysex data. char *buffer = (char *) malloc( nBytes ); if ( buffer == NULL ) { errorString_ = "RtMidiOut::sendMessage: error allocating sysex message memory!"; error( RtError::MEMORY_ERROR ); } // Copy data to buffer. for ( unsigned int i=0; i<nBytes; ++i ) buffer[i] = message->at(i); // Create and prepare MIDIHDR structure. MIDIHDR sysex; sysex.lpData = (LPSTR) buffer; sysex.dwBufferLength = nBytes; sysex.dwFlags = 0; result = midiOutPrepareHeader( data->outHandle, &sysex, sizeof(MIDIHDR) ); if ( result != MMSYSERR_NOERROR ) { free( buffer ); errorString_ = "RtMidiOut::sendMessage: error preparing sysex header."; error( RtError::DRIVER_ERROR ); } // Send the message. result = midiOutLongMsg( data->outHandle, &sysex, sizeof(MIDIHDR) ); if ( result != MMSYSERR_NOERROR ) { free( buffer ); errorString_ = "RtMidiOut::sendMessage: error sending sysex message."; error( RtError::DRIVER_ERROR ); } // Unprepare the buffer and MIDIHDR. while ( MIDIERR_STILLPLAYING == midiOutUnprepareHeader( data->outHandle, &sysex, sizeof (MIDIHDR) ) ) Sleep( 1 ); free( buffer ); } else { // Channel or system message. // Make sure the message size isn't too big. if ( nBytes > 3 ) { errorString_ = "RtMidiOut::sendMessage: message size is greater than 3 bytes (and not sysex)!"; error( RtError::WARNING ); return; } // Pack MIDI bytes into double word. DWORD packet; unsigned char *ptr = (unsigned char *) &packet; for ( unsigned int i=0; i<nBytes; ++i ) { *ptr = message->at(i); ++ptr; } // Send the message immediately. result = midiOutShortMsg( data->outHandle, packet ); if ( result != MMSYSERR_NOERROR ) { errorString_ = "RtMidiOut::sendMessage: error sending MIDI message."; error( RtError::DRIVER_ERROR ); } } }
static void test_midiStream(UINT udev, HWND hwnd) { HMIDISTRM hm; MMRESULT rc, rc2; MIDIHDR mhdr; union { MIDIPROPTEMPO tempo; MIDIPROPTIMEDIV tdiv; } midiprop; if (hwnd) rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)hwnd, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); else rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)callback_func, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); if (rc == MMSYSERR_NOTSUPPORTED) { skip( "MIDI stream not supported\n" ); return; } ok(!rc, "midiStreamOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return; test_notification(hwnd, "midiStreamOpen", MOM_OPEN, 0); midiprop.tempo.cbStruct = sizeof(midiprop.tempo); rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET|MIDIPROP_TEMPO); ok(!rc, "midiStreamProperty TEMPO rc=%s\n", mmsys_error(rc)); ok(midiprop.tempo.dwTempo==500000, "default stream tempo %u microsec per quarter note\n", midiprop.tempo.dwTempo); midiprop.tdiv.cbStruct = sizeof(midiprop.tdiv); rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET|MIDIPROP_TIMEDIV); ok(!rc, "midiStreamProperty TIMEDIV rc=%s\n", mmsys_error(rc)); todo_wine ok(24==LOWORD(midiprop.tdiv.dwTimeDiv), "default stream time division %u\n", midiprop.tdiv.dwTimeDiv); memset(&mhdr, 0, sizeof(mhdr)); mhdr.dwFlags = 0; mhdr.dwUser = 0x56FA552C; mhdr.dwOffset = 1234567890; mhdr.dwBufferLength = sizeof(strmEvents); mhdr.dwBytesRecorded = mhdr.dwBufferLength; mhdr.lpData = (LPSTR)&strmEvents[0]; if (mhdr.lpData) { rc = midiOutLongMsg((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER); rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)-1); ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutPrepare old size rc=%s\n", mmsys_error(rc)); ok(mhdr.dwFlags & MHDR_PREPARED, "MHDR.dwFlags when prepared %x\n", mhdr.dwFlags); /* The device is still in paused mode and should queue the message. */ rc = midiStreamOut(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiStreamOut old size rc=%s\n", mmsys_error(rc)); rc2 = rc; trace("MIDIHDR flags=%x when submitted\n", mhdr.dwFlags); /* w9X/me does not set MHDR_ISSTRM when StreamOut exits, * but it will be set on all systems after the job is finished. */ Sleep(90); /* Wine <1.1.39 started playing immediately */ test_notification(hwnd, "midiStream still paused", 0, WHATEVER); /* MSDN asks to use midiStreamRestart prior to midiStreamOut() * because the starting state is 'pause', but some apps seem to * work with the inverse order: queue everything, then play. */ rc = midiStreamRestart(hm); ok(!rc, "midiStreamRestart rc=%s\n", mmsys_error(rc)); if (!rc2) while(mhdr.dwFlags & MHDR_INQUEUE) { trace("async MIDI still queued\n"); Sleep(100); } /* Checking INQUEUE is not the recommended way to wait for the end of a job, but we're testing. */ /* MHDR_ISSTRM is not necessarily set when midiStreamOut returns * rather than when the queue is eventually processed. */ ok(mhdr.dwFlags & MHDR_ISSTRM, "MHDR.dwFlags %x no ISSTRM when out of queue\n", mhdr.dwFlags); if (!rc2) while(!(mhdr.dwFlags & MHDR_DONE)) { /* Never to be seen except perhaps on multicore */ trace("async MIDI still not done\n"); Sleep(100); } ok(mhdr.dwFlags & MHDR_DONE, "MHDR.dwFlags %x not DONE when out of queue\n", mhdr.dwFlags); test_notification(hwnd, "midiStream callback", MOM_POSITIONCB, (DWORD_PTR)&mhdr); test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr); /* Native fills dwOffset regardless of the cbMidiHdr size argument to midiStreamOut */ ok(1234567890!=mhdr.dwOffset, "play left MIDIHDR.dwOffset at %u\n", mhdr.dwOffset); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutUnprepare #2 rc=%s\n", mmsys_error(rc)); trace("MIDIHDR stream flags=%x when finished\n", mhdr.dwFlags); ok(mhdr.dwFlags & MHDR_DONE, "MHDR.dwFlags when done %x\n", mhdr.dwFlags); test_position(hm, TIME_MS, TIME_MS); test_position(hm, TIME_TICKS, TIME_TICKS); todo_wine test_position(hm, TIME_MIDI, TIME_MIDI); test_position(hm, TIME_SMPTE, TIME_MS); test_position(hm, TIME_SAMPLES, TIME_MS); test_position(hm, TIME_BYTES, TIME_MS); Sleep(400); /* Hear note */ midiprop.tempo.cbStruct = sizeof(midiprop.tempo); rc = midiStreamProperty(hm, (void*)&midiprop, MIDIPROP_GET|MIDIPROP_TEMPO); ok(!rc, "midiStreamProperty TEMPO rc=%s\n", mmsys_error(rc)); ok(0x0493E0==midiprop.tempo.dwTempo, "stream set tempo %u\n", midiprop.tdiv.dwTimeDiv); rc = midiStreamRestart(hm); ok(!rc, "midiStreamRestart #2 rc=%s\n", mmsys_error(rc)); mhdr.dwFlags |= MHDR_ISSTRM; /* Preset flags (e.g. MHDR_ISSTRM) do not disturb. */ rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutPrepare used flags %x rc=%s\n", mhdr.dwFlags, mmsys_error(rc)); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutUnprepare used flags %x rc=%s\n", mhdr.dwFlags, mmsys_error(rc)); rc = midiStreamRestart(hm); ok(!rc, "midiStreamRestart #3 rc=%s\n", mmsys_error(rc)); } ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser); ok(0==((MIDISHORTEVENT*)&strmEvents)[0].dwStreamID, "dwStreamID set to %x\n", ((LPMIDIEVENT)&strmEvents[0])->dwStreamID); /* dwBytesRecorded controls how much is played, not dwBufferLength * allowing to immediately forward packets from midiIn to midiOut */ mhdr.dwOffset = 1234123123; mhdr.dwBufferLength = sizeof(strmNops); trace("buffer: %u\n", mhdr.dwBufferLength); mhdr.dwBytesRecorded = 0; mhdr.lpData = (LPSTR)&strmNops[0]; strmNops[0].dwEvent |= MEVT_F_CALLBACK; strmNops[1].dwEvent |= MEVT_F_CALLBACK; rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc)); rc = playStream(hm, &mhdr); ok(!rc, "midiStreamOut 0 bytes recorded rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiStreamOut", MOM_DONE, (DWORD_PTR)&mhdr); test_notification(hwnd, "0 bytes recorded", 0, WHATEVER); /* FIXME: check dwOffset within callback * instead of the unspecified value afterwards */ ok(1234123123==mhdr.dwOffset || broken(0==mhdr.dwOffset), "play 0 set MIDIHDR.dwOffset to %u\n", mhdr.dwOffset); /* w2k and later only set dwOffset when processing MEVT_T_CALLBACK, * while w9X/me/nt always sets it. Have Wine behave like w2k because the * dwOffset slot does not exist in the small size MIDIHDR. */ mhdr.dwOffset = 1234123123; mhdr.dwBytesRecorded = 1*sizeof(MIDISHORTEVENT); rc = playStream(hm, &mhdr); ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "1 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr); test_notification(hwnd, "1 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr); test_notification(hwnd, "1 of 2 events", 0, WHATEVER); ok(0==mhdr.dwOffset, "MIDIHDR.dwOffset 1/2 changed to %u\n", mhdr.dwOffset); mhdr.dwOffset = 1234123123; mhdr.dwBytesRecorded = 2*sizeof(MIDISHORTEVENT); rc = playStream(hm, &mhdr); ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr); test_notification(hwnd, "2 of 2 events", MOM_POSITIONCB, (DWORD_PTR)&mhdr); test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr); test_notification(hwnd, "2 of 2 events", 0, WHATEVER); ok(sizeof(MIDISHORTEVENT)==mhdr.dwOffset, "MIDIHDR.dwOffset 2/2 changed to %u\n", mhdr.dwOffset); ok(mhdr.dwBytesRecorded == 2*sizeof(MIDISHORTEVENT), "dwBytesRecorded changed to %u\n", mhdr.dwBytesRecorded); strmNops[0].dwEvent &= ~MEVT_F_CALLBACK; strmNops[1].dwEvent &= ~MEVT_F_CALLBACK; mhdr.dwOffset = 1234123123; rc = playStream(hm, &mhdr); ok(!rc, "midiStreamOut 1 event out of 2 rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "0 CB in 2 events", MOM_DONE, (DWORD_PTR)&mhdr); test_notification(hwnd, "0 CB in 2 events", 0, WHATEVER); /* w9X/me/nt set dwOffset to the position played last */ ok(1234123123==mhdr.dwOffset || broken(sizeof(MIDISHORTEVENT)==mhdr.dwOffset), "MIDIHDR.dwOffset nocb changed to %u\n", mhdr.dwOffset); mhdr.dwBytesRecorded = mhdr.dwBufferLength-1; rc = playStream(hm, &mhdr); ok(rc==MMSYSERR_INVALPARAM,"midiStreamOut dwBytesRecorded modulo MIDIEVENT rc=%s\n", mmsys_error(rc)); if (!rc) { test_notification(hwnd, "2 of 2 events", MOM_DONE, (DWORD_PTR)&mhdr); } mhdr.dwBytesRecorded = mhdr.dwBufferLength+1; rc = playStream(hm, &mhdr); ok(rc==MMSYSERR_INVALPARAM,"midiStreamOut dwBufferLength<dwBytesRecorded rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "past MIDIHDR tests", 0, WHATEVER); rc = midiStreamStop(hm); ok(!rc, "midiStreamStop rc=%s\n", mmsys_error(rc)); ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); ok(0==strmNops[0].dwStreamID, "dwStreamID[0] set to %x\n", strmNops[0].dwStreamID); ok(0==strmNops[1].dwStreamID, "dwStreamID[1] set to %x\n", strmNops[1].dwStreamID); mhdr.dwBufferLength = 70000; /* > 64KB! */ mhdr.lpData = HeapAlloc(GetProcessHeap(), 0 , mhdr.dwBufferLength); ok(mhdr.lpData!=NULL, "No %d bytes of memory!\n", mhdr.dwBufferLength); if (mhdr.lpData) { mhdr.dwFlags = 0; /* PrepareHeader detects the too large buffer is for a stream. */ rc = midiOutPrepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); todo_wine ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare stream too large rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader((HMIDIOUT)hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); HeapFree(GetProcessHeap(), 0, mhdr.lpData); } rc = midiStreamClose(hm); ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiStreamClose", MOM_CLOSE, 0); test_notification(hwnd, "midiStream over", 0, WHATEVER); rc = midiStreamOpen(&hm, &udev, 1, 0, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); ok(!rc /*w2k*/|| rc==MMSYSERR_INVALPARAM/*w98*/, "midiStreamOpen NULL function rc=%s\n", mmsys_error(rc)); if (!rc) { trace("Device %d accepts NULL CALLBACK_FUNCTION\n", udev); rc = midiStreamClose(hm); ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc)); } rc = midiStreamOpen(&hm, &udev, 1, (DWORD_PTR)0xDEADBEEF, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); ok(rc==MMSYSERR_INVALPARAM, "midiStreamOpen bad window rc=%s\n", mmsys_error(rc)); if (!rc) { rc = midiStreamClose(hm); ok(!rc, "midiStreamClose rc=%s\n", mmsys_error(rc)); } }
static void test_midiOut_device(UINT udev, HWND hwnd) { HMIDIOUT hm; MMRESULT rc; MIDIOUTCAPSA capsA; DWORD ovolume; UINT udevid; MIDIHDR mhdr; rc = midiOutGetDevCapsA(udev, &capsA, sizeof(capsA)); ok(!rc, "midiOutGetDevCaps(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (!rc) { trace("* %s: manufacturer=%d, product=%d, tech=%d, support=%X: %d voices, %d notes\n", capsA.szPname, capsA.wMid, capsA.wPid, capsA.wTechnology, capsA.dwSupport, capsA.wVoices, capsA.wNotes); ok(!((MIDIMAPPER==udev) ^ (MOD_MAPPER==capsA.wTechnology)), "technology %d on device %d\n", capsA.wTechnology, udev); if (MOD_MIDIPORT == capsA.wTechnology) { ok(capsA.wVoices == 0 && capsA.wNotes == 0, "external device with notes or voices\n"); ok(capsA.wChannelMask == 0xFFFF, "external device channel mask %x\n", capsA.wChannelMask); ok(!(capsA.dwSupport & (MIDICAPS_VOLUME|MIDICAPS_LRVOLUME|MIDICAPS_CACHE)), "external device support=%X\n", capsA.dwSupport); } } if (hwnd) rc = midiOutOpen(&hm, udev, (DWORD_PTR)hwnd, (DWORD_PTR)MYCBINST, CALLBACK_WINDOW); else rc = midiOutOpen(&hm, udev, (DWORD_PTR)callback_func, (DWORD_PTR)MYCBINST, CALLBACK_FUNCTION); if (rc == MMSYSERR_NOTSUPPORTED) { skip( "MIDI out not supported\n" ); return; } ok(!rc, "midiOutOpen(dev=%d) rc=%s\n", udev, mmsys_error(rc)); if (rc) return; test_notification(hwnd, "midiOutOpen", MOM_OPEN, 0); rc = midiOutGetVolume(hm, &ovolume); ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume rc=%s\n", mmsys_error(rc)); /* The native mapper responds with FFFFFFFF initially, * real devices with the volume GUI SW-synth settings. */ if (!rc) trace("Current volume %x on device %d\n", ovolume, udev); /* The W95 ESFM Synthesis device reports NOTENABLED although * GetVolume by handle works and music plays. */ rc = midiOutGetVolume(UlongToHandle(udev), &ovolume); ok((capsA.dwSupport & MIDICAPS_VOLUME) ? rc==MMSYSERR_NOERROR || broken(rc==MMSYSERR_NOTENABLED) : rc==MMSYSERR_NOTSUPPORTED, "midiOutGetVolume(dev=%d) rc=%s\n", udev, mmsys_error(rc)); rc = midiOutGetVolume(hm, NULL); ok(rc==MMSYSERR_INVALPARAM, "midiOutGetVolume NULL rc=%s\n", mmsys_error(rc)); /* Tests with midiOutSetvolume show that the midi mapper forwards * the value to the real device, but Get initially always reports * FFFFFFFF. Therefore, a Get+SetVolume pair with the mapper is * not adequate to restore the value prior to tests. */ if (winetest_interactive && (capsA.dwSupport & MIDICAPS_VOLUME)) { DWORD volume2 = (ovolume < 0x80000000) ? 0xC000C000 : 0x40004000; rc = midiOutSetVolume(hm, volume2); ok(!rc, "midiOutSetVolume rc=%s\n", mmsys_error(rc)); if (!rc) { DWORD volume3; rc = midiOutGetVolume(hm, &volume3); ok(!rc, "midiOutGetVolume new rc=%s\n", mmsys_error(rc)); if (!rc) trace("New volume %x on device %d\n", volume3, udev); todo_wine ok(volume2==volume3, "volume Set %x = Get %x\n", volume2, volume3); rc = midiOutSetVolume(hm, ovolume); ok(!rc, "midiOutSetVolume restore rc=%s\n", mmsys_error(rc)); } } rc = midiOutGetDevCapsA((UINT_PTR)hm, &capsA, sizeof(capsA)); ok(!rc, "midiOutGetDevCaps(dev=%d) by handle rc=%s\n", udev, mmsys_error(rc)); rc = midiInGetDevCapsA((UINT_PTR)hm, (LPMIDIINCAPSA)&capsA, sizeof(DWORD)); ok(rc==MMSYSERR_BADDEVICEID, "midiInGetDevCaps(dev=%d) by out handle rc=%s\n", udev, mmsys_error(rc)); { DWORD e = 0x006F4893; /* velocity, note (#69 would be 440Hz) channel */ trace("ShortMsg type %x\n", LOBYTE(LOWORD(e))); rc = midiOutShortMsg(hm, e); ok(!rc, "midiOutShortMsg rc=%s\n", mmsys_error(rc)); if (!rc) Sleep(400); /* Hear note */ } memset(&mhdr, 0, sizeof(mhdr)); mhdr.dwFlags = 0; mhdr.dwUser = 0x56FA552C; mhdr.dwOffset = 0xDEADBEEF; mhdr.dwBufferLength = 70000; /* > 64KB! */ mhdr.lpData = HeapAlloc(GetProcessHeap(), 0 , mhdr.dwBufferLength); ok(mhdr.lpData!=NULL, "No %d bytes of memory!\n", mhdr.dwBufferLength); if (mhdr.lpData) { rc = midiOutLongMsg(hm, &mhdr, sizeof(mhdr)); ok(rc==MIDIERR_UNPREPARED, "midiOutLongMsg unprepared rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiOutLong unprepared", 0, WHATEVER); rc = midiOutPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)-1); ok(rc==MMSYSERR_INVALPARAM, "midiOutPrepare tiny rc=%s\n", mmsys_error(rc)); rc = midiOutPrepareHeader(hm, &mhdr, offsetof(MIDIHDR,dwOffset)); ok(!rc, "midiOutPrepare old size rc=%s\n", mmsys_error(rc)); rc = midiOutPrepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutPrepare rc=%s\n", mmsys_error(rc)); rc = midiOutUnprepareHeader(hm, &mhdr, sizeof(mhdr)); ok(!rc, "midiOutUnprepare rc=%s\n", mmsys_error(rc)); trace("MIDIHDR flags=%x when unsent\n", mhdr.dwFlags); HeapFree(GetProcessHeap(), 0, mhdr.lpData); } ok(mhdr.dwUser==0x56FA552C, "MIDIHDR.dwUser changed to %lx\n", mhdr.dwUser); ok(mhdr.dwOffset==0xDEADBEEF, "MIDIHDR.dwOffset changed to %x\n", mhdr.dwOffset); rc = midiOutGetID(hm, &udevid); ok(!rc, "midiOutGetID rc=%s\n", mmsys_error(rc)); if(!rc) ok(udevid==udev, "midiOutGetID gives %d, expect %d\n", udevid, udev); rc = midiOutReset(hm); /* Quiet everything */ ok(!rc, "midiOutReset rc=%s\n", mmsys_error(rc)); rc = midiOutClose(hm); ok(!rc, "midiOutClose rc=%s\n", mmsys_error(rc)); test_notification(hwnd, "midiOutClose", MOM_CLOSE, 0); test_notification(hwnd, "midiOut over", 0, WHATEVER); }
/************************************************************************** * MMSYSTEM_MidiStream_Player [internal] */ static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) { WINE_MIDIStream* lpMidiStrm = pmt; WINE_MIDI* lpwm; MSG msg; DWORD dwToGo; DWORD dwCurrTC; LPMIDIHDR lpMidiHdr; DWORD dwOffset; TRACE("(%p)!\n", lpMidiStrm); if (!lpMidiStrm || (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) goto the_end; /* force thread's queue creation */ PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE); lpMidiStrm->dwStartTicks = 0; lpMidiStrm->dwPulses = 0; lpMidiStrm->lpMidiHdr = 0; /* midiStreamOpen is waiting for ack */ SetEvent(lpMidiStrm->hEvent); start_header: lpMidiHdr = lpMidiStrm->lpMidiHdr; if (!lpMidiHdr) { /* for first message, block until one arrives, then process all that are available */ GetMessageA(&msg, 0, 0, 0); do { if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) goto the_end; } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); goto start_header; } dwOffset = 0; while (dwOffset + offsetof(MIDIEVENT,dwParms) <= lpMidiHdr->dwBytesRecorded) { LPMIDIEVENT me = (LPMIDIEVENT)(lpMidiHdr->lpData+dwOffset); /* do we have to wait ? */ if (me->dwDeltaTime) { lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); lpMidiStrm->dwPulses += me->dwDeltaTime; dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; TRACE("%d/%d/%d\n", dwToGo, GetTickCount(), me->dwDeltaTime); while ((dwCurrTC = GetTickCount()) < dwToGo) { if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { /* got a message, handle it */ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) goto the_end; /* is lpMidiHdr still current? */ if (lpMidiHdr != lpMidiStrm->lpMidiHdr) { goto start_header; } } } else { /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ break; } } } switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { case MEVT_COMMENT: FIXME("NIY: MEVT_COMMENT\n"); /* do nothing, skip bytes */ break; case MEVT_LONGMSG: midiOutLongMsg(lpMidiStrm->hDevice, lpMidiStrm->lpMidiHdr, MEVT_EVENTPARM(me->dwEvent)); break; case MEVT_NOP: break; case MEVT_SHORTMSG: midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); break; case MEVT_TEMPO: lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); break; case MEVT_VERSION: break; default: FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); break; } if (me->dwEvent & MEVT_F_CALLBACK) { /* native fills dwOffset regardless of the cbMidiHdr size argument to midiStreamOut */ lpMidiHdr->dwOffset = dwOffset; DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); } dwOffset += offsetof(MIDIEVENT,dwParms); if (me->dwEvent & MEVT_F_LONG) dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; } /* done with this header */ lpMidiStrm->lpMidiHdr = lpMidiHdr->lpNext; lpMidiHdr->dwFlags |= MHDR_DONE; lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, lpwm->mod.dwInstance, (DWORD_PTR)lpMidiHdr, 0); goto start_header; the_end: TRACE("End of thread\n"); return 0; }
//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴 //Procedure SF_SendRouterCommand //Author Robert Slater //Date Fri 3 Jul 1998 // //Description // //Inputs // //Returns // //------------------------------------------------------------------------------ Bool SndFonts::SF_SendRouterCommand(ULong sfRouterID, CSFRouterData *pRoute) { char sfRouteCommand[20], Text[200]; ULong bufLength = 0; //DeadCode RJS 20Oct00 UWord numDevs=0; MIDIHDR sysExMessage; SWord status; Bool bOK=TRUE; if (hMIDIOutInteractive) { if (pRoute == NULL) { if (lastDev != NO_DEVID) pRoute = &last; else return FALSE; } else { last = *pRoute; lastDev = sfRouterID; } sfRouteCommand[0] = (BYTE) 0xF0; sfRouteCommand[1] = (BYTE) 0x00; sfRouteCommand[2] = (BYTE) 0x20; sfRouteCommand[3] = (BYTE) 0x21; sfRouteCommand[4] = (BYTE) 0x5F; sfRouteCommand[5] = (BYTE) 0x00; // 0 or 127 sfRouteCommand[6] = pRoute->m_RouterCommand; switch(pRoute->m_RouterCommand) { case SFROUTER_RESET_ALL_ROUTINGS: sfRouteCommand[7] = (BYTE)0xF7; bufLength = 8; break; case SFROUTER_ROUTE_ALL_CHANS_TO_DEV: bufLength = 12; SFMAN_GET_ROUTING_INDEX(sfRouterID, sfRouteCommand[7], sfRouteCommand[8], sfRouteCommand[9], sfRouteCommand[10]); sfRouteCommand[11] = (BYTE) 0xF7; break; case SFROUTER_ROUTE_BANKPRG_TO_DEV_BANKPRG: sfRouteCommand[7] = 0; sfRouteCommand[8] = (BYTE)pRoute->m_SourceLocation.m_BankIndex; sfRouteCommand[9] = 0; sfRouteCommand[10] = (BYTE)pRoute->m_SourceLocation.m_PresetIndex; SFMAN_GET_ROUTING_INDEX(sfRouterID, sfRouteCommand[11], sfRouteCommand[12], sfRouteCommand[13], sfRouteCommand[14]); sfRouteCommand[15] = (BYTE)pRoute->m_TargetLocation.m_BankIndex; sfRouteCommand[16] = 0; sfRouteCommand[17] = (BYTE)pRoute->m_TargetLocation.m_PresetIndex; sfRouteCommand[18] = (BYTE) 0xF7; bufLength = 19; break; case SFROUTER_ROUTE_CHAN_TO_DEV: sfRouteCommand[7] = (BYTE)pRoute->m_Channel; SFMAN_GET_ROUTING_INDEX(sfRouterID, sfRouteCommand[8], sfRouteCommand[9], sfRouteCommand[10], sfRouteCommand[11]); sfRouteCommand[12] = (BYTE)0xF7; bufLength = 13; break; default: return FALSE; } memset ( &sysExMessage , 0, sizeof(MIDIHDR) ) ; sysExMessage.lpData = (char*) sfRouteCommand ; sysExMessage.dwBufferLength = bufLength ; if (midiOutPrepareHeader( hMIDIOutInteractive, &sysExMessage, sizeof(MIDIHDR)) == 0) { if (midiOutLongMsg ( hMIDIOutInteractive, &sysExMessage, sizeof(MIDIHDR)) != 0) bOK = FALSE; } else bOK = FALSE; } return bOK; }
//컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴컴 //Procedure InitSFDLL //Author Robert Slater //Date Fri 3 Jul 1998 // //Description // // This function loads the SF Manager DLL, and then queries all the SoundFont devices in // the system. Each device is given a rating (see #define statements above for details), // and the device with the best rating is opened. A router command to route all MIDI data // to this device is then sent. // // Pass TRUE to this function to do the above and // Pass FALSE to close the SF device, and unload the SF Manager library. // //Inputs // //Returns // //------------------------------------------------------------------------------ Bool SndFonts::InitSFDLL(Bool bStartUp) { UWord count,done; ULong dwMaxMem,dwAvailableMemCurrent; UByte Rating[MAXNUMDEVICES] = {0}; LRESULT dwErr; CSFMIDILocation midiLoc; CSFCapsObject sfCaps; char String[60]; ULong dwRouterID; UByte sfRouterCommand[12] = {0xf0, 0x00, 0x20, 0x21, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7 }; MIDIHDR sysExMessage; Bool retval = TRUE; if (bStartUp == TRUE) { // Load the SoundFont Master Manager hSFMANDLL = LoadLibrary (SF_MASTER_MANAGER_FILENAME); if (hSFMANDLL == NULL ) { // MessageBox(NULL, "Error loading SoundFont Manager", "Error", MB_OK) ; return FALSE; } // Get the address of the SoundFont manager function table lpSFManager = (PSFMANAGER)GetProcAddress((HINSTANCE__*)hSFMANDLL, SF_FUNCTION_TABLE_NAME); if (lpSFManager == NULL) { FreeLibrary((HINSTANCE__*)hSFMANDLL); // MessageBox(NULL, "Error getting SFMAN function table", "Error", MB_OK) ; return FALSE; } // Use SF_QueryInterface to get access to the appropriate function table if ((dwErr = lpSFManager->SF_QueryInterface(ID_SFMANL101API,(ULong*)&lpSFL1API))!=0) { FreeLibrary((HINSTANCE__*)hSFMANDLL); // MessageBox(NULL,"Failed to Query Interface","Error !",MB_OK); return FALSE ; } // Get the number of SoundFont compatible devices in system lpSFL1API->SF_GetNumDevs(&numSFDevs); if (numSFDevs != 0) { // For each SF compatible device, query the caps, and assign a // rating to it. for (count=0; count<numSFDevs; count++) { // Get current device capabilities memset(&sfCaps, 0, sizeof(CSFCapsObject)); sfCaps.m_SizeOf = sizeof(sfCaps); lpSFL1API->SF_GetDevCaps(count,&sfCaps); // Does this device have a Hardware synthesiser ? if ((sfCaps.m_DevCaps & SFMANCAP_SOFTWARE_SYNTH_CAP) == 0) { // Yes, device has a hardware synthesier ... // Does this device use hardware memory? if ((sfCaps.m_DevCaps & SFMANCAP_DYNAMIC_MEM_CAP) == 0) { // Yes, device has hardware memory ... // Open the device so that the amount of memory can be queried lpSFL1API->SF_Open(count); // Query the amount of memory available for this device lpSFL1API->SF_QueryStaticSampleMemorySize(count,&dwMaxMem, &dwAvailableMemCurrent); Rating[count]=(BYTE)(dwAvailableMemCurrent/HWMemBlock); Rating[count]+=HWSynthHWMem; // If hardware RAM size is less than HWMemBlock, then do not use this // device. (This caters for unexpanded SB32 cards which have no memory) if (Rating[count]==HWSynthHWMem) Rating[count]=0; lpSFL1API->SF_Close(count); } else Rating[count]=(BYTE)HWSynthSysMem; // No, device uses system memory } else Rating[count]=SWSynthSysMem; //No, device has a software synthesier ... } // Choose best device and try to open it, if it fails then find next best device // and open that and so on ... done = numSFDevs; while (done>0) { BestsfIdx = 0; done--; // Search through the other devices, for one with a higher rating for (count = 1; count<numSFDevs; count++) { if (Rating[count] > Rating[BestsfIdx]) BestsfIdx = count; } // Found best device - now try to open it if (lpSFL1API->SF_Open(BestsfIdx) != SFERR_NOERR) Rating[BestsfIdx]=0; else done=0; } if (Rating[BestsfIdx] == 0) { // Failed to open any devices FreeLibrary((HINSTANCE__*)hSFMANDLL); return FALSE; } // Query and capabilities of the best device, and set dwAvailableMemBest to the amount // of RAM available. memset(&sfCaps, 0, sizeof(CSFCapsObject)); sfCaps.m_SizeOf = sizeof(sfCaps); lpSFL1API->SF_GetDevCaps(BestsfIdx,&sfCaps); if ((sfCaps.m_DevCaps & SFMANCAP_DYNAMIC_MEM_CAP) == 0) lpSFL1API->SF_QueryStaticSampleMemorySize(BestsfIdx,&dwMaxMem,&dwAvailableMemBest); else dwAvailableMemBest=0xFFFFFFFF; // Need to find the Router ID associated with this device lpSFL1API->SF_GetRouterID(BestsfIdx, &dwRouterID); // Call macro to obtain routing index SFMAN_GET_ROUTING_INDEX(dwRouterID, sfRouterCommand[7], sfRouterCommand[8], sfRouterCommand[9], sfRouterCommand[10]); memset(&sysExMessage, 0, sizeof(MIDIHDR)); sysExMessage.lpData = (char*) sfRouterCommand; sysExMessage.dwBufferLength = 12; if (midiOutPrepareHeader(hMIDIOutInteractive, &sysExMessage, sizeof(MIDIHDR)) ==0 ) { if (midiOutLongMsg(hMIDIOutInteractive, &sysExMessage, sizeof(MIDIHDR)) ==0 ) SFontSet = TRUE; else retval = FALSE; } else retval = FALSE; } else retval = FALSE; } else { // Close down the SoundFont compatible device. SFontSet = FALSE; if ((lpSFL1API != NULL) && (numSFDevs != 0)) { ClearBank(); lpSFL1API->SF_Close(BestsfIdx); FreeLibrary ((HINSTANCE__*) hSFMANDLL ); lpSFL1API = NULL; numSFDevs = 0; } } return retval; }
static void midi_flush_current_buffer(void) { MMRESULT rv; MIDIEVENT * evt; BOOL needsPrepare = FALSE; if (!currentMidiBuffer) { return; } evt = (MIDIEVENT *) currentMidiBuffer->hdr.lpData; if (!midiThread) { // immediate messages don't use a MIDIEVENT header so strip it off and // make some adjustments currentMidiBuffer->hdr.dwBufferLength = currentMidiBuffer->hdr.dwBytesRecorded - 12; currentMidiBuffer->hdr.dwBytesRecorded = 0; currentMidiBuffer->hdr.lpData = (LPSTR) &evt->dwParms[0]; if (currentMidiBuffer->hdr.dwBufferLength > 0) { needsPrepare = TRUE; } } else { needsPrepare = TRUE; } if (needsPrepare) { // playing a file, or sending a sysex when not playing means // we need to prepare the buffer rv = midiOutPrepareHeader( (HMIDIOUT) midiStream, ¤tMidiBuffer->hdr, sizeof(MIDIHDR) ); if (rv != MMSYSERR_NOERROR) { midi_error(rv, "WinMM midi_flush_current_buffer midiOutPrepareHeader"); return; } currentMidiBuffer->prepared = TRUE; } if (midiThread) { // midi file playing, so send events to the stream LL_Add( (MidiBuffer*) &activeMidiBuffers, currentMidiBuffer, next, prev ); rv = midiStreamOut(midiStream, ¤tMidiBuffer->hdr, sizeof(MIDIHDR)); if (rv != MMSYSERR_NOERROR) { midi_error(rv, "WinMM midi_flush_current_buffer midiStreamOut"); midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer"); return; } //fprintf(stderr, "WinMM midi_flush_current_buffer queued buffer %p\n", currentMidiBuffer); } else { // midi file not playing, so send immediately if (currentMidiBuffer->hdr.dwBufferLength > 0) { rv = midiOutLongMsg( (HMIDIOUT) midiStream, ¤tMidiBuffer->hdr, sizeof(MIDIHDR) ); if (rv == MMSYSERR_NOERROR) { // busy-wait for Windows to be done with it while (!(currentMidiBuffer->hdr.dwFlags & MHDR_DONE)) ; //fprintf(stderr, "WinMM midi_flush_current_buffer sent immediate long\n"); } else { midi_error(rv, "WinMM midi_flush_current_buffer midiOutLongMsg"); } } else { rv = midiOutShortMsg( (HMIDIOUT) midiStream, evt->dwEvent ); if (rv == MMSYSERR_NOERROR) { //fprintf(stderr, "WinMM midi_flush_current_buffer sent immediate short\n"); } else { midi_error(rv, "WinMM midi_flush_current_buffer midiOutShortMsg"); } } midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer"); } currentMidiBuffer = 0; }
void MIDISong2::Play (bool looping) { MIDIOUTCAPS caps; DWORD tid; m_Status = STATE_Stopped; m_Looping = looping; // Find out if this an FM synth or not for EMIDI DesignationMask = 0xFF0F; if (MMSYSERR_NOERROR == midiOutGetDevCaps (mididevice, &caps, sizeof(caps))) { if (caps.wTechnology == MOD_FMSYNTH) { DesignationMask = 0x00F0; } else if (caps.wTechnology == MOD_MIDIPORT) { DesignationMask = 0x0001; } } if (MMSYSERR_NOERROR != midiOutOpen (&MidiOut, mididevice, 0, 0, CALLBACK_NULL)) { Printf (PRINT_BOLD, "Could not open MIDI out device\n"); return; } // Try two different methods for setting the stream to full volume. // Unfortunately, this isn't as reliable as it once was, which is a pity. // The real volume selection is done by setting the volume controller for // each channel. Because every General MIDI-compliant device must support // this controller, it is the most reliable means of setting the volume. VolumeWorks = (MMSYSERR_NOERROR == midiOutGetVolume (MidiOut, &SavedVolume)); if (VolumeWorks) { VolumeWorks &= (MMSYSERR_NOERROR == midiOutSetVolume (MidiOut, 0xffffffff)); } else { // Send the standard SysEx message for full master volume BYTE volmess[] = { 0xf0, 0x7f, 0x7f, 0x04, 0x01, 0x7f, 0x7f, 0xf7 }; MIDIHDR hdr = { (LPSTR)volmess, sizeof(volmess), }; if (MMSYSERR_NOERROR == midiOutPrepareHeader (MidiOut, &hdr, sizeof(hdr))) { midiOutLongMsg (MidiOut, &hdr, sizeof(hdr)); while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader (MidiOut, &hdr, sizeof(hdr))) { Sleep (10); } } } snd_midivolume.Callback(); // set volume to current music's properties PlayerThread = CreateThread (NULL, 0, PlayerProc, this, 0, &tid); if (PlayerThread == NULL) { if (VolumeWorks) { midiOutSetVolume (MidiOut, SavedVolume); } midiOutClose (MidiOut); MidiOut = NULL; } m_Status = STATE_Playing; }
static PmError winmm_write_sysex_byte(PmInternal *midi, unsigned char byte) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; unsigned char *msg_buffer; /* at the beginning of sysex, m->hdr is NULL */ if (!m->hdr) { /* allocate a buffer if none allocated yet */ m->hdr = get_free_output_buffer(midi); if (!m->hdr) return pmInsufficientMemory; m->sysex_byte_count = 0; } /* figure out where to write byte */ msg_buffer = (unsigned char *) (m->hdr->lpData); assert(m->hdr->lpData == (char *) (m->hdr + 1)); /* check for overflow */ if (m->sysex_byte_count >= m->hdr->dwBufferLength) { /* allocate a bigger message -- double it every time */ LPMIDIHDR big = allocate_buffer(m->sysex_byte_count * 2); /* printf("expand to %d bytes\n", m->sysex_byte_count * 2); */ if (!big) return pmInsufficientMemory; m->error = midiOutPrepareHeader(m->handle.out, big, sizeof(MIDIHDR)); if (m->error) { m->hdr = NULL; return pmHostError; } memcpy(big->lpData, msg_buffer, m->sysex_byte_count); msg_buffer = (unsigned char *) (big->lpData); if (m->buffers[0] == m->hdr) { m->buffers[0] = big; pm_free(m->hdr); /* printf("freed m->hdr\n"); */ } else if (m->buffers[1] == m->hdr) { m->buffers[1] = big; pm_free(m->hdr); /* printf("freed m->hdr\n"); */ } m->hdr = big; } /* append byte to message */ msg_buffer[m->sysex_byte_count++] = byte; /* see if we have a complete message */ if (byte == MIDI_EOX) { m->hdr->dwBytesRecorded = m->sysex_byte_count; /* { int i; int len = m->hdr->dwBytesRecorded; printf("OutLongMsg %d ", len); for (i = 0; i < len; i++) { printf("%2x ", msg_buffer[i]); } } */ m->error = midiOutLongMsg(m->handle.out, m->hdr, sizeof(MIDIHDR)); m->hdr = NULL; /* stop using this message buffer */ if (m->error) return pmHostError; } return pmNoError; }