1 /*
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>
5 
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.
10 
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.
15 
foo(map<char *,int> & m)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
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif /* HAVE_CONFIG_H */
24 //#define DEBUG
25 #define STRICT
26 #ifndef _WIN32_WINNT
27 #define _WIN32_WINNT 0x0400
28 #endif
29 
30 #if __DMC__
31 unsigned long _beginthreadex( void *security, unsigned stack_size,
32 		unsigned ( __stdcall *start_address )( void * ), void *arglist,
33 		unsigned initflag, unsigned *thrdaddr );
34 void _endthreadex( unsigned retval );
35 #endif
36 
37 #ifdef DEBUG
38 #include <stdio.h>
39 #endif
40 
41 #include <windows.h>
42 #include "mmddk.h"
43 #include <mmsystem.h>
f()44 #if defined(__DMC__)
45 //following codes are from wine's mmsystem.h
46 typedef struct tagMIDIOUTCAPS2A {
47     WORD	wMid;
48     WORD	wPid;
49     MMVERSION	vDriverVersion;
50     CHAR	szPname[MAXPNAMELEN];
51     WORD	wTechnology;
52     WORD	wVoices;
53     WORD	wNotes;
54     WORD	wChannelMask;
55     DWORD	dwSupport;
56     GUID	ManufacturerGuid;
57     GUID	ProductGuid;
58     GUID	NameGuid;
59 } MIDIOUTCAPS2A, *LPMIDIOUTCAPS2A;
60 
61 typedef struct tagMIDIOUTCAPS2W {
62     WORD	wMid;
63     WORD	wPid;
64     MMVERSION	vDriverVersion;
65     WCHAR	szPname[MAXPNAMELEN];
66     WORD	wTechnology;
67     WORD	wVoices;
68     WORD	wNotes;
69     WORD	wChannelMask;
70     DWORD	dwSupport;
71     GUID	ManufacturerGuid;
72     GUID	ProductGuid;
73     GUID	NameGuid;
74 } MIDIOUTCAPS2W, *LPMIDIOUTCAPS2W;
75 
76 //DECL_WINELIB_TYPE_AW(MIDIOUTCAPS2)
77 //DECL_WINELIB_TYPE_AW(LPMIDIOUTCAPS2)
78 #endif
79 
80 #include <process.h>
81 
82 // GUID definitions from wine's guiddef.h
83 #ifndef GUID_DEFINED
84 #define GUID_DEFINED
85 typedef struct _GUID
86 {
87     unsigned long  Data1;
88     unsigned short Data2;
89     unsigned short Data3;
90     unsigned char  Data4[ 8 ];
91 } GUID;
92 
93 #endif
94 //GUID numbers are generated by timiditydrv.idl
95 const GUID CLSID_tim_synth = {0x0FEC4C35,0xA705,0x41d7,{0xA3,0xBB,0xD5,0x87,0xA2,0x31,0x04,0x5A}};
96 
97 #include "config.h"
98 #include "sysdep.h"
99 #include "output.h"
100 
101 #include "timiwp_timidity.h"
102 
103 static volatile int OpenCount = 0;
104 static volatile int modm_closed = 1;
105 
106 static HDRVR hdrvrInstance;
107 static MIDIOPENDESC mid_desc;
108 static DWORD dwOpenFlags;
109 
110 static CRITICAL_SECTION mim_section;
111 static volatile int stop_thread = 0;
112 static HANDLE hRtsynThread = NULL;
113 static DWORD processPriority;
114 
115 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ){
116 	if (fdwReason == DLL_PROCESS_ATTACH){
117 		DisableThreadLibraryCalls(hinstDLL);
118 	}else if(fdwReason == DLL_PROCESS_DETACH){
119 		;
120 	}
121 	return TRUE;
122 }
123 
124 STDAPI DllCanUnloadNow(void){
125 	return S_OK;
126 }
127 
128 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv){
129 	return S_OK;
130 }
131 
132 STDAPI DllRegisterServer(void){
133 	return S_OK;
134 }
135 
136 STDAPI DllUnregisterServer(void)
137 {
138 	return S_OK;
139 }
140 
141 STDAPI_(LRESULT) DriverProc(DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, LPARAM lParam1, LPARAM lParam2){
142 	switch(msg) {
143 	case DRV_OPEN:
144 		hdrvrInstance = hdrvr;
145 		return 1;
146 	case DRV_REMOVE:
147 		if (modm_closed == 0){
148 			int maxloop=500;
149 
150 			stop_thread = 1;    //why thread can't stop by this????
151 			while( stop_thread != 0 && maxloop-- > 0) Sleep(10);
152 			if(stop_thread != 0) TerminateThread(hRtsynThread, FALSE);
153 			CloseHandle(hRtsynThread);
154 			SetPriorityClass(GetCurrentProcess(), processPriority);
155 		}
156 		DeleteCriticalSection(&mim_section);
157 		return 1;
158 	case DRV_LOAD:
159 		processPriority = GetPriorityClass(GetCurrentProcess());
160 		InitializeCriticalSection(&mim_section);
161 		return 1;
162 	case DRV_CLOSE:
163 	case DRV_CONFIGURE:
164 	case DRV_DISABLE:
165 	case DRV_ENABLE:
166 	case DRV_EXITSESSION:
167 	case DRV_FREE:
168 	case DRV_INSTALL:
169 	case DRV_POWER:
170 	case DRV_QUERYCONFIGURE:
171 	default:
172 		return 1;
173 	}
174 	return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2);
175 }
176 
177 HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) {
178 	MIDIOUTCAPSA * myCapsA;
179 	MIDIOUTCAPSW * myCapsW;
180 	MIDIOUTCAPS2A * myCaps2A;
181 	MIDIOUTCAPS2W * myCaps2W;
182 
183 	CHAR synthName[] = "Timidity++ Driver\0";
184 	WCHAR synthNameW[] = L"Timidity++ Driver\0";
185 
186 	switch (capsSize) {
187 	case (sizeof(MIDIOUTCAPSA)):
188 		myCapsA = (MIDIOUTCAPSA *)capsPtr;
189 		myCapsA->wMid = 0xffff; //MM_UNMAPPED
190 		myCapsA->wPid = 0xffff; //MM_PID_UNMAPPED
191 		memcpy(myCapsA->szPname, synthName, sizeof(synthName));
192 		myCapsA->wTechnology = MOD_MIDIPORT;
193 		myCapsA->vDriverVersion = 0x0090;
194 		myCapsA->wVoices = 0;
195 		myCapsA->wNotes = 0;
196 		myCapsA->wChannelMask = 0xffff;
197 		myCapsA->dwSupport = 0;
198 		return MMSYSERR_NOERROR;
199 	case (sizeof(MIDIOUTCAPSW)):
200 		myCapsW = (MIDIOUTCAPSW *)capsPtr;
201 		myCapsW->wMid = 0xffff;
202 		myCapsW->wPid = 0xffff;
203 		memcpy(myCapsW->szPname, synthNameW, sizeof(synthNameW));
204 		myCapsW->wTechnology = MOD_MIDIPORT;
205 		myCapsW->vDriverVersion = 0x0090;
206 		myCapsW->wVoices = 0;
207 		myCapsW->wNotes = 0;
208 		myCapsW->wChannelMask = 0xffff;
209 		myCapsW->dwSupport = 0;
210 		return MMSYSERR_NOERROR;
211 	case (sizeof(MIDIOUTCAPS2A)):
212 		myCaps2A = (MIDIOUTCAPS2A *)capsPtr;
213 		myCaps2A->wMid = 0xffff;
214 		myCaps2A->wPid = 0xffff;
215 		memcpy(myCaps2A->szPname, synthName, sizeof(synthName));
216 		myCaps2A->wTechnology = MOD_MIDIPORT;
217 		myCaps2A->vDriverVersion = 0x0090;
218 		myCaps2A->wVoices = 0;
219 		myCaps2A->wNotes = 0;
220 		myCaps2A->wChannelMask = 0xffff;
221 		myCaps2A->dwSupport = 0;
222 		myCaps2A->ManufacturerGuid = CLSID_tim_synth;
223 		myCaps2A->ProductGuid = CLSID_tim_synth;
224 		myCaps2A->NameGuid = CLSID_tim_synth;
225 		return MMSYSERR_NOERROR;
226 	case (sizeof(MIDIOUTCAPS2W)):
227 		myCaps2W = (MIDIOUTCAPS2W *)capsPtr;
228 		myCaps2W->wMid = 0xffff;
229 		myCaps2W->wPid = 0xffff;
230 		memcpy(myCaps2W->szPname, synthNameW, sizeof(synthNameW));
231 		myCaps2W->wTechnology = MOD_MIDIPORT;
232 		myCaps2W->vDriverVersion = 0x0090;
233 		myCaps2W->wVoices = 0;
234 		myCaps2W->wNotes = 0;
235 		myCaps2W->wChannelMask = 0xffff;
236 		myCaps2W->dwSupport = 0;
237 		myCaps2W->ManufacturerGuid = CLSID_tim_synth;
238 		myCaps2W->ProductGuid = CLSID_tim_synth;
239 		myCaps2W->NameGuid = CLSID_tim_synth;
240 		return MMSYSERR_NOERROR;
241 	default:
242 		return MMSYSERR_ERROR;
243 	}
244 
245 }
246 
247 #include <stdio.h>
248 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
249 #ifdef _WIN32
250 #define alloca _alloca
251 #endif
252 
253 unsigned __stdcall threadfunc(LPVOID lpV){
254 	while(stop_thread == 0){
255 		Sleep(1);
256 		//timsyn_play_some_data();
257 		EnterCriticalSection(&mim_section);
258 		rtsyn_play_calculate();
259 		LeaveCriticalSection(&mim_section);
260 	}
261 	rtsyn_stop_playing();
262 	rtsyn_close();
263 	timiwp_main_close();
264 	stop_thread=0;
265 	_endthreadex(0);
266 	return 0;
267 }
268 
269 static void modCallback(UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
270 {
271 //	DWORD_PTR dwUser, dwSend1, dwSend2;
272 	DWORD_PTR dwCallback = mid_desc.dwCallback;
273 	DWORD_PTR dwInstance = mid_desc.dwInstance;
274 
275 	if (!dwCallback) {
276 	    return;
277 	}
278 /*
279 	switch (uMsg) {
280 	case MM_MOM_DONE:
281 	    dwUser = mid_desc.dwInstance;
282 	    dwSend1 = (DWORD_PTR)(mid_desc.hMidi);
283 	    dwSend2 = dwParam1;
284 	    break;
285 	default:
286 	    dwUser = mid_desc.dwInstance;
287 	    dwSend1 = (DWORD_PTR)(mid_desc.hMidi);
288 	    dwSend2 = 0;
289 	    break;
290 	}
291 */
292 
293 	switch (dwOpenFlags & CALLBACK_TYPEMASK) {
294 	case CALLBACK_NULL:
295 	    break;
296 	case CALLBACK_WINDOW:
297 	    {
298 //		HWND hWnd = (HWND)(dwCallback);
299 //		PostMessage(hWnd, uMsg, (WPARAM)(dwSend1), (LPARAM)(dwSend2));
300 		DriverCallback(dwCallback, DCB_WINDOW, hdrvrInstance, uMsg, dwInstance, dwParam1, dwParam2);
301 	    }
302 	    break;
303 	case CALLBACK_FUNCTION:
304 	    {
305 //		typedef void (CALLBACK *MIDIOUTPROC)(HMIDIOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR);
306 //		MIDIOUTPROC MidiOutProc = (MIDIOUTPROC)(dwCallback);
307 //		(*MidiOutProc)((HMIDIOUT)mid_desc.hMidi, uMsg, dwUser, dwSend1, dwSend2);
308 		DriverCallback(dwCallback, DCB_FUNCTION, hdrvrInstance, uMsg, dwInstance, dwParam1, dwParam2);
309 	    }
310 	    break;
311 	case CALLBACK_THREAD:
312 	    {
313 //		DWORD dwThread = (DWORD)(dwCallback);
314 //		PostThreadMessage(dwThread, uMsg, (WPARAM)(dwSend1), (LPARAM)(dwSend2));
315 		DriverCallback(dwCallback, DCB_TASK, hdrvrInstance, uMsg, dwInstance, dwParam1, dwParam2);
316 	    }
317 	    break;
318 	case CALLBACK_EVENT:
319 	    {
320 //		HANDLE hEvent = (HANDLE)(dwCallback);
321 //		SetEvent(hEvent);
322 		DriverCallback(dwCallback, DCB_EVENT, hdrvrInstance, uMsg, dwInstance, dwParam1, dwParam2);
323 	    }
324 	    break;
325 	default:
326 	    {
327 		/* not implemented */
328 	    }
329 	    break;
330 	}
331 
332 	return;
333 }
334 
335 STDAPI_(DWORD) modMessage(UINT uDeviceID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2){
336 	MIDIHDR *IIMidiHdr;
337 
338 	switch (uMsg) {
339 	case MODM_OPEN:
340 		OpenCount++;
341 		if ( OpenCount == 1 && modm_closed  == 1 ){
342 			unsigned thrdaddr;
343 			const char *argv_readOnly[] = {"timidity", "iW", "-B3"};
344 			int argc = ARRAY_SIZE(argv_readOnly),i;
345 			int opend=0;
346 			char **argv = (char **)alloca(argc * sizeof(char *));
347 
348 			ZeroMemory(&mid_desc, sizeof(MIDIOPENDESC));
349 			if (dwParam1) {
350 				CopyMemory(&mid_desc, (LPMIDIOPENDESC)dwParam1, sizeof(MIDIOPENDESC));
351 			}
352 			dwOpenFlags = (DWORD)dwParam2;
353 
354 			processPriority = GetPriorityClass(GetCurrentProcess());
355 			SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
356 			//AllocConsole();
357 			//freopen("CONOUT$", "wb", stdout);
358 			for (i = 0; i < argc; i++)
359 				argv[i] = strdup(argv_readOnly[i]);
360 			while(TRUE) {
361 				if (timiwp_main_ini(argc, argv) == 0){
362 					rtsyn_init();
363 					opend = 1;
364 					break;
365 				}
366 				Sleep(100);
367 			}
368 			for(i = 0 ; i < argc; i++) free(argv[i]);
369 			hRtsynThread=(HANDLE)_beginthreadex(NULL,0,threadfunc,0,0,&thrdaddr);
370 			SetPriorityClass(hRtsynThread, REALTIME_PRIORITY_CLASS);
371 			SetThreadPriority(hRtsynThread, THREAD_PRIORITY_TIME_CRITICAL);
372 			modCallback(MM_MOM_OPEN, dwParam1, dwParam2);
373 			modm_closed = 0;
374 		}
375 		SetPriorityClass(GetCurrentProcess(), processPriority);
376 		return MMSYSERR_NOERROR;
377 	case MODM_PREPARE:
378 		return MMSYSERR_NOTSUPPORTED;
379 	case MODM_UNPREPARE:
380 		return MMSYSERR_NOTSUPPORTED;
381 	case MODM_GETDEVCAPS:
382 		return modGetCaps((PVOID)dwParam1, dwParam2);
383 	case MODM_LONGDATA:
384 		{
385 		double event_time = get_current_calender_time();
386 		DWORD dwLength;
387 		IIMidiHdr = (MIDIHDR *)dwParam1;
388 		if( !(IIMidiHdr->dwFlags & MHDR_PREPARED) ) return MIDIERR_UNPREPARED;
389 		IIMidiHdr->dwFlags &= ~MHDR_INQUEUE;
390 		IIMidiHdr->dwFlags |= MHDR_DONE;
391 		EnterCriticalSection(&mim_section);
392 		dwLength = IIMidiHdr->dwBufferLength;
393 		if (IIMidiHdr->dwBytesRecorded > 0 && IIMidiHdr->dwBytesRecorded <= IIMidiHdr->dwBufferLength) {
394 			dwLength = IIMidiHdr->dwBytesRecorded;
395 		}
396 		rtsyn_play_one_sysex(IIMidiHdr->lpData, dwLength, event_time);
397 		LeaveCriticalSection(&mim_section);
398 		modCallback(MM_MOM_DONE, dwParam1, dwParam2);
399 		return MMSYSERR_NOERROR;
400 		}
401 	case MODM_DATA:
402 		{
403 		double event_time = get_current_calender_time();
404 		EnterCriticalSection(&mim_section);
405 		rtsyn_play_one_data (0, dwParam1, event_time);
406 		LeaveCriticalSection(&mim_section);
407 		return MMSYSERR_NOERROR;
408 		}
409 	case MODM_GETNUMDEVS:
410 		return 0x1;
411 	case MODM_CLOSE:
412 		if ( stop_thread != 0 ) return MIDIERR_STILLPLAYING;
413 		--OpenCount;
414 		if(OpenCount < 0){
415 			OpenCount = 0;
416 			return MMSYSERR_NOTENABLED;
417 		}
418 		modCallback(MM_MOM_CLOSE, dwParam1, dwParam2);
419 		return MMSYSERR_NOERROR;
420 		break;
421 	default:
422 		return MMSYSERR_NOERROR;
423 		break;
424 	}
425 }
426 
427