/* * 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 can play * which is allowed by the MCI standard. */ #include #include #include #include #include #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: FIXME(mci, "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:FIXME(mci,"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: FIXME(mci,"missing timefmt 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:FIXME(mci,"unknown device type %ld, report.\n", dwReturn);break; } break; default: FIXME(mci,"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 * Optional: * "shareable" * "alias " * "element " * Additional: * waveform audio: * "buffer " * Animation: * "nostatic" increaste nr of nonstatic colours * "parent " * "style " bitmask of WS_xxxxx (see windows.h) * "style child" WS_CHILD * "style overlap" WS_OVERLAPPED * "style popup" WS_POPUP * Overlay: * "parent " * "style " 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 (iopenParams.lpstrAlias=(LPSTR)SEGPTR_GET(SEGPTR_STRDUP(keywords[i+1])); i+=2; continue; } if (!STRCMP(keywords[i],"element") && (i+1openParams.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+1animopenParams.hWndParent)); i+=2; continue; } if (!STRCMP(keywords[i],"style") && (i+1animopenParams.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 FIXME(mci,"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+1waveopenParams.dwBufferSeconds)); } break; case MCI_DEVTYPE_OVERLAY: /* looks just like anim, but without NOSTATIC */ if (!STRCMP(keywords[i],"parent") && (i+1ovlyopenParams.hWndParent)); i+=2; continue; } if (!STRCMP(keywords[i],"style") && (i+1ovlyopenParams.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 FIXME(mci,"unknown 'style' keyword %s, please report.\n",keywords[i+1]); i+=2; continue; } break; } FIXME(mci,"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 ]" - returns length [of track ] in current * timeformat * "number of tracks" - returns number of tracks as integer * "position [track ]" - returns position [in track ] 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+1dwItem = item;\ type = xtype;\ i+=2;\ continue;\ } #define ITEM3(str1,str2,str3,item,xtype) \ if ( !STRCMP(keywords[i],str1) &&\ (i+2dwItem = 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 (idwTrack)); 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; } FIXME(mci,"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 " "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 " sets integer formattag value * "any input" accept input from any known source * "any output" output to any known destination * "input " input from source * "output " output to destination * "channels " sets nr of channels * "bytespersec " sets average bytes per second * "samplespersec " sets average samples per second (1 sample can * be 2 bytes!) * "alignment " sets the blockalignment to * "bitspersample " 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 " midioutput to specified port * "tempo " tempo of track (depends on timeformat/divtype) * "offset " 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 (isetParams.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+3setParams.dwTimeFormat = MCI_SEQ_FORMAT_SONGPTR; if (!STRCMP(keywords[i+2],"smpte") && (i+3setParams.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+4setParams.dwTimeFormat = MCI_FORMAT_SMPTE_30DROP; i++; } i++; /*FALLTHROUGH*/ } i+=3; continue; } if (!STRCMP(keywords[i],"audio") && (i+1setParams.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+1wavesetParams.wFormatTag = WAVE_FORMAT_PCM; i+=2; continue; } /* */ #define WII(str,flag,fmt,element) \ if (!STRCMP(keywords[i],str) && (i+1wavesetParams. 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+1seqsetParams.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+1seqsetParams.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+1seqsetParams.dwPort=-1;/* FIXME:not sure*/ dwFlags |= MCI_SEQ_SET_PORT; i+=2; continue; } #define SII(str,flag,element) \ if (!STRCMP(keywords[i],str) && (i+1seqsetParams. 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 " enable break on key with keyid * (I strongly suspect, that there is another parameter: * "window " * 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+1dwItem = item;\ type = xtype;\ i+=2;\ continue;\ } #define ITEM3(str1,str2,str3,item,xtype) \ if ( !STRCMP(keywords[i],str1) &&\ (i+2dwItem = 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 (idwReturn, 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