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