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     rtsyn_winmm.c
22         Copyright (c) 2003 Keishi Suenaga <s_keishi@mutt.freemail.ne.jp>
23 
24     I referenced following sources.
25         alsaseq_c.c - ALSA sequencer server interface
26             Copyright (c) 2000  Takashi Iwai <tiwai@suse.de>
27         readmidi.c
28 
29 */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif /* HAVE_CONFIG_H */
34 #include "interface.h"
35 
36 #ifdef __POCC__
37 #include <sys/types.h>
38 #endif //for off_t
39 
40 #include <stdio.h>
41 
42 #include <stdarg.h>
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 #include <sys/types.h>
47 #ifdef TIME_WITH_SYS_TIME
48 #include <sys/time.h>
49 #endif
50 #ifndef NO_STRING_H
51 #include <string.h>
52 #else
53 #include <strings.h>
54 #endif
55 #include <math.h>
56 #include <signal.h>
57 
58 #include "server_defs.h"
59 
60 #ifdef __W32__
61 #include <windows.h>
62 #include <mmsystem.h>
63 #endif
64 
65 #include "timidity.h"
66 #include "common.h"
67 #include "controls.h"
68 #include "instrum.h"
69 #include "playmidi.h"
70 #include "readmidi.h"
71 #include "recache.h"
72 #include "output.h"
73 #include "aq.h"
74 #include "timer.h"
75 
76 #include "rtsyn.h"
77 
78 int rtsyn_portnumber=1;
79 unsigned int portID[MAX_PORT];
80 char rtsyn_portlist[32][80];
81 int rtsyn_nportlist;
82 
83 #define MAX_EXBUF 20
84 #define BUFF_SIZE 512
85 
86 UINT InNum;
87 HMIDIIN  hMidiIn[MAX_PORT];
88 HMIDIOUT hMidiOut[MAX_PORT];
89 MIDIHDR *IMidiHdr[MAX_PORT][MAX_EXBUF];
90 
91 char sIMidiHdr[MAX_PORT][MAX_EXBUF][sizeof(MIDIHDR)];
92 char sImidiHdr_data[MAX_PORT][MAX_EXBUF][BUFF_SIZE];
93 
94 struct evbuf_t{
95 	UINT wMsg;
96 	DWORD	dwInstance;
97 	DWORD	dwParam1;
98 	DWORD	dwParam2;
99 };
100 #define EVBUFF_SIZE 512
101 struct evbuf_t evbuf[EVBUFF_SIZE];
102 UINT  evbwpoint=0;
103 UINT  evbrpoint=0;
104 UINT evbsysexpoint;
105 UINT  mvbuse=0;
106 
107 CRITICAL_SECTION mim_section;
108 
109 double mim_start_time;
110 
111 void CALLBACK MidiInProc(HMIDIIN,UINT,DWORD,DWORD,DWORD);
112 
rtsyn_get_port_list()113 void rtsyn_get_port_list(){
114 	int i;
115 	MIDIINCAPS InCaps;
116 	InNum = midiInGetNumDevs();
117 	for (i=1;i <=InNum && i<=32;i++){
118 		midiInGetDevCaps(i-1,(LPMIDIINCAPSA) &InCaps,sizeof(InCaps));
119 		sprintf(rtsyn_portlist[i-1],"%d:%s",i,(LPSTR)InCaps.szPname);
120 	}
121 	rtsyn_nportlist=i-1;
122 }
123 
rtsyn_synth_start()124 int rtsyn_synth_start(){
125 	int i;
126 	UINT port;
127 
128 #ifdef __W32__
129 	DWORD processPriority;
130 	processPriority = GetPriorityClass(GetCurrentProcess());
131 #endif
132 
133 
134 	port=0;
135 	sleep(2);
136 	for(port=0;port<rtsyn_portnumber;port++){
137 		for (i=0;i<MAX_EXBUF;i++){
138 			IMidiHdr[port][i] = (MIDIHDR *)sIMidiHdr[port][i];
139 			memset(IMidiHdr[port][i],0,sizeof(MIDIHDR));
140 			IMidiHdr[port][i]->lpData = sImidiHdr_data[port][i];
141 			memset((IMidiHdr[port][i]->lpData),0,BUFF_SIZE);
142 			IMidiHdr[port][i]->dwBufferLength = BUFF_SIZE;
143 		}
144 	}
145 	evbwpoint=0;
146 	evbrpoint=0;
147 	mvbuse=0;
148 
149 	for(port=0;port<rtsyn_portnumber;port++){
150 		midiInOpen(&hMidiIn[port],portID[port],(DWORD)MidiInProc,(DWORD)port,CALLBACK_FUNCTION);
151 		for (i=0;i<MAX_EXBUF;i++){
152 			midiInUnprepareHeader(hMidiIn[port],IMidiHdr[port][i],sizeof(MIDIHDR));
153 			midiInPrepareHeader(hMidiIn[port],IMidiHdr[port][i],sizeof(MIDIHDR));
154 			midiInAddBuffer(hMidiIn[port],IMidiHdr[port][i],sizeof(MIDIHDR));
155 		}
156 	}
157 
158 #ifdef __W32__
159 	// HACK:midiInOpen()�Ń��Z�b�g����Ă��܂����߁A�Đݒ�
160 	SetPriorityClass(GetCurrentProcess(), processPriority);
161 #endif
162 	for(port=0;port<rtsyn_portnumber;port++){
163 		if(MMSYSERR_NOERROR !=midiInStart(hMidiIn[port])){
164 			int i;
165 			for(i=0;i<port;i++){
166 				midiInStop(hMidiIn[i]);
167 				midiInReset(hMidiIn[i]);
168 				midiInClose(hMidiIn[i]);
169 			}
170 			goto winmmerror;
171 		}
172 	}
173 	mim_start_time = get_current_calender_time();
174 	InitializeCriticalSection(&mim_section);
175 	return ~0;
176 
177 winmmerror:
178 	ctl->cmsg(  CMSG_ERROR, VERB_NORMAL, "midiInStarterror\n" );
179 	return 0;
180 }
181 
rtsyn_synth_stop()182 void rtsyn_synth_stop(){
183 	rtsyn_stop_playing();
184 	//	play_mode->close_output();
185 	rtsyn_midiports_close();
186 	DeleteCriticalSection(&mim_section);
187 
188 	return;
189 }
rtsyn_midiports_close(void)190 void rtsyn_midiports_close(void){
191 	UINT port;
192 
193 	for(port=0;port<rtsyn_portnumber;port++){
194 		if( MMSYSERR_NOERROR!=midiInStop(hMidiIn[port]) )
195 			ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIDI Stop Error\n");
196 		if( MMSYSERR_NOERROR!=midiInReset(hMidiIn[port]) )
197 			ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIDI Rest Error\n");
198 		if( MMSYSERR_NOERROR!=midiInClose(hMidiIn[port]) )
199 			ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIDI Close Error\n");
200 	}
201 }
202 
rtsyn_buf_check(void)203 int rtsyn_buf_check(void){
204 	int retval;
205 	EnterCriticalSection(&mim_section);
206 	retval = (evbrpoint != evbwpoint) ? ~0 :  0;
207 	LeaveCriticalSection(&mim_section);
208 	return retval;
209 }
210 
rtsyn_play_some_data(void)211 int rtsyn_play_some_data(void){
212 	UINT wMsg;
213 	DWORD	dwInstance;
214 	DWORD	dwParam1;
215 	DWORD	dwParam2;
216 	DWORD	timestamp;
217 	MidiEvent ev;
218 	MidiEvent evm[260];
219 	int port;
220 	UINT evbpoint;
221 	MIDIHDR *IIMidiHdr;
222 	int exlen;
223 	char *sysexbuffer;
224 	int ne,i,j,chk,played;
225 
226 	played=0;
227 		if( !rtsyn_buf_check() ){
228 			played=~0;
229 			return played;
230 		}
231 		do{
232 			EnterCriticalSection(&mim_section);
233 			evbpoint=evbrpoint;
234 			if (++evbrpoint >= EVBUFF_SIZE)
235 					evbrpoint -= EVBUFF_SIZE;
236 
237 			wMsg=evbuf[evbpoint].wMsg;
238 			dwInstance=evbuf[evbpoint].dwInstance;
239 			dwParam1=evbuf[evbpoint].dwParam1;
240 			dwParam2=evbuf[evbpoint].dwParam2;
241 			LeaveCriticalSection(&mim_section);
242 
243 			port=(UINT)dwInstance;
244 			switch (wMsg) {
245 			case MIM_DATA:
246 				rtsyn_play_one_data (port, dwParam1, mim_start_time+(double)dwParam2/1000.0);
247 				break;
248 			case MIM_LONGDATA:
249 				IIMidiHdr = (MIDIHDR *) dwParam1;
250 				exlen=(int)IIMidiHdr->dwBytesRecorded;
251 				sysexbuffer=IIMidiHdr->lpData;
252 				rtsyn_play_one_sysex (sysexbuffer,exlen, mim_start_time+(double)dwParam2/1000.0);
253 				if (MMSYSERR_NOERROR != midiInUnprepareHeader(
254 						hMidiIn[port], IIMidiHdr, sizeof(MIDIHDR)))
255 					ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"error1\n");
256 				if (MMSYSERR_NOERROR != midiInPrepareHeader(
257 						hMidiIn[port], IIMidiHdr, sizeof(MIDIHDR)))
258 					ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"error5\n");
259 				if (MMSYSERR_NOERROR != midiInAddBuffer(
260 						hMidiIn[port], IIMidiHdr, sizeof(MIDIHDR)))
261 					ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"error6\n");
262 				break;
263 			}
264 		}while(rtsyn_buf_check());
265 	return played;
266 }
267 
MidiInProc(HMIDIIN hMidiInL,UINT wMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)268 void CALLBACK MidiInProc(HMIDIIN hMidiInL, UINT wMsg, DWORD dwInstance,
269 		DWORD dwParam1, DWORD dwParam2)
270 {
271 	UINT evbpoint;
272 	UINT port;
273 
274 	port=(UINT)dwInstance;
275 	switch (wMsg) {
276 	case MIM_DATA:
277 	case MIM_LONGDATA:
278 		EnterCriticalSection(&mim_section);
279 		evbpoint = evbwpoint;
280 		if (++evbwpoint >= EVBUFF_SIZE)
281 			evbwpoint -= EVBUFF_SIZE;
282 		evbuf[evbpoint].wMsg = wMsg;
283 		evbuf[evbpoint].dwInstance = dwInstance;
284 		evbuf[evbpoint].dwParam1 = dwParam1;
285 		evbuf[evbpoint].dwParam2 = dwParam2;
286 		LeaveCriticalSection(&mim_section);
287 		break;
288 	case MIM_OPEN:
289 //		ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIM_OPEN\n");
290 		break;
291 	case MIM_CLOSE:
292 //		ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIM_CLOSE\n");
293 		break;
294 	case MIM_LONGERROR:
295 		ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIM_LONGERROR\n");
296 		break;
297 	case MIM_ERROR:
298 		ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIM_ERROR\n");
299 		break;
300 	case MIM_MOREDATA:
301 		ctl->cmsg(  CMSG_ERROR, VERB_NORMAL,"MIM_MOREDATA\n");
302 		break;
303 	}
304 }
305