/************************************************************************** * midiStreamClose [WINMM.@] */ MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm) { WINE_MIDIStream* lpMidiStrm; MMRESULT ret = 0; TRACE("(%p)!\n", hMidiStrm); if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) return MMSYSERR_INVALHANDLE; midiStreamStop(hMidiStrm); PostThreadMessageA(lpMidiStrm->dwThreadID, WM_QUIT, 0, 0); CloseHandle(lpMidiStrm->hEvent); if (lpMidiStrm->hThread) { if (GetCurrentThreadId() != lpMidiStrm->dwThreadID) WaitForSingleObject(lpMidiStrm->hThread, INFINITE); else { FIXME("leak from call within function callback\n"); ret = MMSYSERR_HANDLEBUSY; /* yet don't signal it to app */ } CloseHandle(lpMidiStrm->hThread); } if(!ret) HeapFree(GetProcessHeap(), 0, lpMidiStrm); return midiOutClose((HMIDIOUT)hMidiStrm); }
void WinMMDrv_MIDI_HaltPlayback(void) { MMRESULT rv; if (midiThread) { SetEvent(midiThreadQuitEvent); WaitForSingleObject(midiThread, INFINITE); fprintf(stderr, "WinMM MIDI_HaltPlayback synched\n"); CloseHandle(midiThread); } if (midiThreadQuitEvent) { CloseHandle(midiThreadQuitEvent); } if (midiStreamRunning) { fprintf(stderr, "stopping stream\n"); rv = midiStreamStop(midiStream); if (rv != MMSYSERR_NOERROR) { midi_error(rv, "WinMM MIDI_HaltPlayback midiStreamStop"); } fprintf(stderr, "stream stopped\n"); midiStreamRunning = FALSE; } midi_free_buffers(); midiThread = 0; midiThreadQuitEvent = 0; }
void hmp_stop(hmp_file *hmp) { MIDIHDR *mhdr; if (!hmp->stop) { hmp->stop = 1; //PumpMessages(); midiStreamStop(hmp->hmidi); while (hmp->bufs_in_mm) { //PumpMessages(); G3_SLEEP(0); } } while ((mhdr = hmp->evbuf)) { midiOutUnprepareHeader((HMIDIOUT)hmp->hmidi, mhdr, sizeof(MIDIHDR)); hmp->evbuf = mhdr->lpNext; delete[] mhdr; mhdr = NULL; } if (hmp->hmidi) { midiStreamClose(hmp->hmidi); hmp->hmidi = NULL; } }
void native_midi_stop() { if (!hMidiStream) return; midiStreamStop(hMidiStream); midiStreamClose(hMidiStream); currentsong=NULL; hMidiStream = 0; }
static PmError winmm_out_abort(PmInternal *midi) { midiwinmm_type m = (midiwinmm_type) midi->descriptor; m->error = MMSYSERR_NOERROR; /* only stop output streams */ if (midi->latency > 0) { m->error = midiStreamStop(m->handle.stream); } return m->error ? pmHostError : pmNoError; }
int MPU_Reset ( void ) { midiStreamStop(hmido); midiStreamClose(hmido); return( MPU_Ok ); }
void native_midi_freesong(NativeMidiSong *song) { if (hMidiStream) { midiStreamStop(hMidiStream); midiStreamClose(hMidiStream); } if (song) { if (song->NewEvents) free(song->NewEvents); free(song); } }
static void Winmidi_Dealloc(WinmidiObject *obj) { assert(obj); /* XXX - s_CleanUpBlockNodes and s_FreeNodes set the Python error * string on errors... Should we do something different? */ if (obj->m_midiOut) midiStreamStop(obj->m_midiOut); (void)s_CleanUpBlockNodes(obj); (void)midiStreamClose(obj->m_midiOut); (void)s_FreeNodes(obj); /* printf("Winmidi object destroyed.\n"); */ PyObject_Del(obj); }
void WinMIDIStreamer::Reset(void) { int i; midiStreamStop(midiStr); // Reset channel settings. for(i = 0; i <= 0xf; ++i) // All channels. { midiOutShortMsg((HMIDIOUT) midiStr, 0xe0 | i | 64 << 16); // Pitch bend. } midiOutReset((HMIDIOUT) midiStr); }
void WinMIDIDevice::Stop() { if (PlayerThread != nullptr) { SetEvent(ExitEvent); WaitForSingleObject(PlayerThread, INFINITE); CloseHandle(PlayerThread); PlayerThread = nullptr; } midiStreamStop(MidiOut); midiOutReset((HMIDIOUT)MidiOut); if (VolumeWorks) { midiOutSetVolume((HMIDIOUT)MidiOut, SavedVolume); } }
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)); } }