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