wine/multimedia/mcistring.c
Alexandre Julliard a69b88b2f2 Release 980315
Sun Mar 15 03:46:50 1998  Dimitrie O. Paun  <dimi@mail.cs.toronto.edu>

	* [*/*]
	Fixed some dprintf_ such that there is one and only one
	new line for each dprintf and that new line occurs at the end.
	Transformed some fprintfs into proper debug statements.
	Removed much redundancy from most of the debug statements. The
	redundancy appeared because now the component and function
	name is output automatically. Most debug statements also used to
	output the name of the function.
	All these changes prepared the source to switch completely to
	the new debugging interface.
	For more info, refer to ./documentation/debug-msg

Sat Mar 14 19:45:23 1997  Andreas Mohr <100.30936@germany.net>

	* [misc/shell.c] [if1632/kernel.spec]
	Changed parameters of FUNC004() to fix a crash.
	Not sure if this fix is correct (doc wanted).

	* [windows/user.c] [if1632/user.spec] [include/user.h]
	Implemented UserSeeUserDo.

	* [msdos/int21.c] [include/msdos.h]
	Added "GET LIST OF LISTS" (INT 21/52h).

Sat Mar 14 15:48:02 1998  Douglas Ridgway <ridgway@gmcl.com>

	* [include/windows.h] [relay32/gdi32.spec] [objects/enhmetafile.c]
	Beginnings of enhanced metafile support.

Fri Mar 13 20:53:09 1998  John Richardson <jrichard@zko.dec.com>

	* [win32/console.c]
	Restart interrupted console writes.

Fri Mar 13 18:59:24 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Updated documentation for API manpages.

	* [windows/dce.c]
	ReleaseDC16: Fixed cast.

	* [include/windows.h] [memory/virtual.c]
	VirtualQuery{Ex} should return DWORD instead of BOOL32.

Fri Mar 13 13:03:06 1998  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [README][documentation/status/]
	README updated, added lzexpand,version and multimedia
	status notes to new documentation/status directory.

	* [ole/*.c][if1632/typelib.spec]
	Added typelib stubs, several small additions and fixes.

	* [loader/pe_image.c]
	Fixed a small bug (fixup_imports got passed the wrong hModule in a
	remapcase).

	* [loader/signal.c][if1632/signal.c][misc/winsock_dns.c]
	  [loader/module.c]
	Fixed some recursive debugger crashes (caused by invalid FS).

	* [misc/registry.c]
	Two bugs fixed.

Fri Mar 13 04:55:01 1998  David Lee Lambert <lamber45@egr.msu.edu>

	* [include/winnt.h] [include/winnls.h]
	Moved LANG_xxx flags to winnls.h

	* [include/winnls.h]
	Added flags for GetDateFormat(); fixed validity of
	LOCALE_SYSTEM_DEFAULT.

	* [include/windows.h] 
	Added GetTimeFormat() prototypes.

	* [ole/ole2nls.c]
	Implemented ASCII date- and time-functions,  using an
	optimized common core;  added stubs for Unicode versions;  
	started work on a Unicode core.

	* [AUTHORS]
	Added my name.

Mon Mar  9 20:10:15 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [relay32/comctl32.spec] [include/imagelist.h]
	  [include/commctrl.h] [misc/imagelist.c] [misc/Makefile.in]
	First attempt at implementing ImageLists.

Sun Mar  8 20:19:49 1998  Uwe Bonnes  <bon@elektron.ikp.physik.tu-darmstadt.de>

	* [files/dos_fs.c] [configure.in]
	Try to get FileTimeToLocalFileTime,FileTimeToSystemTime and
	SystemTimeToFileTime right.
	Use timegm() where available.

	* [misc/lstr.c]
	Fix an off by one error in FormatMessage and handle the case 
	when args = NULL (used by programs to get the length of the 
	string).

	* [win32/console.c]
	Actual display a per-process Title string, better working
	attempt for WriteConsole32W and ReadConsole32W.

Fri Mar  6 20:33:45 1998  Slaven Rezic  <eserte@cs.tu-berlin.de>

	* [include/config.h.in][configure.in][multimedia/audio.c]
	  [multimedia/dsound.c]
	Added check for FreeBSD sound system.

Sun Mar  1 17:40:10 1998  Jason Schonberg <schon@mti.sgi.com>

	* [controls/edit.c] [include/ole.h] [include/shlobj.h]
	Removed final commas in enum types.

Mon Feb 23 07:52:18 1998  Luiz Otavio L. Zorzella  <zorzella@nr.conexware.com>

	* [multimedia/time.c]
	Workaround to avoid infinite recursion inside timeGetTime.

	* [multimedia/audio.c]
	WODM_GETNUMDEVS and WIDM_GETNUMDEVS only return 1 now if the
	SOUND_DEV can be opened, or if it's busy.
1998-03-15 20:29:56 +00:00

2213 lines
64 KiB
C

/*
* MCI stringinterface
*
* Copyright 1995 Marcus Meissner
*/
/* FIXME: special commands of device drivers should be handled by those drivers
*/
/* FIXME: this current implementation does not allow commands like
* capability <filename> can play
* which is allowed by the MCI standard.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "windows.h"
#include "heap.h"
#include "ldt.h"
#include "user.h"
#include "driver.h"
#include "mmsystem.h"
#include "callback.h"
#include "debug.h"
#include "xmalloc.h"
extern struct LINUX_MCIDRIVER mciDrv[MAXMCIDRIVERS];
#define GetDrv(wDevID) (&mciDrv[MMSYSTEM_DevIDToIndex(wDevID)])
#define GetOpenDrv(wDevID) (&(GetDrv(wDevID)->mop))
extern int MMSYSTEM_DevIDToIndex(UINT16 wDevID);
extern UINT16 MMSYSTEM_FirstDevID(void);
extern UINT16 MMSYSTEM_NextDevID(UINT16 wDevID);
extern BOOL32 MMSYSTEM_DevIDValid(UINT16 wDevID);
LONG WINAPI DrvDefDriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
DWORD dwParam1, DWORD dwParam2);
LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
DWORD dwParam1, DWORD dwParam2);
LONG MIDI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
DWORD dwParam1, DWORD dwParam2);
LONG CDAUDIO_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
DWORD dwParam1, DWORD dwParam2);
LONG ANIM_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
DWORD dwParam1, DWORD dwParam2);
/* The reason why I just don't lowercase the keywords array in
* mciSendString is left as an exercise to the reader.
*/
#define STRCMP(x,y) lstrcmpi32A(x,y)
/* standard functionparameters for all functions */
#define _MCISTR_PROTO_ \
WORD wDevID,WORD uDevTyp,LPSTR lpstrReturnString,UINT16 uReturnLength,\
LPCSTR dev,LPSTR *keywords,UINT16 nrofkeywords,DWORD dwFlags,\
HWND16 hwndCallback
/* copy string to return pointer including necessary checks
* for use in mciSendString()
*/
#define _MCI_STR(s) do {\
TRACE(mci,"->returns '%s'\n",s);\
if (lpstrReturnString) {\
lstrcpyn32A(lpstrReturnString,s,uReturnLength);\
TRACE(mci,"-->'%s'\n",lpstrReturnString);\
}\
} while(0)
/* calling DriverProc. We need to pass the struct as SEGMENTED POINTER. */
#define _MCI_CALL_DRIVER(cmd,params) \
switch(uDevTyp) {\
case MCI_DEVTYPE_CD_AUDIO:\
res=CDAUDIO_DriverProc(GetDrv(wDevID)->modp.wDeviceID,0,cmd,dwFlags, (DWORD)(params));\
break;\
case MCI_DEVTYPE_WAVEFORM_AUDIO:\
res=WAVE_DriverProc(GetDrv(wDevID)->modp.wDeviceID,0,cmd,dwFlags,(DWORD)(params));\
break;\
case MCI_DEVTYPE_SEQUENCER:\
res=MIDI_DriverProc(GetDrv(wDevID)->modp.wDeviceID,0,cmd,dwFlags,(DWORD)(params));\
break;\
case MCI_DEVTYPE_ANIMATION:\
res=ANIM_DriverProc(GetDrv(wDevID)->modp.wDeviceID,0,cmd,dwFlags,(DWORD)(params));\
break;\
case MCI_DEVTYPE_DIGITAL_VIDEO:\
FIXME(mci,"_MCI_CALL_DRIVER: No DIGITAL_VIDEO yet !\n");\
res=MCIERR_DEVICE_NOT_INSTALLED;\
break;\
default:\
/*res = Callbacks->CallDriverProc(GetDrv(wDevID)->driverproc,GetDrv(wDevID)->modp.wDeviceID,GetDrv(wDevID)->hdrv,cmd,dwFlags,(DWORD)(params));\
break;*/\
res = MCIERR_DEVICE_NOT_INSTALLED;\
break;\
}
/* print a DWORD in the specified timeformat */
static void
_MCISTR_printtf(char *buf,UINT16 uDevType,DWORD timef,DWORD val) {
*buf='\0';
switch (timef) {
case MCI_FORMAT_MILLISECONDS:
case MCI_FORMAT_FRAMES:
case MCI_FORMAT_BYTES:
case MCI_FORMAT_SAMPLES:
case MCI_VD_FORMAT_TRACK:
/*case MCI_SEQ_FORMAT_SONGPTR: sameas MCI_VD_FORMAT_TRACK */
sprintf(buf,"%ld",val);
break;
case MCI_FORMAT_HMS:
/* well, the macros have the same content*/
/*FALLTRHOUGH*/
case MCI_FORMAT_MSF:
sprintf(buf,"%d:%d:%d",
MCI_HMS_HOUR(val),
MCI_HMS_MINUTE(val),
MCI_HMS_SECOND(val)
);
break;
case MCI_FORMAT_TMSF:
sprintf(buf,"%d:%d:%d:%d",
MCI_TMSF_TRACK(val),
MCI_TMSF_MINUTE(val),
MCI_TMSF_SECOND(val),
MCI_TMSF_FRAME(val)
);
break;
default:
fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %ld, report.\n",timef);
strcpy(buf,"0"); /* hmm */
break;
}
return;
}
/* possible different return types */
#define _MCISTR_int 1
#define _MCISTR_time 2
#define _MCISTR_bool 3
#define _MCISTR_tfname 4
#define _MCISTR_mode 5
#define _MCISTR_divtype 6
#define _MCISTR_seqtype 7
#define _MCISTR_vdmtype 8
#define _MCISTR_devtype 9
static void
_MCISTR_convreturn(int type,DWORD dwReturn,LPSTR lpstrReturnString,
WORD uReturnLength,WORD uDevTyp,int timef
) {
switch (type) {
case _MCISTR_vdmtype:
switch (dwReturn) {
case MCI_VD_MEDIA_CLV:_MCI_STR("CLV");break;
case MCI_VD_MEDIA_CAV:_MCI_STR("CAV");break;
default:
case MCI_VD_MEDIA_OTHER:_MCI_STR("other");break;
}
break;
case _MCISTR_seqtype:
switch (dwReturn) {
case MCI_SEQ_NONE:_MCI_STR("none");break;
case MCI_SEQ_SMPTE:_MCI_STR("smpte");break;
case MCI_SEQ_FILE:_MCI_STR("file");break;
case MCI_SEQ_MIDI:_MCI_STR("midi");break;
default:fprintf(stdnimp,__FILE__":MCISTR_Status:missing sequencer mode %ld\n",dwReturn);
}
break;
case _MCISTR_mode:
switch (dwReturn) {
case MCI_MODE_NOT_READY:_MCI_STR("not ready");break;
case MCI_MODE_STOP:_MCI_STR("stopped");break;
case MCI_MODE_PLAY:_MCI_STR("playing");break;
case MCI_MODE_RECORD:_MCI_STR("recording");break;
case MCI_MODE_SEEK:_MCI_STR("seeking");break;
case MCI_MODE_PAUSE:_MCI_STR("paused");break;
case MCI_MODE_OPEN:_MCI_STR("open");break;
default:break;
}
break;
case _MCISTR_bool:
if (dwReturn)
_MCI_STR("true");
else
_MCI_STR("false");
break;
case _MCISTR_int:{
char buf[16];
sprintf(buf,"%ld",dwReturn);
_MCI_STR(buf);
break;
}
case _MCISTR_time: {
char buf[100];
_MCISTR_printtf(buf,uDevTyp,timef,dwReturn);
_MCI_STR(buf);
break;
}
case _MCISTR_tfname:
switch (timef) {
case MCI_FORMAT_MILLISECONDS:_MCI_STR("milliseconds");break;
case MCI_FORMAT_FRAMES:_MCI_STR("frames");break;
case MCI_FORMAT_BYTES:_MCI_STR("bytes");break;
case MCI_FORMAT_SAMPLES:_MCI_STR("samples");break;
case MCI_FORMAT_HMS:_MCI_STR("hms");break;
case MCI_FORMAT_MSF:_MCI_STR("msf");break;
case MCI_FORMAT_TMSF:_MCI_STR("tmsf");break;
default:
fprintf(stdnimp,__FILE__":MCISTR_Status:missing timeformat for %d, report.\n",timef);
break;
}
break;
case _MCISTR_divtype:
switch (dwReturn) {
case MCI_SEQ_DIV_PPQN:_MCI_STR("PPQN");break;
case MCI_SEQ_DIV_SMPTE_24:_MCI_STR("SMPTE 24 frame");break;
case MCI_SEQ_DIV_SMPTE_25:_MCI_STR("SMPTE 25 frame");break;
case MCI_SEQ_DIV_SMPTE_30:_MCI_STR("SMPTE 30 frame");break;
case MCI_SEQ_DIV_SMPTE_30DROP:_MCI_STR("SMPTE 30 frame drop");break;
}
case _MCISTR_devtype:
switch (dwReturn) {
case MCI_DEVTYPE_VCR:_MCI_STR("vcr");break;
case MCI_DEVTYPE_VIDEODISC:_MCI_STR("videodisc");break;
case MCI_DEVTYPE_CD_AUDIO:_MCI_STR("cd audio");break;
case MCI_DEVTYPE_OVERLAY:_MCI_STR("overlay");break;
case MCI_DEVTYPE_DAT:_MCI_STR("dat");break;
case MCI_DEVTYPE_SCANNER:_MCI_STR("scanner");break;
case MCI_DEVTYPE_ANIMATION:_MCI_STR("animation");break;
case MCI_DEVTYPE_DIGITAL_VIDEO:_MCI_STR("digital video");break;
case MCI_DEVTYPE_OTHER:_MCI_STR("other");break;
case MCI_DEVTYPE_WAVEFORM_AUDIO:_MCI_STR("waveform audio");break;
case MCI_DEVTYPE_SEQUENCER:_MCI_STR("sequencer");break;
default:fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown device type %ld, report.\n",dwReturn);break;
}
break;
default:
fprintf(stdnimp,__FILE__":_MCISTR_convreturn:unknown resulttype %d, report.\n",type);
break;
}
}
#define FLAG1(str,flag) \
if (!STRCMP(keywords[i],str)) {\
dwFlags |= flag;\
i++;\
continue;\
}
#define FLAG2(str1,str2,flag) \
if (!STRCMP(keywords[i],str1) && (i+1<nrofkeywords) && !STRCMP(keywords[i+1],str2)) {\
dwFlags |= flag;\
i+=2;\
continue;\
}
/* All known subcommands are implemented in single functions to avoid
* bloat and a xxxx lines long mciSendString(). All commands are of the
* format MCISTR_Cmd(_MCISTR_PROTO_) where _MCISTR_PROTO_ is the above
* defined line of arguments. (This is just for easy enhanceability.)
* All functions return the MCIERR_ errorvalue as DWORD. Returnvalues
* for the calls are in lpstrReturnString (If I mention return values
* in function headers, I mean returnvalues in lpstrReturnString.)
* Integers are sprintf("%d")ed integers. Boolean values are
* "true" and "false".
* timeformat depending values are "%d" "%d:%d" "%d:%d:%d" "%d:%d:%d:%d"
* FIXME: is above line correct?
*
* Preceding every function is a list of implemented/known arguments.
* Feel free to add missing arguments.
*
*/
/*
* Opens the specified MCI driver.
* Arguments: <name>
* Optional:
* "shareable"
* "alias <aliasname>"
* "element <elementname>"
* Additional:
* waveform audio:
* "buffer <nrBytesPerSec>"
* Animation:
* "nostatic" increaste nr of nonstatic colours
* "parent <windowhandle>"
* "style <mask>" bitmask of WS_xxxxx (see windows.h)
* "style child" WS_CHILD
* "style overlap" WS_OVERLAPPED
* "style popup" WS_POPUP
* Overlay:
* "parent <windowhandle>"
* "style <mask>" bitmask of WS_xxxxx (see windows.h)
* "style child" WS_CHILD
* "style overlap" WS_OVERLAPPED
* "style popup" WS_POPUP
* Returns nothing.
*/
static DWORD
MCISTR_Open(_MCISTR_PROTO_) {
int res,i;
char *s;
union U {
MCI_OPEN_PARMS16 openParams;
MCI_WAVE_OPEN_PARMS16 waveopenParams;
MCI_ANIM_OPEN_PARMS16 animopenParams;
MCI_OVLY_OPEN_PARMS16 ovlyopenParams;
};
union U *pU = SEGPTR_NEW(union U);
pU->openParams.lpstrElementName = NULL;
s=strchr(dev,'!');
if (s!=NULL) {
*s++='\0';
pU->openParams.lpstrElementName=(LPSTR)SEGPTR_GET(SEGPTR_STRDUP(s));
dwFlags |= MCI_OPEN_ELEMENT;
}
if (!STRCMP(dev,"cdaudio")) {
uDevTyp=MCI_DEVTYPE_CD_AUDIO;
} else if (!STRCMP(dev,"waveaudio")) {
uDevTyp=MCI_DEVTYPE_WAVEFORM_AUDIO;
} else if (!STRCMP(dev,"sequencer")) {
uDevTyp=MCI_DEVTYPE_SEQUENCER;
} else if (!STRCMP(dev,"animation1")) {
uDevTyp=MCI_DEVTYPE_ANIMATION;
} else if (!STRCMP(dev,"avivideo")) {
uDevTyp=MCI_DEVTYPE_DIGITAL_VIDEO;
} else {
SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrElementName));
SEGPTR_FREE(pU);
return MCIERR_INVALID_DEVICE_NAME;
}
wDevID=MMSYSTEM_FirstDevID();
while(GetDrv(wDevID)->modp.wType) {
wDevID = MMSYSTEM_NextDevID(wDevID);
if (!MMSYSTEM_DevIDValid(wDevID)) {
TRACE(mci, "MAXMCIDRIVERS reached (%x) !\n", wDevID);
SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrElementName));
SEGPTR_FREE(pU);
return MCIERR_INTERNAL;
}
}
GetDrv(wDevID)->modp.wType = uDevTyp;
GetDrv(wDevID)->modp.wDeviceID = 0; /* FIXME? for multiple devices */
pU->openParams.dwCallback = hwndCallback ;
pU->openParams.wDeviceID = wDevID;
pU->ovlyopenParams.dwStyle = 0;
pU->animopenParams.dwStyle = 0;
pU->openParams.lpstrDeviceType = (LPSTR)SEGPTR_GET(SEGPTR_STRDUP(dev));
pU->openParams.lpstrAlias = NULL;
dwFlags |= MCI_OPEN_TYPE;
i=0;
while (i<nrofkeywords) {
FLAG1("shareable",MCI_OPEN_SHAREABLE);
if (!STRCMP(keywords[i],"alias") && (i+1<nrofkeywords)) {
dwFlags |= MCI_OPEN_ALIAS;
pU->openParams.lpstrAlias=(LPSTR)SEGPTR_GET(SEGPTR_STRDUP(keywords[i+1]));
i+=2;
continue;
}
if (!STRCMP(keywords[i],"element") && (i+1<nrofkeywords)) {
dwFlags |= MCI_OPEN_ELEMENT;
pU->openParams.lpstrElementName=(LPSTR)SEGPTR_GET(SEGPTR_STRDUP(keywords[i+1]));
i+=2;
continue;
}
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
case MCI_DEVTYPE_DIGITAL_VIDEO:
FLAG1("nostatic",MCI_ANIM_OPEN_NOSTATIC);
if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
dwFlags |= MCI_ANIM_OPEN_PARENT;
sscanf(keywords[i+1],"%hu",&(pU->animopenParams.hWndParent));
i+=2;
continue;
}
if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
DWORD st;
dwFlags |= MCI_ANIM_OPEN_WS;
if (!STRCMP(keywords[i+1],"popup")) {
pU->animopenParams.dwStyle |= WS_POPUP;
} else if (!STRCMP(keywords[i+1],"overlap")) {
pU->animopenParams.dwStyle |= WS_OVERLAPPED;
} else if (!STRCMP(keywords[i+1],"child")) {
pU->animopenParams.dwStyle |= WS_CHILD;
} else if (sscanf(keywords[i+1],"%ld",&st)) {
pU->animopenParams.dwStyle |= st;
} else
fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
i+=2;
continue;
}
break;
case MCI_DEVTYPE_WAVEFORM_AUDIO:
if (!STRCMP(keywords[i],"buffer") && (i+1<nrofkeywords)) {
dwFlags |= MCI_WAVE_OPEN_BUFFER;
sscanf(keywords[i+1],"%ld",&(pU->waveopenParams.dwBufferSeconds));
}
break;
case MCI_DEVTYPE_OVERLAY:
/* looks just like anim, but without NOSTATIC */
if (!STRCMP(keywords[i],"parent") && (i+1<nrofkeywords)) {
dwFlags |= MCI_OVLY_OPEN_PARENT;
sscanf(keywords[i+1],"%hd",&(pU->ovlyopenParams.hWndParent));
i+=2;
continue;
}
if (!STRCMP(keywords[i],"style") && (i+1<nrofkeywords)) {
DWORD st;
dwFlags |= MCI_OVLY_OPEN_WS;
if (!STRCMP(keywords[i+1],"popup")) {
pU->ovlyopenParams.dwStyle |= WS_POPUP;
} else if (!STRCMP(keywords[i+1],"overlap")) {
pU->ovlyopenParams.dwStyle |= WS_OVERLAPPED;
} else if (!STRCMP(keywords[i+1],"child")) {
pU->ovlyopenParams.dwStyle |= WS_CHILD;
} else if (sscanf(keywords[i+1],"%ld",&st)) {
pU->ovlyopenParams.dwStyle |= st;
} else
fprintf(stdnimp,__FILE__":MCISTR_Open:unknown 'style' keyword %s, please report.\n",keywords[i+1]);
i+=2;
continue;
}
break;
}
fprintf(stdnimp,__FILE__":MCISTR_Open:unknown parameter passed %s, please report.\n",keywords[i]);
i++;
}
_MCI_CALL_DRIVER( MCI_OPEN, SEGPTR_GET(pU) );
if (res==0)
memcpy(GetOpenDrv(wDevID),&pU->openParams,sizeof(MCI_OPEN_PARMS16));
else {
SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrElementName));
SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrDeviceType));
SEGPTR_FREE(PTR_SEG_TO_LIN(pU->openParams.lpstrAlias));
}
SEGPTR_FREE(pU);
return res;
}
/* A help function for a lot of others ...
* for instance status/play/record/seek etc.
*/
DWORD
_MCISTR_determine_timeformat(LPCSTR dev,WORD wDevID,WORD uDevTyp,int *timef)
{
int res;
DWORD dwFlags = MCI_STATUS_ITEM;
MCI_STATUS_PARMS *statusParams = SEGPTR_NEW(MCI_STATUS_PARMS);
if (!statusParams) return 0;
statusParams->dwItem = MCI_STATUS_TIME_FORMAT;
statusParams->dwReturn = 0;
_MCI_CALL_DRIVER( MCI_STATUS, SEGPTR_GET(statusParams) );
if (res==0) *timef = statusParams->dwReturn;
SEGPTR_FREE(statusParams);
return res;
}
/* query status of MCI drivers
* Arguments:
* Required:
* "mode" - returns "not ready" "paused" "playing" "stopped" "open"
* "parked" "recording" "seeking" ....
* Basics:
* "current track" - returns current track as integer
* "length [track <nr>]" - returns length [of track <nr>] in current
* timeformat
* "number of tracks" - returns number of tracks as integer
* "position [track <nr>]" - returns position [in track <nr>] in current
* timeformat
* "ready" - checks if device is ready to play, -> bool
* "start position" - returns start position in timeformat
* "time format" - returns timeformat (list of possible values:
* "ms" "msf" "milliseconds" "hmsf" "tmsf" "frames"
* "bytes" "samples" "hms")
* "media present" - returns if media is present as bool
* Animation:
* "forward" - returns "true" if device is playing forwards
* "speed" - returns speed for device
* "palette handle" - returns palette handle
* "window handle" - returns window handle
* "stretch" - returns stretch bool
* MIDI sequencer:
* "division type" - ? returns "PPQN" "SMPTE 24 frame"
* "SMPTE 25 frame" "SMPTE 30 frame" "SMPTE 30 drop frame"
* "tempo" - current tempo in (PPQN? speed in frames, SMPTE*? speed in hsmf)
* "offset" - offset in dito.
* "port" - midi port as integer
* "slave" - slave device ("midi","file","none","smpte")
* "master" - masterdevice (dito.)
* Overlay:
* "window handle" - see animation
* "stretch" - dito
* Video Disc:
* "speed" - speed as integer
* "forward" - returns bool (when playing forward)
* "side" - returns 1 or 2
* "media type" - returns "CAV" "CLV" "other"
* "disc size" - returns "8" or "12"
* WAVEFORM audio:
* "input" - base queries on input set
* "output" - base queries on output set
* "format tag" - return integer format tag
* "channels" - return integer nr of channels
* "bytespersec" - return average nr of bytes/sec
* "samplespersec" - return nr of samples per sec
* "bitspersample" - return bitspersample
* "alignment" - return block alignment
* "level" - return level?
*/
#define ITEM1(str,item,xtype) \
if (!STRCMP(keywords[i],str)) {\
statusParams->dwItem = item;\
type = xtype;\
i++;\
continue;\
}
#define ITEM2(str1,str2,item,xtype) \
if ( !STRCMP(keywords[i],str1) &&\
(i+1<nrofkeywords) &&\
!STRCMP(keywords[i+1],str2)\
) {\
statusParams->dwItem = item;\
type = xtype;\
i+=2;\
continue;\
}
#define ITEM3(str1,str2,str3,item,xtype) \
if ( !STRCMP(keywords[i],str1) &&\
(i+2<nrofkeywords) &&\
!STRCMP(keywords[i+1],str2) &&\
!STRCMP(keywords[i+2],str3)\
) {\
statusParams->dwItem = item;\
type = xtype;\
i+=3;\
continue;\
}
static DWORD
MCISTR_Status(_MCISTR_PROTO_) {
MCI_STATUS_PARMS *statusParams = SEGPTR_NEW(MCI_STATUS_PARMS);
int type = 0,i,res,timef;
statusParams->dwCallback = hwndCallback;
dwFlags |= MCI_STATUS_ITEM;
res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
if (res) return res;
statusParams->dwReturn = 0;
statusParams->dwItem = 0;
i = 0;
while (i<nrofkeywords) {
if (!STRCMP(keywords[i],"track") && (i+1<nrofkeywords)) {
sscanf(keywords[i+1],"%ld",&(statusParams->dwTrack));
dwFlags |= MCI_TRACK;
i+=2;
continue;
}
FLAG1("start",MCI_STATUS_START);
/* generic things */
ITEM2("current","track",MCI_STATUS_CURRENT_TRACK,_MCISTR_time);
ITEM2("time","format",MCI_STATUS_TIME_FORMAT,_MCISTR_tfname);
ITEM1("ready",MCI_STATUS_READY,_MCISTR_bool);
ITEM1("mode",MCI_STATUS_MODE,_MCISTR_mode);
ITEM3("number","of","tracks",MCI_STATUS_NUMBER_OF_TRACKS,_MCISTR_int);
ITEM1("length",MCI_STATUS_LENGTH,_MCISTR_time);
ITEM1("position",MCI_STATUS_POSITION,_MCISTR_time);
ITEM2("media","present",MCI_STATUS_MEDIA_PRESENT,_MCISTR_bool);
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
case MCI_DEVTYPE_DIGITAL_VIDEO:
ITEM2("palette","handle",MCI_ANIM_STATUS_HPAL,_MCISTR_int);
ITEM2("window","handle",MCI_ANIM_STATUS_HWND,_MCISTR_int);
ITEM1("stretch",MCI_ANIM_STATUS_STRETCH,_MCISTR_bool);
ITEM1("speed",MCI_ANIM_STATUS_SPEED,_MCISTR_int);
ITEM1("forward",MCI_ANIM_STATUS_FORWARD,_MCISTR_bool);
break;
case MCI_DEVTYPE_SEQUENCER:
/* just completing the list, not working correctly */
ITEM2("division","type",MCI_SEQ_STATUS_DIVTYPE,_MCISTR_divtype);
/* tempo ... PPQN in frames/second, SMPTE in hmsf */
ITEM1("tempo",MCI_SEQ_STATUS_TEMPO,_MCISTR_int);
ITEM1("port",MCI_SEQ_STATUS_PORT,_MCISTR_int);
ITEM1("slave",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
ITEM1("master",MCI_SEQ_STATUS_SLAVE,_MCISTR_seqtype);
/* offset ... PPQN in frames/second, SMPTE in hmsf */
ITEM1("offset",MCI_SEQ_STATUS_SLAVE,_MCISTR_time);
break;
case MCI_DEVTYPE_OVERLAY:
ITEM2("window","handle",MCI_OVLY_STATUS_HWND,_MCISTR_int);
ITEM1("stretch",MCI_OVLY_STATUS_STRETCH,_MCISTR_bool);
break;
case MCI_DEVTYPE_VIDEODISC:
ITEM1("speed",MCI_VD_STATUS_SPEED,_MCISTR_int);
ITEM1("forward",MCI_VD_STATUS_FORWARD,_MCISTR_bool);
ITEM1("side",MCI_VD_STATUS_SIDE,_MCISTR_int);
ITEM2("media","type",MCI_VD_STATUS_SIDE,_MCISTR_vdmtype);
/* returns 8 or 12 */
ITEM2("disc","size",MCI_VD_STATUS_DISC_SIZE,_MCISTR_int);
break;
case MCI_DEVTYPE_WAVEFORM_AUDIO:
/* I am not quite sure if foll. 2 lines are right. */
FLAG1("input",MCI_WAVE_INPUT);
FLAG1("output",MCI_WAVE_OUTPUT);
ITEM2("format","tag",MCI_WAVE_STATUS_FORMATTAG,_MCISTR_int);
ITEM1("channels",MCI_WAVE_STATUS_CHANNELS,_MCISTR_int);
ITEM1("bytespersec",MCI_WAVE_STATUS_AVGBYTESPERSEC,_MCISTR_int);
ITEM1("samplespersec",MCI_WAVE_STATUS_SAMPLESPERSEC,_MCISTR_int);
ITEM1("bitspersample",MCI_WAVE_STATUS_BITSPERSAMPLE,_MCISTR_int);
ITEM1("alignment",MCI_WAVE_STATUS_BLOCKALIGN,_MCISTR_int);
ITEM1("level",MCI_WAVE_STATUS_LEVEL,_MCISTR_int);
break;
}
fprintf(stdnimp,__FILE__":MCISTR_Status:unknown keyword '%s'\n",keywords[i]);
i++;
}
if (!statusParams->dwItem)
return MCIERR_MISSING_STRING_ARGUMENT;
_MCI_CALL_DRIVER( MCI_STATUS, SEGPTR_GET(statusParams) );
if (res==0)
_MCISTR_convreturn(type,statusParams->dwReturn,lpstrReturnString,uReturnLength,uDevTyp,timef);
SEGPTR_FREE(statusParams);
return res;
}
#undef ITEM1
#undef ITEM2
#undef ITEM3
/* set specified parameters in respective MCI drivers
* Arguments:
* "door open" eject media or somesuch
* "door close" load media
* "time format <timeformatname>" "ms" "milliseconds" "msf" "hmsf"
* "tmsf" "SMPTE 24" "SMPTE 25" "SMPTE 30"
* "SMPTE drop 30"
* "audio [all|left|right] [on|off]" sets specified audiochannel on or off
* "video [on|off]" sets video on/off
* Waveform audio:
* "formattag pcm" sets format to pcm
* "formattag <nr>" sets integer formattag value
* "any input" accept input from any known source
* "any output" output to any known destination
* "input <nr>" input from source <nr>
* "output <nr>" output to destination <nr>
* "channels <nr>" sets nr of channels
* "bytespersec <nr>" sets average bytes per second
* "samplespersec <nr>" sets average samples per second (1 sample can
* be 2 bytes!)
* "alignment <nr>" sets the blockalignment to <nr>
* "bitspersample <nr>" sets the nr of bits per sample
* Sequencer:
* "master [midi|file|smpte|none]" sets the midi master device
* "slave [midi|file|smpte|none]" sets the midi master device
* "port mapper" midioutput to portmapper
* "port <nr>" midioutput to specified port
* "tempo <nr>" tempo of track (depends on timeformat/divtype)
* "offset <nr>" start offset?
*/
static DWORD
MCISTR_Set(_MCISTR_PROTO_) {
union U {
MCI_SET_PARMS setParams;
MCI_WAVE_SET_PARMS16 wavesetParams;
MCI_SEQ_SET_PARMS seqsetParams;
};
union U *pU = SEGPTR_NEW(union U);
int i,res;
pU->setParams.dwCallback = hwndCallback;
i = 0;
while (i<nrofkeywords) {
FLAG2("door","open",MCI_SET_DOOR_OPEN);
FLAG2("door","closed",MCI_SET_DOOR_CLOSED);
if ( !STRCMP(keywords[i],"time") &&
(i+2<nrofkeywords) &&
!STRCMP(keywords[i+1],"format")
) {
dwFlags |= MCI_SET_TIME_FORMAT;
/* FIXME:is this a shortcut for milliseconds or
* minutes:seconds? */
if (!STRCMP(keywords[i+2],"ms"))
pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
if (!STRCMP(keywords[i+2],"milliseconds"))
pU->setParams.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
if (!STRCMP(keywords[i+2],"msf"))
pU->setParams.dwTimeFormat = MCI_FORMAT_MSF;
if (!STRCMP(keywords[i+2],"hms"))
pU->setParams.dwTimeFormat = MCI_FORMAT_HMS;
if (!STRCMP(keywords[i+2],"frames"))
pU->setParams.dwTimeFormat = MCI_FORMAT_FRAMES;
if (!STRCMP(keywords[i+2],"track"))
pU->setParams.dwTimeFormat = MCI_VD_FORMAT_TRACK;
if (!STRCMP(keywords[i+2],"bytes"))
pU->setParams.dwTimeFormat = MCI_FORMAT_BYTES;
if (!STRCMP(keywords[i+2],"samples"))
pU->setParams.dwTimeFormat = MCI_FORMAT_SAMPLES;
if (!STRCMP(keywords[i+2],"tmsf"))
pU->setParams.dwTimeFormat = MCI_FORMAT_TMSF;
if ( !STRCMP(keywords[i+2],"song") &&
(i+3<nrofkeywords) &&
!STRCMP(keywords[i+3],"pointer")
)
pU->setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR;
if (!STRCMP(keywords[i+2],"smpte") && (i+3<nrofkeywords)) {
if (!STRCMP(keywords[i+3],"24"))
pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_24;
if (!STRCMP(keywords[i+3],"25"))
pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_25;
if (!STRCMP(keywords[i+3],"30"))
pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30;
if (!STRCMP(keywords[i+3],"drop") && (i+4<nrofkeywords) && !STRCMP(keywords[i+4],"30")) {
pU->setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP;
i++;
}
i++;
/*FALLTHROUGH*/
}
i+=3;
continue;
}
if (!STRCMP(keywords[i],"audio") && (i+1<nrofkeywords)) {
dwFlags |= MCI_SET_AUDIO;
if (!STRCMP(keywords[i+1],"all"))
pU->setParams.dwAudio = MCI_SET_AUDIO_ALL;
if (!STRCMP(keywords[i+1],"left"))
pU->setParams.dwAudio = MCI_SET_AUDIO_LEFT;
if (!STRCMP(keywords[i+1],"right"))
pU->setParams.dwAudio = MCI_SET_AUDIO_RIGHT;
i+=2;
continue;
}
FLAG1("video",MCI_SET_VIDEO);
FLAG1("on",MCI_SET_ON);
FLAG1("off",MCI_SET_OFF);
switch (uDevTyp) {
case MCI_DEVTYPE_WAVEFORM_AUDIO:
FLAG2("any","input",MCI_WAVE_SET_ANYINPUT);
FLAG2("any","output",MCI_WAVE_SET_ANYOUTPUT);
if ( !STRCMP(keywords[i],"formattag") &&
(i+1<nrofkeywords) &&
!STRCMP(keywords[i+1],"pcm")
) {
dwFlags |= MCI_WAVE_SET_FORMATTAG;
pU->wavesetParams.wFormatTag = WAVE_FORMAT_PCM;
i+=2;
continue;
}
/* <keyword> <integer> */
#define WII(str,flag,fmt,element) \
if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
sscanf(keywords[i+1],fmt,&(pU->wavesetParams. element ));\
dwFlags |= flag;\
i+=2;\
continue;\
}
WII("formattag",MCI_WAVE_SET_FORMATTAG,"%hu",wFormatTag);
WII("channels",MCI_WAVE_SET_CHANNELS,"%hu",nChannels);
WII("bytespersec",MCI_WAVE_SET_AVGBYTESPERSEC,"%lu",nAvgBytesPerSec);
WII("samplespersec",MCI_WAVE_SET_SAMPLESPERSEC,"%lu",nSamplesPerSec);
WII("alignment",MCI_WAVE_SET_BLOCKALIGN,"%hu",nBlockAlign);
WII("bitspersample",MCI_WAVE_SET_BITSPERSAMPLE,"%hu",wBitsPerSample);
WII("input",MCI_WAVE_INPUT,"%hu",wInput);
WII("output",MCI_WAVE_OUTPUT,"%hu",wOutput);
#undef WII
break;
case MCI_DEVTYPE_SEQUENCER:
if (!STRCMP(keywords[i],"master") && (i+1<nrofkeywords)) {
dwFlags |= MCI_SEQ_SET_MASTER;
if (!STRCMP(keywords[i+1],"midi"))
pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
if (!STRCMP(keywords[i+1],"file"))
pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
if (!STRCMP(keywords[i+1],"smpte"))
pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
if (!STRCMP(keywords[i+1],"none"))
pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
i+=2;
continue;
}
if (!STRCMP(keywords[i],"slave") && (i+1<nrofkeywords)) {
dwFlags |= MCI_SEQ_SET_SLAVE;
if (!STRCMP(keywords[i+1],"midi"))
pU->seqsetParams.dwMaster = MCI_SEQ_MIDI;
if (!STRCMP(keywords[i+1],"file"))
pU->seqsetParams.dwMaster = MCI_SEQ_FILE;
if (!STRCMP(keywords[i+1],"smpte"))
pU->seqsetParams.dwMaster = MCI_SEQ_SMPTE;
if (!STRCMP(keywords[i+1],"none"))
pU->seqsetParams.dwMaster = MCI_SEQ_NONE;
i+=2;
continue;
}
if ( !STRCMP(keywords[i],"port") &&
(i+1<nrofkeywords) &&
!STRCMP(keywords[i+1],"mapper")
) {
pU->seqsetParams.dwPort=-1;/* FIXME:not sure*/
dwFlags |= MCI_SEQ_SET_PORT;
i+=2;
continue;
}
#define SII(str,flag,element) \
if (!STRCMP(keywords[i],str) && (i+1<nrofkeywords)) {\
sscanf(keywords[i+1],"%ld",&(pU->seqsetParams. element ));\
dwFlags |= flag;\
i+=2;\
continue;\
}
SII("tempo",MCI_SEQ_SET_TEMPO,dwTempo);
SII("port",MCI_SEQ_SET_PORT,dwPort);
SII("offset",MCI_SEQ_SET_PORT,dwOffset);
}
i++;
}
if (!dwFlags)
return MCIERR_MISSING_STRING_ARGUMENT;
_MCI_CALL_DRIVER( MCI_SET, SEGPTR_GET(pU) );
SEGPTR_FREE(pU);
return res;
}
/* specify break key
* Arguments:
* "off" disable break
* "on <keyid>" enable break on key with keyid
* (I strongly suspect, that there is another parameter:
* "window <handle>"
* but I don't see it mentioned in my documentation.
* Returns nothing.
*/
static DWORD
MCISTR_Break(_MCISTR_PROTO_)
{
MCI_BREAK_PARMS16 *breakParams = SEGPTR_NEW(MCI_BREAK_PARMS16);
int res,i;
if (!breakParams) return 0;
/*breakParams.hwndBreak ? */
for (i = 0; i < nrofkeywords; i++)
{
FLAG1("off",MCI_BREAK_OFF);
if (!strcmp(keywords[i],"on") && (nrofkeywords>i+1)) {
dwFlags&=~MCI_BREAK_OFF;
dwFlags|=MCI_BREAK_KEY;
sscanf(keywords[i+1],"%hd",&(breakParams->nVirtKey));
i+=2;
continue;
}
}
_MCI_CALL_DRIVER( MCI_BREAK, SEGPTR_GET(breakParams) );
SEGPTR_FREE(breakParams);
return res;
}
#define ITEM1(str,item,xtype) \
if (!STRCMP(keywords[i],str)) {\
gdcParams->dwItem = item;\
type = xtype;\
i++;\
continue;\
}
#define ITEM2(str1,str2,item,xtype) \
if ( !STRCMP(keywords[i],str1) &&\
(i+1<nrofkeywords) &&\
!STRCMP(keywords[i+1],str2)\
) {\
gdcParams->dwItem = item;\
type = xtype;\
i+=2;\
continue;\
}
#define ITEM3(str1,str2,str3,item,xtype) \
if ( !STRCMP(keywords[i],str1) &&\
(i+2<nrofkeywords) &&\
!STRCMP(keywords[i+1],str2) &&\
!STRCMP(keywords[i+2],str3)\
) {\
gdcParams->dwItem = item;\
type = xtype;\
i+=3;\
continue;\
}
/* get device capabilities of MCI drivers
* Arguments:
* Generic:
* "device type" returns device name as string
* "has audio" returns bool
* "has video" returns bool
* "uses files" returns bool
* "compound device" returns bool
* "can record" returns bool
* "can play" returns bool
* "can eject" returns bool
* "can save" returns bool
* Animation:
* "palettes" returns nr of available palette entries
* "windows" returns nr of available windows
* "can reverse" returns bool
* "can stretch" returns bool
* "slow play rate" returns the slow playrate
* "fast play rate" returns the fast playrate
* "normal play rate" returns the normal playrate
* Overlay:
* "windows" returns nr of available windows
* "can stretch" returns bool
* "can freeze" returns bool
* Videodisc:
* "cav" assume CAV discs (default if no disk inserted)
* "clv" assume CLV discs
* "can reverse" returns bool
* "slow play rate" returns the slow playrate
* "fast play rate" returns the fast playrate
* "normal play rate" returns the normal playrate
* Waveform audio:
* "inputs" returns nr of inputdevices
* "outputs" returns nr of outputdevices
*/
static DWORD
MCISTR_Capability(_MCISTR_PROTO_) {
MCI_GETDEVCAPS_PARMS *gdcParams = SEGPTR_NEW(MCI_GETDEVCAPS_PARMS);
int type=0,i,res;
gdcParams->dwCallback = hwndCallback;
if (!nrofkeywords)
return MCIERR_MISSING_STRING_ARGUMENT;
/* well , thats default */
dwFlags |= MCI_GETDEVCAPS_ITEM;
gdcParams->dwItem = 0;
i=0;
while (i<nrofkeywords) {
ITEM2("device","type",MCI_GETDEVCAPS_DEVICE_TYPE,_MCISTR_devtype);
ITEM2("has","audio",MCI_GETDEVCAPS_HAS_AUDIO,_MCISTR_bool);
ITEM2("has","video",MCI_GETDEVCAPS_HAS_VIDEO,_MCISTR_bool);
ITEM2("uses","files",MCI_GETDEVCAPS_USES_FILES,_MCISTR_bool);
ITEM2("compound","device",MCI_GETDEVCAPS_COMPOUND_DEVICE,_MCISTR_bool);
ITEM2("can","record",MCI_GETDEVCAPS_CAN_RECORD,_MCISTR_bool);
ITEM2("can","play",MCI_GETDEVCAPS_CAN_PLAY,_MCISTR_bool);
ITEM2("can","eject",MCI_GETDEVCAPS_CAN_EJECT,_MCISTR_bool);
ITEM2("can","save",MCI_GETDEVCAPS_CAN_SAVE,_MCISTR_bool);
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
ITEM1("palettes",MCI_ANIM_GETDEVCAPS_PALETTES,_MCISTR_int);
ITEM1("windows",MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
ITEM2("can","reverse",MCI_ANIM_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
ITEM2("can","stretch",MCI_ANIM_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
ITEM3("slow","play","rate",MCI_ANIM_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
ITEM3("fast","play","rate",MCI_ANIM_GETDEVCAPS_FAST_RATE,_MCISTR_int);
ITEM3("normal","play","rate",MCI_ANIM_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
break;
case MCI_DEVTYPE_OVERLAY:
ITEM1("windows",MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,_MCISTR_int);
ITEM2("can","freeze",MCI_OVLY_GETDEVCAPS_CAN_FREEZE,_MCISTR_bool);
ITEM2("can","stretch",MCI_OVLY_GETDEVCAPS_CAN_STRETCH,_MCISTR_bool);
break;
case MCI_DEVTYPE_VIDEODISC:
FLAG1("cav",MCI_VD_GETDEVCAPS_CAV);
FLAG1("clv",MCI_VD_GETDEVCAPS_CLV);
ITEM2("can","reverse",MCI_VD_GETDEVCAPS_CAN_REVERSE,_MCISTR_bool);
ITEM3("slow","play","rate",MCI_VD_GETDEVCAPS_SLOW_RATE,_MCISTR_int);
ITEM3("fast","play","rate",MCI_VD_GETDEVCAPS_FAST_RATE,_MCISTR_int);
ITEM3("normal","play","rate",MCI_VD_GETDEVCAPS_NORMAL_RATE,_MCISTR_int);
break;
case MCI_DEVTYPE_WAVEFORM_AUDIO:
ITEM1("inputs",MCI_WAVE_GETDEVCAPS_INPUTS,_MCISTR_int);
ITEM1("outputs",MCI_WAVE_GETDEVCAPS_OUTPUTS,_MCISTR_int);
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_GETDEVCAPS, SEGPTR_GET(gdcParams) );
/* no timeformat needed */
if (res==0)
_MCISTR_convreturn( type, gdcParams->dwReturn, lpstrReturnString,
uReturnLength, uDevTyp, 0 );
SEGPTR_FREE(gdcParams);
return res;
}
#undef ITEM1
#undef ITEM2
#undef ITEM3
/* resumes operation of device. no arguments, no return values */
static DWORD
MCISTR_Resume(_MCISTR_PROTO_)
{
MCI_GENERIC_PARMS *genParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int res;
genParams->dwCallback = hwndCallback;
_MCI_CALL_DRIVER( MCI_RESUME, SEGPTR_GET(genParams) );
return res;
}
/* pauses operation of device. no arguments, no return values */
static DWORD
MCISTR_Pause(_MCISTR_PROTO_)
{
MCI_GENERIC_PARMS *genParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int res;
genParams->dwCallback = hwndCallback;
_MCI_CALL_DRIVER( MCI_PAUSE, SEGPTR_GET(genParams) );
return res;
}
/* stops operation of device. no arguments, no return values */
static DWORD
MCISTR_Stop(_MCISTR_PROTO_)
{
MCI_GENERIC_PARMS *genParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int res;
genParams->dwCallback = hwndCallback;
_MCI_CALL_DRIVER( MCI_STOP, SEGPTR_GET(genParams) );
return res;
}
/* starts recording.
* Arguments:
* "overwrite" overwrite existing things
* "insert" insert at current position
* "to <time>" record up to <time> (specified in timeformat)
* "from <time>" record from <time> (specified in timeformat)
*/
static DWORD
MCISTR_Record(_MCISTR_PROTO_) {
int i,res,timef,nrargs,j,k,a[4];
char *parsestr;
MCI_RECORD_PARMS *recordParams = SEGPTR_NEW(MCI_RECORD_PARMS);
res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
if (res) return res;
switch (timef) {
case MCI_FORMAT_MILLISECONDS:
case MCI_FORMAT_FRAMES:
case MCI_FORMAT_BYTES:
case MCI_FORMAT_SAMPLES:
nrargs=1;
parsestr="%d";
break;
case MCI_FORMAT_HMS:
case MCI_FORMAT_MSF:
parsestr="%d:%d:%d";
nrargs=3;
break;
case MCI_FORMAT_TMSF:
parsestr="%d:%d:%d:%d";
nrargs=4;
break;
default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
parsestr="%d";
nrargs=1;
break;
}
recordParams->dwCallback = hwndCallback;
i = 0;
while (i<nrofkeywords) {
if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
dwFlags |= MCI_TO;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
/* add up all integers we got, if we have more
* shift them. (Well I should use the macros in
* mmsystem.h, right).
*/
recordParams->dwTo=0;
for (k=0;k<j;k++)
recordParams->dwTo+=a[k]<<(8*(nrargs-k));
i+=2;
continue;
}
if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
dwFlags |= MCI_FROM;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
/* dito. */
recordParams->dwFrom=0;
for (k=0;k<j;k++)
recordParams->dwFrom+=a[k]<<(8*(nrargs-k));
i+=2;
continue;
}
FLAG1("insert",MCI_RECORD_INSERT);
FLAG1("overwrite",MCI_RECORD_OVERWRITE);
i++;
}
_MCI_CALL_DRIVER( MCI_RECORD, SEGPTR_GET(recordParams) );
SEGPTR_FREE(recordParams);
return res;
}
/* play media
* Arguments:
* "to <time>" play up to <time> (specified in set timeformat)
* "from <time>" play from <time> (specified in set timeformat)
* Animation:
* "slow" play slow
* "fast" play fast
* "scan" play as fast as possible (with audio disabled perhaps)
* "reverse" play reverse
* "speed <fps>" play with specified frames per second
* Videodisc:
* "slow" play slow
* "fast" play fast
* "scan" play as fast as possible (with audio disabled perhaps)
* "reverse" play reverse
* "speed <fps>" play with specified frames per second
*/
static DWORD
MCISTR_Play(_MCISTR_PROTO_) {
int i,res,timef,nrargs,j,k,a[4];
char *parsestr;
union U {
MCI_PLAY_PARMS playParams;
MCI_VD_PLAY_PARMS vdplayParams;
MCI_ANIM_PLAY_PARMS animplayParams;
};
union U *pU = SEGPTR_NEW(union U);
res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
if (res) return res;
switch (timef) {
case MCI_FORMAT_MILLISECONDS:
case MCI_FORMAT_FRAMES:
case MCI_FORMAT_BYTES:
case MCI_FORMAT_SAMPLES:
nrargs=1;
parsestr="%d";
break;
case MCI_FORMAT_HMS:
case MCI_FORMAT_MSF:
parsestr="%d:%d:%d";
nrargs=3;
break;
case MCI_FORMAT_TMSF:
parsestr="%d:%d:%d:%d";
nrargs=4;
break;
default:fprintf(stdnimp,"mciSendString:PLAY:unknown timeformat %d, please report.\n",timef);
parsestr="%d";
nrargs=1;
break;
}
pU->playParams.dwCallback=hwndCallback;
i=0;
while (i<nrofkeywords) {
if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
dwFlags |= MCI_TO;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
/* add up all integers we got, if we have more
* shift them. (Well I should use the macros in
* mmsystem.h, right).
*/
pU->playParams.dwTo=0;
for (k=0;k<j;k++)
pU->playParams.dwTo+=a[k]<<(8*(nrargs-k));
i+=2;
continue;
}
if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
dwFlags |= MCI_FROM;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
/* dito. */
pU->playParams.dwFrom=0;
for (k=0;k<j;k++)
pU->playParams.dwFrom+=a[k]<<(8*(nrargs-k));
i+=2;
continue;
}
switch (uDevTyp) {
case MCI_DEVTYPE_VIDEODISC:
FLAG1("slow",MCI_VD_PLAY_SLOW);
FLAG1("fast",MCI_VD_PLAY_FAST);
FLAG1("scan",MCI_VD_PLAY_SCAN);
FLAG1("reverse",MCI_VD_PLAY_REVERSE);
if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
dwFlags |= MCI_VD_PLAY_SPEED;
sscanf(keywords[i+1],"%ld",&(pU->vdplayParams.dwSpeed));
i+=2;
continue;
}
break;
case MCI_DEVTYPE_ANIMATION:
FLAG1("slow",MCI_ANIM_PLAY_SLOW);
FLAG1("fast",MCI_ANIM_PLAY_FAST);
FLAG1("scan",MCI_ANIM_PLAY_SCAN);
FLAG1("reverse",MCI_ANIM_PLAY_REVERSE);
if (!STRCMP(keywords[i],"speed") && (i+1<nrofkeywords)) {
dwFlags |= MCI_ANIM_PLAY_SPEED;
sscanf(keywords[i+1],"%ld",&(pU->animplayParams.dwSpeed));
i+=2;
continue;
}
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_PLAY, SEGPTR_GET(pU) );
SEGPTR_FREE(pU);
return res;
}
/* seek to a specified position
* Arguments:
* "to start" seek to start of medium
* "to end" seek to end of medium
* "to <time>" seek to <time> specified in current timeformat
*/
static DWORD
MCISTR_Seek(_MCISTR_PROTO_) {
int i,res,timef,nrargs,j,k,a[4];
char *parsestr;
MCI_SEEK_PARMS *seekParams = SEGPTR_NEW(MCI_SEEK_PARMS);
res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
if (res) return res;
switch (timef) {
case MCI_FORMAT_MILLISECONDS:
case MCI_FORMAT_FRAMES:
case MCI_FORMAT_BYTES:
case MCI_FORMAT_SAMPLES:
nrargs=1;
parsestr="%d";
break;
case MCI_FORMAT_HMS:
case MCI_FORMAT_MSF:
parsestr="%d:%d:%d";
nrargs=3;
break;
case MCI_FORMAT_TMSF:
parsestr="%d:%d:%d:%d";
nrargs=4;
break;
default:fprintf(stdnimp,"mciSendString:SEEK:unknown timeformat %d, please report.\n",timef);
parsestr="%d";
nrargs=1;
break;
}
seekParams->dwCallback=hwndCallback;
i=0;
while (i<nrofkeywords) {
if ( !STRCMP(keywords[i],"to") && (i+1<nrofkeywords)) {
if (!STRCMP(keywords[i+1],"start")) {
dwFlags|=MCI_SEEK_TO_START;
seekParams->dwTo=0;
i+=2;
continue;
}
if (!STRCMP(keywords[i+1],"end")) {
dwFlags|=MCI_SEEK_TO_END;
seekParams->dwTo=0;
i+=2;
continue;
}
dwFlags|=MCI_TO;
i+=2;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
seekParams->dwTo=0;
for (k=0;k<j;k++)
seekParams->dwTo+=a[k]<<(8*(nrargs-k));
continue;
}
switch (uDevTyp) {
case MCI_DEVTYPE_VIDEODISC:
FLAG1("reverse",MCI_VD_SEEK_REVERSE);
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_SEEK, SEGPTR_GET(seekParams) );
SEGPTR_FREE(seekParams);
return res;
}
/* close media/driver */
static DWORD
MCISTR_Close(_MCISTR_PROTO_)
{
MCI_GENERIC_PARMS *closeParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int res;
_MCI_CALL_DRIVER( MCI_CLOSE, SEGPTR_GET(closeParams) );
SEGPTR_FREE(closeParams);
return res;
}
/* return information.
* Arguments:
* "product" return product name (human readable)
* "file" return filename
* Animation:
* "text" returns text?
* Overlay:
* "text" returns text?
*/
static DWORD
MCISTR_Info(_MCISTR_PROTO_)
{
MCI_INFO_PARMS16 *infoParams = SEGPTR_NEW(MCI_INFO_PARMS16);
DWORD sflags;
int i,res;
sflags = dwFlags;
i=0;while (i<nrofkeywords) {
FLAG1("product",MCI_INFO_PRODUCT);
FLAG1("file",MCI_INFO_FILE);
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
FLAG1("text",MCI_ANIM_INFO_TEXT);
break;
case MCI_DEVTYPE_OVERLAY:
FLAG1("text",MCI_OVLY_INFO_TEXT);
break;
}
i++;
}
if (dwFlags == sflags)
return MCIERR_MISSING_STRING_ARGUMENT;
/* MCI driver will fill in lpstrReturn, dwRetSize.
* FIXME: I don't know if this is correct behaviour
*/
_MCI_CALL_DRIVER( MCI_INFO, SEGPTR_GET(infoParams) );
if (res==0)
_MCI_STR(infoParams->lpstrReturn);
SEGPTR_FREE(infoParams);
return res;
}
DWORD mciSysInfo(DWORD dwFlags,LPMCI_SYSINFO_PARMS16 lpParms);
/* query MCI driver itself for information
* Arguments:
* "installname" return install name of <device> (system.ini)
* "quantity" return nr of installed drivers
* "open" open drivers only (additional flag)
* "name <nr>" return nr of devices with <devicetyp>
* "name all" return nr of all devices
*
* FIXME: mciSysInfo() is broken I think.
*/
static DWORD
MCISTR_Sysinfo(_MCISTR_PROTO_) {
MCI_SYSINFO_PARMS16 sysinfoParams;
int i,res;
sysinfoParams.lpstrReturn = lpstrReturnString;
sysinfoParams.dwRetSize = uReturnLength;
sysinfoParams.wDeviceType = uDevTyp;
i=0;
while (i<nrofkeywords) {
FLAG1("installname",MCI_SYSINFO_INSTALLNAME);
FLAG1("quantity",MCI_SYSINFO_INSTALLNAME);
FLAG1("open",MCI_SYSINFO_OPEN);
if (!strcmp(keywords[i],"name") && (i+1<nrofkeywords)) {
sscanf(keywords[i+1],"%ld",&(sysinfoParams.dwNumber));
dwFlags |= MCI_SYSINFO_NAME;
i+=2;
continue;
}
i++;
}
res=mciSysInfo(dwFlags,&sysinfoParams);
if (dwFlags & MCI_SYSINFO_QUANTITY) {
char buf[100];
sprintf(buf,"%ld",*(long*)PTR_SEG_TO_LIN(lpstrReturnString));
_MCI_STR(buf);
}
/* no need to copy anything back, mciSysInfo did it for us */
return res;
}
/* load file
* Argument: "<filename>"
* Overlay: "at <left> <top> <right> <bottom>" additional
*/
static DWORD
MCISTR_Load(_MCISTR_PROTO_) {
union U {
MCI_LOAD_PARMS16 loadParams;
MCI_OVLY_LOAD_PARMS16 ovlyloadParams;
};
union U *pU = SEGPTR_NEW(union U);
int i,len,res;
char *s;
i=0;len=0;
while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_OVERLAY:
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
dwFlags |= MCI_OVLY_RECT;
sscanf(keywords[i+1],"%hd",&(pU->ovlyloadParams.rc.left));
sscanf(keywords[i+2],"%hd",&(pU->ovlyloadParams.rc.top));
sscanf(keywords[i+3],"%hd",&(pU->ovlyloadParams.rc.right));
sscanf(keywords[i+4],"%hd",&(pU->ovlyloadParams.rc.bottom));
memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
continue;
}
break;
}
len+=strlen(keywords[i])+1;
i++;
}
s=(char*)SEGPTR_ALLOC(len);
*s='\0';
while (i<nrofkeywords) {
strcat(s,keywords[i]);
i++;
if (i<nrofkeywords) strcat(s," ");
}
pU->loadParams.lpfilename=(LPSTR)SEGPTR_GET(s);
dwFlags |= MCI_LOAD_FILE;
_MCI_CALL_DRIVER( MCI_LOAD, SEGPTR_GET(pU) );
SEGPTR_FREE(s);
SEGPTR_FREE(pU);
return res;
}
/* save to file
* Argument: "<filename>"
* Overlay: "at <left> <top> <right> <bottom>" additional
*/
static DWORD
MCISTR_Save(_MCISTR_PROTO_) {
union U {
MCI_SAVE_PARMS saveParams;
MCI_OVLY_SAVE_PARMS16 ovlysaveParams;
};
union U *pU = SEGPTR_NEW(union U);
int i,len,res;
char *s;
i=0;len=0;
while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_OVERLAY:
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
dwFlags |= MCI_OVLY_RECT;
sscanf(keywords[i+1],"%hd",&(pU->ovlysaveParams.rc.left));
sscanf(keywords[i+2],"%hd",&(pU->ovlysaveParams.rc.top));
sscanf(keywords[i+3],"%hd",&(pU->ovlysaveParams.rc.right));
sscanf(keywords[i+4],"%hd",&(pU->ovlysaveParams.rc.bottom));
memcpy(keywords+i,keywords+(i+5),nrofkeywords-(i+5));
continue;
}
break;
}
len+=strlen(keywords[i])+1;
i++;
}
s=(char*)SEGPTR_ALLOC(len);
*s='\0';
while (i<nrofkeywords) {
strcat(s,keywords[i]);
i++;
if (i<nrofkeywords) strcat(s," ");
}
pU->saveParams.lpfilename=(LPSTR)SEGPTR_GET(s);
dwFlags |= MCI_LOAD_FILE;
_MCI_CALL_DRIVER( MCI_SAVE, SEGPTR_GET(pU) );
SEGPTR_FREE(s);
SEGPTR_FREE(pU);
return res;
}
/* prepare device for input/output
* (only applyable to waveform audio)
*/
static DWORD
MCISTR_Cue(_MCISTR_PROTO_) {
MCI_GENERIC_PARMS *cueParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int i,res;
i=0;
while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_WAVEFORM_AUDIO:
FLAG1("input",MCI_WAVE_INPUT);
FLAG1("output",MCI_WAVE_OUTPUT);
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_CUE, SEGPTR_GET(cueParams) );
SEGPTR_FREE(cueParams);
return res;
}
/* delete information */
static DWORD
MCISTR_Delete(_MCISTR_PROTO_) {
int timef,nrargs,i,j,k,a[4],res;
char *parsestr;
MCI_WAVE_DELETE_PARMS *deleteParams = SEGPTR_NEW(MCI_WAVE_DELETE_PARMS);
/* only implemented for waveform audio */
if (uDevTyp != MCI_DEVTYPE_WAVEFORM_AUDIO)
return MCIERR_UNSUPPORTED_FUNCTION; /* well it fits */
res = _MCISTR_determine_timeformat(dev,wDevID,uDevTyp,&timef);
if (res) return res;
switch (timef) {
case MCI_FORMAT_MILLISECONDS:
case MCI_FORMAT_FRAMES:
case MCI_FORMAT_BYTES:
case MCI_FORMAT_SAMPLES:
nrargs=1;
parsestr="%d";
break;
case MCI_FORMAT_HMS:
case MCI_FORMAT_MSF:
parsestr="%d:%d:%d";
nrargs=3;
break;
case MCI_FORMAT_TMSF:
parsestr="%d:%d:%d:%d";
nrargs=4;
break;
default:fprintf(stdnimp,"mciSendString:DELETE:unknown timeformat %d, please report.\n",timef);
parsestr="%d";
nrargs=1;
break;
}
i=0;
while (i<nrofkeywords) {
if (!strcmp(keywords[i],"to") && (i+1<nrofkeywords)) {
dwFlags |= MCI_TO;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
/* add up all integers we got, if we have more
* shift them. (Well I should use the macros in
* mmsystem.h, right).
*/
deleteParams->dwTo=0;
for (k=0;k<j;k++)
deleteParams->dwTo+=a[k]<<(8*(nrargs-k));
i+=2;
continue;
}
if (!strcmp(keywords[i],"from") && (i+1<nrofkeywords)) {
dwFlags |= MCI_FROM;
a[0]=a[1]=a[2]=a[3]=0;
j=sscanf(keywords[i+1],parsestr,&a[0],&a[1],&a[2],&a[3]);
/* dito. */
deleteParams->dwFrom=0;
for (k=0;k<j;k++)
deleteParams->dwFrom+=a[k]<<(8*(nrargs-k));
i+=2;
continue;
}
i++;
}
_MCI_CALL_DRIVER( MCI_DELETE, SEGPTR_GET(deleteParams) );
SEGPTR_FREE(deleteParams);
return res;
}
/* send command to device. only applies to videodisc */
static DWORD
MCISTR_Escape(_MCISTR_PROTO_)
{
MCI_VD_ESCAPE_PARMS16 *escapeParams = SEGPTR_NEW(MCI_VD_ESCAPE_PARMS16);
int i,len,res;
char *s;
if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
return MCIERR_UNSUPPORTED_FUNCTION;
i=0;len=0;
while (i<nrofkeywords) {
len+=strlen(keywords[i])+1;
i++;
}
s=(char*)SEGPTR_ALLOC(len);
*s='\0';
while (i<nrofkeywords) {
strcat(s,keywords[i]);
i++;
if (i<nrofkeywords) strcat(s," ");
}
escapeParams->lpstrCommand = (LPSTR)SEGPTR_GET(s);
dwFlags |= MCI_VD_ESCAPE_STRING;
_MCI_CALL_DRIVER( MCI_ESCAPE, SEGPTR_GET(escapeParams) );
SEGPTR_FREE(s);
SEGPTR_FREE(escapeParams);
return res;
}
/* unfreeze [part of] the overlayed video
* only applyable to Overlay devices
*/
static DWORD
MCISTR_Unfreeze(_MCISTR_PROTO_)
{
MCI_OVLY_RECT_PARMS16 *unfreezeParams = SEGPTR_NEW(MCI_OVLY_RECT_PARMS16);
int i,res;
if (uDevTyp != MCI_DEVTYPE_OVERLAY)
return MCIERR_UNSUPPORTED_FUNCTION;
i=0;while (i<nrofkeywords) {
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
sscanf(keywords[i+1],"%hd",&(unfreezeParams->rc.left));
sscanf(keywords[i+2],"%hd",&(unfreezeParams->rc.top));
sscanf(keywords[i+3],"%hd",&(unfreezeParams->rc.right));
sscanf(keywords[i+4],"%hd",&(unfreezeParams->rc.bottom));
dwFlags |= MCI_OVLY_RECT;
i+=5;
continue;
}
i++;
}
_MCI_CALL_DRIVER( MCI_UNFREEZE, SEGPTR_GET(unfreezeParams) );
SEGPTR_FREE(unfreezeParams);
return res;
}
/* freeze [part of] the overlayed video
* only applyable to Overlay devices
*/
static DWORD
MCISTR_Freeze(_MCISTR_PROTO_)
{
MCI_OVLY_RECT_PARMS16 *freezeParams = SEGPTR_NEW(MCI_OVLY_RECT_PARMS16);
int i,res;
if (uDevTyp != MCI_DEVTYPE_OVERLAY)
return MCIERR_UNSUPPORTED_FUNCTION;
i=0;while (i<nrofkeywords) {
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
sscanf(keywords[i+1],"%hd",&(freezeParams->rc.left));
sscanf(keywords[i+2],"%hd",&(freezeParams->rc.top));
sscanf(keywords[i+3],"%hd",&(freezeParams->rc.right));
sscanf(keywords[i+4],"%hd",&(freezeParams->rc.bottom));
dwFlags |= MCI_OVLY_RECT;
i+=5;
continue;
}
i++;
}
_MCI_CALL_DRIVER( MCI_FREEZE, SEGPTR_GET(freezeParams) );
SEGPTR_FREE(freezeParams);
return res;
}
/* copy parts of image to somewhere else
* "source [at <left> <top> <right> <bottom>]" source is framebuffer [or rect]
* "destination [at <left> <top> <right> <bottom>]" destination is framebuffer [or rect]
* Overlay:
* "frame [at <left> <top> <right> <bottom>]" frame is framebuffer [or rect]
* where the video input is placed
* "video [at <left> <top> <right> <bottom>]" video is whole video [or rect]
* (defining part of input to
* be displayed)
*
* FIXME: This whole junk is passing multiple rectangles.
* I don't know how to do that with the present interface.
* (Means code below is broken)
*/
static DWORD
MCISTR_Put(_MCISTR_PROTO_) {
union U {
MCI_OVLY_RECT_PARMS16 ovlyputParams;
MCI_ANIM_RECT_PARMS16 animputParams;
};
union U *pU = SEGPTR_NEW(union U);
int i,res;
i=0;while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
FLAG1("source",MCI_ANIM_PUT_SOURCE);
FLAG1("destination",MCI_ANIM_PUT_DESTINATION);
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
sscanf(keywords[i+1],"%hd",&(pU->animputParams.rc.left));
sscanf(keywords[i+2],"%hd",&(pU->animputParams.rc.top));
sscanf(keywords[i+3],"%hd",&(pU->animputParams.rc.right));
sscanf(keywords[i+4],"%hd",&(pU->animputParams.rc.bottom));
dwFlags |= MCI_ANIM_RECT;
i+=5;
continue;
}
break;
case MCI_DEVTYPE_OVERLAY:
FLAG1("source",MCI_OVLY_PUT_SOURCE);
FLAG1("destination",MCI_OVLY_PUT_DESTINATION);
FLAG1("video",MCI_OVLY_PUT_VIDEO);
FLAG1("frame",MCI_OVLY_PUT_FRAME);
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
sscanf(keywords[i+1],"%hd",&(pU->ovlyputParams.rc.left));
sscanf(keywords[i+2],"%hd",&(pU->ovlyputParams.rc.top));
sscanf(keywords[i+3],"%hd",&(pU->ovlyputParams.rc.right));
sscanf(keywords[i+4],"%hd",&(pU->ovlyputParams.rc.bottom));
dwFlags |= MCI_OVLY_RECT;
i+=5;
continue;
}
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_PUT, SEGPTR_GET(pU) );
SEGPTR_FREE(pU);
return res;
}
/* palette behaviour changing
* (Animation only)
* "normal" realize the palette normally
* "background" realize the palette as background palette
*/
static DWORD
MCISTR_Realize(_MCISTR_PROTO_)
{
MCI_GENERIC_PARMS *realizeParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int i,res;
if (uDevTyp != MCI_DEVTYPE_ANIMATION)
return MCIERR_UNSUPPORTED_FUNCTION;
i=0;
while (i<nrofkeywords) {
FLAG1("background",MCI_ANIM_REALIZE_BKGD);
FLAG1("normal",MCI_ANIM_REALIZE_NORM);
i++;
}
_MCI_CALL_DRIVER( MCI_REALIZE, SEGPTR_GET(realizeParams) );
SEGPTR_FREE(realizeParams);
return res;
}
/* videodisc spinning
* "up"
* "down"
*/
static DWORD
MCISTR_Spin(_MCISTR_PROTO_)
{
MCI_GENERIC_PARMS *spinParams = SEGPTR_NEW(MCI_GENERIC_PARMS);
int i,res;
if (uDevTyp != MCI_DEVTYPE_VIDEODISC)
return MCIERR_UNSUPPORTED_FUNCTION;
i=0;
while (i<nrofkeywords) {
FLAG1("up",MCI_VD_SPIN_UP);
FLAG1("down",MCI_VD_SPIN_UP);
i++;
}
_MCI_CALL_DRIVER( MCI_SPIN, SEGPTR_GET(spinParams) );
SEGPTR_FREE(spinParams);
return res;
}
/* step single frames
* "reverse" optional flag
* "by <nr>" for <nr> frames
*/
static DWORD
MCISTR_Step(_MCISTR_PROTO_) {
union U {
MCI_ANIM_STEP_PARMS animstepParams;
MCI_VD_STEP_PARMS vdstepParams;
};
union U *pU = SEGPTR_NEW(union U);
int i,res;
i=0;
while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
FLAG1("reverse",MCI_ANIM_STEP_REVERSE);
if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
sscanf(keywords[i+1],"%ld",&(pU->animstepParams.dwFrames));
dwFlags |= MCI_ANIM_STEP_FRAMES;
i+=2;
continue;
}
break;
case MCI_DEVTYPE_VIDEODISC:
FLAG1("reverse",MCI_VD_STEP_REVERSE);
if (!STRCMP(keywords[i],"by") && (i+1<nrofkeywords)) {
sscanf(keywords[i+1],"%ld",&(pU->vdstepParams.dwFrames));
dwFlags |= MCI_VD_STEP_FRAMES;
i+=2;
continue;
}
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_STEP, SEGPTR_GET(pU) );
SEGPTR_FREE(pU);
return res;
}
/* update animation window
* Arguments:
* "at <left> <top> <right> <bottom>" only in this rectangle
* "hdc" device context
*/
static DWORD
MCISTR_Update(_MCISTR_PROTO_) {
int i,res;
MCI_ANIM_UPDATE_PARMS16 *updateParams = SEGPTR_NEW(MCI_ANIM_UPDATE_PARMS16);
i=0;
while (i<nrofkeywords) {
if (!STRCMP(keywords[i],"at") && (i+4<nrofkeywords)) {
sscanf(keywords[i+1],"%hd",&(updateParams->rc.left));
sscanf(keywords[i+2],"%hd",&(updateParams->rc.top));
sscanf(keywords[i+3],"%hd",&(updateParams->rc.right));
sscanf(keywords[i+4],"%hd",&(updateParams->rc.bottom));
dwFlags |= MCI_ANIM_RECT;
i+=5;
continue;
}
if (!STRCMP(keywords[i],"hdc") && (i+1<nrofkeywords)) {
dwFlags |= MCI_ANIM_UPDATE_HDC;
sscanf(keywords[i+1],"%hd",&(updateParams->hDC));
i+=2;
continue;
}
i++;
}
_MCI_CALL_DRIVER( MCI_UPDATE, SEGPTR_GET(updateParams) );
SEGPTR_FREE(updateParams);
return res;
}
/* where command for animation and overlay drivers.
* just returns the specified rectangle as a string
* Arguments:
* "source"
* "destination"
* Overlay special:
* "video"
* "frame"
*/
static DWORD
MCISTR_Where(_MCISTR_PROTO_) {
union U {
MCI_ANIM_RECT_PARMS16 animwhereParams;
MCI_OVLY_RECT_PARMS16 ovlywhereParams;
};
union U *pU = SEGPTR_NEW(union U);
int i,res;
i=0;
while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
FLAG1("source",MCI_ANIM_WHERE_SOURCE);
FLAG1("destination",MCI_ANIM_WHERE_DESTINATION);
break;
case MCI_DEVTYPE_OVERLAY:
FLAG1("source",MCI_OVLY_WHERE_SOURCE);
FLAG1("destination",MCI_OVLY_WHERE_DESTINATION);
FLAG1("video",MCI_OVLY_WHERE_VIDEO);
FLAG1("frame",MCI_OVLY_WHERE_FRAME);
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_WHERE, SEGPTR_GET(pU) );
if (res==0) {
char buf[100];
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
sprintf(buf,"%d %d %d %d",
pU->animwhereParams.rc.left,
pU->animwhereParams.rc.top,
pU->animwhereParams.rc.right,
pU->animwhereParams.rc.bottom
);
break;
case MCI_DEVTYPE_OVERLAY:
sprintf(buf,"%d %d %d %d",
pU->ovlywhereParams.rc.left,
pU->ovlywhereParams.rc.top,
pU->ovlywhereParams.rc.right,
pU->ovlywhereParams.rc.bottom
);
break;
default:strcpy(buf,"0 0 0 0");break;
}
_MCI_STR(buf);
}
SEGPTR_FREE(pU);
return res;
}
static DWORD
MCISTR_Window(_MCISTR_PROTO_) {
int i,res;
char *s;
union U {
MCI_ANIM_WINDOW_PARMS16 animwindowParams;
MCI_OVLY_WINDOW_PARMS16 ovlywindowParams;
};
union U *pU = SEGPTR_NEW(union U);
s=NULL;
i=0;
while (i<nrofkeywords) {
switch (uDevTyp) {
case MCI_DEVTYPE_ANIMATION:
if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
dwFlags |= MCI_ANIM_WINDOW_HWND;
if (!STRCMP(keywords[i+1],"default"))
pU->animwindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
else
sscanf(keywords[i+1],"%hd",&(pU->animwindowParams.hWnd));
i+=2;
continue;
}
if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
dwFlags |= MCI_ANIM_WINDOW_STATE;
if (!STRCMP(keywords[i+1],"hide"))
pU->animwindowParams.nCmdShow = SW_HIDE;
if (!STRCMP(keywords[i+1],"iconic"))
pU->animwindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
if (!STRCMP(keywords[i+1],"minimized"))
pU->animwindowParams.nCmdShow = SW_SHOWMINIMIZED;
if (!STRCMP(keywords[i+1],"maximized"))
pU->animwindowParams.nCmdShow = SW_SHOWMAXIMIZED;
if (!STRCMP(keywords[i+1],"minimize"))
pU->animwindowParams.nCmdShow = SW_MINIMIZE;
if (!STRCMP(keywords[i+1],"normal"))
pU->animwindowParams.nCmdShow = SW_NORMAL;
if (!STRCMP(keywords[i+1],"show"))
pU->animwindowParams.nCmdShow = SW_SHOW;
if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
if (!STRCMP(keywords[i+2],"active"))
pU->animwindowParams.nCmdShow = SW_SHOWNOACTIVATE;
if (!STRCMP(keywords[i+2],"action"))
pU->animwindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
i++;
}
i+=2;
continue;
}
/* text is enclosed in " ... " as it seems */
if (!STRCMP(keywords[i],"text")) {
char *t;
int len,j,k;
if (keywords[i+1][0]!='"') {
i++;
continue;
}
dwFlags |= MCI_ANIM_WINDOW_TEXT;
len = strlen(keywords[i+1])+1;
j = i+2;
while (j<nrofkeywords) {
len += strlen(keywords[j])+1;
if (strchr(keywords[j],'"'))
break;
j++;
}
s=(char*)xmalloc(len);
strcpy(s,keywords[i+1]+1);
k=j;j=i+2;
while (j<=k) {
strcat(s," ");
strcat(s,keywords[j]);
}
if ((t=strchr(s,'"'))) *t='\0';
/* FIXME: segmented pointer? */
pU->animwindowParams.lpstrText = s;
i=k+1;
continue;
}
FLAG1("stretch",MCI_ANIM_WINDOW_ENABLE_STRETCH);
break;
case MCI_DEVTYPE_OVERLAY:
if (!STRCMP(keywords[i],"handle") && (i+1<nrofkeywords)) {
dwFlags |= MCI_OVLY_WINDOW_HWND;
if (!STRCMP(keywords[i+1],"default"))
pU->ovlywindowParams.hWnd = MCI_OVLY_WINDOW_DEFAULT;
else
sscanf(keywords[i+1],"%hd",&(pU->ovlywindowParams.hWnd));
i+=2;
continue;
}
if (!STRCMP(keywords[i],"state") && (i+1<nrofkeywords)) {
dwFlags |= MCI_OVLY_WINDOW_STATE;
if (!STRCMP(keywords[i+1],"hide"))
pU->ovlywindowParams.nCmdShow = SW_HIDE;
if (!STRCMP(keywords[i+1],"iconic"))
pU->ovlywindowParams.nCmdShow = SW_SHOWMINNOACTIVE; /* correct? */
if (!STRCMP(keywords[i+1],"minimized"))
pU->ovlywindowParams.nCmdShow = SW_SHOWMINIMIZED;
if (!STRCMP(keywords[i+1],"maximized"))
pU->ovlywindowParams.nCmdShow = SW_SHOWMAXIMIZED;
if (!STRCMP(keywords[i+1],"minimize"))
pU->ovlywindowParams.nCmdShow = SW_MINIMIZE;
if (!STRCMP(keywords[i+1],"normal"))
pU->ovlywindowParams.nCmdShow = SW_NORMAL;
if (!STRCMP(keywords[i+1],"show"))
pU->ovlywindowParams.nCmdShow = SW_SHOW;
if (!STRCMP(keywords[i+1],"no") && (i+2<nrofkeywords)) {
if (!STRCMP(keywords[i+2],"active"))
pU->ovlywindowParams.nCmdShow = SW_SHOWNOACTIVATE;
if (!STRCMP(keywords[i+2],"action"))
pU->ovlywindowParams.nCmdShow = SW_SHOWNA;/* correct?*/
i++;
}
i+=2;
continue;
}
/* text is enclosed in " ... " as it seems */
if (!STRCMP(keywords[i],"text")) {
char *t;
int len,j,k;
if (keywords[i+1][0]!='"') {
i++;
continue;
}
dwFlags |= MCI_OVLY_WINDOW_TEXT;
len = strlen(keywords[i+1])+1;
j = i+2;
while (j<nrofkeywords) {
len += strlen(keywords[j])+1;
if (strchr(keywords[j],'"'))
break;
j++;
}
s=(char*)xmalloc(len);
strcpy(s,keywords[i+1]+1);
k=j;j=i+2;
while (j<=k) {
strcat(s," ");
strcat(s,keywords[j]);
}
if ((t=strchr(s,'"'))) *t='\0';
/* FIXME: segmented pointer? */
pU->ovlywindowParams.lpstrText = s;
i=k+1;
continue;
}
FLAG1("stretch",MCI_OVLY_WINDOW_ENABLE_STRETCH);
break;
}
i++;
}
_MCI_CALL_DRIVER( MCI_WINDOW, SEGPTR_GET(pU) );
if (s) free(s);
SEGPTR_FREE(pU);
return res;
}
struct _MCISTR_cmdtable {
char *cmd;
DWORD (*fun)(_MCISTR_PROTO_);
} MCISTR_cmdtable[]={
{"break", MCISTR_Break},
{"capability", MCISTR_Capability},
{"close", MCISTR_Close},
{"cue", MCISTR_Cue},
{"delete", MCISTR_Delete},
{"escape", MCISTR_Escape},
{"freeze", MCISTR_Freeze},
{"info", MCISTR_Info},
{"load", MCISTR_Load},
{"open", MCISTR_Open},
{"pause", MCISTR_Pause},
{"play", MCISTR_Play},
{"put", MCISTR_Put},
{"realize", MCISTR_Realize},
{"record", MCISTR_Record},
{"resume", MCISTR_Resume},
{"save", MCISTR_Save},
{"seek", MCISTR_Seek},
{"set", MCISTR_Set},
{"spin", MCISTR_Spin},
{"status", MCISTR_Status},
{"step", MCISTR_Step},
{"stop", MCISTR_Stop},
{"sysinfo", MCISTR_Sysinfo},
{"unfreeze", MCISTR_Unfreeze},
{"update", MCISTR_Update},
{"where", MCISTR_Where},
{"window", MCISTR_Window},
{NULL, NULL}
};
/**************************************************************************
* mciSendString [MMSYSTEM.702]
*/
/* The usercode sends a string with a command (and flags) expressed in
* words in it... We do our best to call aprobiate drivers,
* and return a errorcode AND a readable string (if lpstrRS!=NULL)
* Info gathered by watching cool134.exe and from Borland's mcistrwh.hlp
*/
/* FIXME: "all" is a valid devicetype and we should access all devices if
* it is used. (imagine "close all"). Not implemented yet.
*/
DWORD WINAPI mciSendString (LPCSTR lpstrCommand, LPSTR lpstrReturnString,
UINT16 uReturnLength, HWND16 hwndCallback)
{
char *cmd,*dev,*args,**keywords,*filename;
WORD uDevTyp=0,wDevID=0;
DWORD dwFlags;
int res=0,i,nrofkeywords;
TRACE(mci,"('%s', %p, %d, %X)\n", lpstrCommand,
lpstrReturnString, uReturnLength, hwndCallback
);
/* format is <command> <device> <optargs> */
cmd=strdup(lpstrCommand);
dev=strchr(cmd,' ');
if (dev==NULL) {
free(cmd);
return MCIERR_MISSING_DEVICE_NAME;
}
*dev++='\0';
args=strchr(dev,' ');
if (args!=NULL) *args++='\0';
CharUpper32A(dev);
if (args!=NULL) {
char *s;
i=1;/* nrofkeywords = nrofspaces+1 */
s=args;
while ((s=strchr(s,' '))!=NULL) i++,s++;
keywords=(char**)xmalloc(sizeof(char*)*(i+2));
nrofkeywords=i;
s=args;i=0;
while (s && i<nrofkeywords) {
keywords[i++]=s;
s=strchr(s,' ');
if (s) *s++='\0';
}
keywords[i]=NULL;
} else {
nrofkeywords=0;
keywords=(char**)xmalloc(sizeof(char*));
}
dwFlags = 0; /* default flags */
for (i=0;i<nrofkeywords;) {
/* take care, there is also a "device type" capability */
if ((!STRCMP(keywords[i],"type")) && (i<nrofkeywords-1)) {
filename = dev;
dev = keywords[i+1];
memcpy(keywords+i,keywords+(i+2),(nrofkeywords-i-2)*sizeof(char *));
nrofkeywords -= 2;
continue;
}
if (!STRCMP(keywords[i],"wait")) {
dwFlags |= MCI_WAIT;
memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
nrofkeywords--;
continue;
}
if (!STRCMP(keywords[i],"notify")) {
dwFlags |= MCI_NOTIFY;
memcpy(keywords+i,keywords+(i+1),(nrofkeywords-i-1)*sizeof(char *));
nrofkeywords--;
continue;
}
i++;
}
/* determine wDevID and uDevTyp for all commands except "open" */
if (STRCMP(cmd,"open")!=0) {
wDevID = MMSYSTEM_FirstDevID();
while (1) {
SEGPTR dname;
dname=(SEGPTR)GetOpenDrv(wDevID)->lpstrAlias;
if (dname==NULL)
dname=(SEGPTR)GetOpenDrv(wDevID)->lpstrDeviceType;
if ((dname!=NULL)&&(!STRCMP(PTR_SEG_TO_LIN(dname),dev)))
break;
wDevID = MMSYSTEM_NextDevID(wDevID);
if (!MMSYSTEM_DevIDValid(wDevID)) {
TRACE(mci, "MAXMCIDRIVERS reached!\n");
free(keywords);free(cmd);
return MCIERR_INVALID_DEVICE_NAME;
}
}
uDevTyp=GetDrv(wDevID)->modp.wType;
}
for (i=0;MCISTR_cmdtable[i].cmd!=NULL;i++) {
if (!STRCMP(MCISTR_cmdtable[i].cmd,cmd)) {
res=MCISTR_cmdtable[i].fun(
wDevID,uDevTyp,lpstrReturnString,
uReturnLength,dev,(LPSTR*)keywords,nrofkeywords,
dwFlags,hwndCallback
);
break;
}
}
if (MCISTR_cmdtable[i].cmd!=NULL) {
free(keywords);free(cmd);
return res;
}
fprintf(stdnimp,"mciSendString('%s', %p, %u, %X) // unimplemented, please report.\n", lpstrCommand,
lpstrReturnString, uReturnLength, hwndCallback
);
free(keywords);free(cmd);
return MCIERR_MISSING_COMMAND_STRING;
}