Protect against multiple includes.
[wine/multimedia.git] / multimedia / mcistring.c
blob76580ddc6663a9925bc56e1d1bef7845b25cd3fc
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MCI stringinterface
6 * Copyright 1995 Marcus Meissner
7 */
8 /* FIXME: special commands of device drivers should be handled by those drivers
9 */
11 /* FIXME: this current implementation does not allow commands like
12 * capability <filename> can play
13 * which is allowed by the MCI standard.
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #include "windows.h"
22 #include "heap.h"
23 #include "ldt.h"
24 #include "user.h"
25 #include "driver.h"
26 #include "mmsystem.h"
27 #include "multimedia.h"
28 #include "callback.h"
29 #include "debug.h"
30 #include "xmalloc.h"
32 extern struct WINE_MCIDRIVER mciDrv[MAXMCIDRIVERS];
34 #define MCI_GetDrv(wDevID) (&mciDrv[MCI_DevIDToIndex(wDevID)])
35 #define MCI_GetOpenDrv(wDevID) (&(MCI_GetDrv(wDevID)->mop))
37 LONG WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
38 DWORD dwParam1, DWORD dwParam2);
40 /* The reason why I just don't lowercase the keywords array in
41 * mciSendString is left as an exercise to the reader.
43 #define STRCMP(x,y) lstrcmpi32A(x,y)
45 /* standard functionparameters for all functions */
46 #define _MCISTR_PROTO_ \
47 WORD wDevID,WORD uDevTyp,LPSTR lpstrReturnString,UINT16 uReturnLength,\
48 LPCSTR dev,LPSTR *keywords,UINT16 nrofkeywords,DWORD dwFlags,\
49 HWND16 hwndCallback
51 /* copy string to return pointer including necessary checks
52 * for use in mciSendString()
54 #define _MCI_STR(s) do {\
55 TRACE(mci,"->returns '%s'\n",s);\
56 if (lpstrReturnString) {\
57 lstrcpyn32A(lpstrReturnString,s,uReturnLength);\
58 TRACE(mci,"-->'%s'\n",lpstrReturnString);\
60 } while(0)
62 /* print a DWORD in the specified timeformat */
63 static void
64 _MCISTR_printtf(char *buf,UINT16 uDevType,DWORD timef,DWORD val) {
65 *buf='\0';
66 switch (timef) {
67 case MCI_FORMAT_MILLISECONDS:
68 case MCI_FORMAT_FRAMES:
69 case MCI_FORMAT_BYTES:
70 case MCI_FORMAT_SAMPLES:
71 case MCI_VD_FORMAT_TRACK:
72 /*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
73 sprintf(buf,"%ld",val);
74 break;
75 case MCI_FORMAT_HMS:
76 /* well, the macros have the same content*/
77 /*FALLTRHOUGH*/
78 case MCI_FORMAT_MSF:
79 sprintf(buf,"%d:%d:%d",
80 MCI_HMS_HOUR(val),
81 MCI_HMS_MINUTE(val),
82 MCI_HMS_SECOND(val)
84 break;
85 case MCI_FORMAT_TMSF:
86 sprintf(buf,"%d:%d:%d:%d",
87 MCI_TMSF_TRACK(val),
88 MCI_TMSF_MINUTE(val),
89 MCI_TMSF_SECOND(val),
90 MCI_TMSF_FRAME(val)
92 break;
93 default:
94 FIXME(mci, "missing timeformat for %ld, report.\n",timef);
95 strcpy(buf,"0"); /* hmm */
96 break;
98 return;
100 /* possible different return types */
101 #define _MCISTR_int 1
102 #define _MCISTR_time 2
103 #define _MCISTR_bool 3
104 #define _MCISTR_tfname 4
105 #define _MCISTR_mode 5
106 #define _MCISTR_divtype 6
107 #define _MCISTR_seqtype 7
108 #define _MCISTR_vdmtype 8
109 #define _MCISTR_devtype 9
111 static void
112 _MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
113 WORD uReturnLength,WORD uDevTyp,int timef
115 switch (type) {
116 case _MCISTR_vdmtype:
117 switch (dwReturn) {
118 case MCI_VD_MEDIA_CLV:_MCI_STR("CLV");break;
119 case MCI_VD_MEDIA_CAV:_MCI_STR("CAV");break;
120 default:
121 case MCI_VD_MEDIA_OTHER:_MCI_STR("other");break;
123 break;
124 case _MCISTR_seqtype:
125 switch (dwReturn) {
126 case MCI_SEQ_NONE:_MCI_STR("none");break;
127 case MCI_SEQ_SMPTE:_MCI_STR("smpte");break;
128 case MCI_SEQ_FILE:_MCI_STR("file");break;
129 case MCI_SEQ_MIDI:_MCI_STR("midi");break;
130 default:FIXME(mci,"missing sequencer mode %ld\n",dwReturn);
132 break;
133 case _MCISTR_mode:
134 switch (dwReturn) {
135 case MCI_MODE_NOT_READY:_MCI_STR("not ready");break;
136 case MCI_MODE_STOP:_MCI_STR("stopped");break;
137 case MCI_MODE_PLAY:_MCI_STR("playing");break;
138 case MCI_MODE_RECORD:_MCI_STR("recording");break;
139 case MCI_MODE_SEEK:_MCI_STR("seeking");break;
140 case MCI_MODE_PAUSE:_MCI_STR("paused");break;
141 case MCI_MODE_OPEN:_MCI_STR("open");break;
142 default:break;
144 break;
145 case _MCISTR_bool:
146 if (dwReturn)
147 _MCI_STR("true");
148 else
149 _MCI_STR("false");
150 break;
151 case _MCISTR_int:{
152 char buf[16];
153 sprintf(buf,"%ld",dwReturn);
154 _MCI_STR(buf);
155 break;
157 case _MCISTR_time: {
158 char buf[100];
159 _MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
160 _MCI_STR(buf);
161 break;
163 case _MCISTR_tfname:
164 switch (timef) {
165 case MCI_FORMAT_MILLISECONDS:_MCI_STR("milliseconds");break;
166 case MCI_FORMAT_FRAMES:_MCI_STR("frames");break;
167 case MCI_FORMAT_BYTES:_MCI_STR("bytes");break;
168 case MCI_FORMAT_SAMPLES:_MCI_STR("samples");break;
169 case MCI_FORMAT_HMS:_MCI_STR("hms");break;
170 case MCI_FORMAT_MSF:_MCI_STR("msf");break;
171 case MCI_FORMAT_TMSF:_MCI_STR("tmsf");break;
172 default:
173 FIXME(mci,"missing timefmt for %d, report.\n",timef);
174 break;
176 break;
177 case _MCISTR_divtype:
178 switch (dwReturn) {
179 case MCI_SEQ_DIV_PPQN:_MCI_STR("PPQN");break;
180 case MCI_SEQ_DIV_SMPTE_24:_MCI_STR("SMPTE 24 frame");break;
181 case MCI_SEQ_DIV_SMPTE_25:_MCI_STR("SMPTE 25 frame");break;
182 case MCI_SEQ_DIV_SMPTE_30:_MCI_STR("SMPTE 30 frame");break;
183 case MCI_SEQ_DIV_SMPTE_30DROP:_MCI_STR("SMPTE 30 frame drop");break;
185 case _MCISTR_devtype:
186 switch (dwReturn) {
187 case MCI_DEVTYPE_VCR:_MCI_STR("vcr");break;
188 case MCI_DEVTYPE_VIDEODISC:_MCI_STR("videodisc");break;
189 case MCI_DEVTYPE_CD_AUDIO:_MCI_STR("cd audio");break;
190 case MCI_DEVTYPE_OVERLAY:_MCI_STR("overlay");break;
191 case MCI_DEVTYPE_DAT:_MCI_STR("dat");break;
192 case MCI_DEVTYPE_SCANNER:_MCI_STR("scanner");break;
193 case MCI_DEVTYPE_ANIMATION:_MCI_STR("animation");break;
194 case MCI_DEVTYPE_DIGITAL_VIDEO:_MCI_STR("digital video");break;
195 case MCI_DEVTYPE_OTHER:_MCI_STR("other");break;
196 case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio");break;
197 case MCI_DEVTYPE_SEQUENCER:_MCI_STR("sequencer");break;
198 default:FIXME(mci,"unknown device type %ld, report.\n",
199 dwReturn);break;
201 break;
202 default:
203 FIXME(mci,"unknown resulttype %d, report.\n",type);
204 break;
208 #define FLAG1(str,flag) \
209 if (!STRCMP(keywords[i],str)) {\
210 dwFlags |= flag;\
211 i++;\
212 continue;\
214 #define FLAG2(str1,str2,flag) \
215 if (!STRCMP(keywords[i],str1) && (i+1<nrofkeywords) && !STRCMP(keywords[i+1],str2)) {\
216 dwFlags |= flag;\
217 i+=2;\
218 continue;\
221 /* All known subcommands are implemented in single functions to avoid
222 * bloat and a xxxx lines long mciSendString(). All commands are of the
223 * format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
224 * defined line of arguments. (This is just for easy enhanceability.)
225 * All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
226 * for the calls are in lpstrReturnString (If I mention return values
227 * in function headers, I mean returnvalues in lpstrReturnString.)
228 * Integers are sprintf("%d")ed integers. Boolean values are
229 * "true" and "false".
230 * timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
231 * FIXME: is above line correct?
233 * Preceding every function is a list of implemented/known arguments.
234 * Feel free to add missing arguments.
239 * Opens the specified MCI driver.
240 * Arguments: <name>
241 * Optional:
242 * "shareable"
243 * "alias <aliasname>"
244 * "element <elementname>"
245 * Additional:
246 * waveform audio:
247 * "buffer <nrBytesPerSec>"
248 * Animation:
249 * "nostatic" increaste nr of nonstatic colours
250 * "parent <windowhandle>"
251 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
252 * "style child" WS_CHILD
253 * "style overlap" WS_OVERLAPPED
254 * "style popup" WS_POPUP
255 * Overlay:
256 * "parent <windowhandle>"
257 * "style <mask>" bitmask of WS_xxxxx (see windows.h)
258 * "style child" WS_CHILD
259 * "style overlap" WS_OVERLAPPED
260 * "style popup" WS_POPUP
261 * Returns nothing.
263 static DWORD
264 MCISTR_Open(_MCISTR_PROTO_) {
265 int res,i;
266 char *s;
267 union U {
268 MCI_OPEN_PARMS16 openParams;
269 MCI_WAVE_OPEN_PARMS16 waveopenParams;
270 MCI_ANIM_OPEN_PARMS16 animopenParams;
271 MCI_OVLY_OPEN_PARMS16 ovlyopenParams;
273 union U *pU = xmalloc(sizeof(union U));
275 pU->openParams.lpstrElementName = NULL;
276 s=strchr(dev,'!');
277 if (s!=NULL) {
278 *s++='\0';
279 pU->openParams.lpstrElementName=strdup(s);
280 dwFlags |= MCI_OPEN_ELEMENT;
282 uDevTyp = MCI_GetDevType(dev);
283 if (uDevTyp == 0) {
284 free(pU->openParams.lpstrElementName);
285 free(pU);
286 return MCIERR_INVALID_DEVICE_NAME;
288 wDevID=MCI_FirstDevID();
289 while(MCI_GetDrv(wDevID)->modp.wType) {
290 wDevID = MCI_NextDevID(wDevID);
291 if (!MCI_DevIDValid(wDevID)) {
292 TRACE(mci, "MAXMCIDRIVERS reached (%x) !\n", wDevID);
293 free(pU->openParams.lpstrElementName);
294 free(pU);
295 return MCIERR_INTERNAL;
298 MCI_GetDrv(wDevID)->modp.wType = uDevTyp;
299 MCI_GetDrv(wDevID)->modp.wDeviceID = 0; /* FIXME? for multiple devices */
300 pU->openParams.dwCallback = hwndCallback ;
301 pU->openParams.wDeviceID = wDevID;
302 pU->openParams.wReserved0 = 0;
303 pU->ovlyopenParams.dwStyle = 0;
304 pU->animopenParams.dwStyle = 0;
305 pU->openParams.lpstrDeviceType = strdup(dev);
306 pU->openParams.lpstrAlias = NULL;
307 dwFlags |= MCI_OPEN_TYPE;
308 i=0;
309 while (i<nrofkeywords) {
310 FLAG1("shareable",MCI_OPEN_SHAREABLE);
311 if (!STRCMP(keywords[i],"alias") && (i+1<nrofkeywords)) {
312 dwFlags |= MCI_OPEN_ALIAS;
313 pU->openParams.lpstrAlias=strdup(keywords[i+1]);
314 i+=2;
315 continue;
317 if (!STRCMP(keywords[i],"element") && (i+1<nrofkeywords)) {
318 dwFlags |= MCI_OPEN_ELEMENT;
319 pU->openParams.lpstrElementName=strdup(keywords[i+1]);
320 i+=2;
321 continue;
323 switch (uDevTyp) {
324 case MCI_DEVTYPE_ANIMATION:
325 case MCI_DEVTYPE_DIGITAL_VIDEO:
326 FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
327 if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
328 dwFlags |= MCI_ANIM_OPEN_PARENT;
329 sscanf(keywords[i+1],"%hu",&(pU->animopenParams.hWndParent));
330 i+=2;
331 continue;
333 if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
334 DWORD st;
336 dwFlags |= MCI_ANIM_OPEN_WS;
337 if (!STRCMP(keywords[i+1],"popup")) {
338 pU->animopenParams.dwStyle |= WS_POPUP;
339 } else if (!STRCMP(keywords[i+1],"overlap")) {
340 pU->animopenParams.dwStyle |= WS_OVERLAPPED;
341 } else if (!STRCMP(keywords[i+1],"child")) {
342 pU->animopenParams.dwStyle |= WS_CHILD;
343 } else if (sscanf(keywords[i+1],"%ld",&st)) {
344 pU->animopenParams.dwStyle |= st;
345 } else
346 FIXME(mci,"unknown 'style' keyword %s, please report.\n",keywords[i+1]);
347 i+=2;
348 continue;
350 break;
351 case MCI_DEVTYPE_WAVEFORM_AUDIO:
352 if (!STRCMP(keywords[i],"buffer") && (i+1<nrofkeywords)) {
353 dwFlags |= MCI_WAVE_OPEN_BUFFER;
354 sscanf(keywords[i+1],"%ld",&(pU->waveopenParams.dwBufferSeconds));
356 break;
357 case MCI_DEVTYPE_OVERLAY:
358 /* looks just like anim, but without NOSTATIC */
359 if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
360 dwFlags |= MCI_OVLY_OPEN_PARENT;
361 sscanf(keywords[i+1],"%hd",&(pU->ovlyopenParams.hWndParent));
362 i+=2;
363 continue;
365 if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
366 DWORD st;
368 dwFlags |= MCI_OVLY_OPEN_WS;
369 if (!STRCMP(keywords[i+1],"popup")) {
370 pU->ovlyopenParams.dwStyle |= WS_POPUP;
371 } else if (!STRCMP(keywords[i+1],"overlap")) {
372 pU->ovlyopenParams.dwStyle |= WS_OVERLAPPED;
373 } else if (!STRCMP(keywords[i+1],"child")) {
374 pU->ovlyopenParams.dwStyle |= WS_CHILD;
375 } else if (sscanf(keywords[i+1],"%ld",&st)) {
376 pU->ovlyopenParams.dwStyle |= st;
377 } else
378 FIXME(mci,"unknown 'style' keyword %s, please report.\n",keywords[i+1]);
379 i+=2;
380 continue;
382 break;
384 FIXME(mci,"unknown parameter passed %s, please report.\n",
385 keywords[i]);
386 i++;
388 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_OPEN, dwFlags, (DWORD)pU);
390 if (res==0)
391 memcpy(MCI_GetOpenDrv(wDevID),&pU->openParams,sizeof(MCI_OPEN_PARMS16));
392 else {
393 free(pU->openParams.lpstrElementName);
394 free(pU->openParams.lpstrDeviceType);
395 free(pU->openParams.lpstrAlias);
397 free(pU);
398 return res;
401 /* A help function for a lot of others ...
402 * for instance status/play/record/seek etc.
404 DWORD
405 _MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef)
407 int res;
408 DWORD dwFlags = MCI_STATUS_ITEM;
409 MCI_STATUS_PARMS *statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
411 if (!statusParams) return 0;
412 statusParams->dwItem = MCI_STATUS_TIME_FORMAT;
413 statusParams->dwReturn = 0;
414 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_STATUS, dwFlags, (DWORD)statusParams);
416 if (res==0) *timef = statusParams->dwReturn;
417 free(statusParams);
418 return res;
421 /* query status of MCI drivers
422 * Arguments:
423 * Required:
424 * "mode" - returns "not ready" "paused" "playing" "stopped" "open"
425 * "parked" "recording" "seeking" ....
426 * Basics:
427 * "current track" - returns current track as integer
428 * "length [track <nr>]" - returns length [of track <nr>] in current
429 * timeformat
430 * "number of tracks" - returns number of tracks as integer
431 * "position [track <nr>]" - returns position [in track <nr>] in current
432 * timeformat
433 * "ready" - checks if device is ready to play, -> bool
434 * "start position" - returns start position in timeformat
435 * "time format" - returns timeformat (list of possible values:
436 * "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
437 * "bytes" "samples" "hms")
438 * "media present" - returns if media is present as bool
439 * Animation:
440 * "forward" - returns "true" if device is playing forwards
441 * "speed" - returns speed for device
442 * "palette handle" - returns palette handle
443 * "window handle" - returns window handle
444 * "stretch" - returns stretch bool
445 * MIDI sequencer:
446 * "division type" - ? returns "PPQN" "SMPTE 24 frame"
447 * "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
448 * "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
449 * "offset" - offset in dito.
450 * "port" - midi port as integer
451 * "slave" - slave device ("midi","file","none","smpte")
452 * "master" - masterdevice (dito.)
453 * Overlay:
454 * "window handle" - see animation
455 * "stretch" - dito
456 * Video Disc:
457 * "speed" - speed as integer
458 * "forward" - returns bool (when playing forward)
459 * "side" - returns 1 or 2
460 * "media type" - returns "CAV" "CLV" "other"
461 * "disc size" - returns "8" or "12"
462 * WAVEFORM audio:
463 * "input" - base queries on input set
464 * "output" - base queries on output set
465 * "format tag" - return integer format tag
466 * "channels" - return integer nr of channels
467 * "bytespersec" - return average nr of bytes/sec
468 * "samplespersec" - return nr of samples per sec
469 * "bitspersample" - return bitspersample
470 * "alignment" - return block alignment
471 * "level" - return level?
474 #define ITEM1(str,item,xtype) \
475 if (!STRCMP(keywords[i],str)) {\
476 statusParams->dwItem = item;\
477 type = xtype;\
478 i++;\
479 continue;\
481 #define ITEM2(str1,str2,item,xtype) \
482 if ( !STRCMP(keywords[i],str1) &&\
483 (i+1<nrofkeywords) &&\
484 !STRCMP(keywords[i+1],str2)\
485 ) {\
486 statusParams->dwItem = item;\
487 type = xtype;\
488 i+=2;\
489 continue;\
491 #define ITEM3(str1,str2,str3,item,xtype) \
492 if ( !STRCMP(keywords[i],str1) &&\
493 (i+2<nrofkeywords) &&\
494 !STRCMP(keywords[i+1],str2) &&\
495 !STRCMP(keywords[i+2],str3)\
496 ) {\
497 statusParams->dwItem = item;\
498 type = xtype;\
499 i+=3;\
500 continue;\
502 static DWORD
503 MCISTR_Status(_MCISTR_PROTO_) {
504 MCI_STATUS_PARMS *statusParams = xmalloc(sizeof(MCI_STATUS_PARMS));
505 int type = 0,i,res,timef;
507 statusParams->dwCallback = hwndCallback;
508 dwFlags |= MCI_STATUS_ITEM;
509 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
510 if (res) return res;
512 statusParams->dwReturn = 0;
513 statusParams->dwItem = 0;
514 i = 0;
516 while (i<nrofkeywords) {
517 if (!STRCMP(keywords[i],"track") && (i+1<nrofkeywords)) {
518 sscanf(keywords[i+1],"%ld",&(statusParams->dwTrack));
519 dwFlags |= MCI_TRACK;
520 i+=2;
521 continue;
523 FLAG1("start",MCI_STATUS_START);
524 /* generic things */
525 ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
526 ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
527 ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
528 ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
529 ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
530 ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
531 ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
532 ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
534 switch (uDevTyp) {
535 case MCI_DEVTYPE_ANIMATION:
536 case MCI_DEVTYPE_DIGITAL_VIDEO:
537 ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
538 ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
539 ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
540 ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
541 ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
542 break;
543 case MCI_DEVTYPE_SEQUENCER:
544 /* just completing the list, not working correctly */
545 ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
546 /* tempo ... PPQN in frames/second, SMPTE in hmsf */
547 ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
548 ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
549 ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
550 ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
551 /* offset ... PPQN in frames/second, SMPTE in hmsf */
552 ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
553 break;
554 case MCI_DEVTYPE_OVERLAY:
555 ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
556 ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
557 break;
558 case MCI_DEVTYPE_VIDEODISC:
559 ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
560 ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
561 ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
562 ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
563 /* returns 8 or 12 */
564 ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
565 break;
566 case MCI_DEVTYPE_WAVEFORM_AUDIO:
567 /* I am not quite sure if foll. 2 lines are right. */
568 FLAG1("input",MCI_WAVE_INPUT);
569 FLAG1("output",MCI_WAVE_OUTPUT);
571 ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
572 ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
573 ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
574 ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
575 ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
576 ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
577 ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
578 break;
580 FIXME(mci,"unknown keyword '%s'\n",keywords[i]);
581 i++;
583 if (!statusParams->dwItem)
584 return MCIERR_MISSING_STRING_ARGUMENT;
586 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_STATUS, dwFlags, (DWORD)statusParams);
588 if (res==0)
589 _MCISTR_convreturn(type,statusParams->dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
590 free(statusParams);
591 return res;
593 #undef ITEM1
594 #undef ITEM2
595 #undef ITEM3
597 /* set specified parameters in respective MCI drivers
598 * Arguments:
599 * "door open" eject media or somesuch
600 * "door close" load media
601 * "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
602 * "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
603 * "SMPTE drop 30"
604 * "audio [all|left|right] [on|off]" sets specified audiochannel on or off
605 * "video [on|off]" sets video on/off
606 * Waveform audio:
607 * "formattag pcm" sets format to pcm
608 * "formattag <nr>" sets integer formattag value
609 * "any input" accept input from any known source
610 * "any output" output to any known destination
611 * "input <nr>" input from source <nr>
612 * "output <nr>" output to destination <nr>
613 * "channels <nr>" sets nr of channels
614 * "bytespersec <nr>" sets average bytes per second
615 * "samplespersec <nr>" sets average samples per second (1 sample can
616 * be 2 bytes!)
617 * "alignment <nr>" sets the blockalignment to <nr>
618 * "bitspersample <nr>" sets the nr of bits per sample
619 * Sequencer:
620 * "master [midi|file|smpte|none]" sets the midi master device
621 * "slave [midi|file|smpte|none]" sets the midi master device
622 * "port mapper" midioutput to portmapper
623 * "port <nr>" midioutput to specified port
624 * "tempo <nr>" tempo of track (depends on timeformat/divtype)
625 * "offset <nr>" start offset?
627 static DWORD
628 MCISTR_Set(_MCISTR_PROTO_) {
629 union U {
630 MCI_SET_PARMS setParams;
631 MCI_WAVE_SET_PARMS16 wavesetParams;
632 MCI_SEQ_SET_PARMS seqsetParams;
634 union U *pU = xmalloc(sizeof(union U));
635 int i,res;
637 pU->setParams.dwCallback = hwndCallback;
638 i = 0;
639 while (i<nrofkeywords) {
640 FLAG2("door","open",MCI_SET_DOOR_OPEN);
641 FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
643 if ( !STRCMP(keywords[i],"time") &&
644 (i+2<nrofkeywords) &&
645 !STRCMP(keywords[i+1],"format")
647 dwFlags |= MCI_SET_TIME_FORMAT;
649 /* FIXME:is this a shortcut for milliseconds or
650 * minutes:seconds? */
651 if (!STRCMP(keywords[i+2],"ms"))
652 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
654 if (!STRCMP(keywords[i+2],"milliseconds"))
655 pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
656 if (!STRCMP(keywords[i+2],"msf"))
657 pU->setParams.dwTimeFormat = MCI_FORMAT_MSF;
658 if (!STRCMP(keywords[i+2],"hms"))
659 pU->setParams.dwTimeFormat = MCI_FORMAT_HMS;
660 if (!STRCMP(keywords[i+2],"frames"))
661 pU->setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
662 if (!STRCMP(keywords[i+2],"track"))
663 pU->setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
664 if (!STRCMP(keywords[i+2],"bytes"))
665 pU->setParams.dwTimeFormat = MCI_FORMAT_BYTES;
666 if (!STRCMP(keywords[i+2],"samples"))
667 pU->setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
668 if (!STRCMP(keywords[i+2],"tmsf"))
669 pU->setParams.dwTimeFormat = MCI_FORMAT_TMSF;
670 if ( !STRCMP(keywords[i+2],"song") &&
671 (i+3<nrofkeywords) &&
672 !STRCMP(keywords[i+3],"pointer")
674 pU->setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
675 if (!STRCMP(keywords[i+2],"smpte") && (i+3<nrofkeywords)) {
676 if (!STRCMP(keywords[i+3],"24"))
677 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
678 if (!STRCMP(keywords[i+3],"25"))
679 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
680 if (!STRCMP(keywords[i+3],"30"))
681 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
682 if (!STRCMP(keywords[i+3],"drop") && (i+4<nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
683 pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
684 i++;
686 i++;
687 /*FALLTHROUGH*/
689 i+=3;
690 continue;
692 if (!STRCMP(keywords[i],"audio") && (i+1<nrofkeywords)) {
693 dwFlags |= MCI_SET_AUDIO;
694 if (!STRCMP(keywords[i+1],"all"))
695 pU->setParams.dwAudio = MCI_SET_AUDIO_ALL;
696 if (!STRCMP(keywords[i+1],"left"))
697 pU->setParams.dwAudio = MCI_SET_AUDIO_LEFT;
698 if (!STRCMP(keywords[i+1],"right"))
699 pU->setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
700 i+=2;
701 continue;
703 FLAG1("video",MCI_SET_VIDEO);
704 FLAG1("on",MCI_SET_ON);
705 FLAG1("off",MCI_SET_OFF);
706 switch (uDevTyp) {
707 case MCI_DEVTYPE_WAVEFORM_AUDIO:
708 FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
709 FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
711 if ( !STRCMP(keywords[i],"formattag") &&
712 (i+1<nrofkeywords) &&
713 !STRCMP(keywords[i+1],"pcm")
715 dwFlags |= MCI_WAVE_SET_FORMATTAG;
716 pU->wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
717 i+=2;
718 continue;
721 /* <keyword> <integer> */
722 #define WII(str,flag,fmt,element) \
723 if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
724 sscanf(keywords[i+1],fmt,&(pU->wavesetParams. element ));\
725 dwFlags |= flag;\
726 i+=2;\
727 continue;\
729 WII("formattag",MCI_WAVE_SET_FORMATTAG,"%hu",wFormatTag);
730 WII("channels",MCI_WAVE_SET_CHANNELS,"%hu",nChannels);
731 WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,"%lu",nAvgBytesPerSec);
732 WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,"%lu",nSamplesPerSec);
733 WII("alignment",MCI_WAVE_SET_BLOCKALIGN,"%hu",nBlockAlign);
734 WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,"%hu",wBitsPerSample);
735 WII("input",MCI_WAVE_INPUT,"%hu",wInput);
736 WII("output",MCI_WAVE_OUTPUT,"%hu",wOutput);
737 #undef WII
738 break;
739 case MCI_DEVTYPE_SEQUENCER:
740 if (!STRCMP(keywords[i],"master") && (i+1<nrofkeywords)) {
741 dwFlags |= MCI_SEQ_SET_MASTER;
742 if (!STRCMP(keywords[i+1],"midi"))
743 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
744 if (!STRCMP(keywords[i+1],"file"))
745 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
746 if (!STRCMP(keywords[i+1],"smpte"))
747 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
748 if (!STRCMP(keywords[i+1],"none"))
749 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
750 i+=2;
751 continue;
753 if (!STRCMP(keywords[i],"slave") && (i+1<nrofkeywords)) {
754 dwFlags |= MCI_SEQ_SET_SLAVE;
755 if (!STRCMP(keywords[i+1],"midi"))
756 pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
757 if (!STRCMP(keywords[i+1],"file"))
758 pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
759 if (!STRCMP(keywords[i+1],"smpte"))
760 pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
761 if (!STRCMP(keywords[i+1],"none"))
762 pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
763 i+=2;
764 continue;
766 if ( !STRCMP(keywords[i],"port") &&
767 (i+1<nrofkeywords) &&
768 !STRCMP(keywords[i+1],"mapper")
770 pU->seqsetParams.dwPort=-1;/* FIXME:not sure*/
771 dwFlags |= MCI_SEQ_SET_PORT;
772 i+=2;
773 continue;
775 #define SII(str,flag,element) \
776 if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
777 sscanf(keywords[i+1],"%ld",&(pU->seqsetParams. element ));\
778 dwFlags |= flag;\
779 i+=2;\
780 continue;\
782 SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
783 SII("port",MCI_SEQ_SET_PORT,dwPort);
784 SII("offset",MCI_SEQ_SET_PORT,dwOffset);
786 i++;
788 if (!dwFlags)
789 return MCIERR_MISSING_STRING_ARGUMENT;
790 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_SET, dwFlags, (DWORD)pU);
791 free(pU);
792 return res;
795 /* specify break key
796 * Arguments:
797 * "off" disable break
798 * "on <keyid>" enable break on key with keyid
799 * (I strongly suspect, that there is another parameter:
800 * "window <handle>"
801 * but I don't see it mentioned in my documentation.
802 * Returns nothing.
804 static DWORD
805 MCISTR_Break(_MCISTR_PROTO_)
807 MCI_BREAK_PARMS16 *breakParams = xmalloc(sizeof(MCI_BREAK_PARMS16));
808 int res,i;
810 if (!breakParams) return 0;
811 /*breakParams.hwndBreak ? */
812 for (i = 0; i < nrofkeywords; i++) {
813 FLAG1("off",MCI_BREAK_OFF);
814 if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
815 dwFlags&=~MCI_BREAK_OFF;
816 dwFlags|=MCI_BREAK_KEY;
817 sscanf(keywords[i+1],"%hd",&(breakParams->nVirtKey));
818 i+=2;
819 continue;
822 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_BREAK, dwFlags, (DWORD)breakParams);
823 free(breakParams);
824 return res;
827 #define ITEM1(str,item,xtype) \
828 if (!STRCMP(keywords[i],str)) {\
829 gdcParams->dwItem = item;\
830 type = xtype;\
831 i++;\
832 continue;\
834 #define ITEM2(str1,str2,item,xtype) \
835 if ( !STRCMP(keywords[i],str1) &&\
836 (i+1<nrofkeywords) &&\
837 !STRCMP(keywords[i+1],str2)\
838 ) {\
839 gdcParams->dwItem = item;\
840 type = xtype;\
841 i+=2;\
842 continue;\
844 #define ITEM3(str1,str2,str3,item,xtype) \
845 if ( !STRCMP(keywords[i],str1) &&\
846 (i+2<nrofkeywords) &&\
847 !STRCMP(keywords[i+1],str2) &&\
848 !STRCMP(keywords[i+2],str3)\
849 ) {\
850 gdcParams->dwItem = item;\
851 type = xtype;\
852 i+=3;\
853 continue;\
855 /* get device capabilities of MCI drivers
856 * Arguments:
857 * Generic:
858 * "device type" returns device name as string
859 * "has audio" returns bool
860 * "has video" returns bool
861 * "uses files" returns bool
862 * "compound device" returns bool
863 * "can record" returns bool
864 * "can play" returns bool
865 * "can eject" returns bool
866 * "can save" returns bool
867 * Animation:
868 * "palettes" returns nr of available palette entries
869 * "windows" returns nr of available windows
870 * "can reverse" returns bool
871 * "can stretch" returns bool
872 * "slow play rate" returns the slow playrate
873 * "fast play rate" returns the fast playrate
874 * "normal play rate" returns the normal playrate
875 * Overlay:
876 * "windows" returns nr of available windows
877 * "can stretch" returns bool
878 * "can freeze" returns bool
879 * Videodisc:
880 * "cav" assume CAV discs (default if no disk inserted)
881 * "clv" assume CLV discs
882 * "can reverse" returns bool
883 * "slow play rate" returns the slow playrate
884 * "fast play rate" returns the fast playrate
885 * "normal play rate" returns the normal playrate
886 * Waveform audio:
887 * "inputs" returns nr of inputdevices
888 * "outputs" returns nr of outputdevices
890 static DWORD
891 MCISTR_Capability(_MCISTR_PROTO_) {
892 MCI_GETDEVCAPS_PARMS *gdcParams = xmalloc(sizeof(MCI_GETDEVCAPS_PARMS));
893 int type=0,i,res;
895 gdcParams->dwCallback = hwndCallback;
896 if (!nrofkeywords)
897 return MCIERR_MISSING_STRING_ARGUMENT;
898 /* well , thats default */
899 dwFlags |= MCI_GETDEVCAPS_ITEM;
900 gdcParams->dwItem = 0;
901 i=0;
902 while (i<nrofkeywords) {
903 ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
904 ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
905 ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
906 ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
907 ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
908 ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
909 ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
910 ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
911 ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
912 switch (uDevTyp) {
913 case MCI_DEVTYPE_ANIMATION:
914 ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
915 ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
916 ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
917 ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
918 ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
919 ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
920 ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
921 break;
922 case MCI_DEVTYPE_OVERLAY:
923 ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
924 ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
925 ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
926 break;
927 case MCI_DEVTYPE_VIDEODISC:
928 FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
929 FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
930 ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
931 ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
932 ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
933 ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
934 break;
935 case MCI_DEVTYPE_WAVEFORM_AUDIO:
936 ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
937 ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
938 break;
940 i++;
942 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_GETDEVCAPS, dwFlags, (DWORD)gdcParams);
944 /* no timeformat needed */
945 if (res==0)
946 _MCISTR_convreturn( type, gdcParams->dwReturn, lpstrReturnString,
947 uReturnLength, uDevTyp, 0 );
948 free(gdcParams);
949 return res;
951 #undef ITEM1
952 #undef ITEM2
953 #undef ITEM3
954 /* resumes operation of device. no arguments, no return values */
955 static DWORD
956 MCISTR_Resume(_MCISTR_PROTO_)
958 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
959 int res;
960 genParams->dwCallback = hwndCallback;
961 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_RESUME, dwFlags, (DWORD)genParams);
962 free(genParams);
963 return res;
966 /* pauses operation of device. no arguments, no return values */
967 static DWORD
968 MCISTR_Pause(_MCISTR_PROTO_)
970 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
971 int res;
972 genParams->dwCallback = hwndCallback;
973 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_PAUSE, dwFlags, (DWORD)genParams);
974 free(genParams);
975 return res;
978 /* stops operation of device. no arguments, no return values */
979 static DWORD
980 MCISTR_Stop(_MCISTR_PROTO_)
982 MCI_GENERIC_PARMS *genParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
983 int res;
984 genParams->dwCallback = hwndCallback;
985 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_STOP, dwFlags, (DWORD)genParams);
986 free(genParams);
987 return res;
990 /* starts recording.
991 * Arguments:
992 * "overwrite" overwrite existing things
993 * "insert" insert at current position
994 * "to <time>" record up to <time> (specified in timeformat)
995 * "from <time>" record from <time> (specified in timeformat)
997 static DWORD
998 MCISTR_Record(_MCISTR_PROTO_) {
999 int i,res,timef,nrargs,j,k,a[4];
1000 char *parsestr;
1001 MCI_RECORD_PARMS *recordParams = xmalloc(sizeof(MCI_RECORD_PARMS));
1003 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1004 if (res) return res;
1006 switch (timef) {
1007 case MCI_FORMAT_MILLISECONDS:
1008 case MCI_FORMAT_FRAMES:
1009 case MCI_FORMAT_BYTES:
1010 case MCI_FORMAT_SAMPLES:
1011 nrargs=1;
1012 parsestr="%d";
1013 break;
1014 case MCI_FORMAT_HMS:
1015 case MCI_FORMAT_MSF:
1016 parsestr="%d:%d:%d";
1017 nrargs=3;
1018 break;
1019 case MCI_FORMAT_TMSF:
1020 parsestr="%d:%d:%d:%d";
1021 nrargs=4;
1022 break;
1023 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1024 parsestr="%d";
1025 nrargs=1;
1026 break;
1028 recordParams->dwCallback = hwndCallback;
1029 i = 0;
1030 while (i<nrofkeywords) {
1031 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1032 dwFlags |= MCI_TO;
1033 a[0]=a[1]=a[2]=a[3]=0;
1034 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1035 /* add up all integers we got, if we have more
1036 * shift them. (Well I should use the macros in
1037 * mmsystem.h, right).
1039 recordParams->dwTo=0;
1040 for (k=0;k<j;k++)
1041 recordParams->dwTo+=a[k]<<(8*(nrargs-k));
1042 i+=2;
1043 continue;
1045 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1046 dwFlags |= MCI_FROM;
1047 a[0]=a[1]=a[2]=a[3]=0;
1048 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1049 /* dito. */
1050 recordParams->dwFrom=0;
1051 for (k=0;k<j;k++)
1052 recordParams->dwFrom+=a[k]<<(8*(nrargs-k));
1053 i+=2;
1054 continue;
1056 FLAG1("insert",MCI_RECORD_INSERT);
1057 FLAG1("overwrite",MCI_RECORD_OVERWRITE);
1058 i++;
1060 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_RECORD, dwFlags, (DWORD)recordParams);
1061 free(recordParams);
1062 return res;
1065 /* play media
1066 * Arguments:
1067 * "to <time>" play up to <time> (specified in set timeformat)
1068 * "from <time>" play from <time> (specified in set timeformat)
1069 * Animation:
1070 * "slow" play slow
1071 * "fast" play fast
1072 * "scan" play as fast as possible (with audio disabled perhaps)
1073 * "reverse" play reverse
1074 * "speed <fps>" play with specified frames per second
1075 * Videodisc:
1076 * "slow" play slow
1077 * "fast" play fast
1078 * "scan" play as fast as possible (with audio disabled perhaps)
1079 * "reverse" play reverse
1080 * "speed <fps>" play with specified frames per second
1082 static DWORD
1083 MCISTR_Play(_MCISTR_PROTO_) {
1084 int i,res,timef,nrargs,j,k,a[4];
1085 char *parsestr;
1086 union U {
1087 MCI_PLAY_PARMS playParams;
1088 MCI_VD_PLAY_PARMS vdplayParams;
1089 MCI_ANIM_PLAY_PARMS animplayParams;
1091 union U *pU = xmalloc(sizeof(union U));
1093 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1094 if (res) return res;
1095 switch (timef) {
1096 case MCI_FORMAT_MILLISECONDS:
1097 case MCI_FORMAT_FRAMES:
1098 case MCI_FORMAT_BYTES:
1099 case MCI_FORMAT_SAMPLES:
1100 nrargs=1;
1101 parsestr="%d";
1102 break;
1103 case MCI_FORMAT_HMS:
1104 case MCI_FORMAT_MSF:
1105 parsestr="%d:%d:%d";
1106 nrargs=3;
1107 break;
1108 case MCI_FORMAT_TMSF:
1109 parsestr="%d:%d:%d:%d";
1110 nrargs=4;
1111 break;
1112 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1113 parsestr="%d";
1114 nrargs=1;
1115 break;
1117 pU->playParams.dwCallback=hwndCallback;
1118 i=0;
1119 while (i<nrofkeywords) {
1120 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1121 dwFlags |= MCI_TO;
1122 a[0]=a[1]=a[2]=a[3]=0;
1123 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1124 /* add up all integers we got, if we have more
1125 * shift them. (Well I should use the macros in
1126 * mmsystem.h, right).
1128 pU->playParams.dwTo=0;
1129 for (k=0;k<j;k++)
1130 pU->playParams.dwTo+=a[k]<<(8*(nrargs-k));
1131 i+=2;
1132 continue;
1134 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1135 dwFlags |= MCI_FROM;
1136 a[0]=a[1]=a[2]=a[3]=0;
1137 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1138 /* dito. */
1139 pU->playParams.dwFrom=0;
1140 for (k=0;k<j;k++)
1141 pU->playParams.dwFrom+=a[k]<<(8*(nrargs-k));
1142 i+=2;
1143 continue;
1145 switch (uDevTyp) {
1146 case MCI_DEVTYPE_VIDEODISC:
1147 FLAG1("slow",MCI_VD_PLAY_SLOW);
1148 FLAG1("fast",MCI_VD_PLAY_FAST);
1149 FLAG1("scan",MCI_VD_PLAY_SCAN);
1150 FLAG1("reverse",MCI_VD_PLAY_REVERSE);
1151 if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
1152 dwFlags |= MCI_VD_PLAY_SPEED;
1153 sscanf(keywords[i+1],"%ld",&(pU->vdplayParams.dwSpeed));
1154 i+=2;
1155 continue;
1157 break;
1158 case MCI_DEVTYPE_ANIMATION:
1159 FLAG1("slow",MCI_ANIM_PLAY_SLOW);
1160 FLAG1("fast",MCI_ANIM_PLAY_FAST);
1161 FLAG1("scan",MCI_ANIM_PLAY_SCAN);
1162 FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
1163 if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
1164 dwFlags |= MCI_ANIM_PLAY_SPEED;
1165 sscanf(keywords[i+1],"%ld",&(pU->animplayParams.dwSpeed));
1166 i+=2;
1167 continue;
1169 break;
1171 i++;
1173 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_PLAY, dwFlags, (DWORD)pU);
1174 free(pU);
1175 return res;
1178 /* seek to a specified position
1179 * Arguments:
1180 * "to start" seek to start of medium
1181 * "to end" seek to end of medium
1182 * "to <time>" seek to <time> specified in current timeformat
1184 static DWORD
1185 MCISTR_Seek(_MCISTR_PROTO_) {
1186 int i,res,timef,nrargs,j,k,a[4];
1187 char *parsestr;
1188 MCI_SEEK_PARMS *seekParams = xmalloc(sizeof(MCI_SEEK_PARMS));
1190 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1191 if (res) return res;
1192 switch (timef) {
1193 case MCI_FORMAT_MILLISECONDS:
1194 case MCI_FORMAT_FRAMES:
1195 case MCI_FORMAT_BYTES:
1196 case MCI_FORMAT_SAMPLES:
1197 nrargs=1;
1198 parsestr="%d";
1199 break;
1200 case MCI_FORMAT_HMS:
1201 case MCI_FORMAT_MSF:
1202 parsestr="%d:%d:%d";
1203 nrargs=3;
1204 break;
1205 case MCI_FORMAT_TMSF:
1206 parsestr="%d:%d:%d:%d";
1207 nrargs=4;
1208 break;
1209 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1210 parsestr="%d";
1211 nrargs=1;
1212 break;
1214 seekParams->dwCallback=hwndCallback;
1215 i=0;
1216 while (i<nrofkeywords) {
1217 if ( !STRCMP(keywords[i],"to") && (i+1<nrofkeywords)) {
1218 if (!STRCMP(keywords[i+1],"start")) {
1219 dwFlags|=MCI_SEEK_TO_START;
1220 seekParams->dwTo=0;
1221 i+=2;
1222 continue;
1224 if (!STRCMP(keywords[i+1],"end")) {
1225 dwFlags|=MCI_SEEK_TO_END;
1226 seekParams->dwTo=0;
1227 i+=2;
1228 continue;
1230 dwFlags|=MCI_TO;
1231 i+=2;
1232 a[0]=a[1]=a[2]=a[3]=0;
1233 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1234 seekParams->dwTo=0;
1235 for (k=0;k<j;k++)
1236 seekParams->dwTo+=a[k]<<(8*(nrargs-k));
1237 continue;
1239 switch (uDevTyp) {
1240 case MCI_DEVTYPE_VIDEODISC:
1241 FLAG1("reverse",MCI_VD_SEEK_REVERSE);
1242 break;
1244 i++;
1246 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_SEEK, dwFlags, (DWORD)seekParams);
1247 free(seekParams);
1248 return res;
1251 /* close media/driver */
1252 static DWORD
1253 MCISTR_Close(_MCISTR_PROTO_)
1255 MCI_GENERIC_PARMS *closeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1256 int res;
1258 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_CLOSE, dwFlags, (DWORD)closeParams);
1259 free(closeParams);
1260 return res;
1263 /* return information.
1264 * Arguments:
1265 * "product" return product name (human readable)
1266 * "file" return filename
1267 * Animation:
1268 * "text" returns text?
1269 * Overlay:
1270 * "text" returns text?
1272 static DWORD
1273 MCISTR_Info(_MCISTR_PROTO_)
1275 MCI_INFO_PARMS16 *infoParams = xmalloc(sizeof(MCI_INFO_PARMS16));
1276 DWORD sflags;
1277 int i,res;
1279 sflags = dwFlags;
1280 i=0;
1281 while (i<nrofkeywords) {
1282 FLAG1("product",MCI_INFO_PRODUCT);
1283 FLAG1("file",MCI_INFO_FILE);
1284 switch (uDevTyp) {
1285 case MCI_DEVTYPE_ANIMATION:
1286 FLAG1("text",MCI_ANIM_INFO_TEXT);
1287 break;
1288 case MCI_DEVTYPE_OVERLAY:
1289 FLAG1("text",MCI_OVLY_INFO_TEXT);
1290 break;
1292 i++;
1294 if (dwFlags == sflags)
1295 return MCIERR_MISSING_STRING_ARGUMENT;
1296 /* MCI driver will fill in lpstrReturn, dwRetSize.
1297 * FIXME: I don't know if this is correct behaviour
1299 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_INFO, dwFlags, (DWORD)infoParams);
1300 if (res==0)
1301 _MCI_STR(infoParams->lpstrReturn);
1302 free(infoParams);
1303 return res;
1306 /* query MCI driver itself for information
1307 * Arguments:
1308 * "installname" return install name of <device> (system.ini)
1309 * "quantity" return nr of installed drivers
1310 * "open" open drivers only (additional flag)
1311 * "name <nr>" return nr of devices with <devicetyp>
1312 * "name all" return nr of all devices
1314 * FIXME: mciSysInfo16() is broken I think.
1316 static DWORD
1317 MCISTR_Sysinfo(_MCISTR_PROTO_) {
1318 MCI_SYSINFO_PARMS16 sysinfoParams;
1319 int i,res;
1321 sysinfoParams.lpstrReturn = lpstrReturnString;
1322 sysinfoParams.dwRetSize = uReturnLength;
1323 sysinfoParams.wDeviceType = uDevTyp;
1325 for (i = 0; i < nrofkeywords; i++) {
1326 FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
1327 FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
1328 FLAG1("open",MCI_SYSINFO_OPEN);
1329 if (!strcmp(keywords[i],"name") && (i+1<nrofkeywords)) {
1330 sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
1331 dwFlags |= MCI_SYSINFO_NAME;
1332 i++;
1335 res = mciSendCommand16(0, MCI_SYSINFO, dwFlags, (DWORD)&sysinfoParams);
1337 if (dwFlags & MCI_SYSINFO_QUANTITY) {
1338 char buf[100];
1340 sprintf(buf,"%ld",*(long*)lpstrReturnString);
1341 _MCI_STR(buf);
1343 /* no need to copy anything back, mciSysInfo did it for us */
1344 return res;
1347 /* load file
1348 * Argument: "<filename>"
1349 * Overlay: "at <left> <top> <right> <bottom>" additional
1351 static DWORD
1352 MCISTR_Load(_MCISTR_PROTO_) {
1353 union U {
1354 MCI_LOAD_PARMS16 loadParams;
1355 MCI_OVLY_LOAD_PARMS16 ovlyloadParams;
1357 union U *pU = xmalloc(sizeof(union U));
1358 int i,len,res;
1359 char *s;
1361 i=len=0;
1362 while (i<nrofkeywords) {
1363 switch (uDevTyp) {
1364 case MCI_DEVTYPE_OVERLAY:
1365 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1366 dwFlags |= MCI_OVLY_RECT;
1367 sscanf(keywords[i+1],"%hd",&(pU->ovlyloadParams.rc.left));
1368 sscanf(keywords[i+2],"%hd",&(pU->ovlyloadParams.rc.top));
1369 sscanf(keywords[i+3],"%hd",&(pU->ovlyloadParams.rc.right));
1370 sscanf(keywords[i+4],"%hd",&(pU->ovlyloadParams.rc.bottom));
1371 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1372 continue;
1374 break;
1376 len+=strlen(keywords[i])+1;
1377 i++;
1379 s=(char*)xmalloc(len);
1380 *s='\0';
1381 while (i<nrofkeywords) {
1382 strcat(s,keywords[i]);
1383 i++;
1384 if (i<nrofkeywords) strcat(s," ");
1386 pU->loadParams.lpfilename=s;
1387 dwFlags |= MCI_LOAD_FILE;
1388 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_LOAD, dwFlags, (DWORD)pU);
1389 free(s);
1390 free(pU);
1391 return res;
1394 /* save to file
1395 * Argument: "<filename>"
1396 * Overlay: "at <left> <top> <right> <bottom>" additional
1398 static DWORD
1399 MCISTR_Save(_MCISTR_PROTO_) {
1400 union U {
1401 MCI_SAVE_PARMS saveParams;
1402 MCI_OVLY_SAVE_PARMS16 ovlysaveParams;
1404 union U *pU = xmalloc(sizeof(union U));
1405 int i,len,res;
1406 char *s;
1408 i=0;len=0;
1409 while (i<nrofkeywords) {
1410 switch (uDevTyp) {
1411 case MCI_DEVTYPE_OVERLAY:
1412 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1413 dwFlags |= MCI_OVLY_RECT;
1414 sscanf(keywords[i+1],"%hd",&(pU->ovlysaveParams.rc.left));
1415 sscanf(keywords[i+2],"%hd",&(pU->ovlysaveParams.rc.top));
1416 sscanf(keywords[i+3],"%hd",&(pU->ovlysaveParams.rc.right));
1417 sscanf(keywords[i+4],"%hd",&(pU->ovlysaveParams.rc.bottom));
1418 memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
1419 continue;
1421 break;
1423 len+=strlen(keywords[i])+1;
1424 i++;
1426 s=(char*)xmalloc(len);
1427 *s='\0';
1428 while (i<nrofkeywords) {
1429 strcat(s,keywords[i]);
1430 i++;
1431 if (i<nrofkeywords) strcat(s," ");
1433 pU->saveParams.lpfilename=s;
1434 dwFlags |= MCI_LOAD_FILE;
1435 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_SAVE, dwFlags, (DWORD)pU);
1436 free(s);
1437 free(pU);
1438 return res;
1441 /* prepare device for input/output
1442 * (only applyable to waveform audio)
1444 static DWORD
1445 MCISTR_Cue(_MCISTR_PROTO_) {
1446 MCI_GENERIC_PARMS *cueParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1447 int i,res;
1449 for (i = 0; i < nrofkeywords; i++) {
1450 switch (uDevTyp) {
1451 case MCI_DEVTYPE_WAVEFORM_AUDIO:
1452 FLAG1("input",MCI_WAVE_INPUT);
1453 FLAG1("output",MCI_WAVE_OUTPUT);
1454 break;
1457 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_CUE, dwFlags, (DWORD)cueParams);
1458 free(cueParams);
1459 return res;
1462 /* delete information */
1463 static DWORD
1464 MCISTR_Delete(_MCISTR_PROTO_) {
1465 int timef,nrargs,i,j,k,a[4],res;
1466 char *parsestr;
1467 MCI_WAVE_DELETE_PARMS *deleteParams = xmalloc(sizeof(MCI_WAVE_DELETE_PARMS));
1469 /* only implemented for waveform audio */
1470 if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
1471 return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
1472 res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
1473 if (res) return res;
1474 switch (timef) {
1475 case MCI_FORMAT_MILLISECONDS:
1476 case MCI_FORMAT_FRAMES:
1477 case MCI_FORMAT_BYTES:
1478 case MCI_FORMAT_SAMPLES:
1479 nrargs=1;
1480 parsestr="%d";
1481 break;
1482 case MCI_FORMAT_HMS:
1483 case MCI_FORMAT_MSF:
1484 parsestr="%d:%d:%d";
1485 nrargs=3;
1486 break;
1487 case MCI_FORMAT_TMSF:
1488 parsestr="%d:%d:%d:%d";
1489 nrargs=4;
1490 break;
1491 default:FIXME(mci,"unknown timeformat %d, please report.\n",timef);
1492 parsestr="%d";
1493 nrargs=1;
1494 break;
1496 i=0;
1497 while (i<nrofkeywords) {
1498 if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
1499 dwFlags |= MCI_TO;
1500 a[0]=a[1]=a[2]=a[3]=0;
1501 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1502 /* add up all integers we got, if we have more
1503 * shift them. (Well I should use the macros in
1504 * mmsystem.h, right).
1506 deleteParams->dwTo=0;
1507 for (k=0;k<j;k++)
1508 deleteParams->dwTo+=a[k]<<(8*(nrargs-k));
1509 i+=2;
1510 continue;
1512 if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
1513 dwFlags |= MCI_FROM;
1514 a[0]=a[1]=a[2]=a[3]=0;
1515 j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
1516 /* dito. */
1517 deleteParams->dwFrom=0;
1518 for (k=0;k<j;k++)
1519 deleteParams->dwFrom+=a[k]<<(8*(nrargs-k));
1520 i+=2;
1521 continue;
1523 i++;
1525 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_DELETE, dwFlags, (DWORD)deleteParams);
1526 free(deleteParams);
1527 return res;
1530 /* send command to device. only applies to videodisc */
1531 static DWORD
1532 MCISTR_Escape(_MCISTR_PROTO_)
1534 MCI_VD_ESCAPE_PARMS16 *escapeParams = xmalloc(sizeof(MCI_VD_ESCAPE_PARMS16));
1535 int i,len,res;
1536 char *s;
1538 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1539 return MCIERR_UNSUPPORTED_FUNCTION;
1540 i=0;len=0;
1541 while (i<nrofkeywords) {
1542 len+=strlen(keywords[i])+1;
1543 i++;
1545 s=(char*)malloc(len);
1546 *s='\0';
1547 while (i<nrofkeywords) {
1548 strcat(s,keywords[i]);
1549 i++;
1550 if (i<nrofkeywords) strcat(s," ");
1552 escapeParams->lpstrCommand = s;
1553 dwFlags |= MCI_VD_ESCAPE_STRING;
1554 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_ESCAPE, dwFlags, (DWORD)escapeParams);
1555 free(s);
1556 free(escapeParams);
1557 return res;
1560 /* unfreeze [part of] the overlayed video
1561 * only applyable to Overlay devices
1563 static DWORD
1564 MCISTR_Unfreeze(_MCISTR_PROTO_)
1566 MCI_OVLY_RECT_PARMS16 *unfreezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS16));
1567 int i,res;
1569 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1570 return MCIERR_UNSUPPORTED_FUNCTION;
1571 i=0;while (i<nrofkeywords) {
1572 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1573 sscanf(keywords[i+1],"%hd",&(unfreezeParams->rc.left));
1574 sscanf(keywords[i+2],"%hd",&(unfreezeParams->rc.top));
1575 sscanf(keywords[i+3],"%hd",&(unfreezeParams->rc.right));
1576 sscanf(keywords[i+4],"%hd",&(unfreezeParams->rc.bottom));
1577 dwFlags |= MCI_OVLY_RECT;
1578 i+=5;
1579 continue;
1581 i++;
1583 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_UNFREEZE, dwFlags, (DWORD)unfreezeParams);
1584 free(unfreezeParams);
1585 return res;
1587 /* freeze [part of] the overlayed video
1588 * only applyable to Overlay devices
1590 static DWORD
1591 MCISTR_Freeze(_MCISTR_PROTO_)
1593 MCI_OVLY_RECT_PARMS16 *freezeParams = xmalloc(sizeof(MCI_OVLY_RECT_PARMS16));
1594 int i,res;
1596 if (uDevTyp != MCI_DEVTYPE_OVERLAY)
1597 return MCIERR_UNSUPPORTED_FUNCTION;
1598 i=0;while (i<nrofkeywords) {
1599 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1600 sscanf(keywords[i+1],"%hd",&(freezeParams->rc.left));
1601 sscanf(keywords[i+2],"%hd",&(freezeParams->rc.top));
1602 sscanf(keywords[i+3],"%hd",&(freezeParams->rc.right));
1603 sscanf(keywords[i+4],"%hd",&(freezeParams->rc.bottom));
1604 dwFlags |= MCI_OVLY_RECT;
1605 i+=5;
1606 continue;
1608 i++;
1610 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_FREEZE, dwFlags, (DWORD)freezeParams);
1611 free(freezeParams);
1612 return res;
1615 /* copy parts of image to somewhere else
1616 * "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
1617 * "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
1618 * Overlay:
1619 * "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
1620 * where the video input is placed
1621 * "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
1622 * (defining part of input to
1623 * be displayed)
1625 * FIXME: This whole junk is passing multiple rectangles.
1626 * I don't know how to do that with the present interface.
1627 * (Means code below is broken)
1629 static DWORD
1630 MCISTR_Put(_MCISTR_PROTO_) {
1631 union U {
1632 MCI_OVLY_RECT_PARMS16 ovlyputParams;
1633 MCI_ANIM_RECT_PARMS16 animputParams;
1635 union U *pU = xmalloc(sizeof(union U));
1636 int i,res;
1637 i=0;while (i<nrofkeywords) {
1638 switch (uDevTyp) {
1639 case MCI_DEVTYPE_ANIMATION:
1640 FLAG1("source",MCI_ANIM_PUT_SOURCE);
1641 FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
1642 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1643 sscanf(keywords[i+1],"%hd",&(pU->animputParams.rc.left));
1644 sscanf(keywords[i+2],"%hd",&(pU->animputParams.rc.top));
1645 sscanf(keywords[i+3],"%hd",&(pU->animputParams.rc.right));
1646 sscanf(keywords[i+4],"%hd",&(pU->animputParams.rc.bottom));
1647 dwFlags |= MCI_ANIM_RECT;
1648 i+=5;
1649 continue;
1651 break;
1652 case MCI_DEVTYPE_OVERLAY:
1653 FLAG1("source",MCI_OVLY_PUT_SOURCE);
1654 FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
1655 FLAG1("video",MCI_OVLY_PUT_VIDEO);
1656 FLAG1("frame",MCI_OVLY_PUT_FRAME);
1657 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1658 sscanf(keywords[i+1],"%hd",&(pU->ovlyputParams.rc.left));
1659 sscanf(keywords[i+2],"%hd",&(pU->ovlyputParams.rc.top));
1660 sscanf(keywords[i+3],"%hd",&(pU->ovlyputParams.rc.right));
1661 sscanf(keywords[i+4],"%hd",&(pU->ovlyputParams.rc.bottom));
1662 dwFlags |= MCI_OVLY_RECT;
1663 i+=5;
1664 continue;
1666 break;
1668 i++;
1670 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_PUT, dwFlags, (DWORD)pU);
1671 free(pU);
1672 return res;
1675 /* palette behaviour changing
1676 * (Animation only)
1677 * "normal" realize the palette normally
1678 * "background" realize the palette as background palette
1680 static DWORD
1681 MCISTR_Realize(_MCISTR_PROTO_)
1683 MCI_GENERIC_PARMS *realizeParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1684 int i,res;
1686 if (uDevTyp != MCI_DEVTYPE_ANIMATION)
1687 return MCIERR_UNSUPPORTED_FUNCTION;
1688 i=0;
1689 while (i<nrofkeywords) {
1690 FLAG1("background",MCI_ANIM_REALIZE_BKGD);
1691 FLAG1("normal",MCI_ANIM_REALIZE_NORM);
1692 i++;
1694 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_REALIZE, dwFlags, (DWORD)realizeParams);
1695 free(realizeParams);
1696 return res;
1699 /* videodisc spinning
1700 * "up"
1701 * "down"
1703 static DWORD
1704 MCISTR_Spin(_MCISTR_PROTO_)
1706 MCI_GENERIC_PARMS *spinParams = xmalloc(sizeof(MCI_GENERIC_PARMS));
1707 int i,res;
1709 if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
1710 return MCIERR_UNSUPPORTED_FUNCTION;
1711 i=0;
1712 while (i<nrofkeywords) {
1713 FLAG1("up",MCI_VD_SPIN_UP);
1714 FLAG1("down",MCI_VD_SPIN_UP);
1715 i++;
1717 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_SPIN, dwFlags, (DWORD)spinParams);
1718 free(spinParams);
1719 return res;
1722 /* step single frames
1723 * "reverse" optional flag
1724 * "by <nr>" for <nr> frames
1726 static DWORD
1727 MCISTR_Step(_MCISTR_PROTO_) {
1728 union U {
1729 MCI_ANIM_STEP_PARMS animstepParams;
1730 MCI_VD_STEP_PARMS vdstepParams;
1732 union U *pU = xmalloc(sizeof(union U));
1733 int i,res;
1735 i=0;
1736 while (i<nrofkeywords) {
1737 switch (uDevTyp) {
1738 case MCI_DEVTYPE_ANIMATION:
1739 FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
1740 if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
1741 sscanf(keywords[i+1],"%ld",&(pU->animstepParams.dwFrames));
1742 dwFlags |= MCI_ANIM_STEP_FRAMES;
1743 i+=2;
1744 continue;
1746 break;
1747 case MCI_DEVTYPE_VIDEODISC:
1748 FLAG1("reverse",MCI_VD_STEP_REVERSE);
1749 if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
1750 sscanf(keywords[i+1],"%ld",&(pU->vdstepParams.dwFrames));
1751 dwFlags |= MCI_VD_STEP_FRAMES;
1752 i+=2;
1753 continue;
1755 break;
1757 i++;
1759 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_STEP, dwFlags, (DWORD)pU);
1760 free(pU);
1761 return res;
1764 /* update animation window
1765 * Arguments:
1766 * "at <left> <top> <right> <bottom>" only in this rectangle
1767 * "hdc" device context
1769 static DWORD
1770 MCISTR_Update(_MCISTR_PROTO_) {
1771 int i,res;
1772 MCI_ANIM_UPDATE_PARMS16 *updateParams = xmalloc(sizeof(MCI_ANIM_UPDATE_PARMS16));
1774 i=0;
1775 while (i<nrofkeywords) {
1776 if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
1777 sscanf(keywords[i+1],"%hd",&(updateParams->rc.left));
1778 sscanf(keywords[i+2],"%hd",&(updateParams->rc.top));
1779 sscanf(keywords[i+3],"%hd",&(updateParams->rc.right));
1780 sscanf(keywords[i+4],"%hd",&(updateParams->rc.bottom));
1781 dwFlags |= MCI_ANIM_RECT;
1782 i+=5;
1783 continue;
1785 if (!STRCMP(keywords[i],"hdc") && (i+1<nrofkeywords)) {
1786 dwFlags |= MCI_ANIM_UPDATE_HDC;
1787 sscanf(keywords[i+1],"%hd",&(updateParams->hDC));
1788 i+=2;
1789 continue;
1791 i++;
1793 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_UPDATE, dwFlags, (DWORD)updateParams);
1794 free(updateParams);
1795 return res;
1798 /* where command for animation and overlay drivers.
1799 * just returns the specified rectangle as a string
1800 * Arguments:
1801 * "source"
1802 * "destination"
1803 * Overlay special:
1804 * "video"
1805 * "frame"
1807 static DWORD
1808 MCISTR_Where(_MCISTR_PROTO_) {
1809 union U {
1810 MCI_ANIM_RECT_PARMS16 animwhereParams;
1811 MCI_OVLY_RECT_PARMS16 ovlywhereParams;
1813 union U *pU = xmalloc(sizeof(union U));
1814 int i,res;
1816 i=0;
1817 while (i<nrofkeywords) {
1818 switch (uDevTyp) {
1819 case MCI_DEVTYPE_ANIMATION:
1820 FLAG1("source",MCI_ANIM_WHERE_SOURCE);
1821 FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
1822 break;
1823 case MCI_DEVTYPE_OVERLAY:
1824 FLAG1("source",MCI_OVLY_WHERE_SOURCE);
1825 FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
1826 FLAG1("video",MCI_OVLY_WHERE_VIDEO);
1827 FLAG1("frame",MCI_OVLY_WHERE_FRAME);
1828 break;
1830 i++;
1832 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_WHERE, dwFlags, (DWORD)pU);
1833 if (res==0) {
1834 char buf[100];
1835 switch (uDevTyp) {
1836 case MCI_DEVTYPE_ANIMATION:
1837 sprintf(buf,"%d %d %d %d",
1838 pU->animwhereParams.rc.left,
1839 pU->animwhereParams.rc.top,
1840 pU->animwhereParams.rc.right,
1841 pU->animwhereParams.rc.bottom
1843 break;
1844 case MCI_DEVTYPE_OVERLAY:
1845 sprintf(buf,"%d %d %d %d",
1846 pU->ovlywhereParams.rc.left,
1847 pU->ovlywhereParams.rc.top,
1848 pU->ovlywhereParams.rc.right,
1849 pU->ovlywhereParams.rc.bottom
1851 break;
1852 default:strcpy(buf,"0 0 0 0");break;
1854 _MCI_STR(buf);
1856 free(pU);
1857 return res;
1860 static DWORD
1861 MCISTR_Window(_MCISTR_PROTO_) {
1862 int i,res;
1863 char *s;
1864 union U {
1865 MCI_ANIM_WINDOW_PARMS16 animwindowParams;
1866 MCI_OVLY_WINDOW_PARMS16 ovlywindowParams;
1868 union U *pU = xmalloc(sizeof(union U));
1870 s=NULL;
1871 i=0;
1872 while (i<nrofkeywords) {
1873 switch (uDevTyp) {
1874 case MCI_DEVTYPE_ANIMATION:
1875 if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
1876 dwFlags |= MCI_ANIM_WINDOW_HWND;
1877 if (!STRCMP(keywords[i+1],"default"))
1878 pU->animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1879 else
1880 sscanf(keywords[i+1],"%hd",&(pU->animwindowParams.hWnd));
1881 i+=2;
1882 continue;
1884 if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
1885 dwFlags |= MCI_ANIM_WINDOW_STATE;
1886 if (!STRCMP(keywords[i+1],"hide"))
1887 pU->animwindowParams.nCmdShow = SW_HIDE;
1888 if (!STRCMP(keywords[i+1],"iconic"))
1889 pU->animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1890 if (!STRCMP(keywords[i+1],"minimized"))
1891 pU->animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
1892 if (!STRCMP(keywords[i+1],"maximized"))
1893 pU->animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1894 if (!STRCMP(keywords[i+1],"minimize"))
1895 pU->animwindowParams.nCmdShow = SW_MINIMIZE;
1896 if (!STRCMP(keywords[i+1],"normal"))
1897 pU->animwindowParams.nCmdShow = SW_NORMAL;
1898 if (!STRCMP(keywords[i+1],"show"))
1899 pU->animwindowParams.nCmdShow = SW_SHOW;
1900 if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
1901 if (!STRCMP(keywords[i+2],"active"))
1902 pU->animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1903 if (!STRCMP(keywords[i+2],"action"))
1904 pU->animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1905 i++;
1907 i+=2;
1908 continue;
1910 /* text is enclosed in " ... " as it seems */
1911 if (!STRCMP(keywords[i],"text")) {
1912 char *t;
1913 int len,j,k;
1915 if (keywords[i+1][0]!='"') {
1916 i++;
1917 continue;
1919 dwFlags |= MCI_ANIM_WINDOW_TEXT;
1920 len = strlen(keywords[i+1])+1;
1921 j = i+2;
1922 while (j<nrofkeywords) {
1923 len += strlen(keywords[j])+1;
1924 if (strchr(keywords[j],'"'))
1925 break;
1926 j++;
1928 s=(char*)xmalloc(len);
1929 strcpy(s,keywords[i+1]+1);
1930 k=j;j=i+2;
1931 while (j<=k) {
1932 strcat(s," ");
1933 strcat(s,keywords[j]);
1935 if ((t=strchr(s,'"'))) *t='\0';
1936 /* FIXME: segmented pointer? */
1937 pU->animwindowParams.lpstrText = s;
1938 i=k+1;
1939 continue;
1941 FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
1942 break;
1943 case MCI_DEVTYPE_OVERLAY:
1944 if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
1945 dwFlags |= MCI_OVLY_WINDOW_HWND;
1946 if (!STRCMP(keywords[i+1],"default"))
1947 pU->ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
1948 else
1949 sscanf(keywords[i+1],"%hd",&(pU->ovlywindowParams.hWnd));
1950 i+=2;
1951 continue;
1953 if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
1954 dwFlags |= MCI_OVLY_WINDOW_STATE;
1955 if (!STRCMP(keywords[i+1],"hide"))
1956 pU->ovlywindowParams.nCmdShow = SW_HIDE;
1957 if (!STRCMP(keywords[i+1],"iconic"))
1958 pU->ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
1959 if (!STRCMP(keywords[i+1],"minimized"))
1960 pU->ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
1961 if (!STRCMP(keywords[i+1],"maximized"))
1962 pU->ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
1963 if (!STRCMP(keywords[i+1],"minimize"))
1964 pU->ovlywindowParams.nCmdShow = SW_MINIMIZE;
1965 if (!STRCMP(keywords[i+1],"normal"))
1966 pU->ovlywindowParams.nCmdShow = SW_NORMAL;
1967 if (!STRCMP(keywords[i+1],"show"))
1968 pU->ovlywindowParams.nCmdShow = SW_SHOW;
1969 if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
1970 if (!STRCMP(keywords[i+2],"active"))
1971 pU->ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
1972 if (!STRCMP(keywords[i+2],"action"))
1973 pU->ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
1974 i++;
1976 i+=2;
1977 continue;
1979 /* text is enclosed in " ... " as it seems */
1980 if (!STRCMP(keywords[i],"text")) {
1981 char *t;
1982 int len,j,k;
1984 if (keywords[i+1][0]!='"') {
1985 i++;
1986 continue;
1988 dwFlags |= MCI_OVLY_WINDOW_TEXT;
1989 len = strlen(keywords[i+1])+1;
1990 j = i+2;
1991 while (j<nrofkeywords) {
1992 len += strlen(keywords[j])+1;
1993 if (strchr(keywords[j],'"'))
1994 break;
1995 j++;
1997 s=(char*)xmalloc(len);
1998 strcpy(s,keywords[i+1]+1);
1999 k=j;j=i+2;
2000 while (j<=k) {
2001 strcat(s," ");
2002 strcat(s,keywords[j]);
2004 if ((t=strchr(s,'"'))) *t='\0';
2005 /* FIXME: segmented pointer? */
2006 pU->ovlywindowParams.lpstrText = s;
2007 i=k+1;
2008 continue;
2010 FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
2011 break;
2013 i++;
2015 res = MCI_SendCommand32(MCI_GetDrv(wDevID)->modp.wDeviceID, MCI_WINDOW, dwFlags, (DWORD)pU);
2016 if (s) free(s);
2017 free(pU);
2018 return res;
2021 struct _MCISTR_cmdtable {
2022 char *cmd;
2023 DWORD (*fun)(_MCISTR_PROTO_);
2024 } MCISTR_cmdtable[]={
2025 {"break", MCISTR_Break},
2026 {"capability", MCISTR_Capability},
2027 {"close", MCISTR_Close},
2028 {"cue", MCISTR_Cue},
2029 {"delete", MCISTR_Delete},
2030 {"escape", MCISTR_Escape},
2031 {"freeze", MCISTR_Freeze},
2032 {"info", MCISTR_Info},
2033 {"load", MCISTR_Load},
2034 {"open", MCISTR_Open},
2035 {"pause", MCISTR_Pause},
2036 {"play", MCISTR_Play},
2037 {"put", MCISTR_Put},
2038 {"realize", MCISTR_Realize},
2039 {"record", MCISTR_Record},
2040 {"resume", MCISTR_Resume},
2041 {"save", MCISTR_Save},
2042 {"seek", MCISTR_Seek},
2043 {"set", MCISTR_Set},
2044 {"spin", MCISTR_Spin},
2045 {"status", MCISTR_Status},
2046 {"step", MCISTR_Step},
2047 {"stop", MCISTR_Stop},
2048 {"sysinfo", MCISTR_Sysinfo},
2049 {"unfreeze", MCISTR_Unfreeze},
2050 {"update", MCISTR_Update},
2051 {"where", MCISTR_Where},
2052 {"window", MCISTR_Window},
2053 {NULL, NULL}
2056 /**************************************************************************
2057 * mciSendString16 [MMSYSTEM.702]
2059 /* The usercode sends a string with a command (and flags) expressed in
2060 * words in it... We do our best to call aprobiate drivers,
2061 * and return a errorcode AND a readable string (if lpstrRS!=NULL)
2062 * Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
2064 /* FIXME: "all" is a valid devicetype and we should access all devices if
2065 * it is used. (imagine "close all"). Not implemented yet.
2067 DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2068 UINT16 uReturnLength, HWND16 hwndCallback)
2070 char *cmd,*dev,*args,**keywords,*filename;
2071 WORD uDevTyp=0,wDevID=0;
2072 DWORD dwFlags;
2073 int res=0,i,nrofkeywords;
2075 TRACE(mci,"('%s', %p, %d, %X)\n",
2076 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2078 /* format is <command> <device> <optargs> */
2079 cmd=strdup(lpstrCommand);
2080 dev=strchr(cmd,' ');
2081 if (dev==NULL) {
2082 free(cmd);
2083 return MCIERR_MISSING_DEVICE_NAME;
2085 *dev++='\0';
2086 args=strchr(dev,' ');
2087 if (args!=NULL) *args++='\0';
2088 CharUpper32A(dev);
2089 if (args!=NULL) {
2090 char *s;
2091 i=1;/* nrofkeywords = nrofspaces+1 */
2092 s=args;
2093 while ((s=strchr(s,' '))!=NULL) i++,s++;
2094 keywords=(char**)xmalloc(sizeof(char*)*(i+2));
2095 nrofkeywords=i;
2096 s=args;i=0;
2097 while (s && i<nrofkeywords) {
2098 keywords[i++]=s;
2099 s=strchr(s,' ');
2100 if (s) *s++='\0';
2102 keywords[i]=NULL;
2103 } else {
2104 nrofkeywords=0;
2105 keywords=(char**)xmalloc(sizeof(char*));
2107 dwFlags = 0; /* default flags */
2108 for (i=0;i<nrofkeywords;) {
2109 /* take care, there is also a "device type" capability */
2110 if ((!STRCMP(keywords[i],"type")) && (i<nrofkeywords-1)) {
2111 filename = dev;
2112 dev = keywords[i+1];
2113 memcpy(keywords+i,keywords+(i+2),(nrofkeywords-i-2)*sizeof(char *));
2114 nrofkeywords -= 2;
2115 continue;
2117 if (!STRCMP(keywords[i],"wait")) {
2118 dwFlags |= MCI_WAIT;
2119 memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
2120 nrofkeywords--;
2121 continue;
2123 if (!STRCMP(keywords[i],"notify")) {
2124 dwFlags |= MCI_NOTIFY;
2125 memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
2126 nrofkeywords--;
2127 continue;
2129 i++;
2132 /* determine wDevID and uDevTyp for all commands except "open" */
2133 if (STRCMP(cmd,"open")!=0) {
2134 wDevID = MCI_FirstDevID();
2135 while (1) {
2136 LPSTR dname;
2138 dname=MCI_GetOpenDrv(wDevID)->lpstrAlias;
2139 if (dname==NULL)
2140 dname=MCI_GetOpenDrv(wDevID)->lpstrDeviceType;
2141 if (dname != NULL && !STRCMP(dname,dev))
2142 break;
2143 wDevID = MCI_NextDevID(wDevID);
2144 if (!MCI_DevIDValid(wDevID)) {
2145 TRACE(mci, "MAXMCIDRIVERS reached!\n");
2146 free(keywords);free(cmd);
2147 return MCIERR_INVALID_DEVICE_NAME;
2150 uDevTyp=MCI_GetDrv(wDevID)->modp.wType;
2153 for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
2154 if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
2155 res=MCISTR_cmdtable[i].fun(
2156 wDevID,uDevTyp,lpstrReturnString,
2157 uReturnLength,dev,(LPSTR*)keywords,nrofkeywords,
2158 dwFlags,hwndCallback
2160 break;
2163 if (MCISTR_cmdtable[i].cmd!=NULL) {
2164 free(keywords);free(cmd);
2165 return res;
2167 FIXME(mci,"('%s', %p, %u, %X): unimplemented, please report.\n",
2168 lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2169 free(keywords);free(cmd);
2170 return MCIERR_MISSING_COMMAND_STRING;
2173 /**************************************************************************
2174 * mciSendString32A [MMSYSTEM.702][WINMM.51]
2176 DWORD WINAPI mciSendString32A(LPCSTR lpstrCommand, LPSTR lpstrReturnString,
2177 UINT32 uReturnLength, HWND32 hwndCallback)
2179 return mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2182 /**************************************************************************
2183 * mciSendString32W [WINMM.52]
2185 DWORD WINAPI mciSendString32W(LPCWSTR lpwstrCommand, LPSTR lpstrReturnString,
2186 UINT32 uReturnLength, HWND32 hwndCallback)
2188 LPSTR lpstrCommand;
2189 UINT32 ret;
2191 /* FIXME: is there something to do with lpstrReturnString ? */
2192 lpstrCommand = HEAP_strdupWtoA(GetProcessHeap(), 0, lpwstrCommand);
2193 ret = mciSendString16(lpstrCommand, lpstrReturnString, uReturnLength, hwndCallback);
2194 HeapFree(GetProcessHeap(), 0, lpstrCommand);
2195 return ret;