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