/* -*- tab-width: 8; c-basic-offset: 4 -*- */ /* * MCI stringinterface * * Copyright 1995 Marcus Meissner */ /* FIXME: * + special commands of device drivers should be handled by those drivers * + this current implementation does not allow commands like * "capability can play" which is allowed by the MCI standard. * + return value and their conversion to strings (including error codes) * is not coherent with MCI standard. * + digital video interface has not been throughoutfully tested */ #include #include #include #include #include #include #include "multimedia.h" #include "digitalv.h" #include "heap.h" #include "ldt.h" #include "user.h" #include "driver.h" #include "callback.h" #include "debug.h" #include "xmalloc.h" DEFAULT_DEBUG_CHANNEL(mci) /* The reason why I just don't lowercase the keywords array in * mciSendString is left as an exercise to the reader. * (EP: For the blinds, like me, it's linked to file name handling * which is case sensitive). */ #define STRCMP(x, y) lstrcmpiA(x, y) /* standard function parameters 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) { \ lstrcpynA(lpstrReturnString, s, uReturnLength); \ TRACE(mci, "--> '%s'\n", lpstrReturnString); \ } \ } while(0) static LPSTR _MCISTR_Unquote(LPSTR str) { if (str) { int i, len = strlen(str); if (len > 1 && str[0] == '"' && str[len-1] == '"') { for (i = 1; i < len-1; i++) { str[i - 1] = str[i]; } str[len-2] = 0; } } return str; } /* 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 < 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: * 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_PARMSA openParams; MCI_WAVE_OPEN_PARMSA waveopenParams; MCI_ANIM_OPEN_PARMSA animopenParams; MCI_OVLY_OPEN_PARMSA ovlyopenParams; MCI_DGV_OPEN_PARMSA dgvopenParams; }; union U* pU = xmalloc(sizeof(union U)); pU->openParams.lpstrElementName = NULL; s = strchr(dev, '!'); if (s != NULL) { *s++ = '\0'; pU->openParams.lpstrElementName = strdup(s); dwFlags |= MCI_OPEN_ELEMENT; } for (i = 0; i < nrofkeywords; ) { if ((!STRCMP(keywords[i], "type")) && (i < nrofkeywords-1)) { pU->openParams.lpstrElementName = strdup(dev); dwFlags |= MCI_OPEN_ELEMENT; dev = keywords[i+1]; /* FIXME: isn't there a memory leak here ? keyword+i ? */ memcpy(keywords+i, keywords+(i+2), (nrofkeywords-i-2) * sizeof(char*)); nrofkeywords -= 2; i += 2; continue; } i++; } CharUpperA((char*)dev); uDevTyp = MCI_GetDevTypeFromString(dev); if (uDevTyp == 0) { free(pU->openParams.lpstrElementName); free(pU); return MCIERR_INVALID_DEVICE_NAME; } pU->openParams.dwCallback = hwndCallback; pU->openParams.wDeviceID = wDevID; pU->ovlyopenParams.dwStyle = 0; pU->animopenParams.dwStyle = 0; pU->openParams.lpstrDeviceType = strdup(dev); pU->openParams.lpstrAlias = NULL; dwFlags |= MCI_OPEN_TYPE; for (i = 0; i < nrofkeywords; ) { FLAG1("shareable", MCI_OPEN_SHAREABLE); if (!STRCMP(keywords[i], "alias") && (i+1 < nrofkeywords)) { dwFlags |= MCI_OPEN_ALIAS; pU->openParams.lpstrAlias = strdup(keywords[i+1]); i += 2; continue; } if (!STRCMP(keywords[i], "element") && (i+1 < nrofkeywords)) { dwFlags |= MCI_OPEN_ELEMENT; assert(pU->openParams.lpstrElementName == NULL); pU->openParams.lpstrElementName = strdup(keywords[i+1]); i += 2; continue; } switch (uDevTyp) { case MCI_DEVTYPE_ANIMATION: FLAG1("nostatic", MCI_ANIM_OPEN_NOSTATIC); if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) { dwFlags |= MCI_ANIM_OPEN_PARENT; sscanf(keywords[i+1], "%u", &(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 FIXME(mci, "unknown 'style' keyword %s, please report.\n", keywords[i+1]); i += 2; continue; } break; case MCI_DEVTYPE_DIGITAL_VIDEO: FLAG1("nostatic", MCI_ANIM_OPEN_NOSTATIC); if (!STRCMP(keywords[i], "parent") && (i+1 < nrofkeywords)) { dwFlags |= MCI_DGV_OPEN_PARENT; sscanf(keywords[i+1], "%u", &(pU->dgvopenParams.hWndParent)); i += 2; continue; } if (!STRCMP(keywords[i], "style") && (i+1 < nrofkeywords)) { DWORD st; dwFlags |= MCI_DGV_OPEN_WS; if (!STRCMP(keywords[i+1], "popup")) { pU->dgvopenParams.dwStyle |= WS_POPUP; } else if (!STRCMP(keywords[i+1], "overlap")) { pU->dgvopenParams.dwStyle |= WS_OVERLAPPED; } else if (!STRCMP(keywords[i+1], "child")) { pU->dgvopenParams.dwStyle |= WS_CHILD; } else if (sscanf(keywords[i+1], "%ld", &st)) { pU->dgvopenParams.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+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], "%u", &(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 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++; } _MCISTR_Unquote(pU->openParams.lpstrElementName); res = mciSendCommandA(0, MCI_OPEN, dwFlags, (DWORD)pU); free(pU->openParams.lpstrElementName); free(pU->openParams.lpstrDeviceType); free(pU->openParams.lpstrAlias); free(pU); return res; } /* A helper 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; LPMCI_STATUS_PARMS statusParams = xmalloc(sizeof(MCI_STATUS_PARMS)); if (!statusParams) return 0; statusParams->dwItem = MCI_STATUS_TIME_FORMAT; statusParams->dwReturn = 0; res = mciSendCommandA(wDevID, MCI_STATUS, dwFlags, (DWORD)statusParams); if (res == 0) *timef = statusParams->dwReturn; 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? * Digitalvideo: * "audio" * "audio alignment" * "audio bitspersample" * "audio breaks" * "audio bytespersec" * "audio input" * "audio record" * "audio source" * "audio samplespersec" * "audio stream" * "bass" * "bitsperpel" * "brightness" * "color" * "contrast" * "disk space drive" * "file completion" * "file format " * "file mode" * "forward" * "frames skipped" * "gamma" * "input" * "left volume" * "media present" * "mode" * "monitor" * "monitor method" * "nominal" * "nominal frame rate" * "nominal record frame rate" * "output" * "palette handle" * "pause mode" * "play speed" * "record frame rate" * "reference frame" * "reserved size" * "right volume" * "seek exactly" * "sharpness" * "smpte" * "speed" * "still file format" * "tint" * "treble" * "unsaved" * "video" * "video key index" * "video key color" * "video record" * "video source" * "video source number" * "video stream" * "volume" * "window handle" * "window visible" * "window minimized" * "window maximized" */ #define ITEM1(str, item, xtype) \ if (!STRCMP(keywords[i], str)) { \ pU->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)) { \ pU->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)) { \ pU->statusParams.dwItem = item; \ type = xtype; \ i += 3; \ continue; \ } #define ITEM4(str1, str2, str3, str4, item, xtype) \ if ( !STRCMP(keywords[i], str1) && \ (i+3 < nrofkeywords) && \ !STRCMP(keywords[i+1], str2) && \ !STRCMP(keywords[i+2], str3) && \ !STRCMP(keywords[i+3], str4)) { \ pU->statusParams.dwItem = item; \ type = xtype; \ i += 4; \ continue; \ } static DWORD MCISTR_Status(_MCISTR_PROTO_) { union U { MCI_STATUS_PARMS statusParams; MCI_DGV_STATUS_PARMSA dgvstatusParams; }; union U* pU = xmalloc(sizeof(union U)); int type = 0, i, res, timef; pU->statusParams.dwCallback = hwndCallback; dwFlags |= MCI_STATUS_ITEM; res = _MCISTR_determine_timeformat(dev, wDevID, uDevTyp, &timef); if (res) return res; pU->statusParams.dwReturn = 0; pU->statusParams.dwItem = 0; for (i = 0; i < nrofkeywords; ) { if (!STRCMP(keywords[i], "track") && (i+1 < nrofkeywords)) { sscanf(keywords[i+1], "%ld", &(pU->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: 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; case MCI_DEVTYPE_DIGITAL_VIDEO: ITEM1("audio", MCI_DGV_STATUS_AUDIO, _MCISTR_bool); /* FIXME? doc says MCI_ON/MCI_OFF */ ITEM2("audio", "alignment", MCI_DGV_STATUS_BLOCKALIGN, _MCISTR_int); ITEM2("audio", "bitspersample", MCI_DGV_STATUS_BITSPERSAMPLE, _MCISTR_int); /* EPP ITEM2("audio", "breaks", MCI_AVI_STATUS_AUDIO_BREAKS, _MCISTR_int); */ ITEM2("audio", "bytespersec", MCI_DGV_STATUS_AVGBYTESPERSEC, _MCISTR_int); ITEM2("audio", "input", MCI_DGV_STATUS_AUDIO_INPUT, _MCISTR_int); ITEM2("audio", "record", MCI_DGV_STATUS_AUDIO_RECORD, _MCISTR_bool); /* FIXME? doc says MCI_ON/MCI_OFF */ ITEM3("audio", "source", "number", MCI_DGV_STATUS_AUDIO_SOURCE, _MCISTR_int); /* FIXME: ITEM2("audio", "source", MCI_DGV_STATUS_AUDIO_SOURCE, _MCISTR_dgvaudiosource); */ /* EPP ITEM2("audio", "samplespersec", MCI_DGV_STATUS_SAMPLESPERSECOND, _MCISTR_int); */ ITEM2("audio", "stream", MCI_DGV_STATUS_AUDIO_STREAM, _MCISTR_int); ITEM1("bass", MCI_DGV_STATUS_BASS, _MCISTR_int); ITEM1("bitsperpel", MCI_DGV_STATUS_BITSPERPEL, _MCISTR_int); ITEM1("brightness", MCI_DGV_STATUS_BRIGHTNESS, _MCISTR_int); ITEM1("color", MCI_DGV_STATUS_COLOR, _MCISTR_int); ITEM1("contrast", MCI_DGV_STATUS_CONTRAST, _MCISTR_int); /* EPP * "disk space drive" FIXME */ ITEM2("file", "completion", MCI_DGV_STATUS_FILE_COMPLETION, _MCISTR_int); /* EPP ITEM2("file", "format", MCI_DGV_STATUS_FILEFORMAT, _MCISTR_???); */ /* EPP ITEM2("file", "mode", MCI_DGV_STATUS_FILE_MODE, _MCISTR_gdvfileformat); */ ITEM1("forward", MCI_DGV_STATUS_FORWARD, _MCISTR_bool); /* EPP ITEM2("frames", "skipped", MCI_AVI_STATUS_FRAMES_SKIPPED, _MCISTR_int); */ ITEM1("gamma", MCI_DGV_STATUS_GAMMA, _MCISTR_int); ITEM2("input", "bass", MCI_DGV_STATUS_BASS|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "brightness", MCI_DGV_STATUS_BRIGHTNESS|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "color", MCI_DGV_STATUS_COLOR|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "contrast", MCI_DGV_STATUS_CONTRAST|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "gamma", MCI_DGV_STATUS_GAMMA|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "sharpness", MCI_DGV_STATUS_SHARPNESS|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "tint", MCI_DGV_STATUS_TINT|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("input", "treble", MCI_DGV_STATUS_TREBLE|MCI_DGV_STATUS_INPUT, _MCISTR_int); ITEM2("left", "volume", MCI_DGV_STATUS_VOLUME|MCI_DGV_STATUS_LEFT, _MCISTR_int); ITEM2("media", "present", MCI_STATUS_MEDIA_PRESENT, _MCISTR_bool); /* EPP ITEM2("monitor", "method", MCI_DGV_STATUS_MONITOR_METHOD, _MCISTR_monitor); */ /* EPP ITEM1("monitor", MCI_DGV_STATUS_MONITOR, _MCISTR_monitor2); */ ITEM2("nominal", "bass", MCI_DGV_STATUS_BASS|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "brightness", MCI_DGV_STATUS_BRIGHTNESS|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "color", MCI_DGV_STATUS_COLOR|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "contrast", MCI_DGV_STATUS_CONTRAST|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "gamma", MCI_DGV_STATUS_GAMMA|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "sharpness", MCI_DGV_STATUS_SHARPNESS|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "tint", MCI_DGV_STATUS_TINT|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("nominal", "treble", MCI_DGV_STATUS_TREBLE|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM3("nominal", "frame", "rate", MCI_DGV_STATUS_FRAME_RATE|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM4("nominal", "record", "frame", "rate", MCI_DGV_STATUS_FRAME_RATE|MCI_DGV_STATUS_RECORD|MCI_DGV_STATUS_NOMINAL, _MCISTR_int); ITEM2("output", "bass", MCI_DGV_STATUS_BASS|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "brightness", MCI_DGV_STATUS_BRIGHTNESS|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "color", MCI_DGV_STATUS_COLOR|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "contrast", MCI_DGV_STATUS_CONTRAST|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "gamma", MCI_DGV_STATUS_GAMMA|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "sharpness", MCI_DGV_STATUS_SHARPNESS|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "tint", MCI_DGV_STATUS_TINT|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("output", "treble", MCI_DGV_STATUS_TREBLE|MCI_DGV_STATUS_OUTPUT, _MCISTR_int); ITEM2("palette", "handle", MCI_DGV_STATUS_HPAL, _MCISTR_int); /* FIXME? */ ITEM2("pause", "mode", MCI_DGV_STATUS_PAUSE_MODE, _MCISTR_bool); /* FIXME */ /* EPP ITEM2("play", "speed", MCI_AVI_STATUS_LAST_PLAY_SPEED, _MCISTR_int); */ ITEM3("record", "frame", "rate", MCI_DGV_STATUS_FRAME_RATE|MCI_DGV_STATUS_RECORD, _MCISTR_int); ITEM2("reference", "frame", MCI_DGV_STATUS_FRAME_RATE, _MCISTR_int); /* FIXME */ ITEM2("reserved", "size", MCI_DGV_STATUS_SIZE, _MCISTR_int); ITEM2("right", "volume", MCI_DGV_STATUS_VOLUME|MCI_DGV_STATUS_RIGHT, _MCISTR_int); ITEM2("seek", "exactly", MCI_DGV_STATUS_SEEK_EXACTLY, _MCISTR_bool); ITEM1("sharpness", MCI_DGV_STATUS_SHARPNESS, _MCISTR_int); /* EPP ITEM1("smpte", MCI_DGV_STATUS_SMPTE, _MCISTR_smpte); */ /* EPP ITEM1("speed", MCI_DGV_STATUS_SPEED, _MCISTR_speed); */ /* EPP ITEM3("still", "file", "format", MCI_DGV_STATUS_STILL_FILEFORMAT, _MCISTR_???); */ ITEM1("tint", MCI_DGV_STATUS_TINT, _MCISTR_int); ITEM1("treble", MCI_DGV_STATUS_TREBLE, _MCISTR_int); ITEM1("unsaved", MCI_DGV_STATUS_UNSAVED, _MCISTR_bool); ITEM3("video", "key", "index", MCI_DGV_STATUS_KEY_INDEX, _MCISTR_int); ITEM3("video", "key", "color", MCI_DGV_STATUS_KEY_COLOR, _MCISTR_bool); ITEM2("video", "record", MCI_DGV_STATUS_VIDEO_RECORD, _MCISTR_bool); /* FIXME MCI_ON/OFF */ ITEM3("video", "source", "number", MCI_DGV_STATUS_VIDEO_SOURCE, _MCISTR_int); /* EPP ITEM2("video", "source", MCI_DGV_STATUS_VIDEO_SOURCE, _MCISTR_videosrctype); */ ITEM2("video", "stream", MCI_DGV_STATUS_VIDEO_STREAM, _MCISTR_int); ITEM1("video", MCI_DGV_STATUS_VIDEO, _MCISTR_bool); /* FIXME MCI_ON/OFF */ ITEM1("volume", MCI_DGV_STATUS_VOLUME, _MCISTR_int); ITEM2("window", "handle", MCI_DGV_STATUS_HWND, _MCISTR_int); ITEM2("window", "visible", MCI_DGV_STATUS_WINDOW_VISIBLE, _MCISTR_bool); ITEM2("window", "minimized", MCI_DGV_STATUS_WINDOW_MINIMIZED, _MCISTR_bool); ITEM2("window", "maximized",MCI_DGV_STATUS_WINDOW_MAXIMIZED , _MCISTR_bool); break; } FIXME(mci, "unknown keyword '%s'\n", keywords[i]); i++; } if (!pU->statusParams.dwItem) return MCIERR_MISSING_STRING_ARGUMENT; res = mciSendCommandA(wDevID, MCI_STATUS, dwFlags, (DWORD)pU); if (res == 0) _MCISTR_convreturn(type, pU->statusParams.dwReturn, lpstrReturnString, uReturnLength, uDevTyp, timef); free(pU); return res; } #undef ITEM1 #undef ITEM2 #undef ITEM3 #undef ITEM4 /* 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_PARMS wavesetParams; MCI_SEQ_SET_PARMS seqsetParams; }; union U* pU = xmalloc(sizeof(union U)); int i, res; pU->setParams.dwCallback = hwndCallback; for (i = 0; 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; } /* */ #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, "%u", wFormatTag); WII("channels", MCI_WAVE_SET_CHANNELS, "%u", nChannels); WII("bytespersec", MCI_WAVE_SET_AVGBYTESPERSEC, "%lu", nAvgBytesPerSec); WII("samplespersec", MCI_WAVE_SET_SAMPLESPERSEC, "%lu", nSamplesPerSec); WII("alignment", MCI_WAVE_SET_BLOCKALIGN, "%u", nBlockAlign); WII("bitspersample", MCI_WAVE_SET_BITSPERSAMPLE, "%u", wBitsPerSample); WII("input", MCI_WAVE_INPUT, "%u", wInput); WII("output", MCI_WAVE_OUTPUT, "%u", 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); #undef SII } i++; } if (!dwFlags) return MCIERR_MISSING_STRING_ARGUMENT; res = mciSendCommandA(wDevID, MCI_SET, dwFlags, (DWORD)pU); 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_) { LPMCI_BREAK_PARMS breakParams = xmalloc(sizeof(MCI_BREAK_PARMS)); int res, i; if (!breakParams) return 0; breakParams->dwCallback = hwndCallback; /*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], "%d", &(breakParams->nVirtKey)); i += 2; continue; } } res = mciSendCommandA(wDevID, MCI_BREAK, dwFlags, (DWORD)breakParams); 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 * Digital video * "can freeze" returns bool * "can lock" returns bool * "can reverse" returns bool * "can stretch" returns bool * "can stretch input" returns bool * "can test" returns bool * "has still" returns bool * "maximum play rate" returns the maximum play rate, in fps * "minimum play rate" returns the minimum play rate, in fps * "uses files" returns bool * "uses palettes" returns bool * "windows" returns nr of available windows * 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 = xmalloc(sizeof(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; for (i = 0; i < nrofkeywords; i++) { 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_DIGITAL_VIDEO: ITEM2("can", "freeze", MCI_DGV_GETDEVCAPS_CAN_FREEZE, _MCISTR_bool); ITEM2("can", "lock", MCI_DGV_GETDEVCAPS_CAN_LOCK, _MCISTR_bool); ITEM2("can", "reverse", MCI_DGV_GETDEVCAPS_CAN_REVERSE, _MCISTR_bool); ITEM3("can", "stretch", "input", MCI_DGV_GETDEVCAPS_CAN_STR_IN, _MCISTR_bool); ITEM2("can", "stretch", MCI_DGV_GETDEVCAPS_CAN_STRETCH, _MCISTR_bool); ITEM2("can", "test", MCI_DGV_GETDEVCAPS_CAN_TEST, _MCISTR_bool); ITEM2("has", "still", MCI_DGV_GETDEVCAPS_HAS_STILL, _MCISTR_bool); ITEM3("maximum", "play", "rate", MCI_DGV_GETDEVCAPS_MAXIMUM_RATE, _MCISTR_int); ITEM3("minimum", "play", "rate", MCI_DGV_GETDEVCAPS_MINIMUM_RATE, _MCISTR_int); ITEM2("uses", "files", MCI_GETDEVCAPS_USES_FILES, _MCISTR_bool); ITEM2("uses", "palettes", MCI_DGV_GETDEVCAPS_PALETTES, _MCISTR_bool); ITEM1("windows", MCI_DGV_GETDEVCAPS_MAX_WINDOWS, _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; } } res = mciSendCommandA(wDevID, MCI_GETDEVCAPS, dwFlags, (DWORD)gdcParams); /* no timeformat needed */ if (res == 0) _MCISTR_convreturn(type, gdcParams->dwReturn, lpstrReturnString, uReturnLength, uDevTyp, 0); 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 = xmalloc(sizeof(MCI_GENERIC_PARMS)); int res; genParams->dwCallback = hwndCallback; res = mciSendCommandA(wDevID, MCI_RESUME, dwFlags, (DWORD)genParams); free(genParams); return res; } /* pauses operation of device. no arguments, no return values */ static DWORD MCISTR_Pause(_MCISTR_PROTO_) { MCI_GENERIC_PARMS* genParams = xmalloc(sizeof(MCI_GENERIC_PARMS)); int res; genParams->dwCallback = hwndCallback; res = mciSendCommandA(wDevID, MCI_PAUSE, dwFlags, (DWORD)genParams); free(genParams); return res; } /* stops operation of device. no arguments, no return values */ static DWORD MCISTR_Stop(_MCISTR_PROTO_) { MCI_GENERIC_PARMS* genParams = xmalloc(sizeof(MCI_GENERIC_PARMS)); int res; genParams->dwCallback = hwndCallback; res = mciSendCommandA(wDevID, MCI_STOP, dwFlags, (DWORD)genParams); free(genParams); return res; } /* starts recording. * Arguments: * "overwrite" overwrite existing things * "insert" insert at current position * "to