[Scummvm-git-logs] scummvm master -> 0e47c5ef24e0ee688d2ebb13910e6e282f32f7e7

sev- noreply at scummvm.org
Wed Mar 29 21:49:57 UTC 2023


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
0e47c5ef24 DIRECTOR: Update MCI parser


Commit: 0e47c5ef24e0ee688d2ebb13910e6e282f32f7e7
    https://github.com/scummvm/scummvm/commit/0e47c5ef24e0ee688d2ebb13910e6e282f32f7e7
Author: Evangelos Lamprou (vagoslabrou at gmail.com)
Date: 2023-03-29T23:49:51+02:00

Commit Message:
DIRECTOR: Update MCI parser

- Updated the old MCI parser to work based on the specification described
in https://patentimages.storage.googleapis.com/ad/06/7a/48766ca9df6fbc/US6397263.pdf

- Replaced the old code to showcase how each MCI command can now be
handled through the parsed_cmd object.

Microsoft MCI documentation: https://learn.microsoft.com/en-us/windows/win32/multimedia/mci
Parser code used as reference: https://github.com/wine-mirror/wine/blob/master/dlls/winmm/mci.c

Changed paths:
  A engines/director/lingo/lingo-mci.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/module.mk


diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index cc6f2671ca6..e0add1a92f0 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -42,145 +42,6 @@
 
 namespace Director {
 
-enum MCITokenType {
-	kMCITokenNone,
-
-	kMCITokenOpen,
-	kMCITokenWait,
-	kMCITokenPlay,
-
-	kMCITokenType,
-	kMCITokenAlias,
-	kMCITokenBuffer,
-	kMCITokenFrom,
-	kMCITokenTo,
-	kMCITokenRepeat
-};
-
-struct MCIToken {
-	MCITokenType command; // Command this flag belongs to
-	MCITokenType flag;
-	const char *token;
-	int pos;  // Position of parameter to store. 0 is always filename. Negative parameters mean boolean
-} MCITokens[] = {
-	{ kMCITokenNone, kMCITokenOpen,   "open", 0 },
-	{ kMCITokenOpen, kMCITokenType,   "type", 1 },
-	{ kMCITokenOpen, kMCITokenAlias,  "alias", 2 },
-	{ kMCITokenOpen, kMCITokenBuffer, "buffer", 3 },
-
-	{ kMCITokenNone, kMCITokenPlay,   "play", 0 },
-	{ kMCITokenPlay, kMCITokenFrom,   "from", 1 },
-	{ kMCITokenPlay, kMCITokenTo,     "to", 2 },
-	{ kMCITokenPlay, kMCITokenRepeat, "repeat", -3 }, // This is boolean parameter
-
-	{ kMCITokenNone, kMCITokenWait,   "wait", 0 },
-
-	{ kMCITokenNone, kMCITokenNone,   nullptr, 0 }
-};
-
-void Lingo::func_mci(const Common::String &name) {
-	Common::String params[5];
-	MCITokenType command = kMCITokenNone;
-
-	Common::String s = name;
-	s.trim();
-	s.toLowercase();
-
-	MCITokenType state = kMCITokenNone;
-	Common::String token;
-	const char *ptr = s.c_str();
-	int respos = -1;
-
-	while (*ptr) {
-		while (*ptr && *ptr == ' ')
-			ptr++;
-
-		token.clear();
-
-		while (*ptr && *ptr != ' ')
-			token += *ptr++;
-
-		switch (state) {
-		case kMCITokenNone:
-			{
-				MCIToken *f = MCITokens;
-
-				while (f->token) {
-					if (command == f->command && token == f->token)
-						break;
-
-					f++;
-				}
-
-				if (command == kMCITokenNone) { // We caught command
-					command = f->flag; // Switching to processing this command parameters
-				} else if (f->flag == kMCITokenNone) { // Unmatched token, storing as filename
-					if (!params[0].empty())
-						warning("Duplicate filename in MCI command: %s -> %s", params[0].c_str(), token.c_str());
-					params[0] = token;
-				} else { // This is normal parameter, storing next token to designated position
-					if (f->pos > 0) { // This is normal parameter
-						state = f->flag;
-						respos = f->pos;
-					} else { // This is boolean
-						params[-f->pos] = "true";
-						state = kMCITokenNone;
-					}
-				}
-				break;
-			}
-		default:
-			params[respos] = token;
-			state = kMCITokenNone;
-			break;
-		}
-	}
-
-	switch (command) {
-	case kMCITokenOpen:
-		{
-			warning("MCI open file: %s, type: %s, alias: %s buffer: %s", params[0].c_str(), params[1].c_str(), params[2].c_str(), params[3].c_str());
-
-			Common::File *file = new Common::File();
-
-			if (!file->open(params[0])) {
-				warning("Failed to open %s", params[0].c_str());
-				delete file;
-				return;
-			}
-
-			if (params[1] == "waveaudio") {
-				Audio::AudioStream *sound = Audio::makeWAVStream(file, DisposeAfterUse::YES);
-				_audioAliases[params[2]] = sound;
-			} else {
-				warning("Unhandled audio type %s", params[2].c_str());
-			}
-		}
-		break;
-	case kMCITokenPlay:
-		{
-			warning("MCI play file: %s, from: %s, to: %s, repeat: %s", params[0].c_str(), params[1].c_str(), params[2].c_str(), params[3].c_str());
-
-			if (!_audioAliases.contains(params[0])) {
-				warning("Unknown alias %s", params[0].c_str());
-				return;
-			}
-
-			uint32 from = strtol(params[1].c_str(), nullptr, 10);
-			uint32 to = strtol(params[2].c_str(), nullptr, 10);
-
-			_vm->getCurrentWindow()->getSoundManager()->playMCI(*_audioAliases[params[0]], from, to);
-		}
-		break;
-	default:
-		warning("Unhandled MCI command: %s", s.c_str());
-	}
-}
-
-void Lingo::func_mciwait(const Common::String &name) {
-	warning("STUB: MCI wait file: %s", name.c_str());
-}
-
 void Lingo::func_goto(Datum &frame, Datum &movie, bool calledfromgo) {
 	_vm->_playbackPaused = false;
 
diff --git a/engines/director/lingo/lingo-mci.cpp b/engines/director/lingo/lingo-mci.cpp
new file mode 100644
index 00000000000..42b53814938
--- /dev/null
+++ b/engines/director/lingo/lingo-mci.cpp
@@ -0,0 +1,463 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+/*
+ *  The MCI documentation is: https://learn.microsoft.com/en-us/windows/win32/multimedia/mci
+ *  Based on sources from Wine: https://github.com/wine-mirror/wine/blob/master/dlls/winmm/mci.c
+ *  Table structure and algorithms also described in: https://patentimages.storage.googleapis.com/ad/06/7a/48766ca9df6fbc/US6397263.pdf
+ */
+
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+
+#include "director/score.h"
+#include "director/sound.h"
+#include "director/window.h"
+
+namespace Director {
+
+enum MCITokenType {
+    MCI_PLAY,
+    MCI_OPEN,
+    MCI_CLOSE,
+    MCI_STATUS,
+    MCI_RECORD,
+    MCI_SEEK,
+    MCI_STOP,
+    MCI_PAUSE,
+    MCI_GETDEVCAPS,
+    MCI_SYSINFO,
+    MCI_BREAK,
+    MCI_SOUND,
+    MCI_SAVE,
+    MCI_LOAD,
+    MCI_RESUME,
+    MCI_SET,
+    MCI_INFO,
+};
+
+
+enum MCIDataType {
+    MCI_COMMAND_HEAD,
+    MCI_END_COMMAND,
+    MCI_END_COMMAND_LIST,
+    MCI_CONSTANT,
+    MCI_END_CONSTANT,
+    MCI_RETURN, 
+
+    MCI_FLAG, 
+    MCI_INTEGER,
+    MCI_STRING,
+    MCI_RECT,
+    MCI_DWORD_PTR,
+};
+
+typedef struct MCITokenData {
+    MCIDataType type;
+    Common::String string;
+    int integer = 0;
+} MCITokenData;
+
+typedef struct MCICommand {
+    MCITokenType id;
+    uint flags = 0;
+    Common::String device; /* MCI device name */
+    Common::HashMap<Common::String, MCITokenData> parameters;
+} MCICommand;
+
+enum MCIError {
+    MCIERR_NO_ERROR,
+    MCIERR_UNRECOGNISED_COMMAND,
+    MCIERR_STRING_PARSE,
+};
+
+struct CmdTableRow {
+    const char *keystr;
+    int flag;
+    int num;
+    MCIDataType data_type;
+};
+
+static CmdTableRow table[] = {
+  {"open"            ,MCI_OPEN      ,0          ,MCI_COMMAND_HEAD },
+  {""                ,MCI_INTEGER   ,0          ,MCI_RETURN }      ,
+  {"notify"          ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  {"wait"            ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  {"type"            ,0x00002000L   ,-1         ,MCI_STRING }      ,
+  {"element"         ,0x00000200L   ,-1         ,MCI_STRING }      ,
+  {"alias"           ,0x00000400L   ,-1         ,MCI_STRING }      ,
+  {"shareable"       ,0x00000100L   ,-1         ,MCI_FLAG }        ,
+  {""                ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  {"close"           ,MCI_CLOSE     ,0          ,MCI_COMMAND_HEAD },
+  {"notify"          ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  {"wait"            ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  {""                ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  {"play"            ,MCI_PLAY      ,0          ,MCI_COMMAND_HEAD },
+  {"notify"          ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  {"wait"            ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  {"from"            ,0x00000004L   ,-1         ,MCI_INTEGER }     ,
+  {"to"              ,0x00000008L   ,-1         ,MCI_INTEGER }     ,
+  {""                ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  {"status"          ,MCI_STATUS    ,0          ,MCI_COMMAND_HEAD },
+  {""                ,MCI_DWORD_PTR ,0          ,MCI_RETURN }      ,
+  {"notify"          ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  {"wait"            ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  {""                ,0x00000100L   ,-1         ,MCI_CONSTANT }    ,
+  {"position"        ,0x00000002L   ,-1         ,MCI_INTEGER }     ,
+  {"length"          ,0x00000001L   ,-1         ,MCI_INTEGER }     ,
+  {"number of tracks",-1            ,0x00000003L,MCI_INTEGER }     ,
+  {"ready"           ,0x00000007L   ,-1         ,MCI_INTEGER }     ,
+  {"mode"            ,0x00000004L   ,-1         ,MCI_INTEGER }     ,
+  {"time format"     ,-1            ,0x00000006L,MCI_INTEGER }     ,
+  {"current track"   ,-1            ,0x00000008L,MCI_INTEGER }     ,
+  {""                ,0x00000000L   ,-1         ,MCI_END_CONSTANT },
+  { "track"          ,0x00000010L   ,-1         ,MCI_INTEGER }     ,
+  { "start"          ,0x00000200L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "record"         ,MCI_RECORD    ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { "from"           ,0x00000004L   ,-1         ,MCI_INTEGER }     ,
+  { "to"             ,0x00000008L   ,-1         ,MCI_INTEGER }     ,
+  { "insert"         ,0x00000100L   ,-1         ,MCI_FLAG }        ,
+  { "overwrite"      ,0x00000200L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "seek"           ,MCI_SEEK      ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { "to start"       ,0x00000100L   ,-1         ,MCI_FLAG }        ,
+  { "to end"         ,0x00000200L   ,-1         ,MCI_FLAG }        ,
+  { "to"             ,0x00000008L   ,-1         ,MCI_INTEGER }     ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "stop"           ,MCI_STOP      ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "pause"          ,MCI_PAUSE     ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "capability"     ,MCI_GETDEVCAPS,0          ,MCI_COMMAND_HEAD },
+  { ""               ,MCI_INTEGER   ,0          ,MCI_RETURN }      ,
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000100L   ,-1         ,MCI_CONSTANT }    ,
+  { "can record"     ,0x00000001L   ,-1         ,MCI_INTEGER }     ,
+  { "has audio"      ,0x00000002L   ,-1         ,MCI_INTEGER }     ,
+  { "has video"      ,0x00000003L   ,-1         ,MCI_INTEGER }     ,
+  { "uses files"     ,0x00000005L   ,-1         ,MCI_INTEGER }     ,
+  { "compound device",0x00000006L   ,-1         ,MCI_INTEGER }     ,
+  { "device type"    ,0x00000004L   ,-1         ,MCI_INTEGER }     ,
+  { "can eject"      ,0x00000007L   ,-1         ,MCI_INTEGER }     ,
+  { "can play"       ,0x00000008L   ,-1         ,MCI_INTEGER }     ,
+  { "can save"       ,0x00000009L   ,-1         ,MCI_INTEGER }     ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_CONSTANT },
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "info"           ,MCI_INFO      ,0          ,MCI_COMMAND_HEAD },
+  { ""               ,MCI_STRING    ,0          ,MCI_RETURN }      ,
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { "product"        ,0x00000100L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "set"            ,MCI_SET       ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { "time format"    ,0x00000400L   ,-1         ,MCI_CONSTANT }    ,
+  { "milliseconds"   ,0x00000000L   ,-1         ,MCI_INTEGER }     ,
+  { "ms"             ,0x00000000L   ,-1         ,MCI_INTEGER }     ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_CONSTANT },
+  { "door open"      ,0x00000100L   ,-1         ,MCI_FLAG }        ,
+  { "door closed"    ,0x00000200L   ,-1         ,MCI_FLAG }        ,
+  { "audio"          ,0x00000800L   ,-1         ,MCI_CONSTANT }    ,
+  { "all"            ,0x00000000L   ,-1         ,MCI_INTEGER }     ,
+  { "left"           ,0x00000001L   ,-1         ,MCI_INTEGER }     ,
+  { "right"          ,0x00000002L   ,-1         ,MCI_INTEGER }     ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_CONSTANT },
+  { "video"          ,0x00001000L   ,-1         ,MCI_FLAG }        ,
+  { "on"             ,0x00002000L   ,-1         ,MCI_FLAG }        ,
+  { "off"            ,0x00004000L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "sysinfo"        ,MCI_SYSINFO   ,0          ,MCI_COMMAND_HEAD },
+  { ""               ,MCI_STRING    ,0          ,MCI_RETURN }      ,
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { "quantity"       ,0x00000100L   ,-1         ,MCI_FLAG }        ,
+  { "open"           ,0x00000200L   ,-1         ,MCI_FLAG }        ,
+  { "installname"    ,0x00000800L   ,-1         ,MCI_FLAG }        ,
+  { "name"           ,0x00000400L   ,-1         ,MCI_INTEGER }     ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "break"          ,MCI_BREAK     ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { "on"             ,0x00000100L   ,-1         ,MCI_INTEGER }     ,
+  { "off"            ,0x00000400L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "sound"          ,MCI_SOUND     ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "save"           ,MCI_SAVE      ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000100L   ,-1         ,MCI_STRING }      ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "load"           ,MCI_LOAD      ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000100L   ,-1         ,MCI_STRING }      ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+
+  { "resume"         ,MCI_RESUME    ,0          ,MCI_COMMAND_HEAD },
+  { "notify"         ,0x00000001L   ,-1         ,MCI_FLAG }        ,
+  { "wait"           ,0x00000002L   ,-1         ,MCI_FLAG }        ,
+  { ""               ,0x00000000L   ,-1         ,MCI_END_COMMAND } ,
+  };
+
+static MCIError getString(const Common::String &name, uint &idx, Common::String &str) {
+    uint i_end; 
+    if (name[idx] == '"' || name[idx] == '\'') { /* Quoted string */
+        char quote = name[idx];
+        i_end = name.findFirstOf(quote, idx + 1);
+        if (i_end == Common::String::npos) {
+            return MCIERR_STRING_PARSE; /* Unterminated string */
+        }
+        str = name.substr(idx + 1, i_end - idx - 1);
+        idx = i_end + 2;
+    } else { /* No quotes, so just find the next space */
+        i_end = name.findFirstOf(' ', idx);
+        if (i_end == Common::String::npos) {
+            i_end = name.size();
+        }
+
+        str = name.substr(idx, i_end - idx);
+        idx = i_end + 1;
+    }
+    debugC(5, kDebugLingoExec, "get_string(): Got string \"%s\"", str.c_str());
+    return MCIERR_NO_ERROR;
+}
+
+static void createTokenList(Common::StringArray &tokenList, const Common::String &name) {
+    uint idx = 0; 
+
+    while (idx < name.size()) {
+        Common::String str;
+        MCIError err = getString(name, idx, str);
+        if (err != MCIERR_NO_ERROR) {
+            break;
+        }
+        tokenList.push_back(str);
+    }
+}
+
+static MCIError parseMCICommand(const Common::String &name, MCICommand &parsedCmd) {
+    Common::StringArray token_list;
+    createTokenList(token_list, name);
+
+    uint i_token = 0;
+    int i_table = 0;
+    int tableStart = -1, tableEnd = -1;
+
+    Common::String &verb = token_list[0];
+
+    /* Find the table section corresponding to the command's verb. */
+    for (auto& cmd : table) {
+        if ((tableStart < 0) && (cmd.data_type == MCI_COMMAND_HEAD) && (cmd.keystr == verb)) {
+            tableStart = i_table;
+        } else if ((tableStart >= 0) && (cmd.data_type == MCI_END_COMMAND)) {
+            tableEnd = i_table;
+            break;
+        }
+        i_table++;
+    }
+
+    debugC(5, kDebugLingoExec, "parseMCICommand(): tableStart: %d, tableEnd: %d", tableStart, tableEnd);
+    assert(tableStart >= 0 && tableEnd > 0);
+
+    auto cmd = table[tableStart];
+    parsedCmd.id = (MCITokenType)cmd.flag;
+    parsedCmd.flags = cmd.num;
+
+    /* The MCI device will ALWAYS be the second token. */
+    parsedCmd.device = token_list[1];
+
+    /* Parse the rest of the arguments */
+    i_token = 2;
+
+    while (i_token < token_list.size()) {
+
+        bool found = false;
+        bool inConst = false;
+        int flag, cflag;
+        CmdTableRow *cmdtable, *c_cmdtable;
+        auto& token = token_list[i_token];
+
+        for (i_table = tableStart; i_table < tableEnd; i_table++) {
+
+            MCIDataType cmd_type = table[i_table].data_type;
+            flag = table[i_table].flag;
+            cmdtable = &table[i_table];
+
+            switch (cmd_type) {
+            case MCI_CONSTANT:
+                c_cmdtable = cmdtable; 
+                inConst = true;
+                cflag = flag;
+                break;
+            case MCI_END_CONSTANT:
+                c_cmdtable = nullptr;
+                inConst = false;
+                cflag = 0;
+                break;
+            default: break;
+            }
+
+            if (token != table[i_table].keystr) 
+                continue;
+
+            found = true;
+
+            switch (cmd_type) {
+            case MCI_COMMAND_HEAD:
+            case MCI_RETURN:
+            case MCI_END_COMMAND:
+            case MCI_END_COMMAND_LIST:
+            case MCI_CONSTANT:
+            case MCI_END_CONSTANT:
+                break;
+            case MCI_FLAG:
+                parsedCmd.flags |= flag;
+                i_token++;
+                break;
+            case MCI_INTEGER: {
+                if (inConst) { /* Handle the case where we've hit a MCI_INTEGER which is inside a MCI_CONSTANT block. */
+                    MCITokenData token_data;
+                    if (parsedCmd.parameters.tryGetVal(c_cmdtable->keystr, token_data)) {
+                        token_data.integer |= flag;
+                    } else {
+                        token_data.type = MCI_CONSTANT;
+                        token_data.integer |= flag;
+                        parsedCmd.parameters[c_cmdtable->keystr] = token_data;
+                    }
+                    parsedCmd.flags |= cflag;
+                    inConst = false;
+                } else {
+                    parsedCmd.flags |= flag;
+
+                    MCITokenData token_data;
+                    token_data.type = MCI_INTEGER;
+                    token_data.integer = atoi(token_list[++i_token].c_str());
+                    parsedCmd.parameters[token] = token_data;
+                }
+                i_token++;
+                break;
+                }
+            case MCI_STRING: {
+                parsedCmd.flags |= flag;
+
+                MCITokenData token_data;
+                token_data.type = MCI_STRING;
+                token_data.string = token_list[++i_token];
+                parsedCmd.parameters[token] = token_data;
+                i_token++;
+                break;
+                }
+            default: 
+                warning("parseMCICommand(): Unhandled command type.");
+                return MCIERR_UNRECOGNISED_COMMAND;
+            }
+        }
+
+        if (!found) {
+            warning("parseMCICommand(): Parameter %s not found in table", token_list[i_token].c_str());
+            return MCIERR_UNRECOGNISED_COMMAND;
+        }
+    }
+
+    return MCIERR_NO_ERROR;
+}
+
+void Lingo::func_mci(const Common::String &name) {
+
+    MCICommand parsedCmd;
+    parseMCICommand(name, parsedCmd);
+
+    switch (parsedCmd.id) {
+    case MCI_OPEN: {
+        Common::File *file = new Common::File();
+
+        if (!file->open(parsedCmd.device)) {
+            warning("func_mci(): Failed to open %s", parsedCmd.device.c_str());
+            delete file;
+            return;
+        }
+
+        parsedCmd.parameters["type"].string.toLowercase(); /* In the case the open command type has something like WaveAudio instead of waveaudio */
+
+        if (parsedCmd.parameters["type"].string == "waveaudio") {
+            Audio::AudioStream *sound = Audio::makeWAVStream(file, DisposeAfterUse::YES);
+            if (parsedCmd.parameters.contains("alias")) {
+                _audioAliases[parsedCmd.parameters["alias"].string] = sound;
+            }
+        } else {
+            warning("func_mci(): Unhandled audio type %s", parsedCmd.parameters["type"].string.c_str());
+        }
+        }
+        break;
+    case MCI_PLAY: {
+        warning("func_mci(): MCI play file: %s, from: %d, to: %d", parsedCmd.device.c_str(), parsedCmd.parameters["from"].integer, parsedCmd.parameters["to"].integer);
+
+        if (!_audioAliases.contains(parsedCmd.device)) {
+            warning("func_mci(): Unknown alias %s", parsedCmd.device.c_str());
+            return;
+        }
+
+        uint32 from = parsedCmd.parameters["from"].integer;
+        uint32 to = parsedCmd.parameters.contains("to") ? parsedCmd.parameters["to"].integer : -1;
+
+        _vm->getCurrentWindow()->getSoundManager()->playMCI(*_audioAliases[parsedCmd.device], from, to);
+        }
+        break;
+    default:
+        warning("func_mci: Unhandled MCI command: %d", parsedCmd.id); /* TODO: Convert MCITokenType into string */
+    }
+}
+
+void Lingo::func_mciwait(const Common::String &name) {
+    warning("STUB: MCI wait file: %s", name.c_str());
+}
+
+} // End of namespace Director
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 2d0ba9ccb47..fb0d095fb49 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -34,6 +34,7 @@ MODULE_OBJS = \
 	lingo/lingo-codegen.o \
 	lingo/lingo-events.o \
 	lingo/lingo-funcs.o \
+	lingo/lingo-mci.o \
 	lingo/lingo-gr.o \
 	lingo/lingo-lex.o \
 	lingo/lingo-object.o \




More information about the Scummvm-git-logs mailing list