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