Sweden-Number/multimedia/mcistring.c

2214 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 "stddebug.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 {\
dprintf_mci(stddeb,"->returns \"%s\"",s);\
if (lpstrReturnString) {\
lstrcpyn32A(lpstrReturnString,s,uReturnLength);\
dprintf_mci(stddeb,"-->\"%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:\
dprintf_mci(stddeb,"_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)) {
dprintf_mci(stddeb, __FILE__":MCISTR_Open: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;
dprintf_mci(stddeb,"mciSendString('%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)) {
dprintf_mci(stddeb, __FILE__":mciSendString: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;
}