Пример #1
0
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)));
	}
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
static int BlockOut(NativeMidiSong *song)
{
  MMRESULT err;
  int BlockSize;

  if ((song->MusicLoaded) && (song->NewEvents))
  {
    // proff 12/8/98: Added for savety
    midiOutUnprepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
    if (song->NewPos>=song->Size)
      return 0;
    BlockSize=(song->Size-song->NewPos);
    if (BlockSize<=0)
      return 0;
    if (BlockSize>36000)
      BlockSize=36000;
    song->MidiStreamHdr.lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
    song->NewPos+=BlockSize;
    song->MidiStreamHdr.dwBufferLength=BlockSize;
    song->MidiStreamHdr.dwBytesRecorded=BlockSize;
    song->MidiStreamHdr.dwFlags=0;
    err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
    if (err!=MMSYSERR_NOERROR)
      return 0;
    err=midiStreamOut(hMidiStream,&song->MidiStreamHdr,sizeof(MIDIHDR));
      return 0;
  }
  return 1;
}
Пример #5
0
static LPMIDIHDR get_free_output_buffer(PmInternal *midi)
{
    LPMIDIHDR r = NULL;
    midiwinmm_type m = (midiwinmm_type) midi->descriptor;
    if (!m->buffers) {
        if (allocate_buffers(m, PM_DEFAULT_SYSEX_BUFFER_SIZE, 2)) {
            return NULL;
        }
    }
    /* busy wait until we find a free buffer */
    while (TRUE) {
        int i;
        for (i = 0; i < m->num_buffers; i++) {
            m->next_buffer++;
            if (m->next_buffer >= m->num_buffers) m->next_buffer = 0;
            r = m->buffers[m->next_buffer];
            if ((r->dwFlags & MHDR_PREPARED) == 0) goto found_buffer;
        }
        /* after scanning every buffer and not finding anything, block */
        WaitForSingleObject(m->buffer_signal, INFINITE);
    }
found_buffer:
    r->dwBytesRecorded = 0;
    m->error = midiOutPrepareHeader(m->handle.out, r, sizeof(MIDIHDR));
    return r;
}
Пример #6
0
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;
}
Пример #7
0
// -----------------------------------------------------------------------
//   えくすくるーしぶ ごー
// -----------------------------------------------------------------------
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;
}
Пример #8
0
void MPU_FinishBuffer( int buffer )
{
	if (!eventcnt[buffer]) return;
	ZeroMemory(&bufferheaders[buffer], sizeof(MIDIHDR));
	bufferheaders[buffer].lpData = eventbuf[buffer];
	bufferheaders[buffer].dwBufferLength =
	bufferheaders[buffer].dwBytesRecorded = eventcnt[buffer];
	midiOutPrepareHeader((HMIDIOUT)hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
	midiStreamOut(hmido, &bufferheaders[buffer], sizeof(MIDIHDR));
//	printf("Sending %d bytes (buffer %d)\n",eventcnt[buffer],buffer);
	_MPU_BuffersWaiting++;
}
Пример #9
0
//---------------------------------------------------------------------------
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));
}
Пример #10
0
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;
}
Пример #11
0
int WinMIDIDevice::PrepareHeader(MidiHeader *header)
{
	// This code depends on the driving implementation only having two buffers that get passed alternatingly.
	// If there were more buffers this would require more intelligent handling.
	assert(header->lpNext == nullptr);
	MIDIHDR *syshdr = &WinMidiHeaders[HeaderIndex ^= 1];
	memset(syshdr, 0, sizeof(MIDIHDR));
	syshdr->lpData = (LPSTR)header->lpData;
	syshdr->dwBufferLength = header->dwBufferLength;
	syshdr->dwBytesRecorded = header->dwBytesRecorded;
	// this device does not use the lpNext pointer to link MIDI events so use it to point to the system data structure.
	header->lpNext = (MidiHeader*)syshdr;	
	return midiOutPrepareHeader((HMIDIOUT)MidiOut, syshdr, sizeof(MIDIHDR));
}
Пример #12
0
/*---------------------------------------------------------------------
   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));
	}
}
Пример #13
0
void MidiUartWinClass::midiSendLong(unsigned char *buf, unsigned long len) {
  MIDIHDR midiHdr;

  midiHdr.lpData = (CHAR *)buf;
  midiHdr.dwBufferLength = len;
  midiHdr.dwFlags = 0;

  UINT err = midiOutPrepareHeader(outHandle, &midiHdr, sizeof(MIDIHDR));
  if (err) {
    char errBuf[256];
    midiOutGetErrorText(err, errBuf, sizeof(errBuf));
    printf("error sending long message: %s\n", errBuf);
  }

  while (MIDIERR_STILLPLAYING == midiOutUnprepareHeader(outHandle, &midiHdr, sizeof(MIDIHDR)))
    ;
}
Пример #14
0
static int s_PrepareBlockNodes(WinmidiObject *obj) {
	UINT retVal;
	MidiBlockNode *node;
	MidiBlockNode *firstReady = 0;

	assert(obj);

	/* Go through the list and prepare all written blocks. */
	node = obj->m_list;
	while(node) {
	if(node->m_blockState == BLOCK_WRITING) {
		if(!firstReady) {
		firstReady = node;
		}

		retVal = midiOutPrepareHeader((HMIDIOUT)obj->m_midiOut,
			&node->m_header,
			sizeof(node->m_header));
		if(retVal != MMSYSERR_NOERROR) {
		s_SetMidiError("preparing header", retVal);
		return 0;
		}

		node->m_blockState = BLOCK_READY;
	}
	node = node->m_next;
	}

	/* If we actually prepared some blocks for playing, queue the first
	 * one. */
	if(!obj->m_playNode && firstReady) {
	obj->m_playNode = firstReady;
	(void)midiStreamOut(obj->m_midiOut, &firstReady->m_header,
		sizeof(firstReady->m_header));
	}

	retVal = midiStreamRestart(obj->m_midiOut);
	if(retVal != MMSYSERR_NOERROR) {
	s_SetMidiError("restarting MIDI stream", retVal);
	return 0;
	}

	return 1;
}
Пример #15
0
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;
}
Пример #16
0
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);
}
Пример #18
0
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;
}
Пример #19
0
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;
}
Пример #20
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);
}
Пример #22
0
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;
	}
}
Пример #23
0
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;
}
Пример #24
0
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 );
    }
  }
}
Пример #25
0
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));
    }
}
Пример #26
0
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);
}
Пример #27
0
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, &currentMidiBuffer->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, &currentMidiBuffer->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, &currentMidiBuffer->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;
}
Пример #28
0
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;
}
Пример #29
0
void WinMIDIStreamer::Play(int looped)
{
    UINT                i;

    // Do we need to prepare the MIDI data?
    if(!registered)
    {
        // The song is already loaded in the song buffer.
        DeregisterSong();

        // Prepare the buffers.
        if(song)
        {
            LPMIDIHDR           mh = GetFreeBuffer();
            MIDIEVENT           mev;
            DWORD*              ptr;

            // First add the tempo.
            ptr = (DWORD *) mh->lpData;
            *ptr++ = 0;
            *ptr++ = 0;
            *ptr++ = (MEVT_TEMPO << 24) | 1000000; // One second.
            mh->dwBytesRecorded = 3 * sizeof(DWORD);

            // Start reading the events.
            readPos = (byte *) song + ((musheader_t*)song)->scoreStart;
            readTime = 0;
            while(GetNextEvent(&mev))
            {
                // Is the buffer getting full?
                if(mh->dwBufferLength - mh->dwBytesRecorded < 3 * sizeof(DWORD))
                {
                    // Try to get more buffer.
                    if(!ResizeWorkBuffer(mh))
                    {
                        // Not possible, buffer size has reached the limit.
                        // We need to start working on another one.
                        midiOutPrepareHeader((HMIDIOUT) midiStr, mh, sizeof(*mh));
                        mh = GetFreeBuffer();
                        if(!mh)
                            return; // Oops.
                    }
                }

                // Add the event.
                ptr = (DWORD *) (mh->lpData + mh->dwBytesRecorded);
                *ptr++ = mev.dwDeltaTime;
                *ptr++ = 0;
                *ptr++ = mev.dwEvent;
                mh->dwBytesRecorded += 3 * sizeof(DWORD);
            }

            // Prepare the last buffer, too.
            midiOutPrepareHeader((HMIDIOUT) midiStr, mh, sizeof(*mh));
        }

        // Now there is a registered song.
        registered = TRUE;
    }

    playing = true;
    Reset();

    // Stream out all buffers.
    for(i = 0; i < MAX_BUFFERS; ++i)
    {
        if(midiBuffers[i].dwUser)
        {
            loopBuffer = &midiBuffers[i];
            midiStreamOut(midiStr, &midiBuffers[i], sizeof(midiBuffers[i]));
        }
    }

    // If we aren't looping, don't bother.
    if(!looped)
        loopBuffer = NULL;

    // Start playing.
    midiStreamRestart(midiStr);
}
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;
}