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