From f370a1c5a721153237ae220f64e3dba673538d2e Mon Sep 17 00:00:00 2001 From: Yale Zhang <yzhang1985@gmail.com> Date: Mon, 4 Nov 2013 15:17:55 +0900 Subject: [PATCH] Windows MIDI driver improved - Stop sending all MIDI messages to a worker thread to be played. Instead, call the event handler directly (with mutual exclusion). This simplifies the code and reduces latency. - Move initialization before worker thread creation - without this, TiMidity++ might not be initialized before the 1st message arrives (I actually had this problems when using VMPK, which sends a bank & program change message immediately on startup) Signed-off-by: TAMUKI Shoichi <tamuki@linet.gr.jp> --- windrv/timiditydrv.c | 275 ++++++++--------------------------------- windrv/timiditydrv.def | 6 +- 2 files changed, 56 insertions(+), 225 deletions(-) diff --git a/windrv/timiditydrv.c b/windrv/timiditydrv.c index 79f844be..3d2ae655 100644 --- a/windrv/timiditydrv.c +++ b/windrv/timiditydrv.c @@ -36,10 +36,10 @@ void _endthreadex( unsigned retval ); #endif #include <windows.h> -#include "mmddk.h" +#include "mmddk.h" #include <mmsystem.h> -#if defined(__DMC__) || defined(__MINGW32__) -//following codes are from wine's mmsystem.h +#if 0 +//following codes are from wine's mmsystem.h typedef struct tagMIDIOUTCAPS2A { WORD wMid; WORD wPid; @@ -97,16 +97,11 @@ const GUID CLSID_tim_synth = {0x0FEC4C35,0xA705,0x41d7,{0xA3,0xBB,0xD5,0x87,0xA2 #include "timiwp_timidity.h" - -LONG driverCount; - static volatile int OpenCount = 0; static volatile int modm_closed = 1; static CRITICAL_SECTION mim_section; static volatile int stop_thread = 0; -static volatile int stop_rtthread = 0; -static HANDLE hCalcThread = NULL; static HANDLE hRtsynThread = NULL; static DWORD processPriority; @@ -116,7 +111,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ){ }else if(fdwReason == DLL_PROCESS_DETACH){ ; } - return TRUE; + return TRUE; } STDAPI DllCanUnloadNow(void){ @@ -136,12 +131,7 @@ STDAPI DllUnregisterServer(void) return S_OK; } - -//unsigned __stdcall threadfunc2(LPVOID lpV); -STDAPI_(LONG) DefDriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2); - -STDAPI_(LONG) DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2){ - +STDAPI_(LONG) DriverProc(DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, LPARAM lParam1, LPARAM lParam2){ switch(msg) { case DRV_REMOVE: if (modm_closed == 0){ @@ -149,14 +139,8 @@ STDAPI_(LONG) DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, stop_thread = 1; //why thread can't stop by this???? while( stop_thread != 0 && maxloop-- > 0) Sleep(10); - if(stop_thread == 0) { - stop_rtthread = 1; - while( stop_rtthread != 0 && maxloop-- > 0) Sleep(10); - } - if(stop_thread != 0) TerminateThread(hCalcThread, FALSE); - if(stop_rtthread != 0) TerminateThread(hRtsynThread, FALSE); + if(stop_thread != 0) TerminateThread(hRtsynThread, FALSE); CloseHandle(hRtsynThread); - CloseHandle(hCalcThread); SetPriorityClass(GetCurrentProcess(), processPriority); } DeleteCriticalSection(&mim_section); @@ -177,9 +161,6 @@ STDAPI_(LONG) DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, case DRV_QUERYCONFIGURE: default: return 1; - break; - return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2); - break; } return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2); } @@ -206,8 +187,6 @@ HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) { myCapsA->wChannelMask = 0xffff; myCapsA->dwSupport = 0; return MMSYSERR_NOERROR; - - break; case (sizeof(MIDIOUTCAPSW)): myCapsW = (MIDIOUTCAPSW *)capsPtr; myCapsW->wMid = 0xffff; @@ -220,8 +199,6 @@ HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) { myCapsW->wChannelMask = 0xffff; myCapsW->dwSupport = 0; return MMSYSERR_NOERROR; - - break; case (sizeof(MIDIOUTCAPS2A)): myCaps2A = (MIDIOUTCAPS2A *)capsPtr; myCaps2A->wMid = 0xffff; @@ -237,7 +214,6 @@ HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) { myCaps2A->ProductGuid = CLSID_tim_synth; myCaps2A->NameGuid = CLSID_tim_synth; return MMSYSERR_NOERROR; - case (sizeof(MIDIOUTCAPS2W)): myCaps2W = (MIDIOUTCAPS2W *)capsPtr; myCaps2W->wMid = 0xffff; @@ -253,249 +229,104 @@ HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) { myCaps2W->ProductGuid = CLSID_tim_synth; myCaps2W->NameGuid = CLSID_tim_synth; return MMSYSERR_NOERROR; - default: return MMSYSERR_ERROR; - - break; } } - -struct evbuf_t{ - UINT uMsg; - double event_time; - DWORD dwParam1; - DWORD dwParam2; - int exlen; - char *sysexbuffer; -}; -#define EVBUFF_SIZE 512 -static struct evbuf_t evbuf[EVBUFF_SIZE]; -static UINT evbwpoint=0; -static UINT evbrpoint=0; -static UINT evbsysexpoint; - -int timsyn_buf_check(void){ - int retval; - EnterCriticalSection(&mim_section); - retval = (evbrpoint != evbwpoint) ? ~0 : 0; - LeaveCriticalSection(&mim_section); - return retval; -} - -int timsyn_play_some_data(void){ - UINT uMsg; - DWORD dwParam1; - DWORD dwParam2; - - UINT evbpoint; - MIDIHDR *IIMidiHdr; - int exlen; - char *sysexbuffer; - int played; - double event_time; - - played=0; - if( !timsyn_buf_check() ){ - played=~0; - return played; - } - do{ - EnterCriticalSection(&mim_section); - evbpoint=evbrpoint; - if (++evbrpoint >= EVBUFF_SIZE) - evbrpoint -= EVBUFF_SIZE; - - uMsg=evbuf[evbpoint].uMsg; - dwParam1=evbuf[evbpoint].dwParam1; - dwParam2=evbuf[evbpoint].dwParam2; - event_time=evbuf[evbpoint].event_time; - - LeaveCriticalSection(&mim_section); - exlen=evbuf[evbpoint].exlen; - sysexbuffer=evbuf[evbpoint].sysexbuffer; - switch (uMsg) { - case MODM_DATA: - rtsyn_play_one_data (0, dwParam1, event_time); - break; - case MODM_LONGDATA: -#ifdef DEBUG - FILE * logfile; - logfile = fopen("c:\\dbglog2.log","at"); - if(logfile!=NULL) { - for(int i = 0 ; i < exlen ; i++) - fprintf(logfile,"%x ", sysexbuffer[i]); - fprintf(logfile,"\n"); - } - fclose(logfile); +#include <stdio.h> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#ifdef _WIN32 +#define alloca _alloca #endif - rtsyn_play_one_sysex (sysexbuffer,exlen, event_time); - free(sysexbuffer); - break; - } - }while(timsyn_buf_check()); - return played; -} unsigned __stdcall threadfunc(LPVOID lpV){ while(stop_thread == 0){ Sleep(1); - //EnterCriticalSection(&mim_section); - timsyn_play_some_data(); + //timsyn_play_some_data(); + EnterCriticalSection(&mim_section); rtsyn_play_calculate(); - //LeaveCriticalSection(&mim_section); - } - stop_thread=0; - _endthreadex(0); - return 0; -} - -unsigned __stdcall threadfunc2(LPVOID lpV){ - int argc,i; - char *argv[2]; - HANDLE hThread = NULL; - unsigned int thrdaddr; - int opend=0; - ; - while(opend == 0) { - Sleep(100); - argc = 2; - argv[0] = strdup("timidity"); - argv[1] = strdup("-iW"); - if ( 0 == timiwp_main_ini(argc, argv)){ - rtsyn_init(); - hThread=(HANDLE)_beginthreadex(NULL,0,threadfunc,0,0,&thrdaddr); - SetPriorityClass(hThread, REALTIME_PRIORITY_CLASS); - SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); - opend = 1; - } - for(i = 0 ; i < 2 ; i++) free(argv[i]); - } - hCalcThread = hThread; - - while(stop_rtthread == 0){ - Sleep(10); + LeaveCriticalSection(&mim_section); } - rtsyn_stop_playing(); rtsyn_close(); timiwp_main_close(); - stop_rtthread=0; + stop_thread=0; _endthreadex(0); return 0; } STDAPI_(LONG) modMessage(UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){ - unsigned int thrdaddr; - DWORD tstate; - int OCount; - DWORD Exit; - - MIDIHDR *IIMidiHdr; - UINT evbpoint; - - int exlen = 0; - char *sysexbuffer = NULL ; - + MIDIHDR *IIMidiHdr; switch (uMsg) { case MODM_OPEN: OpenCount++; if ( OpenCount == 1 && modm_closed == 1 ){ + unsigned thrdaddr; + const char *argv_readOnly[] = {"timidity", "iW", "-B3"}; + int argc = ARRAY_SIZE(argv_readOnly),i; + int opend=0; + char **argv = (char **)alloca(argc * sizeof(char *)); + processPriority = GetPriorityClass(GetCurrentProcess()); SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); - hRtsynThread=(HANDLE)_beginthreadex(NULL,0,threadfunc2,0,0,&thrdaddr); + //AllocConsole(); + //freopen("CONOUT$", "wb", stdout); + for (i = 0; i < argc; i++) + argv[i] = strdup(argv_readOnly[i]); + while(TRUE) { + if (timiwp_main_ini(argc, argv) == 0){ + rtsyn_init(); + opend = 1; + break; + } + Sleep(100); + } + for(i = 0 ; i < argc; i++) free(argv[i]); + hRtsynThread=(HANDLE)_beginthreadex(NULL,0,threadfunc,0,0,&thrdaddr); + SetPriorityClass(hRtsynThread, REALTIME_PRIORITY_CLASS); + SetThreadPriority(hRtsynThread, THREAD_PRIORITY_TIME_CRITICAL); modm_closed = 0; } SetPriorityClass(GetCurrentProcess(), processPriority); return MMSYSERR_NOERROR; - break; case MODM_PREPARE: return MMSYSERR_NOTSUPPORTED; - break; case MODM_UNPREPARE: return MMSYSERR_NOTSUPPORTED; - break; case MODM_GETDEVCAPS: return modGetCaps((PVOID)dwParam1, dwParam2); - break; case MODM_LONGDATA: + { + double event_time = get_current_calender_time(); IIMidiHdr = (MIDIHDR *)dwParam1; if( !(IIMidiHdr->dwFlags & MHDR_PREPARED) ) return MIDIERR_UNPREPARED; - IIMidiHdr->dwFlags &= ~MHDR_DONE; - IIMidiHdr->dwFlags |= MHDR_INQUEUE; - IIMidiHdr = (MIDIHDR *) dwParam1; - exlen=(int)IIMidiHdr->dwBufferLength; - if( NULL == (sysexbuffer = (char *)malloc(exlen * sizeof(char)))){ - return MMSYSERR_NOMEM; - }else{ - memcpy(sysexbuffer,IIMidiHdr->lpData,exlen); -#ifdef DEBUG - FILE * logfile; - logfile = fopen("c:\\dbglog.log","at"); - if(logfile!=NULL) { - fprintf(logfile,"sysex %d byete\n", exlen); - for(int i = 0 ; i < exlen ; i++) - fprintf(logfile,"%x ", sysexbuffer[i]); - fprintf(logfile,"\n"); - } - fclose(logfile); -#endif - } IIMidiHdr->dwFlags &= ~MHDR_INQUEUE; IIMidiHdr->dwFlags |= MHDR_DONE; + EnterCriticalSection(&mim_section); + rtsyn_play_one_sysex(IIMidiHdr->lpData, IIMidiHdr->dwBufferLength, event_time); + LeaveCriticalSection(&mim_section); + return MMSYSERR_NOERROR; + } case MODM_DATA: + { + double event_time = get_current_calender_time(); EnterCriticalSection(&mim_section); - evbpoint = evbwpoint; - if (++evbwpoint >= EVBUFF_SIZE) - evbwpoint -= EVBUFF_SIZE; - evbuf[evbpoint].uMsg = uMsg; - evbuf[evbpoint].event_time = get_current_calender_time(); - evbuf[evbpoint].dwParam1 = dwParam1; - evbuf[evbpoint].dwParam2 = dwParam2; - evbuf[evbpoint].exlen=exlen; - evbuf[evbpoint].sysexbuffer=sysexbuffer; + rtsyn_play_one_data (0, dwParam1, event_time); LeaveCriticalSection(&mim_section); return MMSYSERR_NOERROR; - break; + } case MODM_GETNUMDEVS: return 0x1; - break; case MODM_CLOSE: - if ( stop_rtthread != 0 || stop_thread != 0 ) return MIDIERR_STILLPLAYING; + if ( stop_thread != 0 ) return MIDIERR_STILLPLAYING; --OpenCount; -/* - if( ( OpenCount == 0) && (play_mode->id_character != 'd') ){ - int maxloop=100; - - stop_thread = 1; - while( stop_thread != 0 && maxloop-- > 0) Sleep(10); - if(stop_thread == 0) { - stop_rtthread = 1; - while( stop_rtthread != 0 && maxloop-- > 0) Sleep(10); - } - if(stop_thread != 0) TerminateThread(hCalcThread, FALSE); - if(stop_rtthread != 0) TerminateThread(hRtsynThread, FALSE); - - if(maxloop == 0){ - DeleteCriticalSection(&mim_section); - InitializeCriticalSection(&mim_section); - } - stop_rtthread = 0; - stop_thread = 0; - CloseHandle(hRtsynThread); - CloseHandle(hCalcThread); - SetPriorityClass(GetCurrentProcess(), processPriority); - modm_closed=1; - }else{ -*/ - if(OpenCount < 0){ - OpenCount = 0; - return MMSYSERR_NOTENABLED; - } -// } + if(OpenCount < 0){ + OpenCount = 0; + return MMSYSERR_NOTENABLED; + } return MMSYSERR_NOERROR; break; default: diff --git a/windrv/timiditydrv.def b/windrv/timiditydrv.def index 572d14c0..452850b6 100755 --- a/windrv/timiditydrv.def +++ b/windrv/timiditydrv.def @@ -1,7 +1,7 @@ -LIBRARY "timiditydrv.dll" - EXETYPE NT +LIBRARY "timiditydrv.dll" + EXPORTS - DllCanUnloadNow PRIVATE + DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE -- GitLab