Release 960414
[wine.git] / multimedia / mcistring.c
blobde0fb0efd079bc1da0fa4620140e5a3c74338a51
1 /*
2 * MCI stringinterface
4 * Copyright 1995 Marcus Meissner
5 */
6 /* FIXME: special commands of device drivers should be handled by those drivers
7 */
9 #ifndef WINELIB
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <sys/ioctl.h>
17 #include "windows.h"
18 #include "ldt.h"
19 #include "callback.h"
20 #include "user.h"
21 #include "driver.h"
22 #include "mmsystem.h"
23 #include "stddebug.h"
24 #include "debug.h"
25 #include "xmalloc.h"
27 #ifdef WINELIB32
28 #define UIFMT "%u"
29 #else
30 #define UIFMT "%hu"
31 #endif
33 extern MCI_OPEN_DRIVER_PARMS mciDrv[MAXMCIDRIVERS];
35 /* FIXME: I need to remember the aliasname of a spec. driver.
36 * and this is the easiest way. *sigh*
38 static MCI_OPEN_PARMS mciOpenDrv[MAXMCIDRIVERS];
40 LONG DrvDefDriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg,
41 DWORD dwParam1, DWORD dwParam2);
43 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg,
44 DWORD dwParam1, DWORD dwParam2);
45 LONG MIDI_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg,
46 DWORD dwParam1, DWORD dwParam2);
47 LONG CDAUDIO_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg,
48 DWORD dwParam1, DWORD dwParam2);
49 LONG ANIM_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg,
50 DWORD dwParam1, DWORD dwParam2);
52 /* The reason why I just don't lowercase the keywords array in
53 * mciSendString is left as an exercise to the reader.
55 #define STRCMP(x,y) lstrcmpi(x,y)
57 /* standard functionparameters for all functions */
58 #define _MCISTR_PROTO_ \
59 WORD wDevID,WORD uDevTyp,LPSTR lpstrReturnString,UINT uReturnLength,\
60 LPCSTR dev,LPSTR *keywords,UINT nrofkeywords,DWORD dwFlags
62 /* copy string to return pointer including necessary checks
63 * for use in mciSendString()
65 #define _MCI_STR(s) do {\
66 dprintf_mci(stddeb,"->returns \"%s\"",s);\
67 if (lpstrReturnString) {\
68 lstrcpyn(lpstrReturnString,s,uReturnLength);\
69 dprintf_mci(stddeb,"-->\"%s\"\n",lpstrReturnString);\
71 } while(0)
73 /* calling DriverProc. We need to pass the struct as SEGMENTED POINTER. */
74 #define _MCI_CALL_DRIVER(cmd,params) {\
75 DWORD xparams;\
76 xparams=MAKE_SEGPTR(&params);\
77 switch(uDevTyp) {\
78 case MCI_DEVTYPE_CD_AUDIO:\
79 res=CDAUDIO_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags, xparams);\
80 break;\
81 case MCI_DEVTYPE_WAVEFORM_AUDIO:\
82 res=WAVE_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
83 break;\
84 case MCI_DEVTYPE_SEQUENCER:\
85 res=MIDI_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
86 break;\
87 case MCI_DEVTYPE_ANIMATION:\
88 res=ANIM_DriverProc(mciDrv[wDevID].wDeviceID,0,cmd,dwFlags,xparams);\
89 break;\
90 case MCI_DEVTYPE_DIGITAL_VIDEO:\
91 dprintf_mci(stddeb,"_MCI_CALL_DRIVER //No DIGITAL_VIDEO yet !\n");\
92 res=MCIERR_DEVICE_NOT_INSTALLED;\
93 break;\
94 default:\
95 dprintf_mci(stddeb,"_MCI_CALL_DRIVER //Invalid Device Name '%s' !\n",dev);\
96 res=MCIERR_INVALID_DEVICE_NAME;\
97 break;\
100 /* we need to have strings in 16 bit space for some things
101 * FIXME: this is bad.
103 #define _MCI_STRDUP_TO_SEG(dest,source) {\
104 HANDLE x;\
105 x=USER_HEAP_ALLOC(strlen(source));\
106 dest=(LPSTR)MAKELONG(x,USER_HeapSel);\
107 strcpy(PTR_SEG_TO_LIN(dest),source);\
110 /* print a DWORD in the specified timeformat */
111 static void
112 _MCISTR_printtf(char *buf,UINT uDevType,DWORD timef,DWORD val) {
113 *buf='\0';
114 switch (timef) {
115 case MCI_FORMAT_MILLISECONDS:
116 case MCI_FORMAT_FRAMES:
117 case MCI_FORMAT_BYTES:
118 case MCI_FORMAT_SAMPLES:
119 case MCI_VD_FORMAT_TRACK:
120 /*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
121 sprintf(buf,"%ld",val);
122 break;
123 case MCI_FORMAT_HMS:
124 /* well, the macros have the same content*/
125 /*FALLTRHOUGH*/
126 case MCI_FORMAT_MSF:
127 sprintf(buf,"%d:%d:%d",
128 MCI_HMS_HOUR(val),
129 MCI_HMS_MINUTE(val),
130 MCI_HMS_SECOND(val)
132 break;
133 case MCI_FORMAT_TMSF:
134 sprintf(buf,"%d:%d:%d:%d",
135 MCI_TMSF_TRACK(val),
136 MCI_TMSF_MINUTE(val),
137 MCI_TMSF_SECOND(val),
138 MCI_TMSF_FRAME(val)
140 break;
141 default:
142 fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %ld, report.\n",timef);
143 strcpy(buf,"0"); /* hmm */
144 break;
146 return;
148 /* possible different return types */
149 #define _MCISTR_int 1
150 #define _MCISTR_time 2
151 #define _MCISTR_bool 3
152 #define _MCISTR_tfname 4
153 #define _MCISTR_mode 5
154 #define _MCISTR_divtype 6
155 #define _MCISTR_seqtype 7
156 #define _MCISTR_vdmtype 8
157 #define _MCISTR_devtype 9
159 static void
160 _MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
161 WORD uReturnLength,WORD uDevTyp,int timef
163 switch (type) {
164 case _MCISTR_vdmtype:
165 switch (dwReturn) {
166 case MCI_VD_MEDIA_CLV:_MCI_STR("CLV");break;
167 case MCI_VD_MEDIA_CAV:_MCI_STR("CAV");break;
168 default:
169 case MCI_VD_MEDIA_OTHER:_MCI_STR("other");break;
171 break;
172 case _MCISTR_seqtype:
173 switch (dwReturn) {
174 case MCI_SEQ_NONE:_MCI_STR("none");break;
175 case MCI_SEQ_SMPTE:_MCI_STR("smpte");break;
176 case MCI_SEQ_FILE:_MCI_STR("file");break;
177 case MCI_SEQ_MIDI:_MCI_STR("midi");break;
178 default:fprintf(stdnimp,__FILE__":MCISTR_Status:missing sequencer mode %ld\n",dwReturn);
180 break;
181 case _MCISTR_mode:
182 switch (dwReturn) {
183 case MCI_MODE_NOT_READY:_MCI_STR("not ready");break;
184 case MCI_MODE_STOP:_MCI_STR("stopped");break;
185 case MCI_MODE_PLAY:_MCI_STR("playing");break;
186 case MCI_MODE_RECORD:_MCI_STR("recording");break;
187 case MCI_MODE_SEEK:_MCI_STR("seeking");break;
188 case MCI_MODE_PAUSE:_MCI_STR("paused");break;
189 case MCI_MODE_OPEN:_MCI_STR("open");break;
190 default:break;
192 break;
193 case _MCISTR_bool:
194 if (dwReturn)
195 _MCI_STR("true");
196 else
197 _MCI_STR("false");
198 break;
199 case _MCISTR_int:{
200 char buf[16];
201 sprintf(buf,"%ld",dwReturn);
202 _MCI_STR(buf);
203 break;
205 case _MCISTR_time: {
206 char buf[100];
207 _MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
208 _MCI_STR(buf);
209 break;
211 case _MCISTR_tfname:
212 switch (timef) {
213 case MCI_FORMAT_MILLISECONDS:_MCI_STR("milliseconds");break;
214 case MCI_FORMAT_FRAMES:_MCI_STR("frames");break;
215 case MCI_FORMAT_BYTES:_MCI_STR("bytes");break;
216 case MCI_FORMAT_SAMPLES:_MCI_STR("samples");break;
217 case MCI_FORMAT_HMS:_MCI_STR("hms");break;
218 case MCI_FORMAT_MSF:_MCI_STR("msf");break;
219 case MCI_FORMAT_TMSF:_MCI_STR("tmsf");break;
220 default:
221 fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %d, report.\n",timef);
222 break;
224 break;
225 case _MCISTR_divtype:
226 switch (dwReturn) {
227 case MCI_SEQ_DIV_PPQN:_MCI_STR("PPQN");break;
228 case MCI_SEQ_DIV_SMPTE_24:_MCI_STR("SMPTE 24 frame");break;
229 case MCI_SEQ_DIV_SMPTE_25:_MCI_STR("SMPTE 25 frame");break;
230 case MCI_SEQ_DIV_SMPTE_30:_MCI_STR("SMPTE 30 frame");break;
231 case MCI_SEQ_DIV_SMPTE_30DROP:_MCI_STR("SMPTE 30 frame drop");break;
233 case _MCISTR_devtype:
234 switch (dwReturn) {
235 case MCI_DEVTYPE_VCR:_MCI_STR("vcr");break;
236 case MCI_DEVTYPE_VIDEODISC:_MCI_STR("videodisc");break;
237 case MCI_DEVTYPE_CD_AUDIO:_MCI_STR("cd audio");break;
238 case MCI_DEVTYPE_OVERLAY:_MCI_STR("overlay");break;
239 case MCI_DEVTYPE_DAT:_MCI_STR("dat");break;
240 case MCI_DEVTYPE_SCANNER:_MCI_STR("scanner");break;
241 case MCI_DEVTYPE_ANIMATION:_MCI_STR("animation");break;
242 case MCI_DEVTYPE_DIGITAL_VIDEO:_MCI_STR("digital video");break;
243 case MCI_DEVTYPE_OTHER:_MCI_STR("other");break;
244 case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio");break;
245 case MCI_DEVTYPE_SEQUENCER:_MCI_STR("sequencer");break;
246 default:fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown device type %ld, report.\n",dwReturn);break;
248 break;
249 default:
250 fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown resulttype %d, report.\n",type);
251 break;
255 #define FLAG1(str,flag) \
256 if (!STRCMP(keywords[i],str)) {\
257 dwFlags |= flag;\
258 i++;\
259 continue;\
261 #define FLAG2(str1,str2,flag) \
262 if (!STRCMP(keywords[i],str1) && (i+1<nrofkeywords) && !STRCMP(keywords[i+1],str2)) {\
263 dwFlags |= flag;\
264 i+=2;\
265 continue;\
268 /* All known subcommands are implemented in single functions to avoid
269 * bloat and a xxxx lines long mciSendString(). All commands are of the
270 * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
271 * defined line of arguments. (This is just for easy enhanceability.)
272 * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
273 * for the calls are in lpstrReturnString (If I mention return values
274 * in function headers, I mean returnvalues in lpstrReturnString.)
275 * Integers are sprintf("%d")ed integers. Boolean values are
276 * "true" and "false".
277 * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
278 * FIXME: is above line correct?
280 * Preceding every function is a list of implemented/known arguments.
281 * Feel free to add missing arguments.
286 * Opens the specified MCI driver.
287 * Arguments: <name>
288 * Optional:
289 * "shareable"
290 * "alias <aliasname>"
291 * "element <elementname>"
292 * Additional:
293 * waveform audio:
294 * "buffer <nrBytesPerSec>"
295 * Animation:
296 * "nostatic" increaste nr of nonstatic colours
297 * "parent <windowhandle>"
298 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
299 * "style child" WS_CHILD
300 * "style overlap" WS_OVERLAPPED
301 * "style popup" WS_POPUP
302 * Overlay:
303 * "parent <windowhandle>"
304 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
305 * "style child" WS_CHILD
306 * "style overlap" WS_OVERLAPPED
307 * "style popup" WS_POPUP
308 * Returns nothing.
310 static DWORD
311 MCISTR_Open(_MCISTR_PROTO_) {
312 int res,i;
313 char *s;
314 union {
315 MCI_OPEN_PARMS openParams;
316 MCI_WAVE_OPEN_PARMS waveopenParams;
317 MCI_ANIM_OPEN_PARMS animopenParams;
318 MCI_OVLY_OPEN_PARMS ovlyopenParams;
319 } U;
321 U.openParams.lpstrElementName = NULL;
322 s=strchr(dev,'!');
323 if (s!=NULL) {
324 *s++='\0';
325 _MCI_STRDUP_TO_SEG(U.openParams.lpstrElementName,s);
327 if (!STRCMP(dev,"cdaudio")) {
328 uDevTyp=MCI_DEVTYPE_CD_AUDIO;
329 } else if (!STRCMP(dev,"waveaudio")) {
330 uDevTyp=MCI_DEVTYPE_WAVEFORM_AUDIO;
331 } else if (!STRCMP(dev,"sequencer")) {
332 uDevTyp=MCI_DEVTYPE_SEQUENCER;
333 } else if (!STRCMP(dev,"animation1")) {
334 uDevTyp=MCI_DEVTYPE_ANIMATION;
335 } else if (!STRCMP(dev,"avivideo")) {
336 uDevTyp=MCI_DEVTYPE_DIGITAL_VIDEO;
337 } else {
338 return MCIERR_INVALID_DEVICE_NAME;
340 wDevID=0;
341 while(mciDrv[wDevID].wType) {
342 if (++wDevID>=MAXMCIDRIVERS) {
343 dprintf_mci(stddeb, __FILE__":MCISTR_Open:MAXMCIDRIVERS reached!\n");
344 return MCIERR_INTERNAL;
347 mciDrv[wDevID].wType = uDevTyp;
348 mciDrv[wDevID].wDeviceID = wDevID;
349 U.openParams.dwCallback = 0;
350 U.openParams.wDeviceID = wDevID;
351 U.ovlyopenParams.dwStyle = 0;
352 U.animopenParams.dwStyle = 0;
354 _MCI_STRDUP_TO_SEG(U.openParams.lpstrDeviceType,dev);
355 U.openParams.lpstrAlias = NULL;
356 dwFlags |= MCI_OPEN_TYPE;
357 i=0;
358 while (i<nrofkeywords) {
359 FLAG1("shareable",MCI_OPEN_SHAREABLE);
360 if (!strcmp(keywords[i],"alias") && (i+1<nrofkeywords)) {
361 dwFlags |= MCI_OPEN_ALIAS;
362 _MCI_STRDUP_TO_SEG(U.openParams.lpstrAlias,keywords[i]);
363 i+=2;
364 continue;
366 if (!strcmp(keywords[i],"element") && (i+1<nrofkeywords)) {
367 dwFlags |= MCI_OPEN_ELEMENT;
368 _MCI_STRDUP_TO_SEG(U.openParams.lpstrElementName,keywords[i]);
369 i+=2;
370 continue;
372 switch (uDevTyp) {
373 case MCI_DEVTYPE_ANIMATION:
374 case MCI_DEVTYPE_DIGITAL_VIDEO:
375 FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
376 if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
377 dwFlags |= MCI_ANIM_OPEN_PARENT;
378 sscanf(keywords[i+1],"%hu",&(U.animopenParams.hWndParent));
379 i+=2;
380 continue;
382 if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
383 DWORD st;
385 dwFlags |= MCI_ANIM_OPEN_WS;
386 if (!STRCMP(keywords[i+1],"popup")) {
387 U.animopenParams.dwStyle |= WS_POPUP;
388 } else if (!STRCMP(keywords[i+1],"overlap")) {
389 U.animopenParams.dwStyle |= WS_OVERLAPPED;
390 } else if (!STRCMP(keywords[i+1],"child")) {
391 U.animopenParams.dwStyle |= WS_CHILD;
392 } else if (sscanf(keywords[i+1],"%ld",&st)) {
393 U.animopenParams.dwStyle |= st;
394 } else
395 fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
396 i+=2;
397 continue;
399 break;
400 case MCI_DEVTYPE_WAVEFORM_AUDIO:
401 if (!STRCMP(keywords[i],"buffer") && (i+1<nrofkeywords)) {
402 dwFlags |= MCI_WAVE_OPEN_BUFFER;
403 sscanf(keywords[i+1],"%ld",&(U.waveopenParams.dwBufferSeconds));
405 break;
406 case MCI_DEVTYPE_OVERLAY:
407 /* looks just like anim, but without NOSTATIC */
408 if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
409 dwFlags |= MCI_OVLY_OPEN_PARENT;
410 sscanf(keywords[i+1],"%hd",&(U.ovlyopenParams.hWndParent));
411 i+=2;
412 continue;
414 if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
415 DWORD st;
417 dwFlags |= MCI_OVLY_OPEN_WS;
418 if (!STRCMP(keywords[i+1],"popup")) {
419 U.ovlyopenParams.dwStyle |= WS_POPUP;
420 } else if (!STRCMP(keywords[i+1],"overlap")) {
421 U.ovlyopenParams.dwStyle |= WS_OVERLAPPED;
422 } else if (!STRCMP(keywords[i+1],"child")) {
423 U.ovlyopenParams.dwStyle |= WS_CHILD;
424 } else if (sscanf(keywords[i+1],"%ld",&st)) {
425 U.ovlyopenParams.dwStyle |= st;
426 } else
427 fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
428 i+=2;
429 continue;
431 break;
433 fprintf(stdnimp,__FILE__":MCISTR_Open:unknown parameter passed %s, please report.\n",keywords[i]);
434 i++;
436 _MCI_CALL_DRIVER(MCI_OPEN,U);
437 if (res==0)
438 memcpy(&mciOpenDrv[wDevID],&U.openParams,sizeof(MCI_OPEN_PARMS));
439 return res;
442 /* A help function for a lot of others ...
443 * for instance status/play/record/seek etc.
445 DWORD
446 _MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef) {
447 MCI_STATUS_PARMS statusParams;
448 DWORD dwFlags;
449 int res;
451 dwFlags = MCI_STATUS_ITEM;
452 statusParams.dwItem = MCI_STATUS_TIME_FORMAT;
453 statusParams.dwReturn = 0;
454 _MCI_CALL_DRIVER(MCI_STATUS,statusParams);
455 if (res==0) *timef=statusParams.dwReturn;
456 return res;
459 /* query status of MCI drivers
460 * Arguments:
461 * Required:
462 * "mode" - returns "not ready" "paused" "playing" "stopped" "open"
463 * "parked" "recording" "seeking" ....
464 * Basics:
465 * "current track" - returns current track as integer
466 * "length [track <nr>]" - returns length [of track <nr>] in current
467 * timeformat
468 * "number of tracks" - returns number of tracks as integer
469 * "position [track <nr>]" - returns position [in track <nr>] in current
470 * timeformat
471 * "ready" - checks if device is ready to play, -> bool
472 * "start position" - returns start position in timeformat
473 * "time format" - returns timeformat (list of possible values:
474 * "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
475 * "bytes" "samples" "hms")
476 * "media present" - returns if media is present as bool
477 * Animation:
478 * "forward" - returns "true" if device is playing forwards
479 * "speed" - returns speed for device
480 * "palette handle" - returns palette handle
481 * "window handle" - returns window handle
482 * "stretch" - returns stretch bool
483 * MIDI sequencer:
484 * "division type" - ? returns "PPQN" "SMPTE 24 frame"
485 * "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
486 * "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
487 * "offset" - offset in dito.
488 * "port" - midi port as integer
489 * "slave" - slave device ("midi","file","none","smpte")
490 * "master" - masterdevice (dito.)
491 * Overlay:
492 * "window handle" - see animation
493 * "stretch" - dito
494 * Video Disc:
495 * "speed" - speed as integer
496 * "forward" - returns bool (when playing forward)
497 * "side" - returns 1 or 2
498 * "media type" - returns "CAV" "CLV" "other"
499 * "disc size" - returns "8" or "12"
500 * WAVEFORM audio:
501 * "input" - base queries on input set
502 * "output" - base queries on output set
503 * "format tag" - return integer format tag
504 * "channels" - return integer nr of channels
505 * "bytespersec" - return average nr of bytes/sec
506 * "samplespersec" - return nr of samples per sec
507 * "bitspersample" - return bitspersample
508 * "alignment" - return block alignment
509 * "level" - return level?
512 #define ITEM1(str,item,xtype) \
513 if (!STRCMP(keywords[i],str)) {\
514 statusParams.dwItem = item;\
515 type = xtype;\
516 i++;\
517 continue;\
519 #define ITEM2(str1,str2,item,xtype) \
520 if ( !STRCMP(keywords[i],str1) &&\
521 (i+1<nrofkeywords) &&\
522 !STRCMP(keywords[i+1],str2)\
523 ) {\
524 statusParams.dwItem = item;\
525 type = xtype;\
526 i+=2;\
527 continue;\
529 #define ITEM3(str1,str2,str3,item,xtype) \
530 if ( !STRCMP(keywords[i],str1) &&\
531 (i+2<nrofkeywords) &&\
532 !STRCMP(keywords[i+1],str2) &&\
533 !STRCMP(keywords[i+2],str3)\
534 ) {\
535 statusParams.dwItem = item;\
536 type = xtype;\
537 i+=3;\
538 continue;\
540 static DWORD
541 MCISTR_Status(_MCISTR_PROTO_) {
542 MCI_STATUS_PARMS statusParams;
543 int type = 0,i,res,timef;
545 statusParams.dwCallback = 0;
546 dwFlags |= MCI_STATUS_ITEM;
547 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
548 if (res) return res;
550 statusParams.dwReturn = 0;
551 statusParams.dwItem = 0;
552 i = 0;
554 while (i<nrofkeywords) {
555 if (!STRCMP(keywords[i],"track") && (i+1<nrofkeywords)) {
556 sscanf(keywords[i+1],"%ld",&(statusParams.dwTrack));
557 dwFlags |= MCI_TRACK;
558 i+=2;
559 continue;
561 FLAG1("start",MCI_STATUS_START);
562 /* generic things */
563 ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
564 ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
565 ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
566 ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
567 ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
568 ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
569 ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
570 ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
572 switch (uDevTyp) {
573 case MCI_DEVTYPE_ANIMATION:
574 case MCI_DEVTYPE_DIGITAL_VIDEO:
575 ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
576 ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
577 ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
578 ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
579 ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
580 break;
581 case MCI_DEVTYPE_SEQUENCER:
582 /* just completing the list, not working correctly */
583 ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
584 /* tempo ... PPQN in frames/second, SMPTE in hmsf */
585 ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
586 ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
587 ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
588 ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
589 /* offset ... PPQN in frames/second, SMPTE in hmsf */
590 ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
591 break;
592 case MCI_DEVTYPE_OVERLAY:
593 ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
594 ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
595 break;
596 case MCI_DEVTYPE_VIDEODISC:
597 ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
598 ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
599 ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
600 ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
601 /* returns 8 or 12 */
602 ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
603 break;
604 case MCI_DEVTYPE_WAVEFORM_AUDIO:
605 /* I am not quite sure if foll. 2 lines are right. */
606 FLAG1("input",MCI_WAVE_INPUT);
607 FLAG1("output",MCI_WAVE_OUTPUT);
609 ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
610 ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
611 ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
612 ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
613 ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
614 ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
615 ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
616 break;
618 fprintf(stdnimp,__FILE__":MCISTR_Status:unknown keyword '%s'\n",keywords[i]);
619 i++;
621 if (!statusParams.dwItem)
622 return MCIERR_MISSING_STRING_ARGUMENT;
624 _MCI_CALL_DRIVER(MCI_STATUS,statusParams);
625 if (res==0)
626 _MCISTR_convreturn(type,statusParams.dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
627 return res;
629 #undef ITEM1
630 #undef ITEM2
631 #undef ITEM3
633 /* set specified parameters in respective MCI drivers
634 * Arguments:
635 * "door open" eject media or somesuch
636 * "door close" load media
637 * "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
638 * "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
639 * "SMPTE drop 30"
640 * "audio [all|left|right] [on|off]" sets specified audiochannel on or off
641 * "video [on|off]" sets video on/off
642 * Waveform audio:
643 * "formattag pcm" sets format to pcm
644 * "formattag <nr>" sets integer formattag value
645 * "any input" accept input from any known source
646 * "any output" output to any known destination
647 * "input <nr>" input from source <nr>
648 * "output <nr>" output to destination <nr>
649 * "channels <nr>" sets nr of channels
650 * "bytespersec <nr>" sets average bytes per second
651 * "samplespersec <nr>" sets average samples per second (1 sample can
652 * be 2 bytes!)
653 * "alignment <nr>" sets the blockalignment to <nr>
654 * "bitspersample <nr>" sets the nr of bits per sample
655 * Sequencer:
656 * "master [midi|file|smpte|none]" sets the midi master device
657 * "slave [midi|file|smpte|none]" sets the midi master device
658 * "port mapper" midioutput to portmapper
659 * "port <nr>" midioutput to specified port
660 * "tempo <nr>" tempo of track (depends on timeformat/divtype)
661 * "offset <nr>" start offset?
663 static DWORD
664 MCISTR_Set(_MCISTR_PROTO_) {
665 union {
666 MCI_SET_PARMS setParams;
667 MCI_WAVE_SET_PARMS wavesetParams;
668 MCI_SEQ_SET_PARMS seqsetParams;
669 } U;
670 int i,res;
672 U.setParams.dwCallback = 0;
673 i = 0;
674 while (i<nrofkeywords) {
675 FLAG2("door","open",MCI_SET_DOOR_OPEN);
676 FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
678 if ( !STRCMP(keywords[i],"time") &&
679 (i+2<nrofkeywords) &&
680 !STRCMP(keywords[i+1],"format")
682 dwFlags |= MCI_SET_TIME_FORMAT;
684 /* FIXME:is this a shortcut for milliseconds or
685 * minutes:seconds? */
686 if (!STRCMP(keywords[i+2],"ms"))
687 U.setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
689 if (!STRCMP(keywords[i+2],"milliseconds"))
690 U.setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
691 if (!STRCMP(keywords[i+2],"msf"))
692 U.setParams.dwTimeFormat = MCI_FORMAT_MSF;
693 if (!STRCMP(keywords[i+2],"hms"))
694 U.setParams.dwTimeFormat = MCI_FORMAT_HMS;
695 if (!STRCMP(keywords[i+2],"frames"))
696 U.setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
697 if (!STRCMP(keywords[i+2],"track"))
698 U.setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
699 if (!STRCMP(keywords[i+2],"bytes"))
700 U.setParams.dwTimeFormat = MCI_FORMAT_BYTES;
701 if (!STRCMP(keywords[i+2],"samples"))
702 U.setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
703 if (!STRCMP(keywords[i+2],"tmsf"))
704 U.setParams.dwTimeFormat = MCI_FORMAT_TMSF;
705 if ( !STRCMP(keywords[i+2],"song") &&
706 (i+3<nrofkeywords) &&
707 !STRCMP(keywords[i+3],"pointer")
709 U.setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
710 if (!STRCMP(keywords[i+2],"smpte") && (i+3<nrofkeywords)) {
711 if (!STRCMP(keywords[i+3],"24"))
712 U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
713 if (!STRCMP(keywords[i+3],"25"))
714 U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
715 if (!STRCMP(keywords[i+3],"30"))
716 U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
717 if (!STRCMP(keywords[i+3],"drop") && (i+4<nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
718 U.setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
719 i++;
721 i++;
722 /*FALLTHROUGH*/
724 i+=3;
725 continue;
727 if (!STRCMP(keywords[i],"audio") && (i+1<nrofkeywords)) {
728 dwFlags |= MCI_SET_AUDIO;
729 if (!STRCMP(keywords[i+1],"all"))
730 U.setParams.dwAudio = MCI_SET_AUDIO_ALL;
731 if (!STRCMP(keywords[i+1],"left"))
732 U.setParams.dwAudio = MCI_SET_AUDIO_LEFT;
733 if (!STRCMP(keywords[i+1],"right"))
734 U.setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
735 i+=2;
736 continue;
738 FLAG1("video",MCI_SET_VIDEO);
739 FLAG1("on",MCI_SET_ON);
740 FLAG1("off",MCI_SET_OFF);
741 switch (uDevTyp) {
742 case MCI_DEVTYPE_WAVEFORM_AUDIO:
743 FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
744 FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
746 if ( !STRCMP(keywords[i],"formattag") &&
747 (i+1<nrofkeywords) &&
748 !STRCMP(keywords[i+1],"pcm")
750 dwFlags |= MCI_WAVE_SET_FORMATTAG;
751 U.wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
752 i+=2;
753 continue;
756 /* <keyword> <integer> */
757 #define WII(str,flag,fmt,element) \
758 if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
759 sscanf(keywords[i+1],fmt,&(U.wavesetParams. element ));\
760 dwFlags |= flag;\
761 i+=2;\
762 continue;\
764 WII("formattag",MCI_WAVE_SET_FORMATTAG,UIFMT,wFormatTag);
765 WII("channels",MCI_WAVE_SET_CHANNELS,UIFMT,nChannels);
766 WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,"%lu",nAvgBytesPerSec);
767 WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,"%lu",nSamplesPerSec);
768 WII("alignment",MCI_WAVE_SET_BLOCKALIGN,UIFMT,nBlockAlign);
769 WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,UIFMT,wBitsPerSample);
770 WII("input",MCI_WAVE_INPUT,UIFMT,wInput);
771 WII("output",MCI_WAVE_OUTPUT,UIFMT,wOutput);
772 #undef WII
773 break;
774 case MCI_DEVTYPE_SEQUENCER:
775 if (!STRCMP(keywords[i],"master") && (i+1<nrofkeywords)) {
776 dwFlags |= MCI_SEQ_SET_MASTER;
777 if (!STRCMP(keywords[i+1],"midi"))
778 U.seqsetParams.dwMaster = MCI_SEQ_MIDI;
779 if (!STRCMP(keywords[i+1],"file"))
780 U.seqsetParams.dwMaster = MCI_SEQ_FILE;
781 if (!STRCMP(keywords[i+1],"smpte"))
782 U.seqsetParams.dwMaster = MCI_SEQ_SMPTE;
783 if (!STRCMP(keywords[i+1],"none"))
784 U.seqsetParams.dwMaster = MCI_SEQ_NONE;
785 i+=2;
786 continue;
788 if (!STRCMP(keywords[i],"slave") && (i+1<nrofkeywords)) {
789 dwFlags |= MCI_SEQ_SET_SLAVE;
790 if (!STRCMP(keywords[i+1],"midi"))
791 U.seqsetParams.dwMaster = MCI_SEQ_MIDI;
792 if (!STRCMP(keywords[i+1],"file"))
793 U.seqsetParams.dwMaster = MCI_SEQ_FILE;
794 if (!STRCMP(keywords[i+1],"smpte"))
795 U.seqsetParams.dwMaster = MCI_SEQ_SMPTE;
796 if (!STRCMP(keywords[i+1],"none"))
797 U.seqsetParams.dwMaster = MCI_SEQ_NONE;
798 i+=2;
799 continue;
801 if ( !STRCMP(keywords[i],"port") &&
802 (i+1<nrofkeywords) &&
803 !STRCMP(keywords[i+1],"mapper")
805 U.seqsetParams.dwPort=-1;/* FIXME:not sure*/
806 dwFlags |= MCI_SEQ_SET_PORT;
807 i+=2;
808 continue;
810 #define SII(str,flag,element) \
811 if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
812 sscanf(keywords[i+1],"%ld",&(U.seqsetParams. element ));\
813 dwFlags |= flag;\
814 i+=2;\
815 continue;\
817 SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
818 SII("port",MCI_SEQ_SET_PORT,dwPort);
819 SII("offset",MCI_SEQ_SET_PORT,dwOffset);
821 i++;
823 if (!dwFlags)
824 return MCIERR_MISSING_STRING_ARGUMENT;
825 _MCI_CALL_DRIVER(MCI_SET,U);
826 return res;
829 /* specify break key
830 * Arguments:
831 * "off" disable break
832 * "on <keyid>" enable break on key with keyid
833 * (I strongly suspect, that there is another parameter:
834 * "window <handle>"
835 * but I don't see it mentioned in my documentation.
836 * Returns nothing.
838 static DWORD
839 MCISTR_Break(_MCISTR_PROTO_) {
840 MCI_BREAK_PARMS breakParams;
841 int res,i;
843 /*breakParams.hwndBreak ? */
844 i=0;while (i<nrofkeywords) {
845 FLAG1("off",MCI_BREAK_OFF);
846 if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
847 dwFlags&=~MCI_BREAK_OFF;
848 dwFlags|=MCI_BREAK_KEY;
849 sscanf(keywords[i+1],"%d",&(breakParams.nVirtKey));
850 i+=2;
851 continue;
853 i++;
855 _MCI_CALL_DRIVER(MCI_BREAK,breakParams);
856 return res;
859 #define ITEM1(str,item,xtype) \
860 if (!STRCMP(keywords[i],str)) {\
861 gdcParams.dwItem = item;\
862 type = xtype;\
863 i++;\
864 continue;\
866 #define ITEM2(str1,str2,item,xtype) \
867 if ( !STRCMP(keywords[i],str1) &&\
868 (i+1<nrofkeywords) &&\
869 !STRCMP(keywords[i+1],str2)\
870 ) {\
871 gdcParams.dwItem = item;\
872 type = xtype;\
873 i+=2;\
874 continue;\
876 #define ITEM3(str1,str2,str3,item,xtype) \
877 if ( !STRCMP(keywords[i],str1) &&\
878 (i+2<nrofkeywords) &&\
879 !STRCMP(keywords[i+1],str2) &&\
880 !STRCMP(keywords[i+2],str3)\
881 ) {\
882 gdcParams.dwItem = item;\
883 type = xtype;\
884 i+=3;\
885 continue;\
887 /* get device capabilities of MCI drivers
888 * Arguments:
889 * Generic:
890 * "device type" returns device name as string
891 * "has audio" returns bool
892 * "has video" returns bool
893 * "uses files" returns bool
894 * "compound device" returns bool
895 * "can record" returns bool
896 * "can play" returns bool
897 * "can eject" returns bool
898 * "can save" returns bool
899 * Animation:
900 * "palettes" returns nr of available palette entries
901 * "windows" returns nr of available windows
902 * "can reverse" returns bool
903 * "can stretch" returns bool
904 * "slow play rate" returns the slow playrate
905 * "fast play rate" returns the fast playrate
906 * "normal play rate" returns the normal playrate
907 * Overlay:
908 * "windows" returns nr of available windows
909 * "can stretch" returns bool
910 * "can freeze" returns bool
911 * Videodisc:
912 * "cav" assume CAV discs (default if no disk inserted)
913 * "clv" assume CLV discs
914 * "can reverse" returns bool
915 * "slow play rate" returns the slow playrate
916 * "fast play rate" returns the fast playrate
917 * "normal play rate" returns the normal playrate
918 * Waveform audio:
919 * "inputs" returns nr of inputdevices
920 * "outputs" returns nr of outputdevices
922 static DWORD
923 MCISTR_Capability(_MCISTR_PROTO_) {
924 MCI_GETDEVCAPS_PARMS gdcParams;
925 int type=0,i,res;
927 gdcParams.dwCallback = 0;
928 if (!nrofkeywords)
929 return MCIERR_MISSING_STRING_ARGUMENT;
930 /* well , thats default */
931 dwFlags |= MCI_GETDEVCAPS_ITEM;
932 gdcParams.dwItem = 0;
933 i=0;
934 while (i<nrofkeywords) {
935 ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
936 ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
937 ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
938 ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
939 ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
940 ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
941 ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
942 ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
943 ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
944 switch (uDevTyp) {
945 case MCI_DEVTYPE_ANIMATION:
946 ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
947 ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
948 ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
949 ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
950 ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
951 ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
952 ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
953 break;
954 case MCI_DEVTYPE_OVERLAY:
955 ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
956 ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
957 ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
958 break;
959 case MCI_DEVTYPE_VIDEODISC:
960 FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
961 FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
962 ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
963 ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
964 ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
965 ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
966 break;
967 case MCI_DEVTYPE_WAVEFORM_AUDIO:
968 ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
969 ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
970 break;
972 i++;
974 _MCI_CALL_DRIVER(MCI_GETDEVCAPS,gdcParams);
975 /* no timeformat needed */
976 if (res==0)
977 _MCISTR_convreturn(type,gdcParams.dwReturn,lpstrReturnString,uReturnLength,uDevTyp,0);
978 return res;
980 #undef ITEM1
981 #undef ITEM2
982 #undef ITEM3
983 /* resumes operation of device. no arguments, no return values */
984 static DWORD
985 MCISTR_Resume(_MCISTR_PROTO_) {
986 MCI_GENERIC_PARMS genParams;
987 int res;
989 genParams.dwCallback=0;
990 _MCI_CALL_DRIVER(MCI_RESUME,genParams);
991 return res;
994 /* pauses operation of device. no arguments, no return values */
995 static DWORD
996 MCISTR_Pause(_MCISTR_PROTO_) {
997 MCI_GENERIC_PARMS genParams;
998 int res;
999 genParams.dwCallback=0;
1000 _MCI_CALL_DRIVER(MCI_PAUSE,genParams);
1001 return res;
1004 /* stops operation of device. no arguments, no return values */
1005 static DWORD
1006 MCISTR_Stop(_MCISTR_PROTO_) {
1007 MCI_GENERIC_PARMS genParams;
1008 int res;
1009 genParams.dwCallback=0;
1010 _MCI_CALL_DRIVER(MCI_STOP,genParams);
1011 return res;
1014 /* starts recording.
1015 * Arguments:
1016 * "overwrite" overwrite existing things
1017 * "insert" insert at current position
1018 * "to <time>" record up to <time> (specified in timeformat)
1019 * "from <time>" record from <time> (specified in timeformat)
1021 static DWORD
1022 MCISTR_Record(_MCISTR_PROTO_) {
1023 int i,res,timef,nrargs,j,k,a[4];
1024 char *parsestr;
1025 MCI_RECORD_PARMS recordParams;
1027 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1028 if (res) return res;
1030 switch (timef) {
1031 case MCI_FORMAT_MILLISECONDS:
1032 case MCI_FORMAT_FRAMES:
1033 case MCI_FORMAT_BYTES:
1034 case MCI_FORMAT_SAMPLES:
1035 nrargs=1;
1036 parsestr="%d";
1037 break;
1038 case MCI_FORMAT_HMS:
1039 case MCI_FORMAT_MSF:
1040 parsestr="%d:%d:%d";
1041 nrargs=3;
1042 break;
1043 case MCI_FORMAT_TMSF:
1044 parsestr="%d:%d:%d:%d";
1045 nrargs=4;
1046 break;
1047 default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
1048 parsestr="%d";
1049 nrargs=1;
1050 break;
1052 recordParams.dwCallback = 0;
1053 i = 0;
1054 while (i<nrofkeywords) {
1055 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1056 dwFlags |= MCI_TO;
1057 a[0]=a[1]=a[2]=a[3]=0;
1058 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1059 /* add up all integers we got, if we have more
1060 * shift them. (Well I should use the macros in
1061 * mmsystem.h, right).
1063 recordParams.dwTo=0;
1064 for (k=0;k<j;k++)
1065 recordParams.dwTo+=a[k]<<(8*(nrargs-k));
1066 i+=2;
1067 continue;
1069 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1070 dwFlags |= MCI_FROM;
1071 a[0]=a[1]=a[2]=a[3]=0;
1072 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1073 /* dito. */
1074 recordParams.dwFrom=0;
1075 for (k=0;k<j;k++)
1076 recordParams.dwFrom+=a[k]<<(8*(nrargs-k));
1077 i+=2;
1078 continue;
1080 FLAG1("insert",MCI_RECORD_INSERT);
1081 FLAG1("overwrite",MCI_RECORD_OVERWRITE);
1082 i++;
1084 _MCI_CALL_DRIVER(MCI_RECORD,recordParams);
1085 return res;
1088 /* play media
1089 * Arguments:
1090 * "to <time>" play up to <time> (specified in set timeformat)
1091 * "from <time>" play from <time> (specified in set timeformat)
1092 * Animation:
1093 * "slow" play slow
1094 * "fast" play fast
1095 * "scan" play as fast as possible (with audio disabled perhaps)
1096 * "reverse" play reverse
1097 * "speed <fps>" play with specified frames per second
1098 * Videodisc:
1099 * "slow" play slow
1100 * "fast" play fast
1101 * "scan" play as fast as possible (with audio disabled perhaps)
1102 * "reverse" play reverse
1103 * "speed <fps>" play with specified frames per second
1105 static DWORD
1106 MCISTR_Play(_MCISTR_PROTO_) {
1107 int i,res,timef,nrargs,j,k,a[4];
1108 char *parsestr;
1109 union {
1110 MCI_PLAY_PARMS playParams;
1111 MCI_VD_PLAY_PARMS vdplayParams;
1112 MCI_ANIM_PLAY_PARMS animplayParams;
1113 } U;
1115 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1116 if (res) return res;
1117 switch (timef) {
1118 case MCI_FORMAT_MILLISECONDS:
1119 case MCI_FORMAT_FRAMES:
1120 case MCI_FORMAT_BYTES:
1121 case MCI_FORMAT_SAMPLES:
1122 nrargs=1;
1123 parsestr="%d";
1124 break;
1125 case MCI_FORMAT_HMS:
1126 case MCI_FORMAT_MSF:
1127 parsestr="%d:%d:%d";
1128 nrargs=3;
1129 break;
1130 case MCI_FORMAT_TMSF:
1131 parsestr="%d:%d:%d:%d";
1132 nrargs=4;
1133 break;
1134 default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
1135 parsestr="%d";
1136 nrargs=1;
1137 break;
1139 U.playParams.dwCallback=0;
1140 i=0;
1141 while (i<nrofkeywords) {
1142 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1143 dwFlags |= MCI_TO;
1144 a[0]=a[1]=a[2]=a[3]=0;
1145 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1146 /* add up all integers we got, if we have more
1147 * shift them. (Well I should use the macros in
1148 * mmsystem.h, right).
1150 U.playParams.dwTo=0;
1151 for (k=0;k<j;k++)
1152 U.playParams.dwTo+=a[k]<<(8*(nrargs-k));
1153 i+=2;
1154 continue;
1156 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1157 dwFlags |= MCI_FROM;
1158 a[0]=a[1]=a[2]=a[3]=0;
1159 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1160 /* dito. */
1161 U.playParams.dwFrom=0;
1162 for (k=0;k<j;k++)
1163 U.playParams.dwFrom+=a[k]<<(8*(nrargs-k));
1164 i+=2;
1165 continue;
1167 switch (uDevTyp) {
1168 case MCI_DEVTYPE_VIDEODISC:
1169 FLAG1("slow",MCI_VD_PLAY_SLOW);
1170 FLAG1("fast",MCI_VD_PLAY_FAST);
1171 FLAG1("scan",MCI_VD_PLAY_SCAN);
1172 FLAG1("reverse",MCI_VD_PLAY_REVERSE);
1173 if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
1174 dwFlags |= MCI_VD_PLAY_SPEED;
1175 sscanf(keywords[i+1],"%ld",&(U.vdplayParams.dwSpeed));
1176 i+=2;
1177 continue;
1179 break;
1180 case MCI_DEVTYPE_ANIMATION:
1181 FLAG1("slow",MCI_ANIM_PLAY_SLOW);
1182 FLAG1("fast",MCI_ANIM_PLAY_FAST);
1183 FLAG1("scan",MCI_ANIM_PLAY_SCAN);
1184 FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
1185 if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
1186 dwFlags |= MCI_ANIM_PLAY_SPEED;
1187 sscanf(keywords[i+1],"%ld",&(U.animplayParams.dwSpeed));
1188 i+=2;
1189 continue;
1191 break;
1193 i++;
1195 _MCI_CALL_DRIVER(MCI_PLAY,U);
1196 return res;
1199 /* seek to a specified position
1200 * Arguments:
1201 * "to start" seek to start of medium
1202 * "to end" seek to end of medium
1203 * "to <time>" seek to <time> specified in current timeformat
1205 static DWORD
1206 MCISTR_Seek(_MCISTR_PROTO_) {
1207 int i,res,timef,nrargs,j,k,a[4];
1208 char *parsestr;
1209 MCI_SEEK_PARMS seekParams;
1211 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1212 if (res) return res;
1213 switch (timef) {
1214 case MCI_FORMAT_MILLISECONDS:
1215 case MCI_FORMAT_FRAMES:
1216 case MCI_FORMAT_BYTES:
1217 case MCI_FORMAT_SAMPLES:
1218 nrargs=1;
1219 parsestr="%d";
1220 break;
1221 case MCI_FORMAT_HMS:
1222 case MCI_FORMAT_MSF:
1223 parsestr="%d:%d:%d";
1224 nrargs=3;
1225 break;
1226 case MCI_FORMAT_TMSF:
1227 parsestr="%d:%d:%d:%d";
1228 nrargs=4;
1229 break;
1230 default:fprintf(stdnimp,"mciSendString:SEEK:unknown timeformat %d, please report.\n",timef);
1231 parsestr="%d";
1232 nrargs=1;
1233 break;
1235 seekParams.dwCallback=0;
1236 i=0;
1237 while (i<nrofkeywords) {
1238 if ( !STRCMP(keywords[i],"to") && (i+1<nrofkeywords)) {
1239 if (!STRCMP(keywords[i+1],"start")) {
1240 dwFlags|=MCI_SEEK_TO_START;
1241 seekParams.dwTo=0;
1242 i+=2;
1243 continue;
1245 if (!STRCMP(keywords[i+1],"end")) {
1246 dwFlags|=MCI_SEEK_TO_END;
1247 seekParams.dwTo=0;
1248 i+=2;
1249 continue;
1251 dwFlags|=MCI_TO;
1252 i+=2;
1253 a[0]=a[1]=a[2]=a[3]=0;
1254 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1255 seekParams.dwTo=0;
1256 for (k=0;k<j;k++)
1257 seekParams.dwTo+=a[k]<<(8*(nrargs-k));
1258 continue;
1260 switch (uDevTyp) {
1261 case MCI_DEVTYPE_VIDEODISC:
1262 FLAG1("reverse",MCI_VD_SEEK_REVERSE);
1263 break;
1265 i++;
1267 _MCI_CALL_DRIVER(MCI_SEEK,seekParams);
1268 return res;
1271 /* close media/driver */
1272 static DWORD
1273 MCISTR_Close(_MCISTR_PROTO_) {
1274 MCI_GENERIC_PARMS closeParams;
1275 int res;
1277 _MCI_CALL_DRIVER(MCI_CLOSE,closeParams);
1278 return res;
1281 /* return information.
1282 * Arguments:
1283 * "product" return product name (human readable)
1284 * "file" return filename
1285 * Animation:
1286 * "text" returns text?
1287 * Overlay:
1288 * "text" returns text?
1290 static DWORD
1291 MCISTR_Info(_MCISTR_PROTO_) {
1292 MCI_INFO_PARMS infoParams;
1293 DWORD sflags;
1294 int i,res;
1296 sflags = dwFlags;
1297 i=0;while (i<nrofkeywords) {
1298 FLAG1("product",MCI_INFO_PRODUCT);
1299 FLAG1("file",MCI_INFO_FILE);
1300 switch (uDevTyp) {
1301 case MCI_DEVTYPE_ANIMATION:
1302 FLAG1("text",MCI_ANIM_INFO_TEXT);
1303 break;
1304 case MCI_DEVTYPE_OVERLAY:
1305 FLAG1("text",MCI_OVLY_INFO_TEXT);
1306 break;
1308 i++;
1310 if (dwFlags == sflags)
1311 return MCIERR_MISSING_STRING_ARGUMENT;
1312 /* MCI driver will fill in lpstrReturn, dwRetSize.
1313 * FIXME: I don't know if this is correct behaviour
1315 _MCI_CALL_DRIVER(MCI_INFO,infoParams);
1316 if (res==0)
1317 _MCI_STR(infoParams.lpstrReturn);
1318 return res;
1321 DWORD mciSysInfo(DWORD dwFlags,LPMCI_SYSINFO_PARMS lpParms);
1323 /* query MCI driver itself for information
1324 * Arguments:
1325 * "installname" return install name of <device> (system.ini)
1326 * "quantity" return nr of installed drivers
1327 * "open" open drivers only (additional flag)
1328 * "name <nr>" return nr of devices with <devicetyp>
1329 * "name all" return nr of all devices
1331 * FIXME: mciSysInfo() is broken I think.
1333 static DWORD
1334 MCISTR_Sysinfo(_MCISTR_PROTO_) {
1335 MCI_SYSINFO_PARMS sysinfoParams;
1336 int i,res;
1338 sysinfoParams.lpstrReturn = lpstrReturnString;
1339 sysinfoParams.dwRetSize = uReturnLength;
1340 sysinfoParams.wDeviceType = uDevTyp;
1341 i=0;
1342 while (i<nrofkeywords) {
1343 FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
1344 FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
1345 FLAG1("open",MCI_SYSINFO_OPEN);
1346 if (!strcmp(keywords[i],"name") && (i+1<nrofkeywords)) {
1347 sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
1348 dwFlags |= MCI_SYSINFO_NAME;
1349 i+=2;
1350 continue;
1352 i++;
1354 res=mciSysInfo(dwFlags,&sysinfoParams);
1355 if (dwFlags & MCI_SYSINFO_QUANTITY) {
1356 char buf[100];
1358 sprintf(buf,"%ld",*(long*)PTR_SEG_TO_LIN(lpstrReturnString));
1359 _MCI_STR(buf);
1361 /* no need to copy anything back, mciSysInfo did it for us */
1362 return res;
1365 /* load file
1366 * Argument: "<filename>"
1367 * Overlay: "at <left> <top> <right> <bottom>" additional
1369 static DWORD
1370 MCISTR_Load(_MCISTR_PROTO_) {
1371 union {
1372 MCI_LOAD_PARMS loadParams;
1373 MCI_OVLY_LOAD_PARMS ovlyloadParams;
1374 } U;
1375 int i,len,res;
1376 char *s;
1377 HANDLE x;
1379 i=0;len=0;
1380 while (i<nrofkeywords) {
1381 switch (uDevTyp) {
1382 case MCI_DEVTYPE_OVERLAY:
1383 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1384 dwFlags |= MCI_OVLY_RECT;
1385 sscanf(keywords[i+1],"%hd",&(U.ovlyloadParams.rc.left));
1386 sscanf(keywords[i+2],"%hd",&(U.ovlyloadParams.rc.top));
1387 sscanf(keywords[i+3],"%hd",&(U.ovlyloadParams.rc.right));
1388 sscanf(keywords[i+4],"%hd",&(U.ovlyloadParams.rc.bottom));
1389 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1390 continue;
1392 break;
1394 len+=strlen(keywords[i])+1;
1395 i++;
1397 s=(char*)xmalloc(len);
1398 *s='\0';
1399 while (i<nrofkeywords) {
1400 strcat(s,keywords[i]);
1401 i++;
1402 if (i<nrofkeywords) strcat(s," ");
1404 /* FIXME: messy, but I strongly suspect we have to use a
1405 * segmented pointer, so I am doing that
1407 x=USER_HEAP_ALLOC(len);
1408 U.loadParams.lpfilename=(LPSTR)MAKELONG(x,USER_HeapSel);
1409 strcpy(PTR_SEG_TO_LIN(U.loadParams.lpfilename),s);
1410 free(s);
1411 dwFlags |= MCI_LOAD_FILE;
1412 _MCI_CALL_DRIVER(MCI_LOAD,U);
1413 USER_HEAP_FREE(x);
1414 return res;
1417 /* save to file
1418 * Argument: "<filename>"
1419 * Overlay: "at <left> <top> <right> <bottom>" additional
1421 static DWORD
1422 MCISTR_Save(_MCISTR_PROTO_) {
1423 union {
1424 MCI_SAVE_PARMS saveParams;
1425 MCI_OVLY_SAVE_PARMS ovlysaveParams;
1426 } U;
1427 int i,len,res;
1428 char *s;
1429 HANDLE x;
1431 i=0;len=0;
1432 while (i<nrofkeywords) {
1433 switch (uDevTyp) {
1434 case MCI_DEVTYPE_OVERLAY:
1435 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1436 dwFlags |= MCI_OVLY_RECT;
1437 sscanf(keywords[i+1],"%hd",&(U.ovlysaveParams.rc.left));
1438 sscanf(keywords[i+2],"%hd",&(U.ovlysaveParams.rc.top));
1439 sscanf(keywords[i+3],"%hd",&(U.ovlysaveParams.rc.right));
1440 sscanf(keywords[i+4],"%hd",&(U.ovlysaveParams.rc.bottom));
1441 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1442 continue;
1444 break;
1446 len+=strlen(keywords[i])+1;
1447 i++;
1449 s=(char*)xmalloc(len);
1450 *s='\0';
1451 while (i<nrofkeywords) {
1452 strcat(s,keywords[i]);
1453 i++;
1454 if (i<nrofkeywords) strcat(s," ");
1456 /* FIXME: messy, but I strongly suspect we have to use a
1457 * segmented pointer, so I am doing that
1459 x=USER_HEAP_ALLOC(len);
1460 U.saveParams.lpfilename=(LPSTR)MAKELONG(x,USER_HeapSel);
1461 strcpy(PTR_SEG_TO_LIN(U.saveParams.lpfilename),s);
1462 free(s);
1463 dwFlags |= MCI_LOAD_FILE;
1464 _MCI_CALL_DRIVER(MCI_SAVE,U);
1465 USER_HEAP_FREE(x);
1466 return res;
1469 /* prepare device for input/output
1470 * (only applyable to waveform audio)
1472 static DWORD
1473 MCISTR_Cue(_MCISTR_PROTO_) {
1474 MCI_GENERIC_PARMS cueParams;
1475 int i,res;
1477 i=0;
1478 while (i<nrofkeywords) {
1479 switch (uDevTyp) {
1480 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1481 FLAG1("input",MCI_WAVE_INPUT);
1482 FLAG1("output",MCI_WAVE_OUTPUT);
1483 break;
1485 i++;
1487 _MCI_CALL_DRIVER(MCI_CUE,cueParams);
1488 return res;
1491 /* delete information */
1492 static DWORD
1493 MCISTR_Delete(_MCISTR_PROTO_) {
1494 int timef,nrargs,i,j,k,a[4],res;
1495 char *parsestr;
1496 MCI_WAVE_DELETE_PARMS deleteParams;
1498 /* only implemented for waveform audio */
1499 if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
1500 return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
1501 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1502 if (res) return res;
1503 switch (timef) {
1504 case MCI_FORMAT_MILLISECONDS:
1505 case MCI_FORMAT_FRAMES:
1506 case MCI_FORMAT_BYTES:
1507 case MCI_FORMAT_SAMPLES:
1508 nrargs=1;
1509 parsestr="%d";
1510 break;
1511 case MCI_FORMAT_HMS:
1512 case MCI_FORMAT_MSF:
1513 parsestr="%d:%d:%d";
1514 nrargs=3;
1515 break;
1516 case MCI_FORMAT_TMSF:
1517 parsestr="%d:%d:%d:%d";
1518 nrargs=4;
1519 break;
1520 default:fprintf(stdnimp,"mciSendString:DELETE:unknown timeformat %d, please report.\n",timef);
1521 parsestr="%d";
1522 nrargs=1;
1523 break;
1525 i=0;
1526 while (i<nrofkeywords) {
1527 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1528 dwFlags |= MCI_TO;
1529 a[0]=a[1]=a[2]=a[3]=0;
1530 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1531 /* add up all integers we got, if we have more
1532 * shift them. (Well I should use the macros in
1533 * mmsystem.h, right).
1535 deleteParams.dwTo=0;
1536 for (k=0;k<j;k++)
1537 deleteParams.dwTo+=a[k]<<(8*(nrargs-k));
1538 i+=2;
1539 continue;
1541 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1542 dwFlags |= MCI_FROM;
1543 a[0]=a[1]=a[2]=a[3]=0;
1544 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1545 /* dito. */
1546 deleteParams.dwFrom=0;
1547 for (k=0;k<j;k++)
1548 deleteParams.dwFrom+=a[k]<<(8*(nrargs-k));
1549 i+=2;
1550 continue;
1552 i++;
1554 _MCI_CALL_DRIVER(MCI_DELETE,deleteParams);
1555 return res;
1558 /* send command to device. only applies to videodisc */
1559 static DWORD
1560 MCISTR_Escape(_MCISTR_PROTO_) {
1561 MCI_VD_ESCAPE_PARMS escapeParams;
1562 int i,len,res;
1563 char *s;
1564 HANDLE x;
1566 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1567 return MCIERR_UNSUPPORTED_FUNCTION;
1568 i=0;len=0;
1569 while (i<nrofkeywords) {
1570 len+=strlen(keywords[i])+1;
1571 i++;
1573 s=(char*)xmalloc(len);
1574 *s='\0';
1575 while (i<nrofkeywords) {
1576 strcat(s,keywords[i]);
1577 i++;
1578 if (i<nrofkeywords) strcat(s," ");
1580 /* FIXME: messy, but I strongly suspect we have to use a
1581 * segmented pointer, so I am doing that
1583 x=USER_HEAP_ALLOC(len);
1584 escapeParams.lpstrCommand=(LPSTR)MAKELONG(x,USER_HeapSel);
1585 strcpy(PTR_SEG_TO_LIN(escapeParams.lpstrCommand),s);
1586 free(s);
1587 dwFlags |= MCI_VD_ESCAPE_STRING;
1588 _MCI_CALL_DRIVER(MCI_ESCAPE,escapeParams);
1589 USER_HEAP_FREE(x);
1590 return res;
1593 /* unfreeze [part of] the overlayed video
1594 * only applyable to Overlay devices
1596 static DWORD
1597 MCISTR_Unfreeze(_MCISTR_PROTO_) {
1598 MCI_OVLY_RECT_PARMS unfreezeParams;
1599 int i,res;
1601 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1602 return MCIERR_UNSUPPORTED_FUNCTION;
1603 i=0;while (i<nrofkeywords) {
1604 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1605 sscanf(keywords[i+1],"%hd",&(unfreezeParams.rc.left));
1606 sscanf(keywords[i+2],"%hd",&(unfreezeParams.rc.top));
1607 sscanf(keywords[i+3],"%hd",&(unfreezeParams.rc.right));
1608 sscanf(keywords[i+4],"%hd",&(unfreezeParams.rc.bottom));
1609 dwFlags |= MCI_OVLY_RECT;
1610 i+=5;
1611 continue;
1613 i++;
1615 _MCI_CALL_DRIVER(MCI_UNFREEZE,unfreezeParams);
1616 return res;
1618 /* freeze [part of] the overlayed video
1619 * only applyable to Overlay devices
1621 static DWORD
1622 MCISTR_Freeze(_MCISTR_PROTO_) {
1623 MCI_OVLY_RECT_PARMS freezeParams;
1624 int i,res;
1626 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1627 return MCIERR_UNSUPPORTED_FUNCTION;
1628 i=0;while (i<nrofkeywords) {
1629 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1630 sscanf(keywords[i+1],"%hd",&(freezeParams.rc.left));
1631 sscanf(keywords[i+2],"%hd",&(freezeParams.rc.top));
1632 sscanf(keywords[i+3],"%hd",&(freezeParams.rc.right));
1633 sscanf(keywords[i+4],"%hd",&(freezeParams.rc.bottom));
1634 dwFlags |= MCI_OVLY_RECT;
1635 i+=5;
1636 continue;
1638 i++;
1640 _MCI_CALL_DRIVER(MCI_FREEZE,freezeParams);
1641 return res;
1644 /* copy parts of image to somewhere else
1645 * "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
1646 * "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
1647 * Overlay:
1648 * "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
1649 * where the video input is placed
1650 * "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
1651 * (defining part of input to
1652 * be displayed)
1654 * FIXME: This whole junk is passing multiple rectangles.
1655 * I don't know how to do that with the present interface.
1656 * (Means code below is broken)
1658 static DWORD
1659 MCISTR_Put(_MCISTR_PROTO_) {
1660 union {
1661 MCI_OVLY_RECT_PARMS ovlyputParams;
1662 MCI_ANIM_RECT_PARMS animputParams;
1663 } U;
1664 int i,res;
1665 i=0;while (i<nrofkeywords) {
1666 switch (uDevTyp) {
1667 case MCI_DEVTYPE_ANIMATION:
1668 FLAG1("source",MCI_ANIM_PUT_SOURCE);
1669 FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
1670 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1671 sscanf(keywords[i+1],"%hd",&(U.animputParams.rc.left));
1672 sscanf(keywords[i+2],"%hd",&(U.animputParams.rc.top));
1673 sscanf(keywords[i+3],"%hd",&(U.animputParams.rc.right));
1674 sscanf(keywords[i+4],"%hd",&(U.animputParams.rc.bottom));
1675 dwFlags |= MCI_ANIM_RECT;
1676 i+=5;
1677 continue;
1679 break;
1680 case MCI_DEVTYPE_OVERLAY:
1681 FLAG1("source",MCI_OVLY_PUT_SOURCE);
1682 FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
1683 FLAG1("video",MCI_OVLY_PUT_VIDEO);
1684 FLAG1("frame",MCI_OVLY_PUT_FRAME);
1685 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1686 sscanf(keywords[i+1],"%hd",&(U.ovlyputParams.rc.left));
1687 sscanf(keywords[i+2],"%hd",&(U.ovlyputParams.rc.top));
1688 sscanf(keywords[i+3],"%hd",&(U.ovlyputParams.rc.right));
1689 sscanf(keywords[i+4],"%hd",&(U.ovlyputParams.rc.bottom));
1690 dwFlags |= MCI_OVLY_RECT;
1691 i+=5;
1692 continue;
1694 break;
1696 i++;
1698 _MCI_CALL_DRIVER(MCI_PUT,U);
1699 return res;
1702 /* palette behaviour changing
1703 * (Animation only)
1704 * "normal" realize the palette normally
1705 * "background" realize the palette as background palette
1707 static DWORD
1708 MCISTR_Realize(_MCISTR_PROTO_) {
1709 MCI_GENERIC_PARMS realizeParams;
1710 int i,res;
1712 if (uDevTyp != MCI_DEVTYPE_ANIMATION)
1713 return MCIERR_UNSUPPORTED_FUNCTION;
1714 i=0;
1715 while (i<nrofkeywords) {
1716 FLAG1("background",MCI_ANIM_REALIZE_BKGD);
1717 FLAG1("normal",MCI_ANIM_REALIZE_NORM);
1718 i++;
1720 _MCI_CALL_DRIVER(MCI_REALIZE,realizeParams);
1721 return res;
1724 /* videodisc spinning
1725 * "up"
1726 * "down"
1728 static DWORD
1729 MCISTR_Spin(_MCISTR_PROTO_) {
1730 MCI_GENERIC_PARMS spinParams;
1731 int i,res;
1733 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1734 return MCIERR_UNSUPPORTED_FUNCTION;
1735 i=0;
1736 while (i<nrofkeywords) {
1737 FLAG1("up",MCI_VD_SPIN_UP);
1738 FLAG1("down",MCI_VD_SPIN_UP);
1739 i++;
1741 _MCI_CALL_DRIVER(MCI_SPIN,spinParams);
1742 return res;
1745 /* step single frames
1746 * "reverse" optional flag
1747 * "by <nr>" for <nr> frames
1749 static DWORD
1750 MCISTR_Step(_MCISTR_PROTO_) {
1751 union {
1752 MCI_ANIM_STEP_PARMS animstepParams;
1753 MCI_VD_STEP_PARMS vdstepParams;
1754 } U;
1755 int i,res;
1757 i=0;
1758 while (i<nrofkeywords) {
1759 switch (uDevTyp) {
1760 case MCI_DEVTYPE_ANIMATION:
1761 FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
1762 if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
1763 sscanf(keywords[i+1],"%ld",&(U.animstepParams.dwFrames));
1764 dwFlags |= MCI_ANIM_STEP_FRAMES;
1765 i+=2;
1766 continue;
1768 break;
1769 case MCI_DEVTYPE_VIDEODISC:
1770 FLAG1("reverse",MCI_VD_STEP_REVERSE);
1771 if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
1772 sscanf(keywords[i+1],"%ld",&(U.vdstepParams.dwFrames));
1773 dwFlags |= MCI_VD_STEP_FRAMES;
1774 i+=2;
1775 continue;
1777 break;
1779 i++;
1781 _MCI_CALL_DRIVER(MCI_STEP,U);
1782 return res;
1785 /* update animation window
1786 * Arguments:
1787 * "at <left> <top> <right> <bottom>" only in this rectangle
1788 * "hdc" device context
1790 static DWORD
1791 MCISTR_Update(_MCISTR_PROTO_) {
1792 int i,res;
1793 MCI_ANIM_UPDATE_PARMS updateParams;
1795 i=0;
1796 while (i<nrofkeywords) {
1797 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1798 sscanf(keywords[i+1],"%hd",&(updateParams.rc.left));
1799 sscanf(keywords[i+2],"%hd",&(updateParams.rc.top));
1800 sscanf(keywords[i+3],"%hd",&(updateParams.rc.right));
1801 sscanf(keywords[i+4],"%hd",&(updateParams.rc.bottom));
1802 dwFlags |= MCI_ANIM_RECT;
1803 i+=5;
1804 continue;
1806 if (!STRCMP(keywords[i],"hdc") && (i+1<nrofkeywords)) {
1807 dwFlags |= MCI_ANIM_UPDATE_HDC;
1808 sscanf(keywords[i+1],"%hd",&(updateParams.hDC));
1809 i+=2;
1810 continue;
1812 i++;
1814 _MCI_CALL_DRIVER(MCI_UPDATE,updateParams);
1815 return res;
1818 /* where command for animation and overlay drivers.
1819 * just returns the specified rectangle as a string
1820 * Arguments:
1821 * "source"
1822 * "destination"
1823 * Overlay special:
1824 * "video"
1825 * "frame"
1827 static DWORD
1828 MCISTR_Where(_MCISTR_PROTO_) {
1829 union {
1830 MCI_ANIM_RECT_PARMS animwhereParams;
1831 MCI_OVLY_RECT_PARMS ovlywhereParams;
1832 } U;
1833 int i,res;
1835 i=0;
1836 while (i<nrofkeywords) {
1837 switch (uDevTyp) {
1838 case MCI_DEVTYPE_ANIMATION:
1839 FLAG1("source",MCI_ANIM_WHERE_SOURCE);
1840 FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
1841 break;
1842 case MCI_DEVTYPE_OVERLAY:
1843 FLAG1("source",MCI_OVLY_WHERE_SOURCE);
1844 FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
1845 FLAG1("video",MCI_OVLY_WHERE_VIDEO);
1846 FLAG1("frame",MCI_OVLY_WHERE_FRAME);
1847 break;
1849 i++;
1851 _MCI_CALL_DRIVER(MCI_WHERE,U);
1852 if (res==0) {
1853 char buf[100];
1854 switch (uDevTyp) {
1855 case MCI_DEVTYPE_ANIMATION:
1856 sprintf(buf,"%d %d %d %d",
1857 U.animwhereParams.rc.left,
1858 U.animwhereParams.rc.top,
1859 U.animwhereParams.rc.right,
1860 U.animwhereParams.rc.bottom
1862 break;
1863 case MCI_DEVTYPE_OVERLAY:
1864 sprintf(buf,"%d %d %d %d",
1865 U.ovlywhereParams.rc.left,
1866 U.ovlywhereParams.rc.top,
1867 U.ovlywhereParams.rc.right,
1868 U.ovlywhereParams.rc.bottom
1870 break;
1871 default:strcpy(buf,"0 0 0 0");break;
1873 _MCI_STR(buf);
1875 return res;
1878 static DWORD
1879 MCISTR_Window(_MCISTR_PROTO_) {
1880 int i,res;
1881 char *s;
1882 union {
1883 MCI_ANIM_WINDOW_PARMS animwindowParams;
1884 MCI_OVLY_WINDOW_PARMS ovlywindowParams;
1885 } U;
1887 s=NULL;
1888 i=0;
1889 while (i<nrofkeywords) {
1890 switch (uDevTyp) {
1891 case MCI_DEVTYPE_ANIMATION:
1892 if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
1893 dwFlags |= MCI_ANIM_WINDOW_HWND;
1894 if (!STRCMP(keywords[i+1],"default"))
1895 U.animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1896 else
1897 sscanf(keywords[i+1],"%hd",&(U.animwindowParams.hWnd));
1898 i+=2;
1899 continue;
1901 if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
1902 dwFlags |= MCI_ANIM_WINDOW_STATE;
1903 if (!STRCMP(keywords[i+1],"hide"))
1904 U.animwindowParams.nCmdShow = SW_HIDE;
1905 if (!STRCMP(keywords[i+1],"iconic"))
1906 U.animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1907 if (!STRCMP(keywords[i+1],"minimized"))
1908 U.animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
1909 if (!STRCMP(keywords[i+1],"maximized"))
1910 U.animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1911 if (!STRCMP(keywords[i+1],"minimize"))
1912 U.animwindowParams.nCmdShow = SW_MINIMIZE;
1913 if (!STRCMP(keywords[i+1],"normal"))
1914 U.animwindowParams.nCmdShow = SW_NORMAL;
1915 if (!STRCMP(keywords[i+1],"show"))
1916 U.animwindowParams.nCmdShow = SW_SHOW;
1917 if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
1918 if (!STRCMP(keywords[i+2],"active"))
1919 U.animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1920 if (!STRCMP(keywords[i+2],"action"))
1921 U.animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1922 i++;
1924 i+=2;
1925 continue;
1927 /* text is enclosed in " ... " as it seems */
1928 if (!STRCMP(keywords[i],"text")) {
1929 char *t;
1930 int len,j,k;
1932 if (keywords[i+1][0]!='"') {
1933 i++;
1934 continue;
1936 dwFlags |= MCI_ANIM_WINDOW_TEXT;
1937 len = strlen(keywords[i+1])+1;
1938 j = i+2;
1939 while (j<nrofkeywords) {
1940 len += strlen(keywords[j])+1;
1941 if (strchr(keywords[j],'"'))
1942 break;
1943 j++;
1945 s=(char*)xmalloc(len);
1946 strcpy(s,keywords[i+1]+1);
1947 k=j;j=i+2;
1948 while (j<=k) {
1949 strcat(s," ");
1950 strcat(s,keywords[j]);
1952 if ((t=strchr(s,'"'))) *t='\0';
1953 /* FIXME: segmented pointer? */
1954 U.animwindowParams.lpstrText = s;
1955 i=k+1;
1956 continue;
1958 FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
1959 break;
1960 case MCI_DEVTYPE_OVERLAY:
1961 if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
1962 dwFlags |= MCI_OVLY_WINDOW_HWND;
1963 if (!STRCMP(keywords[i+1],"default"))
1964 U.ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1965 else
1966 sscanf(keywords[i+1],"%hd",&(U.ovlywindowParams.hWnd));
1967 i+=2;
1968 continue;
1970 if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
1971 dwFlags |= MCI_OVLY_WINDOW_STATE;
1972 if (!STRCMP(keywords[i+1],"hide"))
1973 U.ovlywindowParams.nCmdShow = SW_HIDE;
1974 if (!STRCMP(keywords[i+1],"iconic"))
1975 U.ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1976 if (!STRCMP(keywords[i+1],"minimized"))
1977 U.ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
1978 if (!STRCMP(keywords[i+1],"maximized"))
1979 U.ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1980 if (!STRCMP(keywords[i+1],"minimize"))
1981 U.ovlywindowParams.nCmdShow = SW_MINIMIZE;
1982 if (!STRCMP(keywords[i+1],"normal"))
1983 U.ovlywindowParams.nCmdShow = SW_NORMAL;
1984 if (!STRCMP(keywords[i+1],"show"))
1985 U.ovlywindowParams.nCmdShow = SW_SHOW;
1986 if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
1987 if (!STRCMP(keywords[i+2],"active"))
1988 U.ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1989 if (!STRCMP(keywords[i+2],"action"))
1990 U.ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1991 i++;
1993 i+=2;
1994 continue;
1996 /* text is enclosed in " ... " as it seems */
1997 if (!STRCMP(keywords[i],"text")) {
1998 char *t;
1999 int len,j,k;
2001 if (keywords[i+1][0]!='"') {
2002 i++;
2003 continue;
2005 dwFlags |= MCI_OVLY_WINDOW_TEXT;
2006 len = strlen(keywords[i+1])+1;
2007 j = i+2;
2008 while (j<nrofkeywords) {
2009 len += strlen(keywords[j])+1;
2010 if (strchr(keywords[j],'"'))
2011 break;
2012 j++;
2014 s=(char*)xmalloc(len);
2015 strcpy(s,keywords[i+1]+1);
2016 k=j;j=i+2;
2017 while (j<=k) {
2018 strcat(s," ");
2019 strcat(s,keywords[j]);
2021 if ((t=strchr(s,'"'))) *t='\0';
2022 /* FIXME: segmented pointer? */
2023 U.ovlywindowParams.lpstrText = s;
2024 i=k+1;
2025 continue;
2027 FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
2028 break;
2030 i++;
2032 _MCI_CALL_DRIVER(MCI_WINDOW,U);
2033 if (s) free(s);
2034 return res;
2037 struct _MCISTR_cmdtable {
2038 char *cmd;
2039 DWORD (*fun)(_MCISTR_PROTO_);
2040 } MCISTR_cmdtable[]={
2041 {"break", MCISTR_Break},
2042 {"capability", MCISTR_Capability},
2043 {"close", MCISTR_Close},
2044 {"cue", MCISTR_Cue},
2045 {"delete", MCISTR_Delete},
2046 {"escape", MCISTR_Escape},
2047 {"freeze", MCISTR_Freeze},
2048 {"info", MCISTR_Info},
2049 {"load", MCISTR_Load},
2050 {"open", MCISTR_Open},
2051 {"pause", MCISTR_Pause},
2052 {"play", MCISTR_Play},
2053 {"put", MCISTR_Put},
2054 {"realize", MCISTR_Realize},
2055 {"record", MCISTR_Record},
2056 {"resume", MCISTR_Resume},
2057 {"save", MCISTR_Save},
2058 {"seek", MCISTR_Seek},
2059 {"set", MCISTR_Set},
2060 {"spin", MCISTR_Spin},
2061 {"status", MCISTR_Status},
2062 {"step", MCISTR_Step},
2063 {"stop", MCISTR_Stop},
2064 {"sysinfo", MCISTR_Sysinfo},
2065 {"unfreeze", MCISTR_Unfreeze},
2066 {"update", MCISTR_Update},
2067 {"where", MCISTR_Where},
2068 {"window", MCISTR_Window},
2069 {NULL, NULL}
2071 /**************************************************************************
2072 * mciSendString [MMSYSTEM.702]
2074 /* The usercode sends a string with a command (and flags) expressed in
2075 * words in it... We do our best to call aprobiate drivers,
2076 * and return a errorcode AND a readable string (if lpstrRS!=NULL)
2077 * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
2079 /* FIXME: "all" is a valid devicetype and we should access all devices if
2080 * it is used. (imagine "close all"). Not implemented yet.
2082 DWORD mciSendString (LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2083 UINT uReturnLength, HWND hwndCallback)
2085 char *cmd,*dev,*args,**keywords;
2086 WORD uDevTyp=0,wDevID=0;
2087 DWORD dwFlags;
2088 int res=0,i,nrofkeywords;
2090 dprintf_mci(stdnimp,"mciSendString('%s', %p, %d, %X)\n", lpstrCommand,
2091 lpstrReturnString, uReturnLength, hwndCallback
2093 /* format is <command> <device> <optargs> */
2094 cmd=strdup(lpstrCommand);
2095 dev=strchr(cmd,' ');
2096 if (dev==NULL) {
2097 free(cmd);
2098 return MCIERR_MISSING_DEVICE_NAME;
2100 *dev++='\0';
2101 args=strchr(dev,' ');
2102 if (args!=NULL) *args++='\0';
2103 AnsiUpper(dev);
2104 if (args!=NULL) {
2105 char *s;
2106 i=1;/* nrofkeywords = nrofspaces+1 */
2107 s=args;
2108 while ((s=strchr(s,' '))!=NULL) i++,s++;
2109 keywords=(char**)xmalloc(sizeof(char*)*(i+2));
2110 nrofkeywords=i;
2111 s=args;i=0;
2112 while (s && i<nrofkeywords) {
2113 keywords[i++]=s;
2114 s=strchr(s,' ');
2115 if (s) *s++='\0';
2117 keywords[i]=NULL;
2118 } else {
2119 nrofkeywords=0;
2120 keywords=(char**)xmalloc(sizeof(char*));
2122 dwFlags = 0; /* default flags */
2123 for (i=0;i<nrofkeywords;) {
2124 if (!STRCMP(keywords[i],"wait")) {
2125 dwFlags |= MCI_WAIT;
2126 memcpy(keywords+i,keywords+(i+1),nrofkeywords-i-1);
2127 nrofkeywords--;
2128 continue;
2130 if (!STRCMP(keywords[i],"notify")) {
2131 /* how should we callback? I don't know. */
2132 /*dwFlags |= MCI_NOTIFY;*/
2133 memcpy(keywords+i,keywords+(i+1),nrofkeywords-i-1);
2134 nrofkeywords--;
2135 continue;
2137 i++;
2140 /* determine wDevID and uDevTyp for all commands except "open" */
2141 if (STRCMP(cmd,"open")!=0) {
2142 wDevID=0;
2143 while (1) {
2144 SEGPTR dname;
2146 dname=(SEGPTR)mciOpenDrv[wDevID].lpstrAlias;
2147 if (dname==NULL)
2148 dname=(SEGPTR)mciOpenDrv[wDevID].lpstrDeviceType;
2149 if (!STRCMP(PTR_SEG_TO_LIN(dname),dev))
2150 break;
2151 if (++wDevID >= MAXMCIDRIVERS) {
2152 dprintf_mci(stddeb, __FILE__":mciSendString:MAXMCIDRIVERS reached!\n");
2153 free(keywords);free(cmd);
2154 return MCIERR_INTERNAL;
2157 uDevTyp=mciDrv[wDevID].wType;
2160 for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
2161 if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
2162 res=MCISTR_cmdtable[i].fun(
2163 wDevID,uDevTyp,lpstrReturnString,
2164 uReturnLength,dev,keywords,nrofkeywords,
2165 dwFlags
2167 break;
2170 if (MCISTR_cmdtable[i].cmd!=NULL) {
2171 free(keywords);free(cmd);
2172 return res;
2174 fprintf(stdnimp,"mciSendString('%s', %p, %u, %X) // unimplemented, please report.\n", lpstrCommand,
2175 lpstrReturnString, uReturnLength, hwndCallback
2177 free(keywords);free(cmd);
2178 return MCIERR_MISSING_COMMAND_STRING;
2180 #endif