2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #define _WIN32_WINNT 0x0400
30 unsigned long _beginthreadex( void *security, unsigned stack_size,
31 unsigned ( __stdcall *start_address )( void * ), void *arglist,
32 unsigned initflag, unsigned *thrdaddr );
34 void _endthreadex( unsigned retval );
45 #include "timiditydrv.h"
48 /* Use XP SDK's mmsystem.h. mingw's lacks some definitions */
49 #include "mmsystem.h" //From SDK (Digital mars can't use SDK's mmsystem.h)
51 #if defined(__MINGW32__) || defined(__WATCOMC__)
52 #define __IID_DEFINED__ 1
54 #include "timiditydrv_i.c"
55 #include "mmreg.h" //Fom SDK
62 #include "timiwp_timidity.h"
67 static volatile int OpenCount = 0;
68 static volatile int modm_closed = 1;
70 static CRITICAL_SECTION mim_section;
71 static volatile int stop_thread = 0;
72 static volatile int stop_rtthread = 0;
73 static HANDLE hCalcThread = NULL;
74 static HANDLE hRtsynThread = NULL;
77 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ){
78 if (fdwReason == DLL_PROCESS_ATTACH){
79 DisableThreadLibraryCalls(hinstDLL);
80 }else if(fdwReason == DLL_PROCESS_DETACH){
86 STDAPI DllCanUnloadNow(void){
90 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv){
94 STDAPI DllRegisterServer(void){
98 STDAPI DllUnregisterServer(void)
104 //unsigned __stdcall threadfunc2(LPVOID lpV);
105 STDAPI_(LONG) DefDriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2);
107 STDAPI_(LONG) DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2){
111 DeleteCriticalSection(&mim_section);
114 InitializeCriticalSection(&mim_section);
120 case DRV_EXITSESSION:
125 case DRV_QUERYCONFIGURE:
129 return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2);
132 return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2);
135 HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) {
136 MIDIOUTCAPSA * myCapsA;
137 MIDIOUTCAPSW * myCapsW;
139 MIDIOUTCAPS2A * myCaps2A;
140 MIDIOUTCAPS2W * myCaps2W;
143 CHAR synthName[] = "Timidity++ Driver\0";
144 WCHAR synthNameW[] = L"Timidity++ Driver\0";
149 case (sizeof(MIDIOUTCAPSA)):
150 myCapsA = (MIDIOUTCAPSA *)capsPtr;
151 myCapsA->wMid = MM_UNMAPPED;
152 myCapsA->wPid = MM_MPU401_MIDIOUT;
153 memcpy(myCapsA->szPname, synthName, sizeof(synthName));
154 myCapsA->wTechnology = MOD_MIDIPORT;
155 myCapsA->vDriverVersion = 0x0090;
156 myCapsA->wVoices = 0;
158 myCapsA->wChannelMask = 0xffff;
159 myCapsA->dwSupport = 0;
160 return MMSYSERR_NOERROR;
163 case (sizeof(MIDIOUTCAPSW)):
164 myCapsW = (MIDIOUTCAPSW *)capsPtr;
165 myCapsW->wMid = MM_UNMAPPED;
166 myCapsW->wPid = MM_MPU401_MIDIOUT;
167 memcpy(myCapsW->szPname, synthNameW, sizeof(synthNameW));
168 myCapsW->wTechnology = MOD_MIDIPORT;
169 myCapsW->vDriverVersion = 0x0090;
170 myCapsW->wVoices = 0;
172 myCapsW->wChannelMask = 0xffff;
173 myCapsW->dwSupport = 0;
174 return MMSYSERR_NOERROR;
178 case (sizeof(MIDIOUTCAPS2A)):
179 myCaps2A = (MIDIOUTCAPS2A *)capsPtr;
180 myCaps2A->wMid = MM_UNMAPPED;
181 myCaps2A->wPid = MM_MPU401_MIDIOUT;
182 memcpy(myCaps2A->szPname, synthName, sizeof(synthName));
183 myCaps2A->wTechnology = MOD_MIDIPORT;
184 myCaps2A->vDriverVersion = 0x0090;
185 myCaps2A->wVoices = 0;
186 myCaps2A->wNotes = 0;
187 myCaps2A->wChannelMask = 0xffff;
188 myCaps2A->dwSupport = 0;
189 myCaps2A->ManufacturerGuid = CLSID_tim_synth;
190 myCaps2A->ProductGuid = CLSID_tim_synth;
191 myCaps2A->NameGuid = CLSID_tim_synth;
192 return MMSYSERR_NOERROR;
194 case (sizeof(MIDIOUTCAPS2W)):
195 myCaps2W = (MIDIOUTCAPS2W *)capsPtr;
196 myCaps2W->wMid = MM_UNMAPPED;
197 myCaps2W->wPid = MM_MPU401_MIDIOUT;
198 memcpy(myCaps2W->szPname, synthNameW, sizeof(synthNameW));
199 myCaps2W->wTechnology = MOD_MIDIPORT;
200 myCaps2W->vDriverVersion = 0x0090;
201 myCaps2W->wVoices = 0;
202 myCaps2W->wNotes = 0;
203 myCaps2W->wChannelMask = 0xffff;
204 myCaps2W->dwSupport = 0;
205 myCaps2W->ManufacturerGuid = CLSID_tim_synth;
206 myCaps2W->ProductGuid = CLSID_tim_synth;
207 myCaps2W->NameGuid = CLSID_tim_synth;
208 return MMSYSERR_NOERROR;
212 return MMSYSERR_ERROR;
228 #define EVBUFF_SIZE 512
229 static struct evbuf_t evbuf[EVBUFF_SIZE];
230 static UINT evbwpoint=0;
231 static UINT evbrpoint=0;
232 static UINT evbsysexpoint;
234 int timsyn_buf_check(void){
236 EnterCriticalSection(&mim_section);
237 retval = (evbrpoint != evbwpoint) ? ~0 : 0;
238 LeaveCriticalSection(&mim_section);
242 int timsyn_play_some_data(void){
255 if( !timsyn_buf_check() ){
260 EnterCriticalSection(&mim_section);
262 if (++evbrpoint >= EVBUFF_SIZE)
263 evbrpoint -= EVBUFF_SIZE;
265 uMsg=evbuf[evbpoint].uMsg;
266 dwParam1=evbuf[evbpoint].dwParam1;
267 dwParam2=evbuf[evbpoint].dwParam2;
268 event_time=evbuf[evbpoint].event_time;
270 LeaveCriticalSection(&mim_section);
271 exlen=evbuf[evbpoint].exlen;
272 sysexbuffer=evbuf[evbpoint].sysexbuffer;
275 rtsyn_play_one_data (0, dwParam1, event_time);
280 logfile = fopen("c:\\dbglog2.log","at");
282 for(int i = 0 ; i < exlen ; i++)
283 fprintf(logfile,"%x ", sysexbuffer[i]);
284 fprintf(logfile,"\n");
288 rtsyn_play_one_sysex (sysexbuffer,exlen, event_time);
292 }while(timsyn_buf_check());
296 unsigned __stdcall threadfunc(LPVOID lpV){
297 while(stop_thread == 0){
299 //EnterCriticalSection(&mim_section);
300 timsyn_play_some_data();
301 rtsyn_play_calculate();
302 //LeaveCriticalSection(&mim_section);
309 unsigned __stdcall threadfunc2(LPVOID lpV){
312 HANDLE hThread = NULL;
313 unsigned int thrdaddr;
319 argv[0] = strdup("timidity");
320 argv[1] = strdup("-iW");
321 if ( 0 == timiwp_main_ini(argc, argv)){
323 hThread=(HANDLE)_beginthreadex(NULL,0,threadfunc,0,0,&thrdaddr);
324 SetPriorityClass(hThread, REALTIME_PRIORITY_CLASS);
325 SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
328 for(i = 0 ; i < 2 ; i++) free(argv[i]);
330 hCalcThread = hThread;
332 while(stop_rtthread == 0){
336 rtsyn_stop_playing();
344 STDAPI_(LONG) modMessage(UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){
345 unsigned int thrdaddr;
352 static DWORD processPriority;
355 char *sysexbuffer = NULL ;
361 if ( OpenCount == 1 && modm_closed == 1 ){
362 processPriority = GetPriorityClass(GetCurrentProcess());
363 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
364 hRtsynThread=(HANDLE)_beginthreadex(NULL,0,threadfunc2,0,0,&thrdaddr);
369 SetPriorityClass(GetCurrentProcess(), processPriority);
370 return MMSYSERR_NOERROR;
373 return MMSYSERR_NOTSUPPORTED;
376 return MMSYSERR_NOTSUPPORTED;
378 case MODM_GETDEVCAPS:
379 return modGetCaps((PVOID)dwParam1, dwParam2);
382 IIMidiHdr = (MIDIHDR *)dwParam1;
383 if( !(IIMidiHdr->dwFlags & MHDR_PREPARED) ) return MIDIERR_UNPREPARED;
384 IIMidiHdr->dwFlags &= ~MHDR_DONE;
385 IIMidiHdr->dwFlags |= MHDR_INQUEUE;
386 IIMidiHdr = (MIDIHDR *) dwParam1;
387 exlen=(int)IIMidiHdr->dwBufferLength;
388 if( NULL == (sysexbuffer = (char *)malloc(exlen * sizeof(char)))){
391 memcpy(sysexbuffer,IIMidiHdr->lpData,exlen);
394 logfile = fopen("c:\\dbglog.log","at");
396 fprintf(logfile,"sysex %d byete\n", exlen);
397 for(int i = 0 ; i < exlen ; i++)
398 fprintf(logfile,"%x ", sysexbuffer[i]);
399 fprintf(logfile,"\n");
404 IIMidiHdr->dwFlags &= ~MHDR_INQUEUE;
405 IIMidiHdr->dwFlags |= MHDR_DONE;
407 EnterCriticalSection(&mim_section);
408 evbpoint = evbwpoint;
409 if (++evbwpoint >= EVBUFF_SIZE)
410 evbwpoint -= EVBUFF_SIZE;
411 evbuf[evbpoint].uMsg = uMsg;
412 evbuf[evbpoint].event_time = get_current_calender_time();
413 evbuf[evbpoint].dwParam1 = dwParam1;
414 evbuf[evbpoint].dwParam2 = dwParam2;
415 evbuf[evbpoint].exlen=exlen;
416 evbuf[evbpoint].sysexbuffer=sysexbuffer;
417 LeaveCriticalSection(&mim_section);
418 return MMSYSERR_NOERROR;
420 case MODM_GETNUMDEVS:
424 if ( stop_rtthread != 0 || stop_thread != 0 ) return MIDIERR_STILLPLAYING;
430 while( stop_thread != 0 && maxloop-- > 0) Sleep(1);
431 if(stop_thread == 0) {
433 while( stop_rtthread != 0 && maxloop-- > 0) Sleep(1);
435 if(stop_rtthread != 0) TerminateThread(hRtsynThread, GetExitCodeThread(hRtsynThread,&Exit));
436 if(stop_thread != 0) TerminateThread(hCalcThread, GetExitCodeThread(hCalcThread,&Exit));
438 DeleteCriticalSection(&mim_section);
439 InitializeCriticalSection(&mim_section);
443 CloseHandle(hRtsynThread);
444 CloseHandle(hCalcThread);
445 SetPriorityClass(GetCurrentProcess(), processPriority);
450 return MMSYSERR_NOTENABLED;
453 return MMSYSERR_NOERROR;
456 return MMSYSERR_NOERROR;