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