OSDN Git Service

* configure.in doc/ja_JP.eucJP/README.w32
[timidity41/timidity41.git] / windrv / timiditydrv.cpp
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
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 //#define DEBUG
22 #define STRICT
23 #ifndef _WIN32_WINNT
24 #define _WIN32_WINNT 0x0400
25 #endif
26
27 #include <process.h>
28 #if __DMC__
29 extern "C" 
30 unsigned long _beginthreadex( void *security, unsigned stack_size,
31                 unsigned ( __stdcall *start_address )( void * ), void *arglist,
32                 unsigned initflag, unsigned *thrdaddr );
33 extern "C" 
34 void _endthreadex( unsigned retval );
35 #endif
36
37 #ifdef DEBUG
38 #include <stdio.h>
39 #endif
40
41 #if __DMC__
42 #include <objbase.h>
43 #endif
44 #include <initguid.h>
45 #include "timiditydrv.h"
46
47 #include "mmddk.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)
50
51 #if defined(__MINGW32__) || defined(__WATCOMC__)
52 #define __IID_DEFINED__ 1
53 #endif
54 #include "timiditydrv_i.c"
55 #include "mmreg.h"      //Fom SDK
56
57 extern "C" {
58 #include "config.h"
59 #include "sysdep.h"
60 }
61
62 #include "timiwp_timidity.h"
63
64
65 LONG driverCount;
66
67 static volatile int OpenCount = 0;
68 static volatile int modm_closed = 1;
69
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;
75
76 extern "C" 
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){
81                 ;
82         }
83         return TRUE;    
84 }
85
86 STDAPI DllCanUnloadNow(void){
87         return S_OK;
88 }
89
90 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv){
91         return S_OK;
92 }
93
94 STDAPI DllRegisterServer(void){
95         return S_OK;
96 }
97
98 STDAPI DllUnregisterServer(void)
99 {
100         return S_OK;
101 }
102
103
104 //unsigned __stdcall threadfunc2(LPVOID lpV);
105 STDAPI_(LONG) DefDriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2);
106
107 STDAPI_(LONG) DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg, LONG lParam1, LONG lParam2){
108  
109         switch(msg) {
110         case DRV_REMOVE:
111                 DeleteCriticalSection(&mim_section);
112                 return 1;
113         case DRV_LOAD:
114                 InitializeCriticalSection(&mim_section);
115                 return 1;
116         case DRV_CLOSE:
117         case DRV_CONFIGURE:
118         case DRV_DISABLE:
119         case DRV_ENABLE:
120         case DRV_EXITSESSION:
121         case DRV_FREE:
122         case DRV_INSTALL:
123         case DRV_OPEN:
124         case DRV_POWER:
125         case DRV_QUERYCONFIGURE:
126         default:
127                 return 1;
128                 break;
129                 return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2);
130                 break;
131         }
132         return DefDriverProc(dwDriverId, hdrvr, msg, lParam1, lParam2);
133 }
134
135 HRESULT modGetCaps(PVOID capsPtr, DWORD capsSize) {
136         MIDIOUTCAPSA * myCapsA;
137         MIDIOUTCAPSW * myCapsW;
138 #ifndef __DMC__
139         MIDIOUTCAPS2A * myCaps2A;
140         MIDIOUTCAPS2W * myCaps2W;
141 #endif
142
143         CHAR synthName[] = "Timidity++ Driver\0";
144         WCHAR synthNameW[] = L"Timidity++ Driver\0";
145
146
147         
148         switch (capsSize) {
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;
157                 myCapsA->wNotes = 0;
158                 myCapsA->wChannelMask = 0xffff;
159                 myCapsA->dwSupport = 0;
160                 return MMSYSERR_NOERROR;
161
162                 break;
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;
171                 myCapsW->wNotes = 0;
172                 myCapsW->wChannelMask = 0xffff;
173                 myCapsW->dwSupport = 0;
174                 return MMSYSERR_NOERROR;
175
176                 break;
177 #ifndef __DMC__
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;
193
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;
209 #endif
210
211         default:
212                 return MMSYSERR_ERROR;
213
214                 break;
215         }
216
217 }
218
219
220 struct evbuf_t{
221         UINT uMsg;
222         double event_time;
223         DWORD   dwParam1;
224         DWORD   dwParam2;
225         int exlen;
226         char *sysexbuffer;
227 };
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;
233
234 int timsyn_buf_check(void){
235         int retval;
236         EnterCriticalSection(&mim_section);
237         retval = (evbrpoint != evbwpoint) ? ~0 :  0;
238         LeaveCriticalSection(&mim_section);
239         return retval;
240 }
241
242 int timsyn_play_some_data(void){
243         UINT uMsg;
244         DWORD   dwParam1;
245         DWORD   dwParam2;
246         
247         UINT evbpoint;
248         MIDIHDR *IIMidiHdr;
249         int exlen;
250         char *sysexbuffer;
251         int played;
252         double event_time;
253                 
254         played=0;
255                 if( !timsyn_buf_check() ){ 
256                         played=~0;
257                         return played;
258                 }
259                 do{
260                         EnterCriticalSection(&mim_section);
261                         evbpoint=evbrpoint;
262                         if (++evbrpoint >= EVBUFF_SIZE)
263                                         evbrpoint -= EVBUFF_SIZE;
264
265                         uMsg=evbuf[evbpoint].uMsg;
266                         dwParam1=evbuf[evbpoint].dwParam1;
267                         dwParam2=evbuf[evbpoint].dwParam2;
268                         event_time=evbuf[evbpoint].event_time;
269                         
270                         LeaveCriticalSection(&mim_section);
271                     exlen=evbuf[evbpoint].exlen;
272                         sysexbuffer=evbuf[evbpoint].sysexbuffer;
273                         switch (uMsg) {
274                         case MODM_DATA:
275                                 rtsyn_play_one_data (0, dwParam1, event_time);
276                                 break;
277                         case MODM_LONGDATA:
278 #ifdef DEBUG
279         FILE * logfile;
280         logfile = fopen("c:\\dbglog2.log","at");
281         if(logfile!=NULL) {
282                 for(int i = 0 ; i < exlen ; i++)
283                         fprintf(logfile,"%x ", sysexbuffer[i]);
284                 fprintf(logfile,"\n");
285         }
286         fclose(logfile);
287 #endif
288                                 rtsyn_play_one_sysex (sysexbuffer,exlen, event_time);
289                                 free(sysexbuffer);
290                                 break;
291                         }
292                 }while(timsyn_buf_check());     
293         return played;
294 }
295
296 unsigned __stdcall threadfunc(LPVOID lpV){
297         while(stop_thread == 0){
298                 Sleep(1);
299                 //EnterCriticalSection(&mim_section);
300                 timsyn_play_some_data();
301                 rtsyn_play_calculate();
302                 //LeaveCriticalSection(&mim_section);
303         }
304         stop_thread=0;
305         _endthreadex(0);
306         return 0;
307 }
308
309 unsigned __stdcall threadfunc2(LPVOID lpV){
310         int argc,i;
311         char *argv[2];
312         HANDLE hThread = NULL;
313         unsigned int thrdaddr;
314         int opend=0;
315         ;
316         while(opend == 0) {
317                 Sleep(100);
318                 argc = 2;
319                 argv[0] = strdup("timidity");
320                 argv[1] = strdup("-iW");
321                 if ( 0 == timiwp_main_ini(argc, argv)){
322                         rtsyn_init();
323                         hThread=(HANDLE)_beginthreadex(NULL,0,threadfunc,0,0,&thrdaddr);
324                         SetPriorityClass(hThread, REALTIME_PRIORITY_CLASS);
325                         SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
326                         opend = 1;
327                 }
328                 for(i = 0 ; i < 2 ; i++) free(argv[i]);
329         }
330         hCalcThread = hThread;
331         
332         while(stop_rtthread == 0){
333                 Sleep(10);
334         }
335
336         rtsyn_stop_playing();
337         rtsyn_close();
338         timiwp_main_close();
339         stop_rtthread=0;
340         _endthreadex(0);
341         return 0;
342 }
343
344 STDAPI_(LONG) modMessage(UINT uDeviceID, UINT uMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2){
345         unsigned int thrdaddr;
346         DWORD tstate;
347         int OCount;
348         DWORD Exit;
349         
350         MIDIHDR *IIMidiHdr;     
351         UINT evbpoint;
352         static DWORD processPriority;
353         
354         int exlen = 0;
355         char *sysexbuffer = NULL ;
356
357         
358         switch (uMsg) {
359         case MODM_OPEN:
360                 OpenCount++;
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);
365                         modm_closed = 0;
366                 }
367                 
368         
369                 SetPriorityClass(GetCurrentProcess(), processPriority);
370                 return MMSYSERR_NOERROR;
371                 break;
372         case MODM_PREPARE:
373                 return MMSYSERR_NOTSUPPORTED;
374                 break;
375         case MODM_UNPREPARE:
376                 return MMSYSERR_NOTSUPPORTED;
377                 break;
378         case MODM_GETDEVCAPS:
379                 return modGetCaps((PVOID)dwParam1, dwParam2);
380                 break;
381         case MODM_LONGDATA:
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)))){
389                         exlen = 0;
390                 }else{
391                         memcpy(sysexbuffer,IIMidiHdr->lpData,exlen);
392 #ifdef DEBUG
393         FILE * logfile;
394         logfile = fopen("c:\\dbglog.log","at");
395         if(logfile!=NULL) {
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");
400         }
401         fclose(logfile);
402 #endif
403                 }
404                 IIMidiHdr->dwFlags &= ~MHDR_INQUEUE;
405                 IIMidiHdr->dwFlags |= MHDR_DONE;
406         case MODM_DATA:
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;
419                 break;          
420         case MODM_GETNUMDEVS:
421                 return 0x1;
422                 break;
423         case MODM_CLOSE:
424                 if ( stop_rtthread != 0 || stop_thread != 0 ) return MIDIERR_STILLPLAYING;
425                 --OpenCount;
426                 if( OpenCount == 1){
427                         int maxloop=1000;
428                         
429                         stop_thread = 1;
430                         while( stop_thread != 0 && maxloop-- > 0) Sleep(1);
431                         if(stop_thread == 0) {
432                                 stop_rtthread = 1;
433                                 while( stop_rtthread != 0 && maxloop-- > 0) Sleep(1);
434                         }
435                         if(stop_rtthread != 0) TerminateThread(hRtsynThread, GetExitCodeThread(hRtsynThread,&Exit));
436                         if(stop_thread != 0) TerminateThread(hCalcThread, GetExitCodeThread(hCalcThread,&Exit));
437                         if(maxloop == 0){
438                                 DeleteCriticalSection(&mim_section);
439                                 InitializeCriticalSection(&mim_section);
440                         }
441                         stop_rtthread = 0;
442                         stop_thread = 0;
443                         CloseHandle(hRtsynThread);
444                         CloseHandle(hCalcThread);
445                         SetPriorityClass(GetCurrentProcess(), processPriority);
446                         modm_closed=1;
447                 }else{ 
448                         if(OpenCount < 0){
449                                 OpenCount = 0;
450                                 return MMSYSERR_NOTENABLED;
451                         }
452                 }
453                 return MMSYSERR_NOERROR;
454                 break;
455         default:
456                 return MMSYSERR_NOERROR;
457                 break;
458         }
459 }
460